diff --git a/src/aiodynamo/expressions.py b/src/aiodynamo/expressions.py index 08a4354..31cc2ef 100644 --- a/src/aiodynamo/expressions.py +++ b/src/aiodynamo/expressions.py @@ -8,6 +8,8 @@ Any, Callable, Dict, + Generator, + Iterable, Iterator, List, Optional, @@ -19,7 +21,7 @@ from .errors import CannotAddToNestedField from .types import AttributeType, Numeric, ParametersDict -from .utils import MinLen2AppendOnlyList, deparametetrize, low_level_serialize +from .utils import deparametetrize, low_level_serialize _ParametersCache = Dict[Tuple[Any, Any], str] @@ -384,7 +386,7 @@ def __and__(self, other: Condition) -> Condition: return AndCondition(self.children.appending(other)) elif isinstance(other, AndCondition): return AndCondition(other.children.prepending(self)) - return AndCondition(MinLen2AppendOnlyList.create(self, other)) + return AndCondition(SubConditions.create(self, other)) def __or__(self, other: Condition) -> Condition: if isinstance(self, OrCondition): @@ -394,7 +396,7 @@ def __or__(self, other: Condition) -> Condition: return OrCondition(self.children.appending(other)) elif isinstance(other, OrCondition): return OrCondition(other.children.prepending(self)) - return OrCondition(MinLen2AppendOnlyList.create(self, other)) + return OrCondition(SubConditions.create(self, other)) def __invert__(self) -> Condition: return NotCondition(self) @@ -422,7 +424,7 @@ def encode(self, params: Parameters) -> str: @dataclass(frozen=True) class AndCondition(Condition): - children: MinLen2AppendOnlyList[Condition] + children: SubConditions def encode(self, params: Parameters) -> str: return "(" + " AND ".join(child.encode(params) for child in self.children) + ")" @@ -430,7 +432,7 @@ def encode(self, params: Parameters) -> str: @dataclass(frozen=True) class OrCondition(Condition): - children: MinLen2AppendOnlyList[Condition] + children: SubConditions def encode(self, params: Parameters) -> str: return "(" + " OR ".join(child.encode(params) for child in self.children) + ")" @@ -671,3 +673,30 @@ def __and__(self, field: F) -> ProjectionExpression: def encode(self, params: Parameters) -> str: return ",".join(params.encode_path(field.path) for field in self.fields) + + +@dataclass(frozen=True) +class SubConditions: + first: Condition + second: Condition + rest: tuple[Condition, ...] + + @classmethod + def create( + cls, first: Condition, second: Condition, *rest: Condition + ) -> SubConditions: + return cls(first, second, rest) + + def prepending(self, value: Condition) -> SubConditions: + return SubConditions(value, self.first, (self.second, *self.rest)) + + def appending(self, value: Condition) -> SubConditions: + return SubConditions(self.first, self.second, (*self.rest, value)) + + def extending(self, values: Iterable[Condition]) -> SubConditions: + return SubConditions(self.first, self.second, (*self.rest, *values)) + + def __iter__(self) -> Generator[Condition, None, None]: + yield self.first + yield self.second + yield from self.rest diff --git a/src/aiodynamo/utils.py b/src/aiodynamo/utils.py index 52a6dd4..0258857 100644 --- a/src/aiodynamo/utils.py +++ b/src/aiodynamo/utils.py @@ -5,7 +5,6 @@ import decimal import logging from collections import abc as collections_abc -from dataclasses import dataclass from functools import reduce from typing import ( TYPE_CHECKING, @@ -13,9 +12,6 @@ Awaitable, Callable, Dict, - Generator, - Generic, - Iterable, List, Mapping, Set, @@ -201,28 +197,3 @@ def deparametetrize( for key, value in params.names.items(): expression = expression.replace(key, value) return expression - - -@dataclass(frozen=True) -class MinLen2AppendOnlyList(Generic[T]): - first: T - second: T - rest: tuple[T, ...] - - @classmethod - def create(cls, first: T, second: T, *rest: T) -> MinLen2AppendOnlyList[T]: - return cls(first, second, rest) - - def prepending(self, value: T) -> MinLen2AppendOnlyList[T]: - return MinLen2AppendOnlyList(value, self.first, (self.second, *self.rest)) - - def appending(self, value: T) -> MinLen2AppendOnlyList[T]: - return MinLen2AppendOnlyList(self.first, self.second, (*self.rest, value)) - - def extending(self, values: Iterable[T]) -> MinLen2AppendOnlyList[T]: - return MinLen2AppendOnlyList(self.first, self.second, (*self.rest, *values)) - - def __iter__(self) -> Generator[T, None, None]: - yield self.first - yield self.second - yield from self.rest diff --git a/tests/unit/test_expressions.py b/tests/unit/test_expressions.py index 8ef3004..ec9c2c2 100644 --- a/tests/unit/test_expressions.py +++ b/tests/unit/test_expressions.py @@ -11,9 +11,9 @@ OrCondition, Parameters, ProjectionExpression, + SubConditions, UpdateExpression, ) -from aiodynamo.utils import MinLen2AppendOnlyList @pytest.mark.parametrize( @@ -149,7 +149,7 @@ def test_update_expression_debug(expr: UpdateExpression, expected: str) -> None: ( F("a").equals("a") & F("b").equals("b"), AndCondition( - MinLen2AppendOnlyList.create( + SubConditions.create( Comparison(F("a"), "=", "a"), Comparison(F("b"), "=", "b") ) ), @@ -157,7 +157,7 @@ def test_update_expression_debug(expr: UpdateExpression, expected: str) -> None: ( (F("a").equals("a") & F("b").equals("b")) & F("c").equals("c"), AndCondition( - MinLen2AppendOnlyList.create( + SubConditions.create( Comparison(F("a"), "=", "a"), Comparison(F("b"), "=", "b"), Comparison(F("c"), "=", "c"), @@ -167,7 +167,7 @@ def test_update_expression_debug(expr: UpdateExpression, expected: str) -> None: ( F("a").equals("a") & (F("b").equals("b") & F("c").equals("c")), AndCondition( - MinLen2AppendOnlyList.create( + SubConditions.create( Comparison(F("a"), "=", "a"), Comparison(F("b"), "=", "b"), Comparison(F("c"), "=", "c"), @@ -178,7 +178,7 @@ def test_update_expression_debug(expr: UpdateExpression, expected: str) -> None: (F("a").equals("a") & F("b").equals("b")) & (F("c").equals("c") & F("d").equals("d")), AndCondition( - MinLen2AppendOnlyList.create( + SubConditions.create( Comparison(F("a"), "=", "a"), Comparison(F("b"), "=", "b"), Comparison(F("c"), "=", "c"), @@ -189,7 +189,7 @@ def test_update_expression_debug(expr: UpdateExpression, expected: str) -> None: ( F("a").equals("a") | F("b").equals("b"), OrCondition( - MinLen2AppendOnlyList.create( + SubConditions.create( Comparison(F("a"), "=", "a"), Comparison(F("b"), "=", "b") ) ), @@ -197,7 +197,7 @@ def test_update_expression_debug(expr: UpdateExpression, expected: str) -> None: ( (F("a").equals("a") | F("b").equals("b")) | F("c").equals("c"), OrCondition( - MinLen2AppendOnlyList.create( + SubConditions.create( Comparison(F("a"), "=", "a"), Comparison(F("b"), "=", "b"), Comparison(F("c"), "=", "c"), @@ -207,7 +207,7 @@ def test_update_expression_debug(expr: UpdateExpression, expected: str) -> None: ( F("a").equals("a") | (F("b").equals("b") | F("c").equals("c")), OrCondition( - MinLen2AppendOnlyList.create( + SubConditions.create( Comparison(F("a"), "=", "a"), Comparison(F("b"), "=", "b"), Comparison(F("c"), "=", "c"), @@ -218,7 +218,7 @@ def test_update_expression_debug(expr: UpdateExpression, expected: str) -> None: (F("a").equals("a") | F("b").equals("b")) | (F("c").equals("c") | F("d").equals("d")), OrCondition( - MinLen2AppendOnlyList.create( + SubConditions.create( Comparison(F("a"), "=", "a"), Comparison(F("b"), "=", "b"), Comparison(F("c"), "=", "c"), @@ -230,14 +230,14 @@ def test_update_expression_debug(expr: UpdateExpression, expected: str) -> None: (F("a").equals("a") | F("b").equals("b")) & (F("c").equals("c") | F("d").equals("d")), AndCondition( - MinLen2AppendOnlyList.create( + SubConditions.create( OrCondition( - MinLen2AppendOnlyList.create( + SubConditions.create( Comparison(F("a"), "=", "a"), Comparison(F("b"), "=", "b") ) ), OrCondition( - MinLen2AppendOnlyList.create( + SubConditions.create( Comparison(F("c"), "=", "c"), Comparison(F("d"), "=", "d") ) ),