From 1c73149d5dd477ae882890e155e87f5dd9e4853f Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sun, 7 Feb 2010 00:56:05 +0000 Subject: [PATCH] - FunctionElement subclasses are now directly executable the same way any func.foo() construct is, with automatic SELECT being applied when passed to execute(). - The "type" and "bind" keyword arguments of a func.foo() construct are now local to "func." constructs and are not part of the FunctionElement base class, allowing a "type" to be handled in a custom constructor or class-level variable. --- CHANGES | 12 +++++++++++- lib/sqlalchemy/engine/base.py | 2 +- lib/sqlalchemy/sql/expression.py | 7 ++++--- test/sql/test_functions.py | 15 +++++++++++++-- 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/CHANGES b/CHANGES index e3f22b1ab2..d88a6bfdc8 100644 --- a/CHANGES +++ b/CHANGES @@ -20,7 +20,17 @@ CHANGES - sql - Added math negation operator support, -x. - + + - FunctionElement subclasses are now directly executable the + same way any func.foo() construct is, with automatic + SELECT being applied when passed to execute(). + + - The "type" and "bind" keyword arguments of a func.foo() + construct are now local to "func." constructs and are + not part of the FunctionElement base class, allowing + a "type" to be handled in a custom constructor or + class-level variable. + - mssql - Re-established initial support for pymssql. diff --git a/lib/sqlalchemy/engine/base.py b/lib/sqlalchemy/engine/base.py index 6a4fa5d08e..98d06a792f 100644 --- a/lib/sqlalchemy/engine/base.py +++ b/lib/sqlalchemy/engine/base.py @@ -1194,7 +1194,7 @@ class Connection(Connectable): # poor man's multimethod/generic function thingy executors = { - expression.Function: _execute_function, + expression.FunctionElement: _execute_function, expression.ClauseElement: _execute_clauseelement, Compiled: _execute_compiled, schema.SchemaItem: _execute_default, diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py index 89137d2ce0..878b0d8265 100644 --- a/lib/sqlalchemy/sql/expression.py +++ b/lib/sqlalchemy/sql/expression.py @@ -2481,15 +2481,13 @@ class _Case(ColumnElement): class FunctionElement(ColumnElement, FromClause): """Base for SQL function-oriented constructs.""" - + def __init__(self, *clauses, **kwargs): - self._bind = kwargs.get('bind', None) args = [_literal_as_binds(c, self.name) for c in clauses] self.clause_expr = ClauseList( operator=operators.comma_op, group_contents=True, *args).\ self_group() - self.type = sqltypes.to_instance(kwargs.get('type_', None)) @property def columns(self): @@ -2535,6 +2533,9 @@ class Function(FunctionElement): def __init__(self, name, *clauses, **kw): self.packagenames = kw.pop('packagenames', None) or [] self.name = name + self._bind = kw.get('bind', None) + self.type = sqltypes.to_instance(kw.get('type_', None)) + FunctionElement.__init__(self, *clauses, **kw) def _bind_param(self, obj): diff --git a/test/sql/test_functions.py b/test/sql/test_functions.py index 7a0f12cac3..e6bcd2680d 100644 --- a/test/sql/test_functions.py +++ b/test/sql/test_functions.py @@ -196,15 +196,26 @@ class ExecuteTest(TestBase): assert isinstance(x.execute().scalar(), datetime.date) def test_conn_execute(self): + from sqlalchemy.sql.expression import FunctionElement + from sqlalchemy.ext.compiler import compiles + + class myfunc(FunctionElement): + type = DATE() + + @compiles(myfunc) + def compile(elem, compiler, **kw): + return compiler.process(func.current_date()) + conn = testing.db.connect() try: x = conn.execute(func.current_date()).scalar() y = conn.execute(func.current_date().select()).scalar() z = conn.scalar(func.current_date()) + q = conn.scalar(myfunc()) finally: conn.close() - assert (x == y == z) is True - + assert (x == y == z == q) is True + @engines.close_first def test_update(self): """ -- 2.47.3