if c is None: continue
self.append(c)
self.parens = kwargs.get('parens', False)
+ def hash_key(self):
+ return string.join([c.hash_key() for c in self.clauses], ",")
def copy_container(self):
clauses = [clause.copy_container() for clause in self.clauses]
return ClauseList(parens=self.parens, *clauses)
self.name = name
self.type = kwargs.get('type', sqltypes.NULLTYPE)
ClauseList.__init__(self, parens=True, *clauses)
- key = property(lambda self:self.label or self.name)
+ key = property(lambda self:self.name)
def append(self, clause):
if _is_literal(clause):
if clause is None:
return self
def select(self):
return select([self])
+ def hash_key(self):
+ return self.name + "(" + string.join([c.hash_key() for c in self.clauses], ", ") + ")"
class BinaryClause(ClauseElement, CompareMixin):
"""represents two clauses with an operator in between"""
def _get_from_objects(self):
return self.left._get_from_objects() + self.right._get_from_objects()
def hash_key(self):
- return self.left.hash_key() + self.operator + self.right.hash_key()
+ return self.left.hash_key() + (self.operator or " ") + self.right.hash_key()
def accept_visitor(self, visitor):
self.left.accept_visitor(visitor)
self.right.accept_visitor(visitor)
cc = ColumnClause(self.name, selectable)
selectable.c[self.name] = cc
return cc
+ def hash_key(self):
+ return "Label(%s, %s)" % (self.name, self.obj.hash_key())
class ColumnClause(ColumnElement):
"""represents a textual column clause in a SQL statement. allows the creation
def hash_key(self):
if self.table is not None:
- return "ColumnClause(%s, %s)" % (self.text, self.table.hash_key())
+ return "ColumnClause(%s, %s)" % (self.text, util.hash_key(self.table))
else:
return "ColumnClause(%s)" % self.text
group_by = kwargs.get('group_by', None)
if group_by:
self.group_by(*group_by)
-
+ def hash_key(self):
+ return "CompoundSelect(%s)" % string.join(
+ [util.hash_key(s) for s in self.selects] +
+ ["%s=%s" % (k, repr(getattr(self, k))) for k in ['use_labels', 'keyword']],
+ ",")
def _exportable_columns(self):
return self.selects[0].columns
def _proxy_column(self, column):
else:
setattr(self, attribute, condition)
- def hash_key(self):
- return "Select(%d)" % (id(self))
+ _hash_recursion = util.RecursionStack()
+ def hash_key(self):
+ # selects call alot of stuff so we do some "recursion checking"
+ # to eliminate loops
+ if Select._hash_recursion.push(self):
+ return "recursive_select()"
+ try:
+ return "Select(%s)" % string.join(
+ [
+ "columns=" + repr([util.hash_key(c) for c in self._raw_columns]),
+ "where=" + util.hash_key(self.whereclause),
+ "from=" + repr([util.hash_key(f) for f in self.froms]),
+ "having=" + util.hash_key(self.having),
+ "clauses=" + repr([util.hash_key(c) for c in self.clauses])
+ ] + ["%s=%s" % (k, repr(getattr(self, k))) for k in ['use_labels', 'distinct', 'limit', 'offset']], ","
+ )
+ finally:
+ Select._hash_recursion.pop(self)
+
def clear_from(self, id):
self.append_from(FromClause(from_name = None, from_key = id))
class UpdateBase(ClauseElement):
"""forms the base for INSERT, UPDATE, and DELETE statements."""
+ def hash_key(self):
+ return str(id(self))
+
def _process_colparams(self, parameters):
"""receives the "values" of an INSERT or UPDATE statement and constructs
appropriate ind parameters."""
def generic_repr(obj, exclude=None):
L = ['%s=%s' % (a, repr(getattr(obj, a))) for a in dir(obj) if not callable(getattr(obj, a)) and not a.startswith('_') and (exclude is None or not exclude.has_key(a))]
return '%s(%s)' % (obj.__class__.__name__, ','.join(L))
+
+def hash_key(obj):
+ if obj is None:
+ return 'None'
+ elif isinstance(obj, list):
+ return repr([hash_key(o) for o in obj])
+ elif hasattr(obj, 'hash_key'):
+ return obj.hash_key()
+ else:
+ return repr(obj)
class OrderedProperties(object):
"""an object that maintains the order in which attributes are set upon it.
self.__dict__[key] = object
-
+class RecursionStack(object):
+ """a thread-local stack used to detect recursive object traversals."""
+ def __init__(self):
+ self.stacks = {}
+ def _get_stack(self):
+ try:
+ stack = self.stacks[thread.get_ident()]
+ except KeyError:
+ stack = {}
+ self.stacks[thread.get_ident()] = stack
+ return stack
+ def push(self, obj):
+ s = self._get_stack()
+ if s.has_key(obj):
+ return True
+ else:
+ s[obj] = True
+ return False
+ def pop(self, obj):
+ stack = self._get_stack()
+ del stack[obj]
+ if len(stack) == 0:
+ del self.stacks[thread.get_ident()]
+
class OrderedDict(dict):
"""A Dictionary that keeps its own internal ordering"""
def __init__(self, values = None):
def __init__(self, raiseerror = True):
self.__dict__['_tdict'] = {}
self.__dict__['_raiseerror'] = raiseerror
+ def __hasattr__(self, key):
+ return self._tdict.has_key("%d_%s" % (thread.get_ident(), key))
+ def __delattr__(self, key):
+ try:
+ del self._tdict["%d_%s" % (thread.get_ident(), key)]
+ except KeyError:
+ raise AttributeError(key)
def __getattr__(self, key):
try:
return self._tdict["%d_%s" % (thread.get_ident(), key)]
def __setattr__(self, key, value):
self._tdict["%d_%s" % (thread.get_ident(), key)] = value
+
class HashSet(object):
"""implements a Set."""
def __init__(self, iter = None, ordered = False):