"""
return BindParamClause('literal', value, type=type)
+def label(name, obj):
+ """returns a Label object for the given selectable, used in the column list for a select statement."""
+ return Label(name, obj)
+
def column(table, text):
"""returns a textual column clause, relative to a table. this differs from using straight text
or text() in that the column is treated like a regular column, i.e. gets added to a Selectable's list
def visit_null(self, null):pass
def visit_clauselist(self, list):pass
def visit_function(self, func):pass
-
+ def visit_label(self, label):pass
+
class Compiled(ClauseVisitor):
"""represents a compiled SQL expression. the __str__ method of the Compiled object
should produce the actual text of the statement. Compiled objects are specific to the
engine = property(lambda s: s._find_engine())
- def _get_columns(self):
- try:
- return self._columns
- except AttributeError:
- return [self]
- columns = property(lambda s: s._get_columns())
def compile(self, engine = None, parameters = None, typemap=None):
"""compiles this SQL expression using its underlying SQLEngine to produce
return self._compare('LIKE', str(other) + "%")
def endswith(self, other):
return self._compare('LIKE', "%" + str(other))
+ def label(self, name):
+ return Label(name, self)
# and here come the math operators:
def __add__(self, other):
return self._compare('+', other)
else:
obj = self._bind_param(obj)
- return BinaryClause(self, obj, operator)
+ return BinaryClause(self, obj, operator, type=obj.type)
+
+class Selectable(ClauseElement):
+ """represents a column list-holding object."""
+
+ def _get_columns(self):
+ try:
+ return self._columns
+ except AttributeError:
+ return [self]
+ columns = property(lambda s: s._get_columns())
+ c = property(lambda self: self.columns)
+
+ def accept_visitor(self, visitor):
+ raise NotImplementedError()
+
+ def is_selectable(self):
+ return True
+
+ def select(self, whereclauses = None, **params):
+ return select([self], whereclauses, **params)
+
+ def _get_col_by_original(self, column):
+ """given a column which is a schema.Column object attached to a schema.Table object
+ (i.e. an "original" column), return the Column object from this
+ Selectable which corresponds to that original Column, or None if this Selectable
+ does not contain the column."""
+ raise NotImplementedError()
-class FromClause(ClauseElement):
- """represents an element within the FROM clause of a SELECT statement."""
+ def _group_parenthesized(self):
+ """indicates if this Selectable requires parenthesis when grouped into a compound
+ statement"""
+ return True
+
+class ColumnElement(Selectable, CompareMixin):
+ """represents a column element within the list of a Selectable's columns."""
+ primary_key = property(lambda s:False)
+ original = property(lambda self:self)
+
+class FromClause(Selectable):
+ """represents an element that can be used within the FROM clause of a SELECT statement."""
def __init__(self, from_name = None, from_key = None):
self.from_name = from_name
self.id = from_key or from_name
return "FromClause(%s, %s)" % (repr(self.id), repr(self.from_name))
def accept_visitor(self, visitor):
visitor.visit_fromclause(self)
+ def join(self, right, *args, **kwargs):
+ return Join(self, right, *args, **kwargs)
+ def outerjoin(self, right, *args, **kwargs):
+ return Join(self, right, isouter = True, *args, **kwargs)
+ def alias(self, name):
+ return Alias(self, name)
+
class BindParamClause(ClauseElement, CompareMixin):
"""represents a bind parameter. public constructor is the bindparam() function."""
def hash_key(self):
return string.join([c.hash_key() for c in self.clauses], self.operator or " ")
+
class Function(ClauseList, CompareMixin):
"""describes a SQL function. extends ClauseList to provide comparison operators."""
def __init__(self, name, *clauses, **kwargs):
self.name = name
- self.type = kwargs.get('type', None)
- self.label = kwargs.get('label', None)
+ self.type = kwargs.get('type', types.NULLTYPE)
ClauseList.__init__(self, parens=True, *clauses)
key = property(lambda self:self.label or self.name)
def append(self, clause):
class BinaryClause(ClauseElement, CompareMixin):
"""represents two clauses with an operator in between"""
- def __init__(self, left, right, operator):
+ def __init__(self, left, right, operator, type=None):
self.left = left
self.right = right
self.operator = operator
+ self.type = type
self.parens = False
def copy_container(self):
return BinaryClause(self.left.copy_container(), self.right.copy_container(), self.operator)
c = self.left
self.left = self.right
self.right = c
-
-class Selectable(FromClause):
- """represents a column list-holding object, like a table, alias or subquery. can be used anywhere a Table is used."""
-
- c = property(lambda self: self.columns)
-
- def accept_visitor(self, visitor):
- raise NotImplementedError()
-
- def is_selectable(self):
- return True
-
- def select(self, whereclauses = None, **params):
- return select([self], whereclauses, **params)
-
- def _get_col_by_original(self, column):
- """given a column which is a schema.Column object attached to a schema.Table object
- (i.e. an "original" column), return the Column object from this
- Selectable which corresponds to that original Column, or None if this Selectable
- does not contain the column."""
- raise NotImplementedError()
-
- def join(self, right, *args, **kwargs):
- return Join(self, right, *args, **kwargs)
- def outerjoin(self, right, *args, **kwargs):
- return Join(self, right, isouter = True, *args, **kwargs)
- def alias(self, name):
- return Alias(self, name)
- def _group_parenthesized(self):
- """indicates if this Selectable requires parenthesis when grouped into a compound
- statement"""
- return True
-class Join(Selectable):
+class Join(FromClause):
# TODO: put "using" + "natural" concepts in here and make "onclause" optional
def __init__(self, left, right, onclause=None, isouter = False, allcols = True):
self.left = left
def _get_from_objects(self):
return [self] + self.onclause._get_from_objects() + self.left._get_from_objects() + self.right._get_from_objects()
-class Alias(Selectable):
+class Alias(FromClause):
def __init__(self, selectable, alias = None):
self.selectable = selectable
self._columns = util.OrderedProperties()
engine = property(lambda s: s.selectable.engine)
-class ColumnClause(Selectable, CompareMixin):
+
+class Label(ColumnElement):
+ def __init__(self, name, obj):
+ self.name = name
+ while isinstance(obj, Label):
+ obj = obj.obj
+ self.obj = obj
+ obj.parens=True
+ key = property(lambda s: s.name)
+ _label = property(lambda s: s.name)
+ def accept_visitor(self, visitor):
+ self.obj.accept_visitor(visitor)
+ visitor.visit_label(self)
+ def _get_from_objects(self):
+ return self.obj._get_from_objects()
+ def _make_proxy(self, selectable, name = None):
+ cc = ColumnClause(self.name)
+ selectable.c[self.name] = cc
+ return cc
+
+class ColumnClause(ColumnElement):
"""represents a textual column clause in a SQL statement. allows the creation
of an additional ad-hoc column that is compiled against a particular table."""
def __init__(self, text, selectable=None):
self.text = text
self.table = selectable
- self._impl = ColumnImpl(self)
self.type = types.NullTypeEngine()
name = property(lambda self:self.text)
key = property(lambda self:self.text)
- label = property(lambda self:self.text)
-
+ _label = property(lambda self:self.text)
+
def accept_visitor(self, visitor):
visitor.visit_columnclause(self)
def _make_proxy(self, selectable, name = None):
c = ColumnClause(self.text or name, selectable)
selectable.columns[c.key] = c
- c._impl = ColumnImpl(c)
return c
-class ColumnImpl(Selectable, CompareMixin):
- """Selectable implementation that gets attached to a schema.Column object."""
+class ColumnImpl(ColumnElement):
+ """gets attached to a schema.Column object."""
def __init__(self, column):
self.column = column
self._columns = [self.column]
if column.table.name:
- self.label = column.table.name + "_" + self.column.name
+ self._label = column.table.name + "_" + self.column.name
else:
- self.label = self.column.name
+ self._label = self.column.name
engine = property(lambda s: s.column.engine)
+ def label(self, name):
+ return Label(name, self.column)
+
def copy_container(self):
return self.column
else:
obj = self._bind_param(obj)
- return BinaryClause(self.column, obj, operator)
+ return BinaryClause(self.column, obj, operator, type=self.column.type)
-class TableImpl(Selectable):
+class TableImpl(FromClause):
"""attached to a schema.Table to provide it with a Selectable interface
as well as other functions
"""
else:
return [self]
-class CompoundSelect(SelectBaseMixin, Selectable):
+class CompoundSelect(SelectBaseMixin, FromClause):
def __init__(self, keyword, *selects, **kwargs):
self.id = "Compound(%d)" % id(self)
self.keyword = keyword
else:
return None
-class Select(SelectBaseMixin, Selectable):
+class Select(SelectBaseMixin, FromClause):
"""represents a SELECT statement, with appendable clauses, as well as
the ability to execute itself and return a result set."""
def __init__(self, columns=None, whereclause = None, from_obj = [], order_by = None, group_by=None, having=None, use_labels = False, distinct=False, engine = None, limit=None, offset=None):
for f in column._get_from_objects():
f.accept_visitor(self._correlator)
- if self.rowid_column is None and hasattr(f, 'rowid_column'):
+ if self.rowid_column is None and hasattr(f, 'rowid_column') and f.rowid_column is not None:
self.rowid_column = f.rowid_column._make_proxy(self)
column._process_from_dict(self._froms, False)
if column.is_selectable():
for co in column.columns:
if self.use_labels:
- co._make_proxy(self, name = co.label)
+ co._make_proxy(self, name = co._label)
else:
co._make_proxy(self)
-
+
def _get_col_by_original(self, column):
if self.use_labels:
- return self.columns.get(column.label,None)
+ return self.columns.get(column._label,None)
else:
return self.columns.get(column.key,None)
+ def _pks(self):
+ ret = {}
+ for from_obj in self._get_froms():
+ for c in from_obj.c:
+ if c.primary_key:
+ ret[c] = c
+ return ret.keys()
+ primary_key = property (lambda self: self._pks())
+
def append_whereclause(self, whereclause):
self._append_condition('whereclause', whereclause)
def append_having(self, having):
setattr(self, attribute, and_(getattr(self, attribute), condition))
else:
setattr(self, attribute, condition)
+
+ def hash_key(self):
+ return "Select(%d)" % (id(self))
def clear_from(self, id):
self.append_from(FromClause(from_name = None, from_key = id))