summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2007-08-09 21:50:23 +0000
committerMike Bayer <mike_mp@zzzcomputing.com>2007-08-09 21:50:23 +0000
commit578efcfeb3b0b177ce559f5e7748c02f2fc263a7 (patch)
tree701f524427eb889317f1d8df21fa6f557fc64748 /lib/sqlalchemy/sql.py
parent72b02cc09364da3f7be9e2cac5e2fb5db4222a2d (diff)
downloadsqlalchemy-578efcfeb3b0b177ce559f5e7748c02f2fc263a7.tar.gz
- decoupled all ColumnElements from also being Selectables. this means
that anything which is a column expression does not have a "c" or a "columns" attribute. Also works for select().as_scalar(); _ScalarSelect is a columnelement, so you can't say select().as_scalar().c.foo, which is a pretty confusing mistake to make. in the case of _ScalarSelect made an explicit raise if you try to access 'c'.
Diffstat (limited to 'lib/sqlalchemy/sql.py')
-rw-r--r--lib/sqlalchemy/sql.py97
1 files changed, 63 insertions, 34 deletions
diff --git a/lib/sqlalchemy/sql.py b/lib/sqlalchemy/sql.py
index bc255c5af..cd9e4b4aa 100644
--- a/lib/sqlalchemy/sql.py
+++ b/lib/sqlalchemy/sql.py
@@ -1549,8 +1549,7 @@ class Selectable(ClauseElement):
def select(self, whereclauses = None, **params):
return select([self], whereclauses, **params)
-
-class ColumnElement(Selectable, _CompareMixin):
+class ColumnElement(ClauseElement, _CompareMixin):
"""Represent an element that is useable within the
"column clause" portion of a ``SELECT`` statement.
@@ -1582,11 +1581,6 @@ class ColumnElement(Selectable, _CompareMixin):
which each represent a foreign key placed on this column's ultimate
ancestor.
""")
- columns = property(lambda self:[self],
- doc=\
- """Columns accessor which returns ``self``, to provide compatibility
- with ``Selectable`` objects.
- """)
def _one_fkey(self):
if self._foreign_keys:
@@ -1909,13 +1903,13 @@ class FromClause(Selectable):
"""return the list of ColumnElements represented within this FromClause's _exportable_columns"""
export = self._exportable_columns()
for column in export:
- # TODO: is this conditional needed ?
if isinstance(column, Selectable):
- s = column
+ for co in column.columns:
+ yield co
+ elif isinstance(column, ColumnElement):
+ yield column
else:
continue
- for co in s.columns:
- yield co
def _exportable_columns(self):
return []
@@ -2219,7 +2213,8 @@ class _Function(_CalculatedClause, FromClause):
self.append(c)
key = property(lambda self:self.name)
-
+ columns = property(lambda self:[self])
+
def _copy_internals(self):
_CalculatedClause._copy_internals(self)
self._clone_from_clause()
@@ -2353,18 +2348,21 @@ class _Exists(_UnaryExpression):
def __init__(self, *args, **kwargs):
kwargs['correlate'] = True
- s = select(*args, **kwargs).self_group()
+ s = select(*args, **kwargs).as_scalar().self_group()
_UnaryExpression.__init__(self, s, operator=Operators.exists)
+ def select(self, whereclauses = None, **params):
+ return select([self], whereclauses, **params)
+
def correlate(self, fromclause):
- e = self._clone()
- e.element = self.element.correlate(fromclause).self_group()
- return e
+ e = self._clone()
+ e.element = self.element.correlate(fromclause).self_group()
+ return e
def where(self, clause):
- e = self._clone()
- e.element = self.element.where(clause).self_group()
- return e
+ e = self._clone()
+ e.element = self.element.where(clause).self_group()
+ return e
def _hide_froms(self, **modifiers):
return self._get_from_objects(**modifiers)
@@ -2427,7 +2425,7 @@ class Join(FromClause):
primary_key = property(lambda s:s.__primary_key)
def self_group(self, against=None):
- return _Grouping(self)
+ return _FromGrouping(self)
def _locate_oid_column(self):
return self.left.oid_column
@@ -2639,7 +2637,6 @@ class _ColumnElementAdapter(ColumnElement):
key = property(lambda s: s.elem.key)
_label = property(lambda s: s.elem._label)
- columns = c = property(lambda s:s.elem.columns)
def _copy_internals(self):
self.elem = self.elem._clone()
@@ -2657,8 +2654,33 @@ class _ColumnElementAdapter(ColumnElement):
return getattr(self.elem, attr)
class _Grouping(_ColumnElementAdapter):
+ """represent a grouping within a column expression"""
pass
+class _FromGrouping(FromClause):
+ """represent a grouping of a FROM clause"""
+ __visit_name__ = 'grouping'
+
+ def __init__(self, elem):
+ self.elem = elem
+
+ columns = c = property(lambda s:s.elem.columns)
+
+ def get_children(self, **kwargs):
+ return self.elem,
+
+ def _hide_froms(self, **modifiers):
+ return self.elem._hide_froms(**modifiers)
+
+ def _copy_internals(self):
+ self.elem = self.elem._clone()
+
+ def _get_from_objects(self, **modifiers):
+ return self.elem._get_from_objects(**modifiers)
+
+ def __getattr__(self, attr):
+ return getattr(self.elem, attr)
+
class _Label(ColumnElement):
"""represent a label, as typically applied to any column-level element
using the ``AS`` sql keyword.
@@ -2698,7 +2720,7 @@ class _Label(ColumnElement):
return self.obj._hide_froms(**modifiers)
def _make_proxy(self, selectable, name = None):
- if isinstance(self.obj, Selectable):
+ if isinstance(self.obj, (Selectable, ColumnElement)):
return self.obj._make_proxy(selectable, name=self.name)
else:
return column(self.name)._make_proxy(selectable=selectable)
@@ -2979,7 +3001,10 @@ class _ScalarSelect(_Grouping):
super(_ScalarSelect, self).__init__(elem)
self.type = list(elem.inner_columns)[0].type
- columns = property(lambda self:[self])
+ def _no_cols(self):
+ raise exceptions.InvalidRequestError("Scalar Select expression has no columns; use this object directly within a column-level expression.")
+ c = property(_no_cols)
+ columns = c
def self_group(self, **kwargs):
return self
@@ -3013,7 +3038,7 @@ class CompoundSelect(_SelectBaseMixin, FromClause):
name = property(lambda s:s.keyword + " statement")
def self_group(self, against=None):
- return _Grouping(self)
+ return _FromGrouping(self)
def _locate_oid_column(self):
return self.selects[0].oid_column
@@ -3143,6 +3168,11 @@ class Select(_SelectBaseMixin, FromClause):
return froms
froms = property(_get_display_froms, doc="""Return a list of all FromClause elements which will be applied to the FROM clause of the resulting statement.""")
+
+ name = property(lambda self:"Select statement")
+
+ def expression_element(self):
+ return self.as_scalar()
def locate_all_froms(self):
froms = util.Set()
@@ -3346,7 +3376,7 @@ class Select(_SelectBaseMixin, FromClause):
self._froms.add(fromclause)
def _exportable_columns(self):
- return [c for c in self._raw_columns if isinstance(c, Selectable)]
+ return [c for c in self._raw_columns if isinstance(c, (Selectable, ColumnElement))]
def _proxy_column(self, column):
if self.use_labels:
@@ -3357,7 +3387,7 @@ class Select(_SelectBaseMixin, FromClause):
def self_group(self, against=None):
if isinstance(against, CompoundSelect):
return self
- return _Grouping(self)
+ return _FromGrouping(self)
def _locate_oid_column(self):
for f in self.locate_all_froms():
@@ -3405,14 +3435,13 @@ 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._exportable_columns():
- for c in cc.columns:
- if getattr(c, 'table', None) is self:
- continue
- e = c.bind
- if e is not None:
- self._bind = e
- return e
+ for c in self._exportable_columns():
+ if getattr(c, 'table', None) is self:
+ continue
+ e = c.bind
+ if e is not None:
+ self._bind = e
+ return e
return None
class _UpdateBase(ClauseElement):