From 67c7fce85ecf95fdfbc8d768b7839cdb9ff00d5f Mon Sep 17 00:00:00 2001 From: Bert Blommers Date: Tue, 17 Mar 2020 16:28:49 +0000 Subject: [PATCH 1/2] #2760 - DynamoDB - Ensure proper ordering for Numeric sort keys --- moto/dynamodb2/models.py | 7 +++- tests/test_dynamodb2/test_dynamodb.py | 58 +++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/moto/dynamodb2/models.py b/moto/dynamodb2/models.py index 1527821ed..a80b3211d 100644 --- a/moto/dynamodb2/models.py +++ b/moto/dynamodb2/models.py @@ -981,8 +981,13 @@ class Table(BaseModel): if index_name: if index_range_key: + + # Convert to float if necessary to ensure proper ordering + def conv(x): + return float(x.value) if x.type == "N" else x.value + results.sort( - key=lambda item: item.attrs[index_range_key["AttributeName"]].value + key=lambda item: conv(item.attrs[index_range_key["AttributeName"]]) if item.attrs.get(index_range_key["AttributeName"]) else None ) diff --git a/tests/test_dynamodb2/test_dynamodb.py b/tests/test_dynamodb2/test_dynamodb.py index 82f82ccc9..2b9475b9e 100644 --- a/tests/test_dynamodb2/test_dynamodb.py +++ b/tests/test_dynamodb2/test_dynamodb.py @@ -4026,3 +4026,61 @@ def test_valid_transact_get_items(): "Table": {"CapacityUnits": 2.0, "ReadCapacityUnits": 2.0,}, } ) + + +@mock_dynamodb2 +def test_gsi_verify_negative_number_order(): + table_schema = { + "KeySchema": [{"AttributeName": "partitionKey", "KeyType": "HASH"}], + "GlobalSecondaryIndexes": [ + { + "IndexName": "GSI-K1", + "KeySchema": [ + {"AttributeName": "gsiK1PartitionKey", "KeyType": "HASH"}, + {"AttributeName": "gsiK1SortKey", "KeyType": "RANGE"}, + ], + "Projection": {"ProjectionType": "KEYS_ONLY",}, + } + ], + "AttributeDefinitions": [ + {"AttributeName": "partitionKey", "AttributeType": "S"}, + {"AttributeName": "gsiK1PartitionKey", "AttributeType": "S"}, + {"AttributeName": "gsiK1SortKey", "AttributeType": "N"}, + ], + } + + item1 = { + "partitionKey": "pk-1", + "gsiK1PartitionKey": "gsi-k1", + "gsiK1SortKey": Decimal("-0.6"), + } + + item2 = { + "partitionKey": "pk-2", + "gsiK1PartitionKey": "gsi-k1", + "gsiK1SortKey": Decimal("-0.7"), + } + + item3 = { + "partitionKey": "pk-3", + "gsiK1PartitionKey": "gsi-k1", + "gsiK1SortKey": Decimal("0.7"), + } + + dynamodb = boto3.resource("dynamodb") + dynamodb.create_table( + TableName="test-table", BillingMode="PAY_PER_REQUEST", **table_schema + ) + table = dynamodb.Table("test-table") + table.put_item(Item=item3) + table.put_item(Item=item1) + table.put_item(Item=item2) + + resp = table.query( + KeyConditionExpression=Key("gsiK1PartitionKey").eq("gsi-k1"), + IndexName="GSI-K1", + ) + # Items should be ordered with the lowest number first + [float(item["gsiK1SortKey"]) for item in resp["Items"]].should.equal( + [-0.7, -0.6, 0.7] + ) From aead80c392942d95a6437689d321c564739b795f Mon Sep 17 00:00:00 2001 From: Bert Blommers Date: Tue, 17 Mar 2020 17:11:35 +0000 Subject: [PATCH 2/2] Add missing region --- tests/test_dynamodb2/test_dynamodb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_dynamodb2/test_dynamodb.py b/tests/test_dynamodb2/test_dynamodb.py index 2b9475b9e..5d39e3805 100644 --- a/tests/test_dynamodb2/test_dynamodb.py +++ b/tests/test_dynamodb2/test_dynamodb.py @@ -4067,7 +4067,7 @@ def test_gsi_verify_negative_number_order(): "gsiK1SortKey": Decimal("0.7"), } - dynamodb = boto3.resource("dynamodb") + dynamodb = boto3.resource("dynamodb", region_name="us-east-1") dynamodb.create_table( TableName="test-table", BillingMode="PAY_PER_REQUEST", **table_schema )