|
12 | 12 | dict_to_ddb,
|
13 | 13 | ddb_to_dict,
|
14 | 14 | )
|
| 15 | +from aws_database_encryption_sdk.internal.resource_to_client import ResourceShapeToClientShapeConverter |
| 16 | +from aws_database_encryption_sdk.internal.client_to_resource import ClientShapeToResourceShapeConverter |
15 | 17 |
|
16 | 18 | # TestVectors-only override of ._flush method:
|
17 | 19 | # persist response in self._response for TestVectors output processing.
|
@@ -49,123 +51,87 @@ class DynamoDBClientWrapperForDynamoDBResource:
|
49 | 51 | def __init__(self, resource, client):
|
50 | 52 | self._resource = resource
|
51 | 53 | self._client = client
|
52 |
| - |
53 |
| - def put_item(self, **kwargs): |
54 |
| - pass |
55 |
| - |
56 |
| - def get_item(self, **kwargs): |
57 |
| - key_dynamodb_format = kwargs["Key"] |
58 |
| - key_dict_format = ddb_to_dict(key_dynamodb_format) |
59 |
| - kwargs["Key"] = key_dict_format |
60 |
| - dict_format_output = self._resource.get_item(**kwargs) |
61 |
| - dynamodb_format_item = dict_format_output |
62 |
| - if "Item" in dict_format_output: |
63 |
| - dynamodb_format_item["Item"] = dict_to_ddb(dict_format_output["Item"]) |
64 |
| - return dynamodb_format_item |
65 |
| - |
66 |
| - def _convert_batch_write_item_request_from_dynamo_to_dict(self, **kwargs): |
67 |
| - for table, requests in kwargs["RequestItems"].items(): |
68 |
| - dict_requests = [] |
69 |
| - for request in requests: |
70 |
| - request_name_list = list(request.keys()) |
71 |
| - if len(request_name_list) > 1: |
72 |
| - raise ValueError("Cannot send more than one request in a single request") |
73 |
| - request_name = request_name_list[0] |
74 |
| - if request_name == "PutRequest": |
75 |
| - dict_request = ddb_to_dict(request[request_name]["Item"]) |
76 |
| - dict_requests.append({request_name: {"Item": dict_request}}) |
77 |
| - elif request_name == "DeleteRequest": |
78 |
| - dict_request = ddb_to_dict(request[request_name]["Key"]) |
79 |
| - dict_requests.append({request_name: {"Key": dict_request}}) |
80 |
| - else: |
81 |
| - raise ValueError(f"Unknown batch_write_items method key: {request_name}") |
82 |
| - kwargs["RequestItems"][table] = dict_requests |
83 |
| - return kwargs |
| 54 | + self._client_shape_to_resource_shape_converter = ClientShapeToResourceShapeConverter() |
| 55 | + self._resource_shape_to_client_shape_converter = ResourceShapeToClientShapeConverter() |
84 | 56 |
|
85 | 57 | def batch_write_item(self, **kwargs):
|
86 |
| - print(f"batch_write_item {kwargs=}") |
87 |
| - dict_formatted = self._convert_batch_write_item_request_from_dynamo_to_dict(**kwargs) |
88 |
| - return self._resource.batch_write_item(**dict_formatted) |
89 |
| - |
90 |
| - # # print(f"batch_write_item {kwargs=}") |
91 |
| - # # Parse boto3 client.batch_write_item input into table.batch_writer() calls |
92 |
| - # # client.batch_write_item: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/client/batch_write_item.html |
93 |
| - # # table.batch_writer(): https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/table/batch_writer.html |
94 |
| - # tables = kwargs["RequestItems"] |
95 |
| - # table_names = list(tables.keys()) |
96 |
| - # if len(tables.keys()) > 1: |
97 |
| - # raise ValueError("Table batch_write_item only supports 1 table in a request.") |
98 |
| - # requests = tables[table_names[0]] |
99 |
| - # with self._table.batch_writer() as batch: |
100 |
| - |
101 |
| - # batch._flush=types.MethodType(_flush_and_persist_response, batch) |
102 |
| - |
103 |
| - # for request in requests: |
104 |
| - # request_name_list = list(request.keys()) |
105 |
| - # if len(request_name_list) > 1: |
106 |
| - # raise ValueError("Cannot send more than one request in a single request") |
107 |
| - # request_name = request_name_list[0] |
108 |
| - # if request_name == "PutRequest": |
109 |
| - # dict_request = ddb_to_dict(request[request_name]["Item"]) |
110 |
| - # boto3_request = {"Item": dict_request} |
111 |
| - # batch.put_item(**boto3_request) |
112 |
| - # # dynamodb_request = request[request_name] |
113 |
| - # # print(f"{dynamodb_request}") |
114 |
| - # # batch.put_item(**dynamodb_request) |
115 |
| - # elif request_name == "DeleteRequest": |
116 |
| - # batch.delete_item(Key=ddb_to_dict(request["Key"])) |
117 |
| - # else: |
118 |
| - # raise ValueError(f"Unknown batch_write_items method key: {request_name}") |
119 |
| - # return batch._response |
120 |
| - |
| 58 | + # The input here is from the DBESDK TestVectors, which is in the shape of a client request. |
| 59 | + # Convert the client request to a resource request to be passed to the table. |
| 60 | + table_input = self._client_shape_to_resource_shape_converter.batch_write_item_request(kwargs) |
| 61 | + # ClientShapeToResourceShapeConverters don't convert DynamoDB expressions from strings to Condition objects, |
| 62 | + # because resource shapes can accept strings. |
| 63 | + # For TestVectors coverage, use a TestVectors-internal string-to-Condition converter. |
| 64 | + # TODO: Use a shared Condition converter. |
| 65 | + table_output = self._resource.batch_write_item(**table_input) |
| 66 | + client_output = self._resource_shape_to_client_shape_converter.batch_write_item_response(table_output) |
| 67 | + return client_output |
| 68 | + |
121 | 69 | def batch_get_item(self, **kwargs):
|
122 |
| - # batch_get_item doesn't exist on boto3 tables. |
123 |
| - # For TestVector compatibility, just make a series of get_item calls, |
124 |
| - # and massage inputs/outputs into expected formats. |
125 |
| - tables = kwargs["RequestItems"] |
126 |
| - table_names = list(tables.keys()) |
127 |
| - if len(tables.keys()) > 1: |
128 |
| - raise ValueError("Table batch_get_item only supports 1 table in a request.") |
129 |
| - requests = tables[table_names[0]] |
130 |
| - with self._table.batch_writer() as batch: |
131 |
| - |
132 |
| - batch._flush=types.MethodType(_flush_and_persist_response, batch) |
133 |
| - |
134 |
| - for request in requests: |
135 |
| - request_name_list = list(request.keys()) |
136 |
| - if len(request_name_list) > 1: |
137 |
| - raise ValueError("Cannot send more than one request in a single request") |
138 |
| - request_name = request_name_list[0] |
139 |
| - if request_name == "PutRequest": |
140 |
| - dict_request = ddb_to_dict(request[request_name]["Item"]) |
141 |
| - boto3_request = {"Item": dict_request} |
142 |
| - batch.put_item(**boto3_request) |
143 |
| - # dynamodb_request = request[request_name] |
144 |
| - # print(f"{dynamodb_request}") |
145 |
| - # batch.put_item(**dynamodb_request) |
146 |
| - elif request_name == "DeleteRequest": |
147 |
| - batch.delete_item(Key=ddb_to_dict(request["Key"])) |
148 |
| - else: |
149 |
| - raise ValueError(f"Unknown batch_write_items method key: {request_name}") |
150 |
| - return batch._response |
151 |
| - |
152 |
| - |
| 70 | + table_input = self._client_shape_to_resource_shape_converter.batch_get_item_request(kwargs) |
| 71 | + table_output = self._resource.batch_get_item(**table_input) |
| 72 | + client_output = self._resource_shape_to_client_shape_converter.batch_get_item_response(table_output) |
| 73 | + return client_output |
| 74 | + |
153 | 75 | def scan(self, **kwargs):
|
154 |
| - pass |
| 76 | + # Resources don't have scan, but our EncryptedResources can provide EncryptedTables that do support scan. |
| 77 | + # This path tests that the EncryptedTables provided by EncryptedResources can used for scan. |
| 78 | + table_name = kwargs["TableName"] |
| 79 | + table_input = self._client_shape_to_resource_shape_converter.scan_request(kwargs) |
| 80 | + encrypted_table = self._resource.Table(table_name) |
| 81 | + table_output = encrypted_table.scan(**table_input) |
| 82 | + table_shape_converter = ResourceShapeToClientShapeConverter(table_name=table_name) |
| 83 | + client_output = table_shape_converter.scan_response(table_output) |
| 84 | + return client_output |
| 85 | + |
| 86 | + def put_item(self, **kwargs): |
| 87 | + # Resources don't have put_item, but our EncryptedResources can provide EncryptedTables that do support put_item. |
| 88 | + # This path tests that the EncryptedTables provided by EncryptedResources can used for put_item. |
| 89 | + table_name = kwargs["TableName"] |
| 90 | + table_input = self._client_shape_to_resource_shape_converter.put_item_request(kwargs) |
| 91 | + encrypted_table = self._resource.Table(table_name) |
| 92 | + table_output = encrypted_table.put_item(**table_input) |
| 93 | + table_shape_converter = ResourceShapeToClientShapeConverter(table_name=table_name) |
| 94 | + client_output = table_shape_converter.put_item_response(table_output) |
| 95 | + return client_output |
| 96 | + |
| 97 | + def get_item(self, **kwargs): |
| 98 | + # Resources don't have get_item, but our EncryptedResources can provide EncryptedTables that do support get_item. |
| 99 | + # This path tests that the EncryptedTables provided by EncryptedResources can used for get_item. |
| 100 | + table_name = kwargs["TableName"] |
| 101 | + table_input = self._client_shape_to_resource_shape_converter.get_item_request(kwargs) |
| 102 | + encrypted_table = self._resource.Table(table_name) |
| 103 | + table_output = encrypted_table.get_item(**table_input) |
| 104 | + table_shape_converter = ResourceShapeToClientShapeConverter(table_name=table_name) |
| 105 | + client_output = table_shape_converter.get_item_response(table_output) |
| 106 | + return client_output |
| 107 | + |
| 108 | + def query(self, **kwargs): |
| 109 | + # Resources don't have query, but our EncryptedResources can provide EncryptedTables that do support query. |
| 110 | + # This path tests that the EncryptedTables provided by EncryptedResources can used for query. |
| 111 | + table_name = kwargs["TableName"] |
| 112 | + table_input = self._client_shape_to_resource_shape_converter.put_item_request(kwargs) |
| 113 | + encrypted_table = self._resource.Table(table_name) |
| 114 | + table_output = encrypted_table.query(**table_input) |
| 115 | + table_shape_converter = ResourceShapeToClientShapeConverter(table_name=table_name) |
| 116 | + client_output = table_shape_converter.put_item_response(table_output) |
| 117 | + return client_output |
155 | 118 |
|
156 | 119 | def transact_get_items(self, **kwargs):
|
157 |
| - pass |
| 120 | + raise NotImplementedError("transact_get_items not supported on resources") |
158 | 121 |
|
159 | 122 | def transact_write_items(self, **kwargs):
|
160 |
| - pass |
161 |
| - |
162 |
| - def query(self, **kwargs): |
163 |
| - pass |
| 123 | + raise NotImplementedError("transact_get_items not supported on resources") |
164 | 124 |
|
165 | 125 | def delete_table(self, **kwargs):
|
| 126 | + # Resources don't have delete_table. Plus, DBESDK doesn't intercept DeleteTable calls. |
| 127 | + # TestVectors only use this to ensure a new, clean table is created for each test. |
| 128 | + # Defer to the underlying boto3 client to delete the table. |
166 | 129 | return self._client.delete_table(**kwargs)
|
167 | 130 |
|
168 | 131 | def create_table(self, **kwargs):
|
| 132 | + # Resources don't have create_table. Plus, DBESDK doesn't intercept CreateTable calls. |
| 133 | + # TestVectors only use this to ensure a new, clean table is created for each test. |
| 134 | + # Defer to the underlying boto3 client to create a table. |
169 | 135 | return self._client.create_table(**kwargs)
|
170 | 136 |
|
171 | 137 |
|
|
0 commit comments