Skip to content

Commit 88bcd3e

Browse files
committed
fix(dynamodb): handle zero attribute in BETWEEN
1 parent 55e2fbc commit 88bcd3e

2 files changed

Lines changed: 29 additions & 4 deletions

File tree

moto/dynamodb/comparisons.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1229,16 +1229,17 @@ def expr(self, item: Item | None) -> bool:
12291229
start = self.start.expr(item)
12301230
attr = self.attr.expr(item)
12311231
end = self.end.expr(item)
1232-
# Need to verify whether start has a valid value
1233-
# Can't just check 'if start', because start could be 0, which is a valid number
1232+
# Need to verify whether start/attr/end have a valid value
1233+
# Can't just check 'if start', because start could be 0, which is a valid number
12341234
start_has_value = start is not None and (isinstance(start, Decimal) or start)
1235+
attr_has_value = attr is not None and (isinstance(attr, Decimal) or attr)
12351236
end_has_value = end is not None and (isinstance(end, Decimal) or end)
1236-
if start_has_value and attr and end_has_value:
1237+
if start_has_value and attr_has_value and end_has_value:
12371238
return start <= attr <= end
12381239
elif start is None and attr is None:
12391240
# None is between None and None as well as None is between None and any number
12401241
return True
1241-
elif start is None and attr and end:
1242+
elif start is None and attr_has_value and end_has_value:
12421243
return attr <= end
12431244
else:
12441245
return False

tests/test_dynamodb/test_dynamodb.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1403,6 +1403,30 @@ def test_filter_expression():
14031403
)
14041404
assert filter_expr.expr(row1) is True
14051405

1406+
# BETWEEN test where the attribute itself is exactly 0 -- regression test.
1407+
# 0 is a valid Decimal value and must not be treated as "no value" via
1408+
# bare truthiness (bool(Decimal("0")) is False), the same way start/end
1409+
# already correctly special-case 0. Item with Id=0 must be included in
1410+
# a BETWEEN 0 AND 10 (and BETWEEN -5 AND 10) range.
1411+
row_zero = moto.dynamodb.models.Item(
1412+
hash_key=None,
1413+
range_key=None,
1414+
attrs={"Id": {"N": "0"}},
1415+
)
1416+
filter_expr = moto.dynamodb.comparisons.get_filter_expression(
1417+
"Id BETWEEN :v0 AND :v1", {}, {":v0": {"N": "0"}, ":v1": {"N": "10"}}
1418+
)
1419+
assert filter_expr.expr(row_zero) is True
1420+
filter_expr = moto.dynamodb.comparisons.get_filter_expression(
1421+
"Id BETWEEN :v0 AND :v1", {}, {":v0": {"N": "-5"}, ":v1": {"N": "10"}}
1422+
)
1423+
assert filter_expr.expr(row_zero) is True
1424+
# And it must still correctly exclude 0 when it falls outside the range.
1425+
filter_expr = moto.dynamodb.comparisons.get_filter_expression(
1426+
"Id BETWEEN :v0 AND :v1", {}, {":v0": {"N": "1"}, ":v1": {"N": "10"}}
1427+
)
1428+
assert filter_expr.expr(row_zero) is False
1429+
14061430
# PAREN test
14071431
filter_expr = moto.dynamodb.comparisons.get_filter_expression(
14081432
"Id = :v0 AND (Subs = :v0 OR Subs = :v1)",

0 commit comments

Comments
 (0)