Skip to content

Commit fc72b5d

Browse files
author
Lucas McDonald
committed
m
1 parent 2ed1a0e commit fc72b5d

File tree

2 files changed

+51
-125
lines changed

2 files changed

+51
-125
lines changed

DynamoDbEncryption/runtimes/python/src/aws_database_encryption_sdk/internal/client_to_resource.py

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,44 +13,64 @@ def __init__(self, delete_table_name = True):
1313
)
1414

1515
def condition_handler(self, expression_key, request):
16+
"""Returns the input condition/names/values as-is."""
17+
# Conditions do not need to be converted from strings to boto3 Attrs.
18+
# Resources accept either strings or Attrs.
19+
condition = request[expression_key]
20+
21+
# This conversion in client_to_resource does not update ExpressionAttributeNames nor ExpressionAttributeValues.
22+
# However, resource_to_client condition_handler may add new ExpressionAttributeNames and ExpressionAttributeValues.
23+
# Smithy-generated code expects condition_handlers to return ExpressionAttributeNames and ExpressionAttributeValues.
1624
try:
17-
identity_names = request["ExpressionAttributeNames"]
25+
names = request["ExpressionAttributeNames"]
1826
except KeyError:
19-
identity_names = {}
27+
names = None
2028

2129
try:
22-
identity_values = request["ExpressionAttributeValues"]
30+
values = request["ExpressionAttributeValues"]
2331
except KeyError:
24-
identity_values = {}
25-
return request[expression_key], identity_names, identity_values
32+
values = None
33+
return condition, names, values
2634

2735
def put_item_request(self, put_item_request):
28-
# out = super().put_item_request(put_item_request)
2936
out = self.boto3_converter.PutItemInput(put_item_request)
37+
# put_item requests on a boto3.resource.Table do not have a table name.
3038
if self.delete_table_name:
3139
del out["TableName"]
3240
return out
3341

42+
def put_item_response(self, put_item_response):
43+
return self.boto3_converter.PutItemOutput(put_item_response)
44+
3445
def get_item_request(self, get_item_request):
35-
# out = super().get_item_request(get_item_request)
3646
out = self.boto3_converter.GetItemInput(get_item_request)
47+
# get_item requests on a boto3.resource.Table do not have a table name.
3748
if self.delete_table_name:
3849
del out["TableName"]
3950
return out
4051

52+
def get_item_response(self, get_item_response):
53+
return self.boto3_converter.GetItemOutput(get_item_response)
54+
4155
def query_request(self, query_request):
42-
# out = super().query_request(query_request)
4356
out = self.boto3_converter.QueryInput(query_request)
57+
# query requests on a boto3.resource.Table do not have a table name.
4458
if self.delete_table_name:
4559
del out["TableName"]
4660
return out
61+
62+
def query_response(self, query_response):
63+
return self.boto3_converter.QueryOutput(query_response)
4764

4865
def scan_request(self, scan_request):
49-
# out = super().scan_request(scan_request)
5066
out = self.boto3_converter.ScanInput(scan_request)
67+
# scan requests on a boto3.resource.Table do not have a table name.
5168
if self.delete_table_name:
5269
del out["TableName"]
5370
return out
71+
72+
def scan_response(self, scan_response):
73+
return self.boto3_converter.ScanOutput(scan_response)
5474

5575
def transact_get_items_request(self, transact_get_items_request):
5676
return self.boto3_converter.TransactGetItemsInput(transact_get_items_request)
@@ -75,17 +95,4 @@ def batch_write_item_request(self, batch_write_item_request):
7595

7696
def batch_write_item_response(self, batch_write_item_response):
7797
return self.boto3_converter.BatchWriteItemOutput(batch_write_item_response)
78-
79-
def scan_response(self, scan_response):
80-
return self.boto3_converter.ScanOutput(scan_response)
81-
82-
def query_response(self, query_response):
83-
return self.boto3_converter.QueryOutput(query_response)
84-
85-
def get_item_response(self, get_item_response):
86-
return self.boto3_converter.GetItemOutput(get_item_response)
87-
88-
def put_item_response(self, put_item_response):
89-
return self.boto3_converter.PutItemOutput(put_item_response)
90-
9198

DynamoDbEncryption/runtimes/python/src/aws_database_encryption_sdk/internal/resource_to_client.py

Lines changed: 22 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -10,29 +10,17 @@ class ResourceShapeToClientShapeConverter:
1010
def __init__(self, table_name = None):
1111
self.boto3_converter = InternalBoto3DynamoDBFormatConverter(
1212
item_handler=TypeSerializer().serialize,
13-
condition_handler=self._unpack_built_condition_expression2
13+
condition_handler=self.condition_handler
1414
)
1515
self.table_name = table_name
1616
self.expression_builder = InternalDBESDKDynamoDBConditionExpressionBuilder()
1717

18-
def _unpack_built_condition_expression(self, request_to_update, expression_key):
19-
built_condition_expression = request_to_update[expression_key]
20-
request_to_update[expression_key] = built_condition_expression.condition_expression
21-
attribute_names_from_built_expression = built_condition_expression.attribute_name_placeholders
22-
# Join any placeholder ExpressionAttributeNames with any other ExpressionAttributeNames
23-
try:
24-
request_to_update["ExpressionAttributeNames"] = request_to_update["ExpressionAttributeNames"] | attribute_names_from_built_expression
25-
except KeyError:
26-
request_to_update["ExpressionAttributeNames"] = attribute_names_from_built_expression
27-
# BuiltConditionExpression stores values in resource format; convert to client format before joining
28-
attribute_values_from_built_expression = dict_to_ddb(built_condition_expression.attribute_value_placeholders)
29-
try:
30-
request_to_update["ExpressionAttributeValues"] = request_to_update["ExpressionAttributeValues"] | attribute_values_from_built_expression
31-
except KeyError:
32-
request_to_update["ExpressionAttributeValues"] = attribute_values_from_built_expression
33-
34-
def _unpack_built_condition_expression2(self, expression_key, request):
18+
def condition_handler(self, expression_key, request):
19+
"""Converts an object from boto3.dynamodb.conditions to a string
20+
and updates ExpressionAttributeNames and ExpressionAttributeValues with any new names/values.
21+
The ExpressionAttributeValues are returned in resource format (Python dictionaries)."""
3522
condition_expression = request[expression_key]
23+
3624
try:
3725
existing_expression_attribute_names = request["ExpressionAttributeNames"]
3826
except KeyError:
@@ -42,19 +30,28 @@ def _unpack_built_condition_expression2(self, expression_key, request):
4230
except KeyError:
4331
existing_expression_attribute_values = {}
4432

33+
# Only convert if the condition expression is a boto3.dynamodb.conditions object.
34+
# Resources also accept strings.
35+
# If condition is not from boto3.dynamodb.conditions, assume the condition is string-like, and return as-is.
4536
if hasattr(condition_expression, "__module__") and condition_expression.__module__ == "boto3.dynamodb.conditions":
4637
built_condition_expression = self.expression_builder.build_expression(condition_expression, existing_expression_attribute_names, existing_expression_attribute_values)
4738
else:
4839
return condition_expression, existing_expression_attribute_names, existing_expression_attribute_values
4940

41+
# Unpack returned BuiltConditionExpression.
5042
expression_str = built_condition_expression.condition_expression
5143
attribute_names_from_built_expression = built_condition_expression.attribute_name_placeholders
52-
# Join any placeholder ExpressionAttributeNames with any other ExpressionAttributeNames
44+
# Join any placeholder ExpressionAttributeNames with any other ExpressionAttributeNames.
45+
# The BuiltConditionExpression will return new names, not any that already exist.
46+
# The two sets of names must be joined to form the complete set of names for the condition expression.
5347
try:
5448
out_names = request["ExpressionAttributeNames"] | attribute_names_from_built_expression
5549
except KeyError:
5650
out_names = attribute_names_from_built_expression
57-
# BuiltConditionExpression stores values in resource format; convert to client format before joining
51+
# Join existing and new values.
52+
# BuiltConditionExpression returns values in resource format, but the request provides values in client format.
53+
# The Smithy-generated code will handle converting the values from client to resource format.
54+
# Convert the values to client format before joining.
5855
attribute_values_from_built_expression = dict_to_ddb(built_condition_expression.attribute_value_placeholders)
5956
try:
6057
out_values = request["ExpressionAttributeValues"] | attribute_values_from_built_expression
@@ -63,60 +60,32 @@ def _unpack_built_condition_expression2(self, expression_key, request):
6360

6461
return expression_str, out_names, out_values
6562

66-
def item(self, item):
67-
return dict_to_ddb(item)
68-
69-
def key_to_attribute_value_map(self, key_to_attribute_value):
70-
return dict_to_ddb(key_to_attribute_value)
71-
72-
def attribute_value(self, attribute_value):
73-
serializer = TypeSerializer()
74-
return serializer.serialize(attribute_value)
75-
76-
# def put_item_request(self, put_item_request):
77-
# if not self.table_name:
78-
# raise ValueError("Table name must be provided to ResourceShapeToClientShapeConverter to use put_item")
79-
# put_item_request["TableName"] = self.table_name
80-
# super_conversion = super().put_item_request(put_item_request)
81-
# if "ConditionExpression" in super_conversion and isinstance(super_conversion["ConditionExpression"], BuiltConditionExpression):
82-
# self._unpack_built_condition_expression(super_conversion, "ConditionExpression")
83-
# return super_conversion
84-
8563
def put_item_request(self, put_item_request):
64+
# put_item requests on a boto3.resource.Table require a configured table name.
8665
if not self.table_name:
8766
raise ValueError("Table name must be provided to ResourceShapeToClientShapeConverter to use put_item")
8867
put_item_request["TableName"] = self.table_name
8968
return self.boto3_converter.PutItemInput(put_item_request)
90-
# if "ConditionExpression" in super_conversion and isinstance(super_conversion["ConditionExpression"], BuiltConditionExpression):
91-
# self._unpack_built_condition_expression(super_conversion, "ConditionExpression")
92-
69+
9370
def get_item_request(self, get_item_request):
71+
# get_item requests on a boto3.resource.Table require a configured table name.
9472
if not self.table_name:
9573
raise ValueError("Table name must be provided to ResourceShapeToClientShapeConverter to use get_item")
9674
get_item_request["TableName"] = self.table_name
97-
# return super().get_item_request(get_item_request)
9875
return self.boto3_converter.GetItemInput(get_item_request)
9976

10077
def query_request(self, query_request):
78+
# query requests on a boto3.resource.Table require a configured table name.
10179
if not self.table_name:
10280
raise ValueError("Table name must be provided to ResourceShapeToClientShapeConverter to use query")
10381
query_request["TableName"] = self.table_name
104-
# super_conversion = super().query_request(query_request)
105-
# if "KeyConditionExpression" in super_conversion and isinstance(super_conversion["KeyConditionExpression"], BuiltConditionExpression):
106-
# self._unpack_built_condition_expression(super_conversion, "KeyConditionExpression")
107-
# if "FilterExpression" in super_conversion and isinstance(super_conversion["FilterExpression"], BuiltConditionExpression):
108-
# self._unpack_built_condition_expression(super_conversion, "FilterExpression")
109-
# return super_conversion
11082
return self.boto3_converter.QueryInput(query_request)
11183

11284
def scan_request(self, scan_request):
85+
# scan requests on a boto3.resource.Table require a configured table name.
11386
if not self.table_name:
11487
raise ValueError("Table name must be provided to ResourceShapeToClientShapeConverter to use scan")
11588
scan_request["TableName"] = self.table_name
116-
# super_conversion = super().scan_request(scan_request)
117-
# if "FilterExpression" in super_conversion and isinstance(super_conversion["FilterExpression"], BuiltConditionExpression):
118-
# self._unpack_built_condition_expression(super_conversion, "FilterExpression")
119-
# return super_conversion
12089
return self.boto3_converter.ScanInput(scan_request)
12190

12291
def transact_get_items_request(self, transact_get_items_request):
@@ -154,53 +123,3 @@ def get_item_response(self, get_item_response):
154123

155124
def put_item_response(self, put_item_response):
156125
return self.boto3_converter.PutItemOutput(put_item_response)
157-
158-
159-
160-
161-
# def expression(self, condition_expression, expression_attribute_names, expression_attribute_values):
162-
# # Expressions provided to tables can be Condition objects, which need to be converted to strings.
163-
# if hasattr(condition_expression, "__module__") and condition_expression.__module__ == "boto3.dynamodb.conditions":
164-
# out = self.expression_builder.build_expression(condition_expression, expression_attribute_names, expression_attribute_values)
165-
# return out
166-
# # Expressions provided to tables can also already be string-like.
167-
# # Assume the user has provided something string-like, and let Smithy-Python/DBESDK internals raise exceptions if not.
168-
# print(f"probably a string: {condition_expression=}")
169-
# return condition_expression
170-
171-
# def batch_write_item_request_items(self, tables):
172-
# """Transform a batch write request's items to DynamoDB format."""
173-
# output_tables = {}
174-
# table_names = list(tables.keys())
175-
# for table_name in table_names:
176-
# requests = tables[table_name]
177-
# output_requests = []
178-
# for request in requests:
179-
# request_name_list = list(request.keys())
180-
# if len(request_name_list) > 1:
181-
# raise ValueError("Invalid JSON format")
182-
# request_name = request_name_list[0]
183-
# if request_name == "PutRequest":
184-
# dict_request = dict_to_ddb(request[request_name]["Item"])
185-
# boto3_request = {"Item": dict_request}
186-
# elif request_name == "DeleteRequest":
187-
# # Delete requests are based on Keys, which are expected to already be in DynamoDB JSON.
188-
# # Only Items can be in Python dictionary JSON.
189-
# boto3_request = request[request_name]
190-
# else:
191-
# raise ValueError(f"Unknown batch_write_items method key: {request_name}")
192-
# output_requests.append({request_name: boto3_request})
193-
# output_tables[table_name] = output_requests
194-
# return output_tables
195-
196-
# def batch_get_request(self, **kwargs):
197-
# """Transform a batch get request to DynamoDB format."""
198-
# dynamodb_input = kwargs.copy()
199-
# tables = dynamodb_input["RequestItems"]
200-
201-
# for table_name, table_data in tables.items():
202-
# dynamodb_input["RequestItems"][table_name]["Keys"] = [
203-
# self.key_to_attribute_value_map(key) for key in table_data["Keys"]
204-
# ]
205-
206-
# return dynamodb_input

0 commit comments

Comments
 (0)