DynamoDB: Fix projection expression with binary attribute (#6816)

This commit is contained in:
Bert Blommers 2023-09-15 17:17:57 +00:00 committed by GitHub
parent 971e432ad3
commit 2bae13bf5b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 36 additions and 1 deletions

View File

@ -1,3 +1,4 @@
import base64
import copy
import decimal
@ -195,6 +196,10 @@ class DynamoType(object):
def to_json(self) -> Dict[str, Any]:
# Returns a regular JSON object where the value can still be/contain a DynamoType
if self.is_binary():
# Binary data cannot be represented in JSON
# AWS returns a base64-encoded value - the SDK's then convert that back
return {self.type: base64.b64encode(self.value).decode("utf-8")}
return {self.type: self.value}
def to_regular_json(self) -> Dict[str, Any]:
@ -212,6 +217,8 @@ class DynamoType(object):
val.to_regular_json() if isinstance(val, DynamoType) else val
for val in value
]
if self.is_binary():
value = base64.b64decode(value)
return {self.type: value}
def compare(self, range_comparison: str, range_objs: List[Any]) -> bool:
@ -236,6 +243,9 @@ class DynamoType(object):
def is_map(self) -> bool:
return self.type == DDBType.MAP
def is_binary(self) -> bool:
return self.type == DDBType.BINARY
def same_type(self, other: "DynamoType") -> bool:
return self.type == other.type

View File

@ -14,7 +14,7 @@ def dynamo_json_dump(dynamo_object: Any) -> str:
def bytesize(val: str) -> int:
return len(val.encode("utf-8"))
return len(val if isinstance(val, bytes) else val.encode("utf-8"))
def find_nested_key(

View File

@ -4,6 +4,7 @@ from decimal import Decimal
import boto3
from boto3.dynamodb.conditions import Attr, Key
from boto3.dynamodb.types import Binary
import re
from moto import mock_dynamodb, settings
from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID
@ -5727,6 +5728,30 @@ def test_projection_expression_execution_order():
)
@mock_dynamodb
def test_projection_expression_with_binary_attr():
dynamo_resource = boto3.resource("dynamodb", region_name="us-east-1")
dynamo_resource.create_table(
TableName="test",
AttributeDefinitions=[
{"AttributeName": "pk", "AttributeType": "S"},
{"AttributeName": "sk", "AttributeType": "S"},
],
KeySchema=[
{"AttributeName": "pk", "KeyType": "HASH"},
{"AttributeName": "sk", "KeyType": "RANGE"},
],
BillingMode="PAY_PER_REQUEST",
)
table = dynamo_resource.Table("test")
table.put_item(Item={"pk": "pk", "sk": "sk", "key": b"value\xbf"})
assert table.get_item(
Key={"pk": "pk", "sk": "sk"},
ExpressionAttributeNames={"#key": "key"},
ProjectionExpression="#key",
)["Item"] == {"key": Binary(b"value\xbf")}
@mock_dynamodb
def test_invalid_projection_expressions():
table_name = "test-projection-expressions-table"