diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2022-01-04 14:04:15 -0500 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2022-01-04 16:40:35 -0500 |
| commit | 63eeec396e5d180e11a342920e7c3e49be434eb1 (patch) | |
| tree | 02e203f26828018189ef20d0ff73fcc70f61c386 /test/orm/test_evaluator.py | |
| parent | 400bf1716f84821d63daaf0a988d725dfd55d6a0 (diff) | |
| download | sqlalchemy-63eeec396e5d180e11a342920e7c3e49be434eb1.tar.gz | |
implement python_impl to custom_op for basic ORM evaluator extensibility
Added new parameter :paramref:`_sql.Operators.op.python_impl`, available
from :meth:`_sql.Operators.op` and also when using the
:class:`_sql.Operators.custom_op` constructor directly, which allows an
in-Python evaluation function to be provided along with the custom SQL
operator. This evaluation function becomes the implementation used when the
operator object is used given plain Python objects as operands on both
sides, and in particular is compatible with the
``synchronize_session='evaluate'`` option used with
:ref:`orm_expression_update_delete`.
Fixes: #3162
Change-Id: If46ba6a0e303e2180a177ba418a8cafe9b42608e
Diffstat (limited to 'test/orm/test_evaluator.py')
| -rw-r--r-- | test/orm/test_evaluator.py | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/test/orm/test_evaluator.py b/test/orm/test_evaluator.py index 62acca582..33692505c 100644 --- a/test/orm/test_evaluator.py +++ b/test/orm/test_evaluator.py @@ -8,7 +8,9 @@ from sqlalchemy import Integer from sqlalchemy import not_ from sqlalchemy import or_ from sqlalchemy import String +from sqlalchemy import testing from sqlalchemy import tuple_ +from sqlalchemy.ext.hybrid import hybrid_property from sqlalchemy.orm import evaluator from sqlalchemy.orm import exc as orm_exc from sqlalchemy.orm import relationship @@ -17,6 +19,7 @@ from sqlalchemy.testing import assert_raises_message from sqlalchemy.testing import expect_warnings from sqlalchemy.testing import fixtures from sqlalchemy.testing import is_ +from sqlalchemy.testing.assertions import expect_raises_message from sqlalchemy.testing.fixtures import fixture_session from sqlalchemy.testing.schema import Column from sqlalchemy.testing.schema import Table @@ -200,6 +203,23 @@ class EvaluateTest(fixtures.MappedTest): ], ) + @testing.combinations( + lambda User: User.name + "_foo" == "named_foo", + lambda User: User.name.startswith("nam"), + lambda User: User.name.endswith("named"), + ) + def test_string_ops(self, expr): + User = self.classes.User + + test_expr = testing.resolve_lambda(expr, User=User) + eval_eq( + test_expr, + testcases=[ + (User(name="named"), True), + (User(name="othername"), False), + ], + ) + def test_in(self): User = self.classes.User @@ -225,6 +245,15 @@ class EvaluateTest(fixtures.MappedTest): ], ) + def test_mulitple_expressions(self): + User = self.classes.User + + evaluator = compiler.process(User.id > 5, User.name == "ed") + + is_(evaluator(User(id=7, name="ed")), True) + is_(evaluator(User(id=7, name="noted")), False) + is_(evaluator(User(id=4, name="ed")), False) + def test_in_tuples(self): User = self.classes.User @@ -268,6 +297,52 @@ class EvaluateTest(fixtures.MappedTest): ], ) + def test_hybrids(self, registry): + @registry.mapped + class SomeClass: + __tablename__ = "sc" + id = Column(Integer, primary_key=True) + data = Column(String) + + @hybrid_property + def foo_data(self): + return self.data + "_foo" + + eval_eq( + SomeClass.foo_data == "somedata_foo", + testcases=[ + (SomeClass(data="somedata"), True), + (SomeClass(data="otherdata"), False), + (SomeClass(data=None), None), + ], + ) + + def test_custom_op_no_impl(self): + """test #3162""" + + User = self.classes.User + + with expect_raises_message( + evaluator.UnevaluatableError, + r"Custom operator '\^\^' can't be evaluated in " + "Python unless it specifies", + ): + compiler.process(User.name.op("^^")("bar")) + + def test_custom_op(self): + """test #3162""" + + User = self.classes.User + + eval_eq( + User.name.op("^^", python_impl=lambda a, b: a + "_foo_" + b)("bar") + == "name_foo_bar", + testcases=[ + (User(name="name"), True), + (User(name="notname"), False), + ], + ) + class M2OEvaluateTest(fixtures.DeclarativeMappedTest): @classmethod |
