Skip to content
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

Added Spanner DML/PDML samples. #1742

Merged
merged 2 commits into from
Oct 10, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion spanner/cloud-client/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
google-cloud-spanner==1.4.0
google-cloud-spanner==1.6.0
futures==3.2.0; python_version < "3"
311 changes: 311 additions & 0 deletions spanner/cloud-client/snippets.py
Original file line number Diff line number Diff line change
Expand Up @@ -748,6 +748,273 @@ def query_nested_struct_field(instance_id, database_id):
# [END spanner_field_access_on_nested_struct_parameters]


def insert_data_with_dml(instance_id, database_id):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally we'd show example values for instance_id and database_id

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm I had them on the internal changes, I'm not sure how I lost them. I'll re-update.

"""Inserts sample data into the given database using a DML statement. """
# [START spanner_dml_standard_insert]
# instance_id = "your-spanner-instance"
# database_id = "your-spanner-db-id"

spanner_client = spanner.Client()
instance = spanner_client.instance(instance_id)
database = instance.database(database_id)

def insert_singers(transaction):
row_ct = transaction.execute_update(
"INSERT Singers (SingerId, FirstName, LastName) "
" VALUES (10, 'Virginia', 'Watson')"
)

print("{} record(s) inserted.".format(row_ct))

database.run_in_transaction(insert_singers)
# [END spanner_dml_standard_insert]


def update_data_with_dml(instance_id, database_id):
"""Updates sample data from the database using a DML statement. """
# [START spanner_dml_standard_update]
# instance_id = "your-spanner-instance"
# database_id = "your-spanner-db-id"

spanner_client = spanner.Client()
instance = spanner_client.instance(instance_id)
database = instance.database(database_id)

def update_albums(transaction):
row_ct = transaction.execute_update(
"UPDATE Albums "
"SET MarketingBudget = MarketingBudget * 2 "
"WHERE SingerId = 1 and AlbumId = 1"
)

print("{} record(s) updated.".format(row_ct))

database.run_in_transaction(update_albums)
# [END spanner_dml_standard_update]


def delete_data_with_dml(instance_id, database_id):
"""Deletes sample data from the database using a DML statement. """
# [START spanner_dml_standard_delete]
# instance_id = "your-spanner-instance"
# database_id = "your-spanner-db-id"

spanner_client = spanner.Client()
instance = spanner_client.instance(instance_id)
database = instance.database(database_id)

def delete_singers(transaction):
row_ct = transaction.execute_update(
"DELETE Singers WHERE FirstName = 'Alice'"
)

print("{} record(s) deleted.".format(row_ct))

database.run_in_transaction(delete_singers)
# [END spanner_dml_standard_delete]


def update_data_with_dml_timestamp(instance_id, database_id):
"""Updates data with Timestamp from the database using a DML statement. """
# [START spanner_dml_standard_update_with_timestamp]
# instance_id = "your-spanner-instance"
# database_id = "your-spanner-db-id"

spanner_client = spanner.Client()
instance = spanner_client.instance(instance_id)
database = instance.database(database_id)

def update_albums(transaction):
row_ct = transaction.execute_update(
"UPDATE Albums "
"SET LastUpdateTime = PENDING_COMMIT_TIMESTAMP() "
"WHERE SingerId = 1"
)

print("{} record(s) updated.".format(row_ct))

database.run_in_transaction(update_albums)
# [END spanner_dml_standard_update_with_timestamp]


def dml_write_read_transaction(instance_id, database_id):
"""First inserts data then reads it from within a transaction using DML."""
# [START spanner_dml_write_then_read]
# instance_id = "your-spanner-instance"
# database_id = "your-spanner-db-id"

spanner_client = spanner.Client()
instance = spanner_client.instance(instance_id)
database = instance.database(database_id)

def read_then_write(transaction):
# Insert record.
row_ct = transaction.execute_update(
"INSERT Singers (SingerId, FirstName, LastName) "
" VALUES (11, 'Timothy', 'Campbell')"
)
print("{} record(s) inserted.".format(row_ct))

# Read newly inserted record.
results = transaction.execute_sql(
"SELECT FirstName, LastName FROM Singers WHERE SingerId = 11"
)
for result in results:
print("FirstName: {}, LastName: {}".format(*result))

database.run_in_transaction(read_then_write)
# [END spanner_dml_write_then_read]


def update_data_with_dml_struct(instance_id, database_id):
"""Updates data with a DML statement and STRUCT parameters. """
# [START spanner_dml_structs]
# instance_id = "your-spanner-instance"
# database_id = "your-spanner-db-id"

spanner_client = spanner.Client()
instance = spanner_client.instance(instance_id)
database = instance.database(database_id)

record_type = param_types.Struct([
param_types.StructField('FirstName', param_types.STRING),
param_types.StructField('LastName', param_types.STRING)
])
record_value = ('Timothy', 'Campbell')

def write_with_struct(transaction):
row_ct = transaction.execute_update(
"UPDATE Singers SET LastName = 'Grant' "
"WHERE STRUCT<FirstName STRING, LastName STRING>"
"(FirstName, LastName) = @name",
params={'name': record_value},
param_types={'name': record_type}
)
print("{} record(s) updated.".format(row_ct))

database.run_in_transaction(write_with_struct)
# [END spanner_dml_structs]


def insert_with_dml(instance_id, database_id):
"""Inserts data with a DML statement into the database. """
# [START spanner_dml_getting_started_insert]
# instance_id = "your-spanner-instance"
# database_id = "your-spanner-db-id"
spanner_client = spanner.Client()
instance = spanner_client.instance(instance_id)
database = instance.database(database_id)

def insert_singers(transaction):
row_ct = transaction.execute_update(
"INSERT Singers (SingerId, FirstName, LastName) VALUES "
"(12, 'Melissa', 'Garcia'), "
"(13, 'Russell', 'Morales'), "
"(14, 'Jacqueline', 'Long'), "
"(15, 'Dylan', 'Shaw')"
)
print("{} record(s) inserted.".format(row_ct))

database.run_in_transaction(insert_singers)
# [END spanner_dml_getting_started_insert]


def write_with_dml_transaction(instance_id, database_id):
""" Transfers a marketing budget from one album to another. """
# [START spanner_dml_getting_started_update]
# instance_id = "your-spanner-instance"
# database_id = "your-spanner-db-id"

spanner_client = spanner.Client()
instance = spanner_client.instance(instance_id)
database = instance.database(database_id)

def transfer_budget(transaction):
# Transfer marketing budget from one album to another. Performed in a
# single transaction to ensure that the transfer is atomic.
first_album_result = transaction.execute_sql(
"SELECT MarketingBudget from Albums "
"WHERE SingerId = 1 and AlbumId = 1"
)
first_album_row = list(first_album_result)[0]
first_album_budget = first_album_row[0]

transfer_amount = 300000

# Transaction will only be committed if this condition still holds at
# the time of commit. Otherwise it will be aborted and the callable
# will be rerun by the client library
if first_album_budget >= transfer_amount:
second_album_result = transaction.execute_sql(
"SELECT MarketingBudget from Albums "
"WHERE SingerId = 1 and AlbumId = 1"
)
second_album_row = list(second_album_result)[0]
second_album_budget = second_album_row[0]

first_album_budget -= transfer_amount
second_album_budget += transfer_amount

# Update first album
transaction.execute_update(
"UPDATE Albums "
"SET MarketingBudget = @AlbumBudget "
"WHERE SingerId = 1 and AlbumId = 1",
params={"AlbumBudget": first_album_budget},
param_types={"AlbumBudget": spanner.param_types.INT64}
)

# Update second album
transaction.execute_update(
"UPDATE Albums "
"SET MarketingBudget = @AlbumBudget "
"WHERE SingerId = 2 and AlbumId = 2",
params={"AlbumBudget": second_album_budget},
param_types={"AlbumBudget": spanner.param_types.INT64}
)

print("Transferred {} from Album1's budget to Album2's".format(
transfer_amount))

database.run_in_transaction(transfer_budget)
# [END spanner_dml_getting_started_update]


def update_data_with_partitioned_dml(instance_id, database_id):
""" Update sample data with a partitioned DML statement. """
# [START spanner_dml_partitioned_update]
# instance_id = "your-spanner-instance"
# database_id = "your-spanner-db-id"

spanner_client = spanner.Client()
instance = spanner_client.instance(instance_id)
database = instance.database(database_id)

row_ct = database.execute_partitioned_dml(
"UPDATE Albums SET MarketingBudget = 100000 WHERE SingerId > 1"
)

print("{} records updated.".format(row_ct))
# [END spanner_dml_partitioned_update]


def delete_data_with_partitioned_dml(instance_id, database_id):
""" Delete sample data with a partitioned DML statement. """
# [START spanner_dml_partitioned_delete]
# instance_id = "your-spanner-instance"
# database_id = "your-spanner-db-id"
spanner_client = spanner.Client()
instance = spanner_client.instance(instance_id)
database = instance.database(database_id)

row_ct = database.execute_partitioned_dml(
"DELETE Singers WHERE SingerId > 10"
)

print("{} record(s) deleted.".format(row_ct))
# [END spanner_dml_partitioned_delete]


if __name__ == '__main__': # noqa: C901
parser = argparse.ArgumentParser(
description=__doc__,
Expand Down Expand Up @@ -802,6 +1069,30 @@ def query_nested_struct_field(instance_id, database_id):
'query_struct_field', help=query_struct_field.__doc__)
subparsers.add_parser(
'query_nested_struct_field', help=query_nested_struct_field.__doc__)
subparsers.add_parser(
'insert_data_with_dml', help=insert_data_with_dml.__doc__)
subparsers.add_parser(
'update_data_with_dml', help=update_data_with_dml.__doc__)
subparsers.add_parser(
'delete_data_with_dml', help=delete_data_with_dml.__doc__)
subparsers.add_parser(
'update_data_with_dml_timestamp',
help=update_data_with_dml_timestamp.__doc__)
subparsers.add_parser(
'dml_write_read_transaction',
help=dml_write_read_transaction.__doc__)
subparsers.add_parser(
'update_data_with_dml_struct',
help=update_data_with_dml_struct.__doc__)
subparsers.add_parser('insert_with_dml', help=insert_with_dml.__doc__)
subparsers.add_parser(
'write_with_dml_transaction', help=write_with_dml_transaction.__doc__)
subparsers.add_parser(
'update_data_with_partitioned_dml',
help=update_data_with_partitioned_dml.__doc__)
subparsers.add_parser(
'delete_data_with_partitioned_dml',
help=delete_data_with_partitioned_dml.__doc__)

args = parser.parse_args()

Expand Down Expand Up @@ -857,3 +1148,23 @@ def query_nested_struct_field(instance_id, database_id):
query_struct_field(args.instance_id, args.database_id)
elif args.command == 'query_nested_struct_field':
query_nested_struct_field(args.instance_id, args.database_id)
elif args.command == 'insert_data_with_dml':
insert_data_with_dml(args.instance_id, args.database_id)
elif args.command == 'update_data_with_dml':
update_data_with_dml(args.instance_id, args.database_id)
elif args.command == 'delete_data_with_dml':
delete_data_with_dml(args.instance_id, args.database_id)
elif args.command == 'update_data_with_dml_timestamp':
update_data_with_dml_timestamp(args.instance_id, args.database_id)
elif args.command == 'dml_write_read_transaction':
dml_write_read_transaction(args.instance_id, args.database_id)
elif args.command == 'update_data_with_dml_struct':
update_data_with_dml_struct(args.instance_id, args.database_id)
elif args.command == 'insert_with_dml':
insert_with_dml(args.instance_id, args.database_id)
elif args.command == 'write_with_dml_transaction':
write_with_dml_transaction(args.instance_id, args.database_id)
elif args.command == 'update_data_with_partitioned_dml':
update_data_with_partitioned_dml(args.instance_id, args.database_id)
elif args.command == 'delete_data_with_partitioned_dml':
delete_data_with_partitioned_dml(args.instance_id, args.database_id)
61 changes: 61 additions & 0 deletions spanner/cloud-client/snippets_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,3 +209,64 @@ def test_query_nested_struct_field(capsys):
out, _ = capsys.readouterr()
assert 'SingerId: 6 SongName: Imagination' in out
assert 'SingerId: 9 SongName: Imagination' in out


def test_insert_data_with_dml(capsys):
snippets.insert_data_with_dml(INSTANCE_ID, DATABASE_ID)
out, _ = capsys.readouterr()
assert '1 record(s) inserted.' in out


def test_update_data_with_dml(capsys):
snippets.update_data_with_dml(INSTANCE_ID, DATABASE_ID)
out, _ = capsys.readouterr()
assert '1 record(s) updated.' in out


def test_delete_data_with_dml(capsys):
snippets.delete_data_with_dml(INSTANCE_ID, DATABASE_ID)
out, _ = capsys.readouterr()
assert '1 record(s) deleted.' in out


def test_update_data_with_dml_timestamp(capsys):
snippets.update_data_with_dml_timestamp(INSTANCE_ID, DATABASE_ID)
out, _ = capsys.readouterr()
assert '2 record(s) updated.' in out


def test_dml_write_read_transaction(capsys):
snippets.dml_write_read_transaction(INSTANCE_ID, DATABASE_ID)
out, _ = capsys.readouterr()
assert '1 record(s) inserted.' in out
assert 'FirstName: Timothy, LastName: Campbell' in out


def test_update_data_with_dml_struct(capsys):
snippets.update_data_with_dml_struct(INSTANCE_ID, DATABASE_ID)
out, _ = capsys.readouterr()
assert '1 record(s) updated' in out


def test_insert_with_dml(capsys):
snippets.insert_with_dml(INSTANCE_ID, DATABASE_ID)
out, _ = capsys.readouterr()
assert '4 record(s) inserted' in out


def test_write_with_dml_transaction(capsys):
snippets.write_with_dml_transaction(INSTANCE_ID, DATABASE_ID)
out, _ = capsys.readouterr()
assert "Transferred 300000 from Album1's budget to Album2's" in out


def update_data_with_partitioned_dml(capsys):
snippets.update_data_with_partitioned_dml(INSTANCE_ID, DATABASE_ID)
out, _ = capsys.readouterr()
assert "3 record(s) updated" in out


def delete_data_with_partitioned_dml(capsys):
snippets.delete_data_with_partitioned_dml(INSTANCE_ID, DATABASE_ID)
out, _ = capsys.readouterr()
assert "5 record(s) deleted" in out