diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2022-07-13 12:48:37 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2022-07-13 12:48:37 -0400 |
| commit | 9d3eaae35b9a3bd74114b350f84281ba9e7fb993 (patch) | |
| tree | db70ab9eff3fff44289e840db73da6a74d0fc5f2 /lib/sqlalchemy | |
| parent | ff1086f019efe32c099a5b5dad1160c95c10db62 (diff) | |
| download | sqlalchemy-9d3eaae35b9a3bd74114b350f84281ba9e7fb993.tar.gz | |
implement comparison ops for composites
classes mapped by :class:`_orm.composite` now support
ordering comparison operations, e.g. ``<``, ``>=``, etc.
Change-Id: I44938b9ca2935b2f63c70e930768487ddc6b7669
Diffstat (limited to 'lib/sqlalchemy')
| -rw-r--r-- | lib/sqlalchemy/orm/descriptor_props.py | 39 |
1 files changed, 33 insertions, 6 deletions
diff --git a/lib/sqlalchemy/orm/descriptor_props.py b/lib/sqlalchemy/orm/descriptor_props.py index 6d308e141..52b70b9d4 100644 --- a/lib/sqlalchemy/orm/descriptor_props.py +++ b/lib/sqlalchemy/orm/descriptor_props.py @@ -48,6 +48,7 @@ from .. import schema from .. import sql from .. import util from ..sql import expression +from ..sql import operators from ..sql.elements import BindParameter from ..util.typing import is_pep593 from ..util.typing import typing_get_args @@ -69,6 +70,7 @@ if typing.TYPE_CHECKING: from ..sql._typing import _InfoType from ..sql.elements import ClauseList from ..sql.elements import ColumnElement + from ..sql.operators import OperatorType from ..sql.schema import Column from ..sql.selectable import Select from ..util.typing import _AnnotationScanType @@ -741,21 +743,46 @@ class Composite( return self.prop._comparable_elements def __eq__(self, other: Any) -> ColumnElement[bool]: # type: ignore[override] # noqa: E501 + return self._compare(operators.eq, other) + + def __ne__(self, other: Any) -> ColumnElement[bool]: # type: ignore[override] # noqa: E501 + return self._compare(operators.ne, other) + + def __lt__(self, other: Any) -> ColumnElement[bool]: # type: ignore[override] # noqa: E501 + return self._compare(operators.lt, other) + + def __gt__(self, other: Any) -> ColumnElement[bool]: # type: ignore[override] # noqa: E501 + return self._compare(operators.gt, other) + + def __le__(self, other: Any) -> ColumnElement[bool]: # type: ignore[override] # noqa: E501 + return self._compare(operators.le, other) + + def __ge__(self, other: Any) -> ColumnElement[bool]: # type: ignore[override] # noqa: E501 + return self._compare(operators.ge, other) + + # what might be interesting would be if we create + # an instance of the composite class itself with + # the columns as data members, then use "hybrid style" comparison + # to create these comparisons. then your Point.__eq__() method could + # be where comparison behavior is defined for SQL also. Likely + # not a good choice for default behavior though, not clear how it would + # work w/ dataclasses, etc. also no demand for any of this anyway. + def _compare( + self, operator: OperatorType, other: Any + ) -> ColumnElement[bool]: values: Sequence[Any] if other is None: values = [None] * len(self.prop._comparable_elements) else: values = self.prop._composite_values_from_instance(other) comparisons = [ - a == b for a, b in zip(self.prop._comparable_elements, values) + operator(a, b) + for a, b in zip(self.prop._comparable_elements, values) ] if self._adapt_to_entity: assert self.adapter is not None - comparisons = [self.adapter(x) for x in comparisons] - return sql.and_(*comparisons) - - def __ne__(self, other: Any) -> ColumnElement[bool]: # type: ignore[override] # noqa: E501 - return sql.not_(self.__eq__(other)) + comparisons = [self.adapter(x) for x in comparisons] # type: ignore # noqa: E501 + return sql.and_(*comparisons) # type: ignore def __str__(self) -> str: return str(self.parent.class_.__name__) + "." + self.key |
