diff options
Diffstat (limited to 'lib/sqlalchemy/sql/visitors.py')
| -rw-r--r-- | lib/sqlalchemy/sql/visitors.py | 80 |
1 files changed, 38 insertions, 42 deletions
diff --git a/lib/sqlalchemy/sql/visitors.py b/lib/sqlalchemy/sql/visitors.py index 0c6be97d7..b94f07f58 100644 --- a/lib/sqlalchemy/sql/visitors.py +++ b/lib/sqlalchemy/sql/visitors.py @@ -19,7 +19,7 @@ use a non-visitor traversal system. For many examples of how the visit system is used, see the sqlalchemy.sql.util and the sqlalchemy.sql.compiler modules. For an introduction to clause adaption, see -http://techspot.zzzeek.org/?p=19 . +http://techspot.zzzeek.org/2008/01/23/expression-transformations/ """ @@ -212,55 +212,51 @@ def traverse_depthfirst(obj, opts, visitors): return traverse_using(iterate_depthfirst(obj, opts), obj, visitors) def cloned_traverse(obj, opts, visitors): - """clone the given expression structure, allowing modifications by visitors.""" + """clone the given expression structure, allowing + modifications by visitors.""" cloned = util.column_dict() + stop_on = util.column_set(opts.get('stop_on', [])) - def clone(element): - if element not in cloned: - cloned[element] = element._clone() - return cloned[element] - - obj = clone(obj) - stack = [obj] - - while stack: - t = stack.pop() - if t in cloned: - continue - t._copy_internals(clone=clone) - - meth = visitors.get(t.__visit_name__, None) - if meth: - meth(t) - - for c in t.get_children(**opts): - stack.append(c) + def clone(elem): + if elem in stop_on: + return elem + else: + if elem not in cloned: + cloned[elem] = newelem = elem._clone() + newelem._copy_internals(clone=clone) + meth = visitors.get(newelem.__visit_name__, None) + if meth: + meth(newelem) + return cloned[elem] + + if obj is not None: + obj = clone(obj) return obj + def replacement_traverse(obj, opts, replace): - """clone the given expression structure, allowing element replacement by a given replacement function.""" + """clone the given expression structure, allowing element + replacement by a given replacement function.""" cloned = util.column_dict() stop_on = util.column_set(opts.get('stop_on', [])) - def clone(element): - newelem = replace(element) - if newelem is not None: - stop_on.add(newelem) - return newelem - - if element not in cloned: - cloned[element] = element._clone() - return cloned[element] - - obj = clone(obj) - stack = [obj] - while stack: - t = stack.pop() - if t in stop_on: - continue - t._copy_internals(clone=clone) - for c in t.get_children(**opts): - stack.append(c) + def clone(elem, **kw): + if elem in stop_on or \ + 'no_replacement_traverse' in elem._annotations: + return elem + else: + newelem = replace(elem) + if newelem is not None: + stop_on.add(newelem) + return newelem + else: + if elem not in cloned: + cloned[elem] = newelem = elem._clone() + newelem._copy_internals(clone=clone, **kw) + return cloned[elem] + + if obj is not None: + obj = clone(obj, **opts) return obj |
