summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql/util.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2012-07-28 17:12:09 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2012-07-28 17:12:09 -0400
commitf839b8927099b64b2d120ffd93d5f444b8951e59 (patch)
treec4e6c15d586f0ddd4d76753f0427285e1a3ceb4d /lib/sqlalchemy/sql/util.py
parent22ba1c43b792953ae6f791512d276739c8c09eae (diff)
downloadsqlalchemy-f839b8927099b64b2d120ffd93d5f444b8951e59.tar.gz
- [feature] Added reduce_columns() method
to select() construct, replaces columns inline using the util.reduce_columns utility function to remove equivalent columns. reduce_columns() also adds "with_only_synonyms" to limit the reduction just to those columns which have the same name. The deprecated fold_equivalents() feature is removed [ticket:1729]. - [feature] Added with_labels and reduce_columns keyword arguments to Query.subquery(), to provide two alternate strategies for producing queries with uniquely- named columns. [ticket:1729].
Diffstat (limited to 'lib/sqlalchemy/sql/util.py')
-rw-r--r--lib/sqlalchemy/sql/util.py59
1 files changed, 12 insertions, 47 deletions
diff --git a/lib/sqlalchemy/sql/util.py b/lib/sqlalchemy/sql/util.py
index 0727f0537..6bfaf4b8c 100644
--- a/lib/sqlalchemy/sql/util.py
+++ b/lib/sqlalchemy/sql/util.py
@@ -585,6 +585,7 @@ def reduce_columns(columns, *clauses, **kw):
"""
ignore_nonexistent_tables = kw.pop('ignore_nonexistent_tables', False)
+ only_synonyms = kw.pop('only_synonyms', False)
columns = util.ordered_column_set(columns)
@@ -610,21 +611,27 @@ def reduce_columns(columns, *clauses, **kw):
continue
else:
raise
- if fk_col.shares_lineage(c):
+ if fk_col.shares_lineage(c) and \
+ (not only_synonyms or \
+ c.name == col.name):
omit.add(col)
break
if clauses:
def visit_binary(binary):
if binary.operator == operators.eq:
- cols = util.column_set(chain(*[c.proxy_set for c in columns.difference(omit)]))
+ cols = util.column_set(chain(*[c.proxy_set
+ for c in columns.difference(omit)]))
if binary.left in cols and binary.right in cols:
- for c in columns:
- if c.shares_lineage(binary.right):
+ for c in reversed(columns):
+ if c.shares_lineage(binary.right) and \
+ (not only_synonyms or \
+ c.name == binary.left.name):
omit.add(c)
break
for clause in clauses:
- visitors.traverse(clause, {}, {'binary':visit_binary})
+ if clause is not None:
+ visitors.traverse(clause, {}, {'binary': visit_binary})
return expression.ColumnSet(columns.difference(omit))
@@ -677,48 +684,6 @@ def criterion_as_pairs(expression, consider_as_foreign_keys=None,
visitors.traverse(expression, {}, {'binary':visit_binary})
return pairs
-def folded_equivalents(join, equivs=None):
- """Return a list of uniquely named columns.
-
- The column list of the given Join will be narrowed
- down to a list of all equivalently-named,
- equated columns folded into one column, where 'equated' means they are
- equated to each other in the ON clause of this join.
-
- This function is used by Join.select(fold_equivalents=True).
-
- Deprecated. This function is used for a certain kind of
- "polymorphic_union" which is designed to achieve joined
- table inheritance where the base table has no "discriminator"
- column; [ticket:1131] will provide a better way to
- achieve this.
-
- """
- if equivs is None:
- equivs = set()
- def visit_binary(binary):
- if binary.operator == operators.eq and binary.left.name == binary.right.name:
- equivs.add(binary.right)
- equivs.add(binary.left)
- visitors.traverse(join.onclause, {}, {'binary':visit_binary})
- collist = []
- if isinstance(join.left, expression.Join):
- left = folded_equivalents(join.left, equivs)
- else:
- left = list(join.left.columns)
- if isinstance(join.right, expression.Join):
- right = folded_equivalents(join.right, equivs)
- else:
- right = list(join.right.columns)
- used = set()
- for c in left + right:
- if c in equivs:
- if c.name not in used:
- collist.append(c)
- used.add(c.name)
- else:
- collist.append(c)
- return collist
class AliasedRow(object):
"""Wrap a RowProxy with a translation map.