diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2009-11-09 23:20:31 +0000 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2009-11-09 23:20:31 +0000 |
| commit | c6724a3ff0c88d77431d7e29ed2747eb90953c95 (patch) | |
| tree | 33659a3dd7199b10951eb43024387fa6c102b2ba /lib/sqlalchemy | |
| parent | 89fcf7c3c9fff5737f446d8f4362d7426f934c0d (diff) | |
| download | sqlalchemy-c6724a3ff0c88d77431d7e29ed2747eb90953c95.tar.gz | |
- query.get() can be used with a mapping to an outer join
where one or more of the primary key values are None.
[ticket:1135]
Diffstat (limited to 'lib/sqlalchemy')
| -rw-r--r-- | lib/sqlalchemy/orm/query.py | 13 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/strategies.py | 22 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/util.py | 18 |
3 files changed, 37 insertions, 16 deletions
diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py index a4f85f7b1..1556db7d2 100644 --- a/lib/sqlalchemy/orm/query.py +++ b/lib/sqlalchemy/orm/query.py @@ -1402,6 +1402,7 @@ class Query(object): def _get(self, key=None, ident=None, refresh_state=None, lockmode=None, only_load_props=None, passive=None): lockmode = lockmode or self._lockmode + if not self._populate_existing and not refresh_state and \ not self._mapper_zero().always_refresh and lockmode is None: instance = self.session.identity_map.get(key) @@ -1436,7 +1437,17 @@ class Query(object): mapper = q._mapper_zero() params = {} (_get_clause, _get_params) = mapper._get_clause - + + # None present in ident - turn those comparisons + # into "IS NULL" + if None in ident: + nones = set([ + _get_params[col].key for col, value in + zip(mapper.primary_key, ident) if value is None + ]) + _get_clause = sql_util.adapt_criterion_to_null( + _get_clause, nones) + _get_clause = q._adapt_clause(_get_clause, True, False) q._criterion = _get_clause diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py index 08c60a1d2..ff80fd6e6 100644 --- a/lib/sqlalchemy/orm/strategies.py +++ b/lib/sqlalchemy/orm/strategies.py @@ -412,8 +412,12 @@ class LazyLoader(AbstractRelationLoader): else: (criterion, bind_to_col, rev) = LazyLoader._create_lazy_clause(self.parent_property, reverse_direction=reverse_direction) + if reverse_direction: + mapper = self.parent_property.mapper + else: + mapper = self.parent_property.parent + def visit_bindparam(bindparam): - mapper = reverse_direction and self.parent_property.mapper or self.parent_property.parent if bindparam.key in bind_to_col: # use the "committed" (database) version to get query column values # also its a deferred value; so that when used by Query, the committed value is used @@ -435,20 +439,8 @@ class LazyLoader(AbstractRelationLoader): else: (criterion, bind_to_col, rev) = LazyLoader._create_lazy_clause(self.parent_property, reverse_direction=reverse_direction) - def visit_binary(binary): - mapper = reverse_direction and self.parent_property.mapper or self.parent_property.parent - if isinstance(binary.left, expression._BindParamClause) and binary.left.key in bind_to_col: - # reverse order if the NULL is on the left side - binary.left = binary.right - binary.right = expression.null() - binary.operator = operators.is_ - binary.negate = operators.isnot - elif isinstance(binary.right, expression._BindParamClause) and binary.right.key in bind_to_col: - binary.right = expression.null() - binary.operator = operators.is_ - binary.negate = operators.isnot - - criterion = visitors.cloned_traverse(criterion, {}, {'binary':visit_binary}) + criterion = sql_util.adapt_criterion_to_null(criterion, bind_to_col) + if adapt_source: criterion = adapt_source(criterion) return criterion diff --git a/lib/sqlalchemy/sql/util.py b/lib/sqlalchemy/sql/util.py index d1265c75f..a84a3eb74 100644 --- a/lib/sqlalchemy/sql/util.py +++ b/lib/sqlalchemy/sql/util.py @@ -79,6 +79,24 @@ def find_columns(clause): visitors.traverse(clause, {}, {'column':cols.add}) return cols +def adapt_criterion_to_null(crit, nulls): + """given criterion containing bind params, convert selected elements to IS NULL.""" + + def visit_binary(binary): + if isinstance(binary.left, expression._BindParamClause) and binary.left.key in nulls: + # reverse order if the NULL is on the left side + binary.left = binary.right + binary.right = expression.null() + binary.operator = operators.is_ + binary.negate = operators.isnot + elif isinstance(binary.right, expression._BindParamClause) and binary.right.key in nulls: + binary.right = expression.null() + binary.operator = operators.is_ + binary.negate = operators.isnot + + return visitors.cloned_traverse(crit, {}, {'binary':visit_binary}) + + def join_condition(a, b, ignore_nonexistent_tables=False): """create a join condition between two tables. |
