]> git.ipfire.org Git - thirdparty/sqlalchemy/alembic.git/commitdiff
Clean up _fk_colspec() for link_to_name, no column found
authorMike Bayer <mike_mp@zzzcomputing.com>
Wed, 11 Oct 2017 13:53:22 +0000 (09:53 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Wed, 11 Oct 2017 14:09:04 +0000 (10:09 -0400)
A :class:`.ForeignKeyConstraint` can now render correctly if the
``link_to_name`` flag is set, as it will not attempt to resolve the name
from a "key" in this case.  Additionally, the constraint will render
as-is even if the remote column name isn't present on the referenced
remote table.

Change-Id: Ic030fbc106973231b6877c1acfb5349e515335a8
Fixes: #456
alembic/autogenerate/render.py
docs/build/unreleased/456.rst [new file with mode: 0644]
tests/test_autogen_render.py

index d6f398f54223ad087b27c79ec01baf99ecb935d4..0ba12dac5c1d83177317bb1c9156316c1852a40e 100644 (file)
@@ -665,7 +665,7 @@ def _render_primary_key(constraint, autogen_context):
 
 def _fk_colspec(fk, metadata_schema):
     """Implement a 'safe' version of ForeignKey._get_colspec() that
-    never tries to resolve the remote table.
+    won't fail if the remote table can't be resolved.
 
     """
     colspec = fk._get_colspec()
@@ -677,12 +677,16 @@ def _fk_colspec(fk, metadata_schema):
     else:
         table_fullname = ".".join(tokens[0:-1])
 
-    if fk.parent is not None and fk.parent.table is not None:
-        # try to resolve the remote table and adjust for column.key
+    if not fk.link_to_name and \
+            fk.parent is not None and fk.parent.table is not None:
+        # try to resolve the remote table in order to adjust for column.key.
+        # the FK constraint needs to be rendered in terms of the column
+        # name.
         parent_metadata = fk.parent.table.metadata
         if table_fullname in parent_metadata.tables:
-            colname = _ident(
-                parent_metadata.tables[table_fullname].c[colname].name)
+            col = parent_metadata.tables[table_fullname].c.get(colname)
+            if col is not None:
+                colname = _ident(col.name)
 
     colspec = "%s.%s" % (table_fullname, colname)
 
diff --git a/docs/build/unreleased/456.rst b/docs/build/unreleased/456.rst
new file mode 100644 (file)
index 0000000..352608a
--- /dev/null
@@ -0,0 +1,9 @@
+.. change::
+    :tags: bug, autogenerate
+    :tickets: 456
+
+    A :class:`.ForeignKeyConstraint` can now render correctly if the
+    ``link_to_name`` flag is set, as it will not attempt to resolve the name
+    from a "key" in this case.  Additionally, the constraint will render
+    as-is even if the remote column name isn't present on the referenced
+    remote table.
\ No newline at end of file
index dce7b7157ca5142b58da79a8b76cac6e3a6cd238..c02157b865627a62a80a36583e36d20dceb19235 100644 (file)
@@ -1184,6 +1184,75 @@ class AutogenRenderTest(TestBase):
             "ondelete='CASCADE', initially='XYZ', deferrable=True)"
         )
 
+    def test_render_fk_constraint_resolve_key(self):
+        m = MetaData()
+        t1 = Table('t', m, Column('c', Integer))
+        t2 = Table('t2', m, Column('c_rem', Integer, key='c_remkey'))
+
+        fk = ForeignKeyConstraint(['c'], ['t2.c_remkey'])
+        t1.append_constraint(fk)
+
+        eq_ignore_whitespace(
+            re.sub(
+                r"u'", "'",
+                autogenerate.render._render_constraint(
+                    fk, self.autogen_context)),
+            "sa.ForeignKeyConstraint(['c'], ['t2.c_rem'], )"
+        )
+
+    def test_render_fk_constraint_bad_table_resolve(self):
+        m = MetaData()
+        t1 = Table('t', m, Column('c', Integer))
+        t2 = Table('t2', m, Column('c_rem', Integer))
+
+        fk = ForeignKeyConstraint(['c'], ['t2.nonexistent'])
+        t1.append_constraint(fk)
+
+        eq_ignore_whitespace(
+            re.sub(
+                r"u'", "'",
+                autogenerate.render._render_constraint(
+                    fk, self.autogen_context)),
+            "sa.ForeignKeyConstraint(['c'], ['t2.nonexistent'], )"
+        )
+
+    def test_render_fk_constraint_bad_table_resolve_dont_get_confused(self):
+        m = MetaData()
+        t1 = Table('t', m, Column('c', Integer))
+        t2 = Table(
+            't2', m,
+            Column('c_rem', Integer, key='cr_key'),
+            Column('c_rem_2', Integer, key='c_rem')
+
+        )
+
+        fk = ForeignKeyConstraint(['c'], ['t2.c_rem'], link_to_name=True)
+        t1.append_constraint(fk)
+
+        eq_ignore_whitespace(
+            re.sub(
+                r"u'", "'",
+                autogenerate.render._render_constraint(
+                    fk, self.autogen_context)),
+            "sa.ForeignKeyConstraint(['c'], ['t2.c_rem'], )"
+        )
+
+    def test_render_fk_constraint_link_to_name(self):
+        m = MetaData()
+        t1 = Table('t', m, Column('c', Integer))
+        t2 = Table('t2', m, Column('c_rem', Integer, key='c_remkey'))
+
+        fk = ForeignKeyConstraint(['c'], ['t2.c_rem'], link_to_name=True)
+        t1.append_constraint(fk)
+
+        eq_ignore_whitespace(
+            re.sub(
+                r"u'", "'",
+                autogenerate.render._render_constraint(
+                    fk, self.autogen_context)),
+            "sa.ForeignKeyConstraint(['c'], ['t2.c_rem'], )"
+        )
+
     def test_render_fk_constraint_use_alter(self):
         m = MetaData()
         Table('t', m, Column('c', Integer))