From 703ce7f1791c1143eb983c38e3bd627984ea1953 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sun, 5 Sep 2010 14:44:58 -0400 Subject: - rewrote the "connections" section - improved pool docs - typos etc. - ClauseElement.execute() and scalar() make no sense - these are depreacted. The official home is Executable. - alias() is not executable, allowing it is sloppy so this goes under the deprecated umbrella --- lib/sqlalchemy/sql/expression.py | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) (limited to 'lib/sqlalchemy/sql') diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py index d184816ab..5235a696b 100644 --- a/lib/sqlalchemy/sql/expression.py +++ b/lib/sqlalchemy/sql/expression.py @@ -1269,10 +1269,13 @@ class ClauseElement(Visitable): return engine else: return None - + + @util.deprecated("0.7", "Only SQL expressions which subclass :class:`.Executable` " + "may provide the :func:`.execute` method.") def execute(self, *multiparams, **params): - """Compile and execute this :class:`ClauseElement`.""" - + """Compile and execute this :class:`ClauseElement`. + + """ e = self.bind if e is None: label = getattr(self, 'description', self.__class__.__name__) @@ -1284,6 +1287,8 @@ class ClauseElement(Visitable): raise exc.UnboundExecutionError(msg) return e._execute_clauseelement(self, multiparams, params) + @util.deprecated("0.7", "Only SQL expressions which subclass :class:`.Executable` " + "may provide the :func:`.scalar` method.") def scalar(self, *multiparams, **params): """Compile and execute this :class:`ClauseElement`, returning the result's scalar representation. @@ -2401,7 +2406,7 @@ class Executable(_Generative): COMMIT will be invoked in order to provide its "autocommit" feature. Typically, all INSERT/UPDATE/DELETE statements as well as CREATE/DROP statements have autocommit behavior enabled; SELECT - constructs do not. Use this option when invokving a SELECT or other + constructs do not. Use this option when invoking a SELECT or other specific SQL construct where COMMIT is desired (typically when calling stored procedures and such). @@ -2436,6 +2441,27 @@ class Executable(_Generative): """ self._execution_options = self._execution_options.union(kw) + def execute(self, *multiparams, **params): + """Compile and execute this :class:`.Executable`.""" + + e = self.bind + if e is None: + label = getattr(self, 'description', self.__class__.__name__) + msg = ('This %s is not bound and does not support direct ' + 'execution. Supply this statement to a Connection or ' + 'Engine for execution. Or, assign a bind to the statement ' + 'or the Metadata of its underlying tables to enable ' + 'implicit execution via this method.' % label) + raise exc.UnboundExecutionError(msg) + return e._execute_clauseelement(self, multiparams, params) + + def scalar(self, *multiparams, **params): + """Compile and execute this :class:`.Executable`, returning the + result's scalar representation. + + """ + return self.execute(*multiparams, **params).scalar() + # legacy, some outside users may be calling this _Executable = Executable -- cgit v1.2.1 From 9bf88fa891edfb5b42fe909c45701be510998bf6 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Tue, 7 Sep 2010 11:57:19 -0400 Subject: - pending deprecation in 0.7 for the execute/scalar on clauseelement --- lib/sqlalchemy/sql/expression.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'lib/sqlalchemy/sql') diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py index 5235a696b..1b1cfee8a 100644 --- a/lib/sqlalchemy/sql/expression.py +++ b/lib/sqlalchemy/sql/expression.py @@ -1270,8 +1270,10 @@ class ClauseElement(Visitable): else: return None - @util.deprecated("0.7", "Only SQL expressions which subclass :class:`.Executable` " - "may provide the :func:`.execute` method.") + @util.pending_deprecation('0.7', + 'Only SQL expressions which subclass ' + ':class:`.Executable` may provide the ' + ':func:`.execute` method.') def execute(self, *multiparams, **params): """Compile and execute this :class:`ClauseElement`. @@ -1287,11 +1289,13 @@ class ClauseElement(Visitable): raise exc.UnboundExecutionError(msg) return e._execute_clauseelement(self, multiparams, params) - @util.deprecated("0.7", "Only SQL expressions which subclass :class:`.Executable` " - "may provide the :func:`.scalar` method.") + @util.pending_deprecation('0.7', + 'Only SQL expressions which subclass ' + ':class:`.Executable` may provide the ' + ':func:`.scalar` method.') def scalar(self, *multiparams, **params): - """Compile and execute this :class:`ClauseElement`, returning the - result's scalar representation. + """Compile and execute this :class:`ClauseElement`, returning + the result's scalar representation. """ return self.execute(*multiparams, **params).scalar() -- cgit v1.2.1 From fe250af8eb7294f08f491b3c1af9cf86a769f78c Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sun, 12 Sep 2010 19:18:08 -0400 Subject: - lazy loads for relationship attributes now use the current state, not the "committed" state, of foreign and primary key attributes when issuing SQL, if a flush is not in process. Previously, only the database-committed state would be used. In particular, this would cause a many-to-one get()-on-lazyload operation to fail, as autoflush is not triggered on these loads when the attributes are determined and the "committed" state may not be available. [ticket:1910] - A new flag on relationship(), load_on_pending, allows the lazy loader to fire off on pending objects without a flush taking place, as well as a transient object that's been manually "attached" to the session. Note that this flag blocks attribute events from taking place when an object is loaded, so backrefs aren't available until after a flush. The flag is only intended for very specific use cases. --- lib/sqlalchemy/sql/util.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'lib/sqlalchemy/sql') diff --git a/lib/sqlalchemy/sql/util.py b/lib/sqlalchemy/sql/util.py index c999ab786..bd4f70247 100644 --- a/lib/sqlalchemy/sql/util.py +++ b/lib/sqlalchemy/sql/util.py @@ -92,6 +92,31 @@ def find_columns(clause): visitors.traverse(clause, {}, {'column':cols.add}) return cols +def bind_values(clause): + """Return an ordered list of "bound" values in the given clause. + + E.g.:: + + >>> expr = and_( + ... table.c.foo==5, table.c.foo==7 + ... ) + >>> bind_values(expr) + [5, 7] + """ + + v = [] + def visit_bindparam(bind): + value = bind.value + + # evaluate callables + if callable(value): + value = value() + + v.append(value) + + visitors.traverse(clause, {}, {'bindparam':visit_bindparam}) + return v + def _quote_ddl_expr(element): if isinstance(element, basestring): element = element.replace("'", "''") -- cgit v1.2.1 From 003149c504149849c679a60a1f346a0f0393dce0 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sat, 18 Sep 2010 13:18:44 -0400 Subject: - An informative error message is raised if a Column which has not yet been assigned a name, i.e. as in declarative, is used in a context where it is exported to the columns collection of an enclosing select() construct, or if any construct involving that column is compiled before its name is assigned. [ticket:1862] --- lib/sqlalchemy/sql/compiler.py | 4 ++++ lib/sqlalchemy/sql/expression.py | 20 +++++++++++--------- 2 files changed, 15 insertions(+), 9 deletions(-) (limited to 'lib/sqlalchemy/sql') diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index fcff5e355..e47db7e28 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -332,6 +332,10 @@ class SQLCompiler(engine.Compiled): def visit_column(self, column, result_map=None, **kwargs): name = column.name + if name is None: + raise exc.CompileError("Cannot compile Column object until " + "it's 'name' is assigned.") + if not column.is_literal and isinstance(name, sql._generated_label): name = self._truncated_identifier("colident", name) diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py index 1b1cfee8a..70d5f13fc 100644 --- a/lib/sqlalchemy/sql/expression.py +++ b/lib/sqlalchemy/sql/expression.py @@ -1852,17 +1852,19 @@ class ColumnElement(ClauseElement, _CompareMixin): descending selectable. """ - - if name: - co = ColumnClause(name, selectable, type_=getattr(self, - 'type', None)) + if name is None: + name = self.anon_label + # TODO: may want to change this to anon_label, + # or some value that is more useful than the + # compiled form of the expression + key = str(self) else: - name = str(self) - co = ColumnClause(self.anon_label, selectable, - type_=getattr(self, 'type', None)) - + key = name + + co = ColumnClause(name, selectable, type_=getattr(self, + 'type', None)) co.proxies = [self] - selectable.columns[name] = co + selectable.columns[key] = co return co def compare(self, other, use_proxies=False, equivalents=None, **kw): -- cgit v1.2.1 From c5c8cdf3b4d7dc456cfef29ea04b2b7300060c7a Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sat, 18 Sep 2010 13:34:04 -0400 Subject: - as_scalar(), label() can be called on a selectable which contains a Column that is not yet named. [ticket:1862] --- lib/sqlalchemy/sql/expression.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'lib/sqlalchemy/sql') diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py index 70d5f13fc..5df3b8794 100644 --- a/lib/sqlalchemy/sql/expression.py +++ b/lib/sqlalchemy/sql/expression.py @@ -3685,8 +3685,7 @@ class _ScalarSelect(_Grouping): def __init__(self, element): self.element = element - cols = list(element.c) - self.type = cols[0].type + self.type = element._scalar_type() @property def columns(self): @@ -3737,7 +3736,10 @@ class CompoundSelect(_SelectBaseMixin, FromClause): self.selects.append(s.self_group(self)) _SelectBaseMixin.__init__(self, **kwargs) - + + def _scalar_type(self): + return self.selects[0]._scalar_type() + def self_group(self, against=None): return _FromGrouping(self) @@ -3910,6 +3912,11 @@ class Select(_SelectBaseMixin, FromClause): return froms + def _scalar_type(self): + elem = self._raw_columns[0] + cols = list(elem._select_iterable) + return cols[0].type + @property def froms(self): """Return the displayed list of FromClause elements.""" -- cgit v1.2.1