From: Mike Bayer Date: Wed, 21 Mar 2007 20:43:34 +0000 (+0000) Subject: - slightly better support for bind params as column clauses, either X-Git-Tag: rel_0_3_6~7 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cef652a2d612ecbf078d57fbf81abef21a18b631;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - slightly better support for bind params as column clauses, either via bindparam() or via literal(), i.e. select([literal('foo')]) - removed "table" argument from column(). this does not add the column to the table anyway so was misleading. - Select _exportable_columns() only exports Selectable instances - Select uses _exportable_columns() when searching for engines instead of _raw_columns for similar reasons (non selectables have no engine) - _BindParamClause no longer has a _make_proxy(). its not a ColumnElement. - _Label detects underlying column element and will generate its own column()._make_proxy() if the element is not a ColumnElement. this allows a Label to be declared for nearly anything and it can export itself as a column on a containing Selectable. --- diff --git a/CHANGES b/CHANGES index 2f0f72d5d8..600350ca81 100644 --- a/CHANGES +++ b/CHANGES @@ -6,7 +6,10 @@ with conflicting names, specify "unique=True" - this option is still used internally for all the auto-genererated (value-based) bind parameters. - + + - slightly better support for bind params as column clauses, either + via bindparam() or via literal(), i.e. select([literal('foo')]) + - exists() becomes useable as a standalone selectable, not just in a WHERE clause, i.e. exists([columns], criterion).select() diff --git a/lib/sqlalchemy/sql.py b/lib/sqlalchemy/sql.py index 5c472310a8..8059d95151 100644 --- a/lib/sqlalchemy/sql.py +++ b/lib/sqlalchemy/sql.py @@ -318,14 +318,14 @@ def label(name, obj): return _Label(name, obj) -def column(text, table=None, type=None, **kwargs): +def column(text, type=None): """Return a textual column clause, relative to a table. This is also the primitive version of a ``schema.Column`` which is a subclass. """ - return _ColumnClause(text, table, type, **kwargs) + return _ColumnClause(text, type=type) def literal_column(text, table=None, type=None, **kwargs): """Return a textual column clause with the `literal` flag set. @@ -1327,9 +1327,6 @@ class _BindParamClause(ClauseElement, _CompareMixin): return isinstance(other, _BindParamClause) and other.type.__class__ == self.type.__class__ - def _make_proxy(self, selectable, name = None): - return self - def __repr__(self): return "_BindParamClause(%s, %s, type=%s)" % (repr(self.key), repr(self.value), repr(self.type)) @@ -1845,7 +1842,10 @@ class _Label(ColumnElement): return self.obj._get_from_objects() def _make_proxy(self, selectable, name = None): - return self.obj._make_proxy(selectable, name=self.name) + if isinstance(self.obj, Selectable): + return self.obj._make_proxy(selectable, name=self.name) + else: + return column(self.name)._make_proxy(selectable=selectable) legal_characters = util.Set(string.ascii_letters + string.digits + '_') @@ -1915,7 +1915,7 @@ class _ColumnClause(ColumnElement): # propigate the "is_literal" flag only if we are keeping our name, # otherwise its considered to be a label is_literal = self.is_literal and (name is None or name == self.name) - c = _ColumnClause(name or self.name, selectable, _is_oid=self._is_oid, type=self.type, is_literal=is_literal) + c = _ColumnClause(name or self.name, selectable=selectable, _is_oid=self._is_oid, type=self.type, is_literal=is_literal) c.orig_set = self.orig_set if not self._is_oid: selectable.columns[c.name] = c @@ -2227,7 +2227,8 @@ class Select(_SelectBaseMixin, FromClause): return label(name, self) def _exportable_columns(self): - return self._raw_columns + return [c for c in self._raw_columns if isinstance(c, Selectable)] + def _proxy_column(self, column): if self.use_labels: return column._make_proxy(self, name=column._label) @@ -2325,7 +2326,7 @@ class Select(_SelectBaseMixin, FromClause): return e # look through the columns (largely synomous with looking # through the FROMs except in the case of _CalculatedClause/_Function) - for cc in self._raw_columns: + for cc in self._exportable_columns(): for c in cc.columns: if getattr(c, 'table', None) is self: continue diff --git a/test/sql/select.py b/test/sql/select.py index b6f7699597..1ca8224a8a 100644 --- a/test/sql/select.py +++ b/test/sql/select.py @@ -678,6 +678,13 @@ myothertable.othername != :myothertable_othername AND EXISTS (select yay from fo c = s.compile(parameters = {'test' : 7}) self.assert_(c.get_params() == {'test' : 7}) + def testbindascol(self): + t = table('foo', column('id')) + + s = select([t, literal('lala').label('hoho')]) + self.runtest(s, "SELECT foo.id, :literal AS hoho FROM foo") + assert [str(c) for c in s.c] == ["id", "hoho"] + def testin(self): self.runtest(select([table1], table1.c.myid.in_(1, 2, 3)), "SELECT mytable.myid, mytable.name, mytable.description FROM mytable WHERE mytable.myid IN (:mytable_myid, :mytable_my_1, :mytable_my_2)")