]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- A column can be added to a joined-table declarative
authorMike Bayer <mike_mp@zzzcomputing.com>
Thu, 15 Oct 2009 20:52:30 +0000 (20:52 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Thu, 15 Oct 2009 20:52:30 +0000 (20:52 +0000)
superclass after the class has been constructed
(i.e. via class-level attribute assignment), and
the column will be propagated down to
subclasses. [ticket:1570]  This is the reverse
situation as that of [ticket:1523], fixed in 0.5.6.

CHANGES
lib/sqlalchemy/orm/mapper.py
test/ext/test_declarative.py

diff --git a/CHANGES b/CHANGES
index 5212f0450d53ddc8e3ebeff85484c510a6fae3e2..4ecb2552eaf952501f7007d8517b66a56f482a15 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -33,6 +33,14 @@ CHANGES
     - Changed the name of TrustedConnection to 
       Trusted_Connection when constructing pyodbc connect
       arguments [ticket:1561]
+
+- ext 
+    - A column can be added to a joined-table declarative 
+      superclass after the class has been constructed 
+      (i.e. via class-level attribute assignment), and
+      the column will be propagated down to 
+      subclasses. [ticket:1570]  This is the reverse
+      situation as that of [ticket:1523], fixed in 0.5.6.
       
 0.5.6
 =====
index 1e9d0c1ab7b81b314a40b83d0a435d86ba48137a..714f00f3a817fa84a9bd96d78c4ae20d3bef420c 100644 (file)
@@ -551,6 +551,7 @@ class Mapper(object):
                         if mc:
                             # if the column is in the local table but not the mapped table,
                             # this corresponds to adding a column after the fact to the local table.
+                            # [ticket:1523]
                             self.mapped_table._reset_exported()
                         mc = self.mapped_table.corresponding_column(c)
                         if not mc:
@@ -569,7 +570,24 @@ class Mapper(object):
 
         if isinstance(prop, ColumnProperty):
             col = self.mapped_table.corresponding_column(prop.columns[0])
-            # col might not be present! the selectable given to the mapper need not include "deferred"
+            
+            # if the column is not present in the mapped table, 
+            # test if a column has been added after the fact to the parent table
+            # (or their parent, etc.)
+            # [ticket:1570]
+            if col is None and self.inherits:
+                path = [self]
+                for m in self.inherits.iterate_to_root():
+                    col = m.local_table.corresponding_column(prop.columns[0])
+                    if col is not None:
+                        for m2 in path:
+                            m2.mapped_table._reset_exported()
+                        col = self.mapped_table.corresponding_column(prop.columns[0])
+                        break
+                    path.append(m)
+                
+            # otherwise, col might not be present! the selectable given 
+            # to the mapper need not include "deferred"
             # columns (included in zblog tests)
             if col is None:
                 col = prop.columns[0]
index bb4c616a649a862a2f8c25754274aa93d9a7d68e..17bbd8416b9c36d7ef7c40e4dd9fd5ea863cb560 100644 (file)
@@ -913,6 +913,66 @@ class DeclarativeInheritanceTest(DeclarativeTestBase):
         eq_(sess.query(Person).first(),
             Engineer(primary_language='java', name='dilbert')
         )
+    
+    def test_add_parentcol_after_the_fact(self):
+        class Person(Base, ComparableEntity):
+            __tablename__ = 'people'
+            id = Column('id', Integer, primary_key=True, test_needs_autoincrement=True)
+            discriminator = Column('type', String(50))
+            __mapper_args__ = {'polymorphic_on':discriminator}
+
+        class Engineer(Person):
+            __tablename__ = 'engineers'
+            __mapper_args__ = {'polymorphic_identity':'engineer'}
+            primary_language = Column(String(50))
+            id = Column('id', Integer, ForeignKey('people.id'), primary_key=True)
+        
+        Person.name = Column('name', String(50))
+        
+        Base.metadata.create_all()
+
+        sess = create_session()
+        e1 = Engineer(primary_language='java', name='dilbert')
+        sess.add(e1)
+        sess.flush()
+        sess.expunge_all()
+
+        eq_(sess.query(Person).first(),
+            Engineer(primary_language='java', name='dilbert')
+        )
+
+    def test_add_sub_parentcol_after_the_fact(self):
+        class Person(Base, ComparableEntity):
+            __tablename__ = 'people'
+            id = Column('id', Integer, primary_key=True, test_needs_autoincrement=True)
+            discriminator = Column('type', String(50))
+            __mapper_args__ = {'polymorphic_on':discriminator}
+
+        class Engineer(Person):
+            __tablename__ = 'engineers'
+            __mapper_args__ = {'polymorphic_identity':'engineer'}
+            primary_language = Column(String(50))
+            id = Column('id', Integer, ForeignKey('people.id'), primary_key=True)
+        
+        class Admin(Engineer):
+            __tablename__ = 'admins'
+            __mapper_args__ = {'polymorphic_identity':'admin'}
+            workstation = Column(String(50))
+            id = Column('id', Integer, ForeignKey('engineers.id'), primary_key=True)
+            
+        Person.name = Column('name', String(50))
+
+        Base.metadata.create_all()
+
+        sess = create_session()
+        e1 = Admin(primary_language='java', name='dilbert', workstation='foo')
+        sess.add(e1)
+        sess.flush()
+        sess.expunge_all()
+
+        eq_(sess.query(Person).first(),
+            Admin(primary_language='java', name='dilbert', workstation='foo')
+        )
         
     def test_subclass_mixin(self):
         class Person(Base, ComparableEntity):