forked from aws-samples/aws-dynamodb-examples
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request aws-samples#152 from mkamioner/python-conditional-…
…samples Python conditional samples
- Loading branch information
Showing
2 changed files
with
153 additions
and
4 deletions.
There are no files selected for viewing
50 changes: 48 additions & 2 deletions
50
examples/SDK/python/data_plane/WorkingWithItems/put_item_conditional.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,48 @@ | ||
import boto3, json | ||
from boto3.dynamodb.conditions import Key | ||
from __future__ import print_function # Python 2/3 compatibility | ||
import boto3 | ||
from boto3.dynamodb.conditions import Attr | ||
from botocore.exceptions import ClientError | ||
|
||
dynamodb = boto3.resource("dynamodb", region_name="us-west-2") | ||
table = dynamodb.Table("RetailDatabase") | ||
|
||
|
||
def create_item_if_not_exist(created_at): | ||
try: | ||
table.put_item( | ||
Item={ | ||
"pk": "jim.bob@somewhere.com", | ||
"sk": "metadata", | ||
"name": "Jim Bob", | ||
"first_name": "Jim", | ||
"last_name": "Bob", | ||
"created_at": created_at, | ||
}, | ||
# If this item exists, then an item exists with this pk and/or sk so we should fail if | ||
# we see a matching item with this pk. | ||
ConditionExpression=Attr("pk").not_exists(), | ||
) | ||
except dynamodb.meta.client.exceptions.ConditionalCheckFailedException: | ||
print("PutItem failed since the item already exists") | ||
return False | ||
|
||
print("PutItem succeeded") | ||
return True | ||
|
||
|
||
def get_created_at(email): | ||
response = table.get_item( | ||
Key={"pk": email, "sk": "metadata"}, | ||
AttributesToGet=["created_at"], | ||
) | ||
return response.get("Item", {}).get("created_at") | ||
|
||
|
||
print("The first PutItem should succeed because the item does not exist") | ||
assert create_item_if_not_exist(100) | ||
|
||
print("The same PutItem command should now fail because the item already exists") | ||
assert not create_item_if_not_exist(200) | ||
|
||
assert get_created_at("jim.bob@somewhere.com") == 100 | ||
print("As expected, The second PutItem command failed and the data was not overwritten") |
107 changes: 105 additions & 2 deletions
107
examples/SDK/python/data_plane/WorkingWithItems/update_item_conditional.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,105 @@ | ||
import boto3, json | ||
from boto3.dynamodb.conditions import Key | ||
from __future__ import print_function # Python 2/3 compatibility | ||
import boto3 | ||
from boto3.dynamodb.conditions import Attr | ||
from botocore.exceptions import ClientError | ||
|
||
dynamodb = boto3.resource("dynamodb", region_name="us-west-2") | ||
table = dynamodb.Table("RetailDatabase") | ||
|
||
|
||
class ConditionalCheckFailedError(Exception): | ||
""" | ||
An error indicating that a DynamoDB conditional check failed. | ||
Wrapped as a separate error for readability. | ||
""" | ||
|
||
|
||
def delete_item(email): | ||
response = table.delete_item( | ||
Key={ | ||
"pk": email, | ||
"sk": "metadata", | ||
}, | ||
) | ||
|
||
|
||
def create_user(email, name): | ||
initial_change_version = 0 | ||
|
||
try: | ||
table.put_item( | ||
Item={ | ||
"pk": email, | ||
"sk": "metadata", | ||
"name": name, | ||
"change_version": initial_change_version, | ||
}, | ||
ConditionExpression=Attr("pk").not_exists(), | ||
) | ||
except dynamodb.meta.client.exceptions.ConditionalCheckFailedException as e: | ||
raise ConditionalCheckFailedError() from e | ||
|
||
return initial_change_version | ||
|
||
|
||
def update_name(email, name, last_change_version): | ||
try: | ||
response = table.update_item( | ||
Key={"pk": email, "sk": "metadata"}, | ||
UpdateExpression="SET #n = :nm, #cv = #cv + :one", | ||
ExpressionAttributeNames={"#n": "name", "#cv": "change_version"}, | ||
ExpressionAttributeValues={":nm": name, ":one": 1}, | ||
ReturnValues="UPDATED_NEW", | ||
ConditionExpression=Attr("change_version").eq(last_change_version), | ||
) | ||
except dynamodb.meta.client.exceptions.ConditionalCheckFailedException as e: | ||
raise ConditionalCheckFailedError() from e | ||
|
||
return int(response.get("Attributes", {}).get("change_version")) | ||
|
||
|
||
def get_user(email): | ||
response = table.get_item( | ||
Key={"pk": email, "sk": "metadata"}, | ||
AttributesToGet=["name", "change_version"], | ||
) | ||
return { | ||
"email": email, | ||
"name": response["Item"]["name"], | ||
"change_version": int(response["Item"]["change_version"]), | ||
} | ||
|
||
|
||
def main(): | ||
delete_item("jim.bob@somewhere.com") | ||
|
||
print("Creating an item with change_version = 0") | ||
last_change_version = create_user("jim.bob@somewhere.com", "Jim Bob") | ||
current_user = get_user("jim.bob@somewhere.com") | ||
print("current_user = ", current_user) | ||
|
||
print("Change the user's name") | ||
last_change_version = update_name( | ||
"jim.bob@somewhere.com", "Jim Roberts", last_change_version | ||
) | ||
current_user = get_user("jim.bob@somewhere.com") | ||
print("current_user = ", current_user) | ||
|
||
print( | ||
"Try to update the name with an old change_version imitating a race condition" | ||
) | ||
try: | ||
last_change_version = update_name( | ||
"jim.bob@somewhere.com", "Jonathan Roberts", last_change_version - 1 | ||
) | ||
except ConditionalCheckFailedError: | ||
print("Yup, this failed as expected, the user information did not change") | ||
else: | ||
raise RuntimeError("This should have failed") | ||
|
||
current_user = get_user("jim.bob@somewhere.com") | ||
print("current_user = ", current_user) | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |