-
Notifications
You must be signed in to change notification settings - Fork 87
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
docs: samples and tests for admin database APIs #1099
Changes from 12 commits
4ec3c25
99367f2
dc05bfe
b5ba082
61ea41f
b18c55e
c7a5882
4f6ecce
2d8a528
f18d0e1
48e13e8
ed20cd5
eff4e82
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,351 @@ | ||
#!/usr/bin/env python | ||
|
||
# Copyright 2024 Google, Inc. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
"""This application demonstrates how to do basic operations using Cloud | ||
Spanner PostgreSql dialect. | ||
For more information, see the README.rst under /spanner. | ||
""" | ||
from google.cloud import spanner | ||
from google.cloud.spanner_admin_database_v1.types.common import DatabaseDialect | ||
|
||
OPERATION_TIMEOUT_SECONDS = 240 | ||
|
||
|
||
# [START spanner_postgresql_create_database] | ||
def create_database(instance_id, database_id): | ||
"""Creates a PostgreSql database and tables for sample data.""" | ||
|
||
from google.cloud.spanner_admin_database_v1.types import spanner_database_admin | ||
|
||
spanner_client = spanner.Client() | ||
instance = spanner_client.instance(instance_id) | ||
|
||
request = spanner_database_admin.CreateDatabaseRequest( | ||
parent=instance.name, | ||
create_statement=f'CREATE DATABASE "{database_id}"', | ||
database_dialect=DatabaseDialect.POSTGRESQL, | ||
) | ||
|
||
operation = spanner_client.database_admin_api.create_database(request=request) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @rahul2393 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We are only initializing admin clients once per client object lifecycle There is exit method in all of the autogenerated classes which get's called when object is ready for garbage collection. |
||
|
||
print("Waiting for operation to complete...") | ||
database = operation.result(OPERATION_TIMEOUT_SECONDS) | ||
|
||
create_table_using_ddl(database.name) | ||
print("Created database {} on instance {}".format(database_id, instance_id)) | ||
|
||
|
||
def create_table_using_ddl(database_name): | ||
from google.cloud.spanner_admin_database_v1.types import spanner_database_admin | ||
|
||
spanner_client = spanner.Client() | ||
request = spanner_database_admin.UpdateDatabaseDdlRequest( | ||
database=database_name, | ||
statements=[ | ||
"""CREATE TABLE Singers ( | ||
SingerId bigint NOT NULL, | ||
FirstName character varying(1024), | ||
LastName character varying(1024), | ||
SingerInfo bytea, | ||
FullName character varying(2048) | ||
GENERATED ALWAYS AS (FirstName || ' ' || LastName) STORED, | ||
PRIMARY KEY (SingerId) | ||
)""", | ||
"""CREATE TABLE Albums ( | ||
SingerId bigint NOT NULL, | ||
AlbumId bigint NOT NULL, | ||
AlbumTitle character varying(1024), | ||
PRIMARY KEY (SingerId, AlbumId) | ||
) INTERLEAVE IN PARENT Singers ON DELETE CASCADE""", | ||
], | ||
) | ||
operation = spanner_client.database_admin_api.update_database_ddl(request) | ||
operation.result(OPERATION_TIMEOUT_SECONDS) | ||
|
||
|
||
# [END spanner_postgresql_create_database] | ||
|
||
|
||
def create_table_with_datatypes(instance_id, database_id): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The existing pg_snippets already has this sample with autogenerated code. Do we still need this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes we need this because there is dependency on this sample in other tests. |
||
"""Creates a table with supported datatypes.""" | ||
# [START spanner_postgresql_create_table_with_datatypes] | ||
# instance_id = "your-spanner-instance" | ||
# database_id = "your-spanner-db-id" | ||
|
||
from google.cloud.spanner_admin_database_v1.types import spanner_database_admin | ||
|
||
spanner_client = spanner.Client() | ||
instance = spanner_client.instance(instance_id) | ||
database = instance.database(database_id) | ||
|
||
request = spanner_database_admin.UpdateDatabaseDdlRequest( | ||
database=database.name, | ||
statements=[ | ||
"""CREATE TABLE Venues ( | ||
VenueId BIGINT NOT NULL, | ||
VenueName character varying(100), | ||
VenueInfo BYTEA, | ||
Capacity BIGINT, | ||
OutdoorVenue BOOL, | ||
PopularityScore FLOAT8, | ||
Revenue NUMERIC, | ||
LastUpdateTime SPANNER.COMMIT_TIMESTAMP NOT NULL, | ||
PRIMARY KEY (VenueId))""" | ||
], | ||
) | ||
operation = spanner_client.database_admin_api.update_database_ddl(request) | ||
|
||
print("Waiting for operation to complete...") | ||
operation.result(OPERATION_TIMEOUT_SECONDS) | ||
|
||
print( | ||
"Created Venues table on database {} on instance {}".format( | ||
database_id, instance_id | ||
) | ||
) | ||
# [END spanner_postgresql_create_table_with_datatypes] | ||
|
||
|
||
# [START spanner_postgresql_add_column] | ||
def add_column(instance_id, database_id): | ||
"""Adds a new column to the Albums table in the example database.""" | ||
|
||
from google.cloud.spanner_admin_database_v1.types import spanner_database_admin | ||
|
||
spanner_client = spanner.Client() | ||
instance = spanner_client.instance(instance_id) | ||
database = instance.database(database_id) | ||
|
||
request = spanner_database_admin.UpdateDatabaseDdlRequest( | ||
database=database.name, | ||
statements=["ALTER TABLE Albums ADD COLUMN MarketingBudget BIGINT"], | ||
) | ||
operation = spanner_client.database_admin_api.update_database_ddl(request) | ||
|
||
print("Waiting for operation to complete...") | ||
operation.result(OPERATION_TIMEOUT_SECONDS) | ||
|
||
print("Added the MarketingBudget column.") | ||
|
||
|
||
# [END spanner_postgresql_add_column] | ||
|
||
|
||
# [START spanner_postgresql_jsonb_add_column] | ||
def add_jsonb_column(instance_id, database_id): | ||
""" | ||
Alters Venues tables in the database adding a JSONB column. | ||
You can create the table by running the `create_table_with_datatypes` | ||
sample or by running this DDL statement against your database: | ||
CREATE TABLE Venues ( | ||
VenueId BIGINT NOT NULL, | ||
VenueName character varying(100), | ||
VenueInfo BYTEA, | ||
Capacity BIGINT, | ||
OutdoorVenue BOOL, | ||
PopularityScore FLOAT8, | ||
Revenue NUMERIC, | ||
LastUpdateTime SPANNER.COMMIT_TIMESTAMP NOT NULL, | ||
PRIMARY KEY (VenueId)) | ||
""" | ||
# instance_id = "your-spanner-instance" | ||
# database_id = "your-spanner-db-id" | ||
|
||
from google.cloud.spanner_admin_database_v1.types import spanner_database_admin | ||
|
||
spanner_client = spanner.Client() | ||
instance = spanner_client.instance(instance_id) | ||
database = instance.database(database_id) | ||
|
||
request = spanner_database_admin.UpdateDatabaseDdlRequest( | ||
database=database.name, | ||
statements=["ALTER TABLE Venues ADD COLUMN VenueDetails JSONB"], | ||
) | ||
|
||
operation = spanner_client.database_admin_api.update_database_ddl(request) | ||
|
||
print("Waiting for operation to complete...") | ||
operation.result(OPERATION_TIMEOUT_SECONDS) | ||
|
||
print( | ||
'Altered table "Venues" on database {} on instance {}.'.format( | ||
database_id, instance_id | ||
) | ||
) | ||
|
||
|
||
# [END spanner_postgresql_jsonb_add_column] | ||
|
||
|
||
# [START spanner_postgresql_create_storing_index] | ||
def add_storing_index(instance_id, database_id): | ||
"""Adds an storing index to the example database.""" | ||
|
||
from google.cloud.spanner_admin_database_v1.types import spanner_database_admin | ||
|
||
spanner_client = spanner.Client() | ||
instance = spanner_client.instance(instance_id) | ||
database = instance.database(database_id) | ||
|
||
request = spanner_database_admin.UpdateDatabaseDdlRequest( | ||
database=database.name, | ||
statements=[ | ||
"CREATE INDEX AlbumsByAlbumTitle2 ON Albums(AlbumTitle)" | ||
"INCLUDE (MarketingBudget)" | ||
], | ||
) | ||
|
||
operation = spanner_client.database_admin_api.update_database_ddl(request) | ||
|
||
print("Waiting for operation to complete...") | ||
operation.result(OPERATION_TIMEOUT_SECONDS) | ||
|
||
print("Added the AlbumsByAlbumTitle2 index.") | ||
|
||
|
||
# [END spanner_postgresql_create_storing_index] | ||
|
||
|
||
# [START spanner_postgresql_create_sequence] | ||
def create_sequence(instance_id, database_id): | ||
"""Creates the Sequence and insert data""" | ||
|
||
from google.cloud.spanner_admin_database_v1.types import spanner_database_admin | ||
|
||
spanner_client = spanner.Client() | ||
instance = spanner_client.instance(instance_id) | ||
database = instance.database(database_id) | ||
|
||
request = spanner_database_admin.UpdateDatabaseDdlRequest( | ||
database=database.name, | ||
statements=[ | ||
"CREATE SEQUENCE Seq BIT_REVERSED_POSITIVE", | ||
"""CREATE TABLE Customers ( | ||
CustomerId BIGINT DEFAULT nextval('Seq'), | ||
CustomerName character varying(1024), | ||
PRIMARY KEY (CustomerId) | ||
)""", | ||
], | ||
) | ||
operation = spanner_client.database_admin_api.update_database_ddl(request) | ||
print("Waiting for operation to complete...") | ||
operation.result(OPERATION_TIMEOUT_SECONDS) | ||
|
||
print( | ||
"Created Seq sequence and Customers table, where the key column CustomerId uses the sequence as a default value on database {} on instance {}".format( | ||
database_id, instance_id | ||
) | ||
) | ||
|
||
def insert_customers(transaction): | ||
results = transaction.execute_sql( | ||
"INSERT INTO Customers (CustomerName) VALUES " | ||
"('Alice'), " | ||
"('David'), " | ||
"('Marc') " | ||
"RETURNING CustomerId" | ||
) | ||
for result in results: | ||
print("Inserted customer record with Customer Id: {}".format(*result)) | ||
print( | ||
"Number of customer records inserted is {}".format( | ||
results.stats.row_count_exact | ||
) | ||
) | ||
|
||
database.run_in_transaction(insert_customers) | ||
|
||
|
||
# [END spanner_postgresql_create_sequence] | ||
|
||
|
||
# [START spanner_postgresql_alter_sequence] | ||
def alter_sequence(instance_id, database_id): | ||
"""Alters the Sequence and insert data""" | ||
|
||
from google.cloud.spanner_admin_database_v1.types import spanner_database_admin | ||
|
||
spanner_client = spanner.Client() | ||
instance = spanner_client.instance(instance_id) | ||
database = instance.database(database_id) | ||
|
||
request = spanner_database_admin.UpdateDatabaseDdlRequest( | ||
database=database.name, | ||
statements=["ALTER SEQUENCE Seq SKIP RANGE 1000 5000000"], | ||
) | ||
operation = spanner_client.database_admin_api.update_database_ddl(request) | ||
|
||
print("Waiting for operation to complete...") | ||
operation.result(OPERATION_TIMEOUT_SECONDS) | ||
|
||
print( | ||
"Altered Seq sequence to skip an inclusive range between 1000 and 5000000 on database {} on instance {}".format( | ||
database_id, instance_id | ||
) | ||
) | ||
|
||
def insert_customers(transaction): | ||
results = transaction.execute_sql( | ||
"INSERT INTO Customers (CustomerName) VALUES " | ||
"('Lea'), " | ||
"('Cataline'), " | ||
"('Smith') " | ||
"RETURNING CustomerId" | ||
) | ||
for result in results: | ||
print("Inserted customer record with Customer Id: {}".format(*result)) | ||
print( | ||
"Number of customer records inserted is {}".format( | ||
results.stats.row_count_exact | ||
) | ||
) | ||
|
||
database.run_in_transaction(insert_customers) | ||
|
||
|
||
# [END spanner_postgresql_alter_sequence] | ||
|
||
|
||
# [START spanner_postgresql_drop_sequence] | ||
def drop_sequence(instance_id, database_id): | ||
"""Drops the Sequence""" | ||
|
||
from google.cloud.spanner_admin_database_v1.types import spanner_database_admin | ||
|
||
spanner_client = spanner.Client() | ||
instance = spanner_client.instance(instance_id) | ||
database = instance.database(database_id) | ||
|
||
request = spanner_database_admin.UpdateDatabaseDdlRequest( | ||
database=database.name, | ||
statements=[ | ||
"ALTER TABLE Customers ALTER COLUMN CustomerId DROP DEFAULT", | ||
"DROP SEQUENCE Seq", | ||
], | ||
) | ||
operation = spanner_client.database_admin_api.update_database_ddl(request) | ||
|
||
print("Waiting for operation to complete...") | ||
operation.result(OPERATION_TIMEOUT_SECONDS) | ||
|
||
print( | ||
"Altered Customers table to drop DEFAULT from CustomerId column and dropped the Seq sequence on database {} on instance {}".format( | ||
database_id, instance_id | ||
) | ||
) | ||
|
||
|
||
# [END spanner_postgresql_drop_sequence] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will we be adding
create_database
sample for postgres? I think that is needed for customers to understand how to set a PG database.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added