From ba0f0bd513f368c8833491df936813f851d247f0 Mon Sep 17 00:00:00 2001 From: David Pedrosa Date: Thu, 25 Mar 2021 21:22:36 +0100 Subject: [PATCH] Improve dynamodb query case sensitivity (#3799) (#3800) * between clause is not case-sensitive anymore * begins_with will raise an exception unless lower-case is used Co-authored-by: David Pedrosa --- moto/dynamodb2/responses.py | 14 +++- .../test_dynamodb_table_with_range_key.py | 66 +++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/moto/dynamodb2/responses.py b/moto/dynamodb2/responses.py index 5958a38c9..8ca9417aa 100644 --- a/moto/dynamodb2/responses.py +++ b/moto/dynamodb2/responses.py @@ -510,7 +510,7 @@ class DynamoHandler(BaseResponse): range_key_expression_components = range_key_expression.split() range_comparison = range_key_expression_components[1] - if "AND" in range_key_expression: + if " and " in range_key_expression.lower(): range_comparison = "BETWEEN" range_values = [ value_alias_map[range_key_expression_components[2]], @@ -521,6 +521,18 @@ class DynamoHandler(BaseResponse): range_values = [ value_alias_map[range_key_expression_components[-1]] ] + elif "begins_with" in range_key_expression.lower(): + function_used = range_key_expression[ + range_key_expression.lower().index("begins_with") : len( + "begins_with" + ) + ] + return self.error( + "com.amazonaws.dynamodb.v20111205#ValidationException", + "Invalid KeyConditionExpression: Invalid function name; function: {}".format( + function_used + ), + ) else: range_values = [value_alias_map[range_key_expression_components[2]]] else: diff --git a/tests/test_dynamodb2/test_dynamodb_table_with_range_key.py b/tests/test_dynamodb2/test_dynamodb_table_with_range_key.py index 1c8c12110..845c0587d 100644 --- a/tests/test_dynamodb2/test_dynamodb_table_with_range_key.py +++ b/tests/test_dynamodb2/test_dynamodb_table_with_range_key.py @@ -1082,6 +1082,72 @@ def test_boto3_conditions(): results["Count"].should.equal(1) +@mock_dynamodb2 +def test_boto3_conditions_ignorecase(): + dynamodb = boto3.client("dynamodb", region_name="us-east-1") + + # Create the DynamoDB table. + dynamodb.create_table( + TableName="users", + KeySchema=[ + {"AttributeName": "forum_name", "KeyType": "HASH"}, + {"AttributeName": "subject", "KeyType": "RANGE"}, + ], + AttributeDefinitions=[ + {"AttributeName": "forum_name", "AttributeType": "S"}, + {"AttributeName": "subject", "AttributeType": "S"}, + ], + ProvisionedThroughput={"ReadCapacityUnits": 5, "WriteCapacityUnits": 5}, + ) + + dynamodb.put_item( + TableName="users", + Item={"forum_name": {"S": "the-key"}, "subject": {"S": "100"}}, + ) + dynamodb.put_item( + TableName="users", + Item={"forum_name": {"S": "the-key"}, "subject": {"S": "199"}}, + ) + dynamodb.put_item( + TableName="users", + Item={"forum_name": {"S": "the-key"}, "subject": {"S": "250"}}, + ) + + between_expressions = [ + "BETWEEN :start AND :end", + "between :start and :end", + "Between :start and :end", + "between :start AnD :end", + ] + for expr in between_expressions: + results = dynamodb.query( + TableName="users", + KeyConditionExpression="forum_name = :forum_name and subject {}".format( + expr + ), + ExpressionAttributeValues={ + ":forum_name": {"S": "the-key"}, + ":start": {"S": "100"}, + ":end": {"S": "200"}, + }, + ) + results["Count"].should.equal(2) + + with pytest.raises(ClientError) as ex: + dynamodb.query( + TableName="users", + KeyConditionExpression="forum_name = :forum_name and BegIns_WiTh(subject, :subject )", + ExpressionAttributeValues={ + ":forum_name": {"S": "the-key"}, + ":subject": {"S": "1"}, + }, + ) + ex.value.response["Error"]["Code"].should.equal("ValidationException") + ex.value.response["Error"]["Message"].should.equal( + "Invalid KeyConditionExpression: Invalid function name; function: BegIns_WiTh" + ) + + @mock_dynamodb2 def test_boto3_put_item_with_conditions(): import botocore