]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- move create_lazy_clause() to relationships
authorMike Bayer <mike_mp@zzzcomputing.com>
Sun, 1 Apr 2012 22:18:12 +0000 (18:18 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sun, 1 Apr 2012 22:18:12 +0000 (18:18 -0400)
- add foreign, remote annotations to declarative

lib/sqlalchemy/ext/declarative.py
lib/sqlalchemy/orm/relationships.py
lib/sqlalchemy/orm/strategies.py
test/ext/test_declarative.py

index 891130a48d5e6505b12b6b635fb52d40862d0ce5..7e5ae03d924349498b6bd52b784167a345b1a4a4 100755 (executable)
@@ -1392,6 +1392,10 @@ class _GetTable(object):
 def _deferred_relationship(cls, prop):
     def resolve_arg(arg):
         import sqlalchemy
+        from sqlalchemy.orm import foreign, remote
+
+        fallback = sqlalchemy.__dict__.copy()
+        fallback.update({'foreign':foreign, 'remote':remote})
 
         def access_cls(key):
             if key in cls._decl_class_registry:
@@ -1401,7 +1405,7 @@ def _deferred_relationship(cls, prop):
             elif key in cls.metadata._schemas:
                 return _GetTable(key, cls.metadata)
             else:
-                return sqlalchemy.__dict__[key]
+                return fallback[key]
 
         d = util.PopulateDict(access_cls)
         def return_cls():
index adf3b0cde9c2a75c3fe87a62eed189cc09a30ba6..c1503a79a6ee4e25af451761963bf58d94a50c40 100644 (file)
@@ -163,38 +163,42 @@ class JoinCondition(object):
                         "condition between parent/child tables on "
                         "relationship %s - there are no foreign keys "
                         "linking these tables via secondary table '%s'.  "
-                        "Ensure that referencing columns are associated with a "\
-                        "ForeignKey or ForeignKeyConstraint, or specify 'primaryjoin' "\
-                        "and 'secondaryjoin' expressions."
+                        "Ensure that referencing columns are associated "
+                        "with a ForeignKey or ForeignKeyConstraint, or "
+                        "specify 'primaryjoin' and 'secondaryjoin' "
+                        "expressions."
                         % (self.prop, self.secondary))
             else:
                 raise sa_exc.NoForeignKeysError("Could not determine join "
                         "condition between parent/child tables on "
                         "relationship %s - there are no foreign keys "
                         "linking these tables.  "
-                        "Ensure that referencing columns are associated with a "
-                        "ForeignKey or ForeignKeyConstraint, or specify a 'primaryjoin' "
-                        "expression."
+                        "Ensure that referencing columns are associated "
+                        "with a ForeignKey or ForeignKeyConstraint, or "
+                        "specify a 'primaryjoin' expression."
                         % self.prop)
         except sa_exc.AmbiguousForeignKeysError, afke:
             if self.secondary is not None:
-                raise sa_exc.AmbiguousForeignKeysError("Could not determine join "
+                raise sa_exc.AmbiguousForeignKeysError(
+                        "Could not determine join "
                         "condition between parent/child tables on "
                         "relationship %s - there are multiple foreign key "
                         "paths linking the tables via secondary table '%s'.  "
                         "Specify the 'foreign_keys' "
                         "argument, providing a list of those columns which "
-                        "should be counted as containing a foreign key reference "
-                        "from the secondary table to each of the parent and child tables."
+                        "should be counted as containing a foreign key "
+                        "reference from the secondary table to each of the "
+                        "parent and child tables."
                         % (self.prop, self.secondary))
             else:
-                raise sa_exc.AmbiguousForeignKeysError("Could not determine join "
+                raise sa_exc.AmbiguousForeignKeysError(
+                        "Could not determine join "
                         "condition between parent/child tables on "
                         "relationship %s - there are multiple foreign key "
-                        "paths linking the tables.  Specify the 'foreign_keys' "
-                        "argument, providing a list of those columns which "
-                        "should be counted as containing a foreign key reference "
-                        "to the parent table."
+                        "paths linking the tables.  Specify the "
+                        "'foreign_keys' argument, providing a list of those "
+                        "columns which should be counted as containing a "
+                        "foreign key reference to the parent table."
                         % self.prop)
 
     @util.memoized_property
@@ -690,13 +694,13 @@ class JoinCondition(object):
 
     def _gather_join_annotations(self, annotation):
         s = set(
-            self._gather_columns_with_annotation(self.primaryjoin, 
-                                                    annotation)
+            self._gather_columns_with_annotation(
+                        self.primaryjoin, annotation)
         )
         if self.secondaryjoin is not None:
             s.update(
-                self._gather_columns_with_annotation(self.secondaryjoin, 
-                                                    annotation)
+                self._gather_columns_with_annotation(
+                        self.secondaryjoin, annotation)
             )
         return s
 
@@ -735,8 +739,8 @@ class JoinCondition(object):
 
         # adjust the join condition for single table inheritance,
         # in the case that the join is to a subclass
-        # this is analogous to the "_adjust_for_single_table_inheritance()"
-        # method in Query.
+        # this is analogous to the 
+        # "_adjust_for_single_table_inheritance()" method in Query.
 
         if single_crit is not None:
             if secondaryjoin is not None:
@@ -778,51 +782,49 @@ class JoinCondition(object):
         return primaryjoin, secondaryjoin, secondary, \
                         target_adapter, dest_selectable
 
+    def create_lazy_clause(self, reverse_direction=False):
+        binds = util.column_dict()
+        lookup = util.column_dict()
+        equated_columns = util.column_dict()
+
+        if reverse_direction and self.secondaryjoin is None:
+            for l, r in self.local_remote_pairs:
+                _list = lookup.setdefault(r, [])
+                _list.append((r, l))
+                equated_columns[l] = r
+        else:
+            for l, r in self.local_remote_pairs:
+                _list = lookup.setdefault(l, [])
+                _list.append((l, r))
+                equated_columns[r] = l
+
+        def col_to_bind(col):
+            if col in lookup:
+                for tobind, equated in lookup[col]:
+                    if equated in binds:
+                        return None
+                if col not in binds:
+                    binds[col] = sql.bindparam(
+                        None, None, type_=col.type, unique=True)
+                return binds[col]
+            return None
+
+        lazywhere = self.primaryjoin
+
+        if self.secondaryjoin is None or not reverse_direction:
+            lazywhere = visitors.replacement_traverse(
+                                            lazywhere, {}, col_to_bind) 
+
+        if self.secondaryjoin is not None:
+            secondaryjoin = self.secondaryjoin
+            if reverse_direction:
+                secondaryjoin = visitors.replacement_traverse(
+                                            secondaryjoin, {}, col_to_bind)
+            lazywhere = sql.and_(lazywhere, secondaryjoin)
+
+        bind_to_col = dict((binds[col].key, col) for col in binds)
 
-################# everything below is TODO ################################
-
-def _create_lazy_clause(cls, prop, reverse_direction=False):
-    binds = util.column_dict()
-    lookup = util.column_dict()
-    equated_columns = util.column_dict()
-
-    if reverse_direction and prop.secondaryjoin is None:
-        for l, r in prop.local_remote_pairs:
-            _list = lookup.setdefault(r, [])
-            _list.append((r, l))
-            equated_columns[l] = r
-    else:
-        for l, r in prop.local_remote_pairs:
-            _list = lookup.setdefault(l, [])
-            _list.append((l, r))
-            equated_columns[r] = l
-
-    def col_to_bind(col):
-        if col in lookup:
-            for tobind, equated in lookup[col]:
-                if equated in binds:
-                    return None
-            if col not in binds:
-                binds[col] = sql.bindparam(None, None, type_=col.type, unique=True)
-            return binds[col]
-        return None
-
-    lazywhere = prop.primaryjoin
-
-    if prop.secondaryjoin is None or not reverse_direction:
-        lazywhere = visitors.replacement_traverse(
-                                        lazywhere, {}, col_to_bind) 
-
-    if prop.secondaryjoin is not None:
-        secondaryjoin = prop.secondaryjoin
-        if reverse_direction:
-            secondaryjoin = visitors.replacement_traverse(
-                                        secondaryjoin, {}, col_to_bind)
-        lazywhere = sql.and_(lazywhere, secondaryjoin)
-
-    bind_to_col = dict((binds[col].key, col) for col in binds)
-
-    return lazywhere, bind_to_col, equated_columns
+        return lazywhere, bind_to_col, equated_columns
 
 
 
index 00739ea03bde0f39c3caa640e28827fd0ae6c917..a4cdfba1a7d5cafdd881846378cc1006f5aa048b 100644 (file)
@@ -324,14 +324,14 @@ class LazyLoader(AbstractRelationshipLoader):
 
     def init(self):
         super(LazyLoader, self).init()
+        join_condition = self.parent_property._join_condition
         self._lazywhere, \
         self._bind_to_col, \
-        self._equated_columns = self._create_lazy_clause(self.parent_property)
+        self._equated_columns = join_condition.create_lazy_clause()
 
         self._rev_lazywhere, \
         self._rev_bind_to_col, \
-        self._rev_equated_columns = self._create_lazy_clause(
-                                                self.parent_property, 
+        self._rev_equated_columns = join_condition.create_lazy_clause(
                                                 reverse_direction=True)
 
         self.logger.info("%s lazy loading clause %s", self, self._lazywhere)
@@ -617,49 +617,6 @@ class LazyLoader(AbstractRelationshipLoader):
 
             return reset_for_lazy_callable, None, None
 
-    @classmethod
-    def _create_lazy_clause(cls, prop, reverse_direction=False):
-        binds = util.column_dict()
-        lookup = util.column_dict()
-        equated_columns = util.column_dict()
-
-        if reverse_direction and prop.secondaryjoin is None:
-            for l, r in prop.local_remote_pairs:
-                _list = lookup.setdefault(r, [])
-                _list.append((r, l))
-                equated_columns[l] = r
-        else:
-            for l, r in prop.local_remote_pairs:
-                _list = lookup.setdefault(l, [])
-                _list.append((l, r))
-                equated_columns[r] = l
-
-        def col_to_bind(col):
-            if col in lookup:
-                for tobind, equated in lookup[col]:
-                    if equated in binds:
-                        return None
-                if col not in binds:
-                    binds[col] = sql.bindparam(None, None, type_=col.type, unique=True)
-                return binds[col]
-            return None
-
-        lazywhere = prop.primaryjoin
-
-        if prop.secondaryjoin is None or not reverse_direction:
-            lazywhere = visitors.replacement_traverse(
-                                            lazywhere, {}, col_to_bind) 
-
-        if prop.secondaryjoin is not None:
-            secondaryjoin = prop.secondaryjoin
-            if reverse_direction:
-                secondaryjoin = visitors.replacement_traverse(
-                                            secondaryjoin, {}, col_to_bind)
-            lazywhere = sql.and_(lazywhere, secondaryjoin)
-
-        bind_to_col = dict((binds[col].key, col) for col in binds)
-
-        return lazywhere, bind_to_col, equated_columns
 
 log.class_logger(LazyLoader)
 
index 69042b5c84336ce95d10acee536b80e2b62b5878..5e185f664565495160f820d1e35ba9f4fb41ac81 100644 (file)
@@ -368,6 +368,28 @@ class DeclarativeTest(DeclarativeTestBase):
         assert class_mapper(User).get_property('props').secondary \
             is user_to_prop
 
+    def test_string_dependency_resolution_annotations(self):
+        Base = decl.declarative_base()
+
+        class Parent(Base):
+            __tablename__ = 'parent'
+            id = Column(Integer, primary_key=True)
+            name = Column(String)
+            children = relationship("Child",
+                    primaryjoin="Parent.name==remote(foreign(func.lower(Child.name_upper)))"
+                )
+
+        class Child(Base):
+            __tablename__ = 'child'
+            id = Column(Integer, primary_key=True)
+            name_upper = Column(String)
+
+        configure_mappers()
+        eq_(
+            Parent.children.property._calculated_foreign_keys,
+            set([Child.name_upper.property.columns[0]])
+        )
+
     def test_shared_class_registry(self):
         reg = {}
         Base1 = decl.declarative_base(testing.db, class_registry=reg)