29
29
DynamoDbTablesEncryptionConfig ,
30
30
)
31
31
32
- from boto3 .dynamodb .conditions import (
33
- Key ,
34
- Equals ,
35
- NotEquals ,
36
- LessThan ,
37
- LessThanEquals ,
38
- GreaterThan ,
39
- GreaterThanEquals ,
40
- In ,
41
- Between ,
42
- BeginsWith ,
43
- And ,
44
- Or ,
45
- Contains ,
46
- )
47
- from boto3 .dynamodb .types import TypeSerializer
48
-
49
- from boto3 .dynamodb .conditions import Key , Attr
50
- from boto3 .dynamodb .types import TypeSerializer
51
-
52
- from boto3 .dynamodb .conditions import Equals , LessThan , GreaterThan , BeginsWith , Between
53
- from boto3 .dynamodb .types import TypeSerializer
54
32
55
33
def transform_transformed_response_for_table_query_or_scan_response (sdk_output , transformed_response ):
56
34
response = transformed_response
@@ -81,20 +59,7 @@ def transform_transformed_request_for_query_or_scan_on_table(transformed_request
81
59
for name , ddb_value in transformed_request ["ExpressionAttributeValues" ].items ():
82
60
dict_item = ddb_to_dict ({name : ddb_value })
83
61
transformed_request ["ExpressionAttributeValues" ][list (dict_item .keys ())[0 ]] = list (dict_item .values ())[0 ]
84
-
85
- # substitution_map = {}
86
- # tokenized_original_string = untransformed_request["KeyConditionExpression"].split(" ")
87
- # tokenized_transformed_string = untransformed_request["KeyConditionExpression"].split(" ")
88
- # assert len(tokenized_original_string) == len(tokenized_transformed_string)
89
- # for i in range(len(tokenized_original_string)):
90
- # original = tokenized_original_string[i]
91
- # transformed = tokenized_original_string[i]
92
- # if original != transformed:
93
- # substitution_map[original] = transformed
94
-
95
-
96
-
97
-
62
+
98
63
return transformed_request
99
64
100
65
@@ -150,9 +115,6 @@ def transform_query_or_scan_input_for_internal_transformer(**kwargs):
150
115
kwargs ["ExpressionAttributeValues" ] = expression_attribute_values
151
116
return kwargs
152
117
153
- def is_number (obj ):
154
- return isinstance (obj , (int , float , Decimal ))
155
-
156
118
def convert_conditions_to_client_expression (condition , expression_attribute_names , expression_attribute_values ):
157
119
"""
158
120
Converts a Key/Attr condition into a client-compatible DynamoDB expression.
@@ -164,279 +126,12 @@ def convert_conditions_to_client_expression(condition, expression_attribute_name
164
126
- ExpressionAttributeNames dictionary
165
127
"""
166
128
167
- # from boto3.dynamodb.conditions import ConditionExpressionBuilder
168
129
from aws_database_encryption_sdk .internal .condition_expression_builder import InternalDBESDKDynamoDBConditionExpressionBuilder
169
130
170
131
a = InternalDBESDKDynamoDBConditionExpressionBuilder ()
171
132
out = a .build_expression (condition , expression_attribute_names , expression_attribute_values )
172
- print (f'our { out = } ' )
173
133
return out
174
134
175
- def _recurse (condition , expression_attribute_names , expression_attribute_values ):
176
- expression = condition .get_expression ()
177
- expression_format = expression ["format" ]
178
- expression_operator = expression ["operator" ]
179
- expression_values = expression ["values" ]
180
- processed_expression_values = []
181
-
182
- for elem in expression_values :
183
- if isinstance (elem , Key ) or isinstance (elem , Attr ):
184
- attribute_name = elem .name
185
- # if attribute_name in expression_attribute_names:
186
- # placeholder_name = expression_attribute_names[attribute_name]
187
- # else:
188
- # placeholder_name = "#pln" + str(len(expression_attribute_names))
189
- # expression_attribute_names[placeholder_name] = attribute_name
190
- elem = attribute_name
191
- elif isinstance (elem , Equals ) or isinstance (elem , And ) or isinstance (elem , Or ) or isinstance (elem , Between ) or isinstance (elem , BeginsWith ) or isinstance (elem , GreaterThanEquals ) or isinstance (elem , NotEquals ) or isinstance (elem , Contains ):
192
- elem , expression_attribute_names , expression_attribute_values = _recurse (elem , expression_attribute_names , expression_attribute_values )
193
- elif isinstance (elem , str ) or is_number (elem ):
194
- # assume it's a value...
195
- attribute_value = elem
196
- # # if attribute_value in expression_attribute_values:
197
- # # placeholder_value = expression_attribute_values[attribute_value]
198
- # # else:
199
- # placeholder_value = ":plv" + str(len(expression_attribute_values))
200
- # expression_attribute_values[placeholder_value] = attribute_value
201
- elem = attribute_value
202
- elif isinstance (elem , list ):
203
- s = "("
204
- for list_elem in elem :
205
- s += str (list_elem )
206
- s += ")"
207
- elem = s
208
- else :
209
- print (f"unknown { elem = } " )
210
- print (f"unknown { elem .__dict__ = } " )
211
- print (f"unknown { dir (elem )= } " )
212
- raise ValueError (f"{ elem = } " )
213
- processed_expression_values .append (elem )
214
- output = expression_format .format (* processed_expression_values , operator = expression_operator )
215
- return (output , expression_attribute_names , expression_attribute_values )
216
-
217
- condition_expression , expression_attribute_names , expression_attribute_values = _recurse (condition , expression_attribute_names , expression_attribute_values )
218
- print (f"{ (condition_expression , expression_attribute_names , expression_attribute_values )= } " )
219
- # expression_attribute_names = {v: k for k, v in swapped_expression_attribute_names.items() if }
220
- # expression_attribute_values = {v: k for k, v in swapped_expression_attribute_values.items()}
221
- return (condition_expression , expression_attribute_names , expression_attribute_values )
222
-
223
-
224
- def process_condition (condition ):
225
- nonlocal expression , expression_attribute_values , expression_attribute_names
226
-
227
- if isinstance (condition , Equals ):
228
- attr_name = f"#{ condition .attr_name } "
229
- placeholder = f":val_{ len (expression_attribute_values )} "
230
- expression_attribute_names [attr_name ] = condition .attr_name
231
- expression_attribute_values [placeholder ] = serializer .serialize (condition .values [0 ])
232
- return f"{ attr_name } = { placeholder } "
233
- elif isinstance (condition , LessThan ):
234
- attr_name = f"#{ condition .attr_name } "
235
- placeholder = f":val_{ len (expression_attribute_values )} "
236
- expression_attribute_names [attr_name ] = condition .attr_name
237
- expression_attribute_values [placeholder ] = serializer .serialize (condition .values [0 ])
238
- return f"{ attr_name } < { placeholder } "
239
- elif isinstance (condition , GreaterThan ):
240
- attr_name = f"#{ condition .attr_name } "
241
- placeholder = f":val_{ len (expression_attribute_values )} "
242
- expression_attribute_names [attr_name ] = condition .attr_name
243
- expression_attribute_values [placeholder ] = serializer .serialize (condition .values [0 ])
244
- return f"{ attr_name } > { placeholder } "
245
- elif isinstance (condition , BeginsWith ):
246
- attr_name = f"#{ condition .attr_name } "
247
- placeholder = f":val_{ len (expression_attribute_values )} "
248
- expression_attribute_names [attr_name ] = condition .attr_name
249
- expression_attribute_values [placeholder ] = serializer .serialize (condition .values [0 ])
250
- return f"begins_with({ attr_name } , { placeholder } )"
251
- elif isinstance (condition , Between ):
252
- attr_name = f"#{ condition .attr_name } "
253
- placeholder1 = f":val_{ len (expression_attribute_values )} "
254
- placeholder2 = f":val_{ len (expression_attribute_values ) + 1 } "
255
- expression_attribute_names [attr_name ] = condition .attr_name
256
- expression_attribute_values [placeholder1 ] = serializer .serialize (condition .values [0 ])
257
- expression_attribute_values [placeholder2 ] = serializer .serialize (condition .values [1 ])
258
- return f"{ attr_name } BETWEEN { placeholder1 } AND { placeholder2 } "
259
- else :
260
- raise ValueError (f"Unsupported condition type: { type (condition ).__name__ } " )
261
-
262
- expression = process_condition (condition )
263
-
264
- return expression , expression_attribute_values , expression_attribute_names
265
- # from boto3.dynamodb.conditions import Key, Attr
266
- # from boto3.dynamodb.types import TypeDeserializer
267
-
268
- # def convert_client_expression_to_conditions(expression, expression_values, expression_names=None):
269
- # """
270
- # Converts DynamoDB client-compatible expressions into Key or Attr conditions.
271
-
272
- # :param expression: A string of the DynamoDB client expression (e.g., "RecNum = :zero").
273
- # :param expression_values: A dictionary of attribute values (e.g., {":zero": {"N": "0"}}).
274
- # :param expression_names: A dictionary of attribute names, if placeholders are used (e.g., {"#attr": "RecNum"}).
275
- # :return: A boto3.dynamodb.conditions object (Key or Attr).
276
- # """
277
- # # Split the expression into attribute and value
278
- # tokens = expression.split()
279
- # # if len(tokens) != 3:
280
- # # raise ValueError("Only simple expressions (e.g., 'AttrName = :val') are supported.")
281
-
282
- # attr_name = tokens[0] # The attribute name or placeholder
283
- # operator = tokens[1].upper() # The operator (e.g., '=', '<', '>', "BETWEEN")
284
- # attr_value_placeholder = tokens[2] # The value placeholder (e.g., ":zero")
285
-
286
- # # Map operator to Key or Attr
287
- # if operator == "=":
288
- # return Key(attr_name).eq(attr_value_placeholder)
289
- # elif operator == "<":
290
- # return Key(attr_name).lt(attr_value_placeholder)
291
- # elif operator == "<=":
292
- # return Key(attr_name).lte(attr_value_placeholder)
293
- # elif operator == ">":
294
- # return Key(attr_name).gt(attr_value_placeholder)
295
- # elif operator == ">=":
296
- # return Key(attr_name).gte(attr_value_placeholder)
297
- # elif operator == "begins_with":
298
- # return Key(attr_name).begins_with(attr_value_placeholder)
299
- # elif operator == "BETWEEN":
300
- # raise NotImplementedError("BETWEEN is not currently supported by this function.")
301
- # else:
302
- # # If no Key match, assume Attr condition
303
- # if operator == "!=" or operator == "<>":
304
- # return Attr(attr_name).ne(attr_value_placeholder)
305
- # elif operator == "contains":
306
- # return Attr(attr_name).contains(attr_value_placeholder)
307
- # else:
308
- # raise ValueError(f"Unsupported operator: {operator}")
309
-
310
- from boto3 .dynamodb .conditions import Key , Attr , And , Or , Not
311
- from boto3 .dynamodb .types import TypeDeserializer
312
-
313
-
314
- def convert_client_expression_to_conditions (expression ):
315
- """
316
- Crypto Tools internal method to convert a DynamoDB filter/key expression to boto3 Resource tokens.
317
- DO NOT USE FOR ANY OTHER PURPOSE.
318
- This is a basic implementation for simple expressions that will fail with complex expressions.
319
-
320
- To extend this to support one or a few complex expressions, consider extending the existing logic.
321
- To extend this to support all expressions, consider implementing and extending the code below:
322
-
323
- ```
324
- from aws_database_encryption_sdk.internaldafny.generated.DynamoDBFilterExpr import default__ as filter_expr
325
- import _dafny
326
- from smithy_dafny_standard_library.internaldafny.generated import Wrappers
327
-
328
- dafny_expr_token = filter_expr.ParseExpr(
329
- _dafny.Seq(
330
- expression
331
- ),
332
- )
333
- ```
334
-
335
- This library's generated internal Dafny code has a DynamoDB string parser.
336
- This will parse a _dafny.Seq and produce Dafny tokens for the expression.
337
- Implementing this will involve
338
- 1. Mapping Dafny tokens to boto3 Resource tokens.
339
- (e.g. class Token_Between -> boto3.dynamodb.conditions.Between)
340
- 2. Converting Dafny token grammar to boto3 Resource token grammar.
341
- (e.g.
342
- Dafny: [Token_Between, Token_Open, Token_Attr, Token_And, Token_Attr, Token_Close]
343
- ->
344
- boto3: [Between(Attr, Attr)]
345
- )
346
-
347
- :param expression: A string of the DynamoDB client expression (e.g., "AttrName = :val").
348
- :param expression_values: A dictionary of attribute values (e.g., {":val": {"N": "0"}}).
349
- :param expression_names: A dictionary of attribute names, if placeholders are used (e.g., {"#attr": "AttrName"}).
350
- :return: A boto3.dynamodb.conditions object (Key, Attr, or a combination of them).
351
- """
352
-
353
- # Recursive parser for complex expressions
354
- def parse_expression (expr_tokens ):
355
- # simple between
356
- if "BETWEEN" == expr_tokens [1 ].upper ():
357
- attr_name = expr_tokens [0 ]
358
- value1 = expr_tokens [2 ]
359
- value2 = expr_tokens [4 ]
360
- return Key (attr_name ).between (value1 , value2 )
361
-
362
- # simple in
363
- elif "IN" == expr_tokens [1 ].upper ():
364
- print (f"IN { expr_tokens = } " )
365
- attr_name = expr_tokens [0 ]
366
- values_in_list = expr_tokens [3 :- 1 ]
367
- for i in range (len (values_in_list )):
368
- if values_in_list [i ][- 1 ] == "," :
369
- values_in_list [i ] = values_in_list [i ][:- 1 ]
370
- return Attr (attr_name ).is_in (values_in_list )
371
-
372
- # simple contains
373
- elif "CONTAINS" == expr_tokens [0 ].upper ():
374
- attr_name = expr_tokens [2 ]
375
- if attr_name [- 1 ] == "," :
376
- attr_name = attr_name [:- 1 ]
377
- value = expr_tokens [3 ]
378
- return Attr (attr_name ).contains (value )
379
-
380
- # simple begins_with
381
- elif "BEGINS_WITH" == expr_tokens [0 ].upper ():
382
- attr_name = expr_tokens [2 ]
383
- if attr_name [- 1 ] == "," :
384
- attr_name = attr_name [:- 1 ]
385
- value = expr_tokens [3 ]
386
- return Attr (attr_name ).begins_with (value )
387
-
388
- # Base case: Single comparison or condition
389
- if "AND" not in [t .upper () for t in expr_tokens ] and "OR" not in [t .upper () for t in expr_tokens ]:
390
-
391
- # simple comparison
392
- attr_name = expr_tokens [0 ]
393
- operator = expr_tokens [1 ].upper ()
394
- value = expr_tokens [2 ]
395
-
396
- # Map operator to Key or Attr
397
- if operator == "=" :
398
- return Key (attr_name ).eq (value )
399
- elif operator == "<" :
400
- return Key (attr_name ).lt (value )
401
- elif operator == "<=" :
402
- return Key (attr_name ).lte (value )
403
- elif operator == ">" :
404
- return Key (attr_name ).gt (value )
405
- elif operator == ">=" :
406
- return Key (attr_name ).gte (value )
407
- elif operator in ("!=" , "<>" ):
408
- return Attr (attr_name ).ne (value )
409
- else :
410
- raise ValueError (f"Unsupported operator: { operator } " )
411
-
412
- # Recursive case: Logical AND/OR
413
- stack = []
414
- current_expr = []
415
-
416
- for token in expr_tokens :
417
- if token .upper () in ("AND" , "OR" ):
418
- left = parse_expression (current_expr )
419
- current_expr = []
420
- stack .append ((left , token )) # Save the left condition and operator
421
- else :
422
- current_expr .append (token )
423
-
424
- # Handle the final condition on the right
425
- right = parse_expression (current_expr )
426
-
427
- # Combine the stack of conditions
428
- while stack :
429
- left , operator = stack .pop ()
430
- if operator .upper () == "AND" :
431
- right = And (left , right )
432
- elif operator .upper () == "OR" :
433
- right = Or (left , right )
434
-
435
- return right
436
-
437
- # Tokenize the expression and parse it
438
- tokens = expression .replace ("(" , " ( " ).replace (")" , " ) " ).split ()
439
- return parse_expression (tokens )
440
135
441
136
class EncryptedTable :
442
137
0 commit comments