From: Mike Bayer Date: Thu, 21 Jun 2012 19:39:48 +0000 (-0400) Subject: - [feature] Added "MATCH" clause to ForeignKey, X-Git-Tag: rel_0_8_0b1~365 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=2272f30af435c5283157724bbb16fb0a573159ce;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - [feature] Added "MATCH" clause to ForeignKey, ForeignKeyConstraint, courtesy Ryan Kelly. [ticket:2502] --- diff --git a/CHANGES b/CHANGES index 757972a753..7e59d638a1 100644 --- a/CHANGES +++ b/CHANGES @@ -199,6 +199,10 @@ underneath "0.7.xx". that aren't in the target table is now an exception. [ticket:2415] + - [feature] Added "MATCH" clause to ForeignKey, + ForeignKeyConstraint, courtesy Ryan Kelly. + [ticket:2502] + - [feature] select() features a correlate_except() method, auto correlates all selectables except those passed. diff --git a/lib/sqlalchemy/schema.py b/lib/sqlalchemy/schema.py index 231da7d035..d50b8af2a6 100644 --- a/lib/sqlalchemy/schema.py +++ b/lib/sqlalchemy/schema.py @@ -1191,7 +1191,7 @@ class ForeignKey(SchemaItem): def __init__(self, column, _constraint=None, use_alter=False, name=None, onupdate=None, ondelete=None, deferrable=None, schema=None, - initially=None, link_to_name=False): + initially=None, link_to_name=False, match=None): """ Construct a column-level FOREIGN KEY. @@ -1236,6 +1236,10 @@ class ForeignKey(SchemaItem): generated/dropped externally from the CREATE TABLE/ DROP TABLE statement. See that classes' constructor for details. + :param match: Optional string. If set, emit MATCH when issuing + DDL for this constraint. Typical values include SIMPLE, PARTIAL + and FULL. + """ self._colspec = column @@ -1255,6 +1259,7 @@ class ForeignKey(SchemaItem): self.deferrable = deferrable self.initially = initially self.link_to_name = link_to_name + self.match = match def __repr__(self): return "ForeignKey(%r)" % self._get_colspec() @@ -1283,7 +1288,8 @@ class ForeignKey(SchemaItem): ondelete=self.ondelete, deferrable=self.deferrable, initially=self.initially, - link_to_name=self.link_to_name + link_to_name=self.link_to_name, + match=self.match ) fk.dispatch._update(self.dispatch) return fk @@ -1445,6 +1451,7 @@ class ForeignKey(SchemaItem): [], [], use_alter=self.use_alter, name=self.name, onupdate=self.onupdate, ondelete=self.ondelete, deferrable=self.deferrable, initially=self.initially, + match=self.match, ) self.constraint._elements[self.parent] = self self.constraint._set_parent_with_dispatch(table) @@ -2031,7 +2038,7 @@ class ForeignKeyConstraint(Constraint): def __init__(self, columns, refcolumns, name=None, onupdate=None, ondelete=None, deferrable=None, initially=None, use_alter=False, - link_to_name=False, table=None): + link_to_name=False, match=None, table=None): """Construct a composite-capable FOREIGN KEY. :param columns: A sequence of local column names. The named columns @@ -2072,6 +2079,10 @@ class ForeignKeyConstraint(Constraint): This is normally used to generate/drop constraints on objects that are mutually dependent on each other. + :param match: Optional string. If set, emit MATCH when issuing + DDL for this constraint. Typical values include SIMPLE, PARTIAL + and FULL. + """ super(ForeignKeyConstraint, self).\ __init__(name, deferrable, initially) @@ -2082,6 +2093,7 @@ class ForeignKeyConstraint(Constraint): if self.name is None and use_alter: raise exc.ArgumentError("Alterable Constraint requires a name") self.use_alter = use_alter + self.match = match self._elements = util.OrderedDict() @@ -2097,7 +2109,8 @@ class ForeignKeyConstraint(Constraint): onupdate=self.onupdate, ondelete=self.ondelete, use_alter=self.use_alter, - link_to_name=self.link_to_name + link_to_name=self.link_to_name, + match=self.match ) if table is not None: @@ -2153,7 +2166,8 @@ class ForeignKeyConstraint(Constraint): use_alter=self.use_alter, deferrable=self.deferrable, initially=self.initially, - link_to_name=self.link_to_name + link_to_name=self.link_to_name, + match=self.match ) fkc.dispatch._update(self.dispatch) return fkc diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index fd7e7d7733..8a8c773f82 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -1726,6 +1726,7 @@ class DDLCompiler(engine.Compiled): ', '.join(preparer.quote(f.column.name, f.column.quote) for f in constraint._elements.values()) ) + text += self.define_constraint_match(constraint) text += self.define_constraint_cascades(constraint) text += self.define_constraint_deferrability(constraint) return text @@ -1765,6 +1766,12 @@ class DDLCompiler(engine.Compiled): text += " INITIALLY %s" % constraint.initially return text + def define_constraint_match(self, constraint): + text = "" + if constraint.match is not None: + text += " MATCH %s" % constraint.match + return text + class GenericTypeCompiler(engine.TypeCompiler): def visit_CHAR(self, type_): diff --git a/test/sql/test_constraints.py b/test/sql/test_constraints.py index 546a14ca2f..fcc6c085e4 100644 --- a/test/sql/test_constraints.py +++ b/test/sql/test_constraints.py @@ -355,6 +355,25 @@ class ConstraintCompilationTest(fixtures.TestBase, AssertsCompiledSQL): "(a) DEFERRABLE INITIALLY DEFERRED)", ) + def test_fk_match_clause(self): + t = Table('tbl', MetaData(), + Column('a', Integer), + Column('b', Integer, + ForeignKey('tbl.a', match="SIMPLE"))) + + self.assert_compile( + schema.CreateTable(t), + "CREATE TABLE tbl (a INTEGER, b INTEGER, " + "FOREIGN KEY(b) REFERENCES tbl " + "(a) MATCH SIMPLE)", + ) + + self.assert_compile( + schema.AddConstraint(list(t.foreign_keys)[0].constraint), + "ALTER TABLE tbl ADD FOREIGN KEY(b) " + "REFERENCES tbl (a) MATCH SIMPLE" + ) + def test_deferrable_unique(self): factory = lambda **kw: UniqueConstraint('b', **kw) self._test_deferrable(factory) @@ -554,4 +573,4 @@ class ConstraintCompilationTest(fixtures.TestBase, AssertsCompiledSQL): ) c = CheckConstraint(t.c.a > t2.c.b) assert c not in t.constraints - assert c not in t2.constraints \ No newline at end of file + assert c not in t2.constraints