]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Support `matmul` (@) as an optional operator.
authorAramís Segovia <aramissegovia@gmail.com>
Sat, 10 May 2025 16:36:46 +0000 (12:36 -0400)
committerAramís Segovia <aramissegovia@gmail.com>
Sat, 10 May 2025 17:01:29 +0000 (13:01 -0400)
Fixes: #12479
doc/build/changelog/unreleased_21/12479.rst [new file with mode: 0644]
lib/sqlalchemy/sql/default_comparator.py
lib/sqlalchemy/sql/elements.py
lib/sqlalchemy/sql/operators.py
test/sql/test_operators.py

diff --git a/doc/build/changelog/unreleased_21/12479.rst b/doc/build/changelog/unreleased_21/12479.rst
new file mode 100644 (file)
index 0000000..4cced47
--- /dev/null
@@ -0,0 +1,6 @@
+.. change::
+    :tags: core, feature, sql
+    :tickets: 12479
+
+      The Core operator system now includes the `matmul` operator, i.e. the
+      @ operator in Python as an optional operator.
index c1305be99470650eda61bd053f438ae48feb594b..eba769f892af446d9293fbd39b8eb17755eef5b1 100644 (file)
@@ -558,6 +558,7 @@ operator_lookup: Dict[
     "getitem": (_getitem_impl, util.EMPTY_DICT),
     "lshift": (_unsupported_impl, util.EMPTY_DICT),
     "rshift": (_unsupported_impl, util.EMPTY_DICT),
+    "matmul": (_unsupported_impl, util.EMPTY_DICT),
     "contains": (_unsupported_impl, util.EMPTY_DICT),
     "regexp_match_op": (_regexp_match_impl, util.EMPTY_DICT),
     "not_regexp_match_op": (_regexp_match_impl, util.EMPTY_DICT),
index 42dfe6110647f1636bbf3649a9ddc6429c69d422..75bf72f03363b8a95a9a266476e68e27f0ffee02 100644 (file)
@@ -924,6 +924,8 @@ class SQLCoreOperations(Generic[_T_co], ColumnOperators, TypingOnly):
 
         def __rshift__(self, other: Any) -> ColumnElement[Any]: ...
 
+        def __matmul__(self, other: Any) -> ColumnElement[Any]: ...
+
         @overload
         def concat(self: _SQO[str], other: Any) -> ColumnElement[str]: ...
 
index 635e5712ad57b2d6abcb12e825f5f20944ca9181..ed0582d309d71df57a5be2c797dd96635a3e2200 100644 (file)
@@ -25,6 +25,7 @@ from operator import inv as _uncast_inv
 from operator import le as _uncast_le
 from operator import lshift as _uncast_lshift
 from operator import lt as _uncast_lt
+from operator import matmul as _uncast_matmul
 from operator import mod as _uncast_mod
 from operator import mul as _uncast_mul
 from operator import ne as _uncast_ne
@@ -110,6 +111,7 @@ inv = cast(OperatorType, _uncast_inv)
 le = cast(OperatorType, _uncast_le)
 lshift = cast(OperatorType, _uncast_lshift)
 lt = cast(OperatorType, _uncast_lt)
+matmul = cast(OperatorType, _uncast_matmul)
 mod = cast(OperatorType, _uncast_mod)
 mul = cast(OperatorType, _uncast_mul)
 ne = cast(OperatorType, _uncast_ne)
@@ -678,6 +680,15 @@ class ColumnOperators(Operators):
         """
         return self.operate(rshift, other)
 
+    def __matmul__(self, other: Any) -> ColumnOperators:
+        """Implement the @ operator.
+
+        Not used by SQLAlchemy core, this is provided
+        for custom operator systems which want to use
+        @ as an extension point.
+        """
+        return self.operate(matmul, other)
+
     def concat(self, other: Any) -> ColumnOperators:
         """Implement the 'concat' operator.
 
index 099301707fcd20f1d868c95cdabc476172dfb9d1..753a2e3c1bde8882a375afe5f6220c8c89347367 100644 (file)
@@ -977,6 +977,16 @@ class ExtensionOperatorTest(fixtures.TestBase, testing.AssertsCompiledSQL):
 
         self.assert_compile(Column("x", MyType()) >> 5, "x -> :x_1")
 
+    def test_matmul(self):
+        class MyType(UserDefinedType):
+            cache_ok = True
+
+            class comparator_factory(UserDefinedType.Comparator):
+                def __matmul__(self, other):
+                    return self.op("->")(other)
+
+        self.assert_compile(Column("x", MyType()) @ 5, "x -> :x_1")
+
 
 class JSONIndexOpTest(fixtures.TestBase, testing.AssertsCompiledSQL):
     def setup_test(self):