Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions moto/dynamodb/comparisons.py
Original file line number Diff line number Diff line change
Expand Up @@ -1233,12 +1233,14 @@ def expr(self, item: Item | None) -> bool:
# Can't just check 'if start', because start could be 0, which is a valid number
start_has_value = start is not None and (isinstance(start, Decimal) or start)
end_has_value = end is not None and (isinstance(end, Decimal) or end)
if start_has_value and attr and end_has_value:
# The tested attribute needs the same zero-safe check, otherwise a value of 0 is excluded
attr_has_value = attr is not None and (isinstance(attr, Decimal) or attr)
if start_has_value and attr_has_value and end_has_value:
return start <= attr <= end
elif start is None and attr is None:
# None is between None and None as well as None is between None and any number
return True
elif start is None and attr and end:
elif start is None and attr_has_value and end_has_value:
return attr <= end
else:
return False
Expand Down
33 changes: 33 additions & 0 deletions tests/test_dynamodb/test_dynamodb_condition_expressions.py
Original file line number Diff line number Diff line change
Expand Up @@ -739,3 +739,36 @@ def test_conditional_check_failed_bytes():
assert "Item" in exc.value.response
assert exc.value.response["Item"]["my_bytes"]["B"] == b"somebytes"
assert exc.value.response["Item"]["my_bytes_set"]["BS"] == [b"byte1", b"byte2"]


@mock_aws
def test_between_condition_includes_zero():
"""
A numeric attribute value of exactly 0 must satisfy a BETWEEN range that
includes it; previously FuncBetween tested the attribute with bare
truthiness, so Decimal("0") was treated as missing and excluded.
"""
dynamodb = boto3.resource("dynamodb", region_name="us-east-2")
table_name = f"T{uuid4()}"
dynamodb.create_table(
TableName=table_name,
KeySchema=[{"AttributeName": "id", "KeyType": "HASH"}],
AttributeDefinitions=[{"AttributeName": "id", "AttributeType": "S"}],
BillingMode="PAY_PER_REQUEST",
)
table = dynamodb.Table(table_name)

table.put_item(Item={"id": "zero", "price": 0})
table.put_item(Item={"id": "five", "price": 5})

result = table.scan(
FilterExpression="price BETWEEN :lo AND :hi",
ExpressionAttributeValues={":lo": 0, ":hi": 100},
)
assert {item["id"] for item in result["Items"]} == {"zero", "five"}

result = table.scan(
FilterExpression="price BETWEEN :lo AND :hi",
ExpressionAttributeValues={":lo": -10, ":hi": 0},
)
assert {item["id"] for item in result["Items"]} == {"zero"}