]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- also added proxying of save_or_update to scoped sessions.
authorAnts Aasma <ants.aasma@gmail.com>
Wed, 31 Oct 2007 16:30:06 +0000 (16:30 +0000)
committerAnts Aasma <ants.aasma@gmail.com>
Wed, 31 Oct 2007 16:30:06 +0000 (16:30 +0000)
- session.update() raises an error when updating an instance that is already in the session with a different identity
- adjusted zoomarks lower limits so I can get a nice clean run

CHANGES
lib/sqlalchemy/orm/scoping.py
lib/sqlalchemy/orm/session.py
test/orm/assorted_eager.py
test/orm/session.py
test/orm/unitofwork.py
test/profiling/zoomark.py
test/zblog/tests.py

diff --git a/CHANGES b/CHANGES
index 333589cc815ebdeada41f9d93c3b7a51c94c7d97..00d16e97c10135ccfc4b055e0e5c700b079966b2 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -59,7 +59,11 @@ CHANGES
 - Fixed a truncation error when re-assigning a subset of a collection
   (obj.relation = obj.relation[1:]) [ticket:834]
 
-- Added proxying of __contains__ and __iter__ methods for scoped sessions.
+- Added proxying of save_or_update, __contains__ and __iter__ methods for
+  scoped sessions.
+
+- session.update() raises an error when updating an instance that is already
+  in the session with a different identity.
 
 0.4.0
 -----
index 3bee9b0e9a07ca240030861eb634d014fe436792..82692aad26669d7cebd2118ba2411894da352117 100644 (file)
@@ -73,7 +73,7 @@ def instrument(name):
     def do(self, *args, **kwargs):
         return getattr(self.registry(), name)(*args, **kwargs)
     return do
-for meth in ('get', 'load', 'close', 'save', 'commit', 'update', 'flush', 'query', 'delete', 'merge', 'clear', 'refresh', 'expire', 'expunge', 'rollback', 'begin', 'begin_nested', 'connection', 'execute', 'scalar', 'get_bind', 'is_modified', '__contains__', '__iter__'):
+for meth in ('get', 'load', 'close', 'save', 'commit', 'update', 'save_or_update', 'flush', 'query', 'delete', 'merge', 'clear', 'refresh', 'expire', 'expunge', 'rollback', 'begin', 'begin_nested', 'connection', 'execute', 'scalar', 'get_bind', 'is_modified', '__contains__', '__iter__'):
     setattr(ScopedSession, meth, instrument(meth))
 
 def makeprop(name):
index 42ad30b6a2c9a278b2537dbaa4cdbd23894644a9..e39062b2cdb2f98ebf4daeb178b0573a5dd7b242 100644 (file)
@@ -800,8 +800,9 @@ class Session(object):
         """Bring the given detached (saved) instance into this
         ``Session``.
 
-        If there is a persistent instance with the same identifier
-        already associated with this ``Session``, an exception is thrown.
+        If there is a persistent instance with the same instance key, but 
+        different identity already associated with this ``Session``, an
+        InvalidRequestError exception is thrown.
 
         This operation cascades the `save_or_update` method to
         associated instances if the relation is mapped with
@@ -969,6 +970,8 @@ class Session(object):
             return
         if not hasattr(obj, '_instance_key'):
             raise exceptions.InvalidRequestError("Instance '%s' is not persisted" % mapperutil.instance_str(obj))
+        elif self.identity_map.get(obj._instance_key, obj) is not obj:
+            raise exceptions.InvalidRequestError("Instance '%s' is with key %s already persisted with a different identity" % (mapperutil.instance_str(obj), obj._instance_key))
         self._attach(obj)
 
     def _register_persistent(self, obj):
index ad95a0a492db77c0fd305e7b4333f982c9f467a2..25a848976fc9041ebee80542c15a1db3f978cb4f 100644 (file)
@@ -652,7 +652,7 @@ class EagerTest7(ORMTest):
         # set up an invoice
         i1 = Invoice()
         i1.date = datetime.datetime.now()
-        i1.company = c1
+        i1.company = a
 
         item1 = Item()
         item1.code = 'aaaa'
index 6efc93d50ebbe326469db60aec1b69997ed59207..530380b8108249e71a125a4193b9b266ef8e73cc 100644 (file)
@@ -681,7 +681,43 @@ class SessionTest(AssertMixin):
         log = []
         sess.commit()
         assert log == ['before_commit', 'after_commit']
+
+    def test_duplicate_update(self):
+        mapper(User, users)
+        Session = sessionmaker()
+        sess = Session()        
+
+        u1 = User()
+        sess.save(u1)
+        sess.flush()
+        assert u1.user_id is not None
+        
+        sess.expunge(u1)
+        
+        assert u1 not in sess
+        
+        u2 = sess.query(User).get(u1.user_id)
+        assert u2 is not None and u2 is not u1
+        assert u2 in sess
         
+        self.assertRaises(Exception, lambda: sess.update(u1))
+
+        sess.expunge(u2)
+        assert u2 not in sess
+        
+        u1.user_name = "John"
+        u2.user_name = "Doe"
+
+        sess.update(u1)
+        assert u1 in sess
+        
+        sess.flush()
+        
+        sess.clear()
+
+        u3 = sess.query(User).get(u1.user_id)
+        assert u3 is not u1 and u3 is not u2 and u3.user_name == u1.user_name
+
 class ScopedSessionTest(ORMTest):
 
     def define_tables(self, metadata):
index 74b08e2c8bc12ebe0e0c4fd85f90e34ae2cb2a0d..7669d25541254c8b5ade606ae107b8ce23601f23 100644 (file)
@@ -1025,7 +1025,8 @@ class SaveTest(ORMTest):
         # check it again, identity should be different but ids the same
         nu = Session.get(m, u.user_id)
         self.assert_(u is not nu and u.user_id == nu.user_id and nu.user_name == 'savetester')
-
+        Session.close()
+        
         # change first users name and save
         Session.update(u)
         u.user_name = 'modifiedname'
index 5c22fd9d8026ac451f38e6674203f7c9c19a5ead..58033ad97617a87f24e53f35023a1def8093a814 100644 (file)
@@ -50,7 +50,7 @@ class ZooMarkTest(testing.AssertMixin):
         metadata.create_all()
         
     @testing.supported('postgres')
-    @profiling.profiled('populate', call_range=(3580, 4400), always=True)
+    @profiling.profiled('populate', call_range=(3360, 4400), always=True)
     def test_1a_populate(self):
         Zoo = metadata.tables['Zoo']
         Animal = metadata.tables['Animal']
@@ -118,7 +118,7 @@ class ZooMarkTest(testing.AssertMixin):
                                 MotherID=bai_yun)
     
     @testing.supported('postgres')
-    @profiling.profiled('insert', call_range=(195, 250), always=True)
+    @profiling.profiled('insert', call_range=(180, 250), always=True)
     def test_2_insert(self):
         Animal = metadata.tables['Animal']
         i = Animal.insert()
@@ -126,7 +126,7 @@ class ZooMarkTest(testing.AssertMixin):
             tick = i.execute(Species='Tick', Name='Tick %d' % x, Legs=8)
     
     @testing.supported('postgres')
-    @profiling.profiled('properties', call_range=(3080, 3430), always=True)
+    @profiling.profiled('properties', call_range=(3060, 3430), always=True)
     def test_3_properties(self):
         Zoo = metadata.tables['Zoo']
         Animal = metadata.tables['Animal']
@@ -149,7 +149,7 @@ class ZooMarkTest(testing.AssertMixin):
             ticks = fullobject(Animal.select(Animal.c.Species=='Tick'))
     
     @testing.supported('postgres')
-    @profiling.profiled('expressions', call_range=(11600, 13200), always=True)
+    @profiling.profiled('expressions', call_range=(11450, 13200), always=True)
     def test_4_expressions(self):
         Zoo = metadata.tables['Zoo']
         Animal = metadata.tables['Animal']
@@ -203,7 +203,7 @@ class ZooMarkTest(testing.AssertMixin):
             assert len(fulltable(Animal.select(func.date_part('day', Animal.c.LastEscape) == 21))) == 1
     
     @testing.supported('postgres')
-    @profiling.profiled('aggregates', call_range=(1050, 1270), always=True)
+    @profiling.profiled('aggregates', call_range=(1020, 1270), always=True)
     def test_5_aggregates(self):
         Animal = metadata.tables['Animal']
         Zoo = metadata.tables['Zoo']
@@ -245,7 +245,7 @@ class ZooMarkTest(testing.AssertMixin):
             legs.sort()
     
     @testing.supported('postgres')
-    @profiling.profiled('editing', call_range=(1330, 1390), always=True)
+    @profiling.profiled('editing', call_range=(1300, 1390), always=True)
     def test_6_editing(self):
         Zoo = metadata.tables['Zoo']
         
@@ -274,7 +274,7 @@ class ZooMarkTest(testing.AssertMixin):
             assert SDZ['Founded'] == datetime.date(1935, 9, 13)
     
     @testing.supported('postgres')
-    @profiling.profiled('multiview', call_range=(2870, 3155), always=True)
+    @profiling.profiled('multiview', call_range=(2850, 3155), always=True)
     def test_7_multiview(self):
         Zoo = metadata.tables['Zoo']
         Animal = metadata.tables['Animal']
index ad6876937d7e5ed11d8d929ac6bcf4503bd8eb45..359e8370b71c220d39fa87c883320a84929be73e 100644 (file)
@@ -79,6 +79,7 @@ class SavePostTest(ZBlogTest):
             s.flush()
             s.clear()
 
+            user = s.query(User).get(user_id)
             blog = s.query(Blog).get(blog_id)
             post = blog.posts[0]
             comment = Comment(subject="some subject", body="some body")