]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- fixed some concrete inheritance ramifications regarding r4866
authorMike Bayer <mike_mp@zzzcomputing.com>
Sat, 21 Jun 2008 18:08:34 +0000 (18:08 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sat, 21 Jun 2008 18:08:34 +0000 (18:08 +0000)
- added explicit test coverage for r4866 with joined table inheritance

lib/sqlalchemy/orm/mapper.py
test/orm/inheritance/concrete.py
test/orm/unitofwork.py

index 99e93df5d53be7c5de4bd5eec575e53fad22c7f2..172b99558c399a94cd1208538a28c7e92c021ac0 100644 (file)
@@ -368,7 +368,7 @@ class Mapper(object):
             for mapper in list(_mapper_registry):
                 if not mapper.compiled:
                     mapper.__initialize_properties()
-
+                    
             _new_mappers = False
             return self
         finally:
@@ -526,10 +526,10 @@ class Mapper(object):
         # mark these as "read only" properties which are refreshed upon 
         # INSERT/UPDATE
         self._readonly_props = util.Set([
-            self._columntoproperty[col] for col in all_cols if 
+            self._columntoproperty[col] for col in self._columntoproperty if 
                 not hasattr(col, 'table') or col.table not in self._cols_by_table
         ])
-            
+        
         # if explicit PK argument sent, add those columns to the primary key mappings
         if self.primary_key_argument:
             for k in self.primary_key_argument:
@@ -1190,7 +1190,7 @@ class Mapper(object):
                 
                 # expire readonly attributes
                 readonly = state.unmodified.intersection([
-                    p.key for p in chain(*[m._readonly_props for m in mapper.iterate_to_root()])
+                    p.key for p in mapper._readonly_props
                 ])
                 
                 if readonly:
index ffc95ac056f545ced5f0124ff290d403317bbb83..b6d31a715da669908757fa961d536eb9fa8bc9cc 100644 (file)
@@ -1,7 +1,9 @@
 import testenv; testenv.configure_for_tests()
 from sqlalchemy import *
 from sqlalchemy.orm import *
+from sqlalchemy.orm import exc as orm_exc
 from testlib import *
+from sqlalchemy.orm import attributes
 
 class ConcreteTest(ORMTest):
     def define_tables(self, metadata):
@@ -133,16 +135,34 @@ class ConcreteTest(ORMTest):
                                concrete=True, polymorphic_identity='hacker')
 
         session = create_session()
-        session.save(Manager('Tom', 'knows how to manage things'))
-        session.save(Engineer('Jerry', 'knows how to program'))
-        session.save(Hacker('Kurt', 'Badass', 'knows how to hack'))
+        tom = Manager('Tom', 'knows how to manage things')
+        jerry = Engineer('Jerry', 'knows how to program')
+        hacker = Hacker('Kurt', 'Badass', 'knows how to hack')
+        session.add_all((tom, jerry, hacker))
         session.flush()
+
+        # ensure "readonly" on save logic didn't pollute the expired_attributes
+        # collection
+        assert 'nickname' not in attributes.instance_state(jerry).expired_attributes
+        assert 'name' not in attributes.instance_state(jerry).expired_attributes
+        assert 'name' not in attributes.instance_state(hacker).expired_attributes
+        assert 'nickname' not in attributes.instance_state(hacker).expired_attributes
+        def go():
+            self.assertEquals(jerry.name, "Jerry")
+            self.assertEquals(hacker.nickname, "Badass")
+        self.assert_sql_count(testing.db, go, 0)
+        
         session.clear()
 
         assert set([repr(x) for x in session.query(Employee).all()]) == set(["Engineer Jerry knows how to program", "Manager Tom knows how to manage things", "Hacker Kurt 'Badass' knows how to hack"])
         assert set([repr(x) for x in session.query(Manager).all()]) == set(["Manager Tom knows how to manage things"])
         assert set([repr(x) for x in session.query(Engineer).all()]) == set(["Engineer Jerry knows how to program", "Hacker Kurt 'Badass' knows how to hack"])
 
+        # because we are concrete, are intentionally repeating integer ids across
+        # tables, and have told the "Engineer" mapper to load polymorphically,
+        # this cannot work:
+        self.assertRaises(orm_exc.MultipleResultsFound, session.query(Engineer).filter(Engineer.employee_id==1).one)
+        
     def test_relation(self):
         class Employee(object):
             def __init__(self, name):
index f0ab709afa0d5da2a8d4aba4d47cc8980ef6d734..371335b0792034a4a00af6b136f26fdd03a42186 100644 (file)
@@ -992,6 +992,11 @@ class ColumnPropertyTest(_base.MappedTest):
             Column('a', String(50)),
             Column('b', String(50))
             )
+
+        Table('subdata', metadata, 
+            Column('id', Integer, ForeignKey('data.id'), primary_key=True),
+            Column('c', String(50)),
+            )
             
     def setup_mappers(self):
         class Data(_base.BasicEntity):
@@ -1009,6 +1014,21 @@ class ColumnPropertyTest(_base.MappedTest):
         m = mapper(Data, data)
         m.add_property('aplusb', column_property(data.c.a + literal_column("' '") + data.c.b))
         self._test()
+    
+    @testing.resolve_artifact_names
+    def test_with_inheritance(self):
+        class SubData(Data):
+            pass
+        mapper(Data, data, properties={
+            'aplusb':column_property(data.c.a + literal_column("' '") + data.c.b)
+        })
+        mapper(SubData, subdata, inherits=Data)
+        
+        sess = create_session()
+        sd1 = SubData(a="hello", b="there", c="hi")
+        sess.add(sd1)
+        sess.flush()
+        self.assertEquals(sd1.aplusb, "hello there")
         
     @testing.resolve_artifact_names
     def _test(self):