summaryrefslogtreecommitdiff
path: root/test/orm
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2007-12-21 06:57:20 +0000
committerMike Bayer <mike_mp@zzzcomputing.com>2007-12-21 06:57:20 +0000
commitc114f096bd0bd786916cbc42eaa91e0e1158ccf4 (patch)
tree2313856ffc6bfe8a3b61017a58efe98b4be322e7 /test/orm
parent2db36bf59c447d4d113cba0ae12f1b739c2ae923 (diff)
downloadsqlalchemy-c114f096bd0bd786916cbc42eaa91e0e1158ccf4.tar.gz
- reworked all lazy/deferred/expired callables to be
serializable class instances, added pickling tests - cleaned up "deferred" polymorphic system so that the mapper handles it entirely - columns which are missing from a Query's select statement now get automatically deferred during load.
Diffstat (limited to 'test/orm')
-rw-r--r--test/orm/alltests.py1
-rw-r--r--test/orm/attributes.py60
-rw-r--r--test/orm/expire.py29
-rw-r--r--test/orm/mapper.py4
-rw-r--r--test/orm/pickled.py119
5 files changed, 204 insertions, 9 deletions
diff --git a/test/orm/alltests.py b/test/orm/alltests.py
index 3748d3f34..dd2bd8446 100644
--- a/test/orm/alltests.py
+++ b/test/orm/alltests.py
@@ -26,6 +26,7 @@ def suite():
'orm.relationships',
'orm.association',
'orm.merge',
+ 'orm.pickled',
'orm.memusage',
'orm.cycles',
diff --git a/test/orm/attributes.py b/test/orm/attributes.py
index a756566d5..dd15e41e5 100644
--- a/test/orm/attributes.py
+++ b/test/orm/attributes.py
@@ -95,6 +95,65 @@ class AttributesTest(PersistTest):
self.assert_(o4.mt2[0].a == 'abcde')
self.assert_(o4.mt2[0].b is None)
+ def test_deferred(self):
+ class Foo(object):pass
+
+ data = {'a':'this is a', 'b':12}
+ def loader(instance, keys):
+ for k in keys:
+ instance.__dict__[k] = data[k]
+ return attributes.ATTR_WAS_SET
+
+ attributes.register_class(Foo, deferred_scalar_loader=loader)
+ attributes.register_attribute(Foo, 'a', uselist=False, useobject=False)
+ attributes.register_attribute(Foo, 'b', uselist=False, useobject=False)
+
+ f = Foo()
+ f._state.expire_attributes(None)
+ self.assertEquals(f.a, "this is a")
+ self.assertEquals(f.b, 12)
+
+ f.a = "this is some new a"
+ f._state.expire_attributes(None)
+ self.assertEquals(f.a, "this is a")
+ self.assertEquals(f.b, 12)
+
+ f._state.expire_attributes(None)
+ f.a = "this is another new a"
+ self.assertEquals(f.a, "this is another new a")
+ self.assertEquals(f.b, 12)
+
+ f._state.expire_attributes(None)
+ self.assertEquals(f.a, "this is a")
+ self.assertEquals(f.b, 12)
+
+ del f.a
+ self.assertEquals(f.a, None)
+ self.assertEquals(f.b, 12)
+
+ f._state.commit_all()
+ self.assertEquals(f.a, None)
+ self.assertEquals(f.b, 12)
+
+ def test_deferred_pickleable(self):
+ data = {'a':'this is a', 'b':12}
+ def loader(instance, keys):
+ for k in keys:
+ instance.__dict__[k] = data[k]
+ return attributes.ATTR_WAS_SET
+
+ attributes.register_class(MyTest, deferred_scalar_loader=loader)
+ attributes.register_attribute(MyTest, 'a', uselist=False, useobject=False)
+ attributes.register_attribute(MyTest, 'b', uselist=False, useobject=False)
+
+ m = MyTest()
+ m._state.expire_attributes(None)
+ assert 'a' not in m.__dict__
+ m2 = pickle.loads(pickle.dumps(m))
+ assert 'a' not in m2.__dict__
+ self.assertEquals(m2.a, "this is a")
+ self.assertEquals(m2.b, 12)
+
def test_list(self):
class User(object):pass
class Address(object):pass
@@ -860,7 +919,6 @@ class HistoryTest(PersistTest):
self.assertEquals(attributes.get_history(f._state, 'bars'), ([bar4], [], []))
lazy_load = [bar1, bar2, bar3]
- f._state.trigger = lazyload(f)
f._state.expire_attributes(['bars'])
self.assertEquals(attributes.get_history(f._state, 'bars'), ([], [bar1, bar2, bar3], []))
diff --git a/test/orm/expire.py b/test/orm/expire.py
index be9c881c0..e1c016612 100644
--- a/test/orm/expire.py
+++ b/test/orm/expire.py
@@ -31,8 +31,6 @@ class ExpireTest(FixtureTest):
self.assert_sql_count(testbase.db, go, 1)
assert 'name' in u.__dict__
- # we're changing the database here, so if this test fails in the middle,
- # it'll screw up the other tests which are hardcoded to 7/'jack'
u.name = 'foo'
sess.flush()
# change the value in the DB
@@ -45,9 +43,9 @@ class ExpireTest(FixtureTest):
# test that it refreshed
assert u.__dict__['name'] == 'jack'
- # object should be back to normal now,
- # this should *not* produce a SELECT statement (not tested here though....)
- assert u.name == 'jack'
+ def go():
+ assert u.name == 'jack'
+ self.assert_sql_count(testbase.db, go, 0)
def test_expire_doesntload_on_set(self):
mapper(User, users)
@@ -76,6 +74,15 @@ class ExpireTest(FixtureTest):
assert o.isopen == 1
self.assert_sql_count(testbase.db, go, 1)
assert o.description == 'order 3 modified'
+
+ del o.description
+ assert "description" not in o.__dict__
+ sess.expire(o, ['isopen'])
+ sess.query(Order).all()
+ assert o.isopen == 1
+ assert "description" not in o.__dict__
+
+ assert o.description is None
def test_expire_committed(self):
"""test that the committed state of the attribute receives the most recent DB data"""
@@ -144,11 +151,16 @@ class ExpireTest(FixtureTest):
def go():
assert u.addresses[0].email_address == 'jack@bean.com'
assert u.name == 'jack'
- # one load
- self.assert_sql_count(testbase.db, go, 1)
+ # two loads, since relation() + scalar are
+ # separate right now
+ self.assert_sql_count(testbase.db, go, 2)
assert 'name' in u.__dict__
assert 'addresses' in u.__dict__
+ sess.expire(u, ['name', 'addresses'])
+ assert 'name' not in u.__dict__
+ assert 'addresses' not in u.__dict__
+
def test_partial_expire(self):
mapper(Order, orders)
@@ -380,6 +392,9 @@ class RefreshTest(FixtureTest):
s.expire(u)
# get the attribute, it refreshes
+ print "OK------"
+# print u.__dict__
+# print u._state.callables
assert u.name == 'jack'
assert id(a) not in [id(x) for x in u.addresses]
diff --git a/test/orm/mapper.py b/test/orm/mapper.py
index 662ac4a29..a7cb3a57d 100644
--- a/test/orm/mapper.py
+++ b/test/orm/mapper.py
@@ -87,7 +87,9 @@ class MapperTest(MapperSuperTest):
a = s.query(Address).from_statement(select([addresses.c.address_id, addresses.c.user_id])).first()
assert a.user_id == 7
assert a.address_id == 1
- assert a.email_address is None
+ # email address auto-defers
+ assert 'email_addres' not in a.__dict__
+ assert a.email_address == 'jack@bean.com'
def test_badconstructor(self):
"""test that if the construction of a mapped class fails, the instnace does not get placed in the session"""
diff --git a/test/orm/pickled.py b/test/orm/pickled.py
new file mode 100644
index 000000000..eac628024
--- /dev/null
+++ b/test/orm/pickled.py
@@ -0,0 +1,119 @@
+import testbase
+from sqlalchemy import *
+from sqlalchemy import exceptions
+from sqlalchemy.orm import *
+from testlib import *
+from testlib.fixtures import *
+import pickle
+
+class EmailUser(User):
+ pass
+
+class PickleTest(FixtureTest):
+ keep_mappers = False
+ keep_data = False
+
+ def test_transient(self):
+ mapper(User, users, properties={
+ 'addresses':relation(Address, backref="user")
+ })
+ mapper(Address, addresses)
+
+ sess = create_session()
+ u1 = User(name='ed')
+ u1.addresses.append(Address(email_address='ed@bar.com'))
+
+ u2 = pickle.loads(pickle.dumps(u1))
+ sess.save(u2)
+ sess.flush()
+
+ sess.clear()
+
+ self.assertEquals(u1, sess.query(User).get(u2.id))
+
+ def test_class_deferred_cols(self):
+ mapper(User, users, properties={
+ 'name':deferred(users.c.name),
+ 'addresses':relation(Address, backref="user")
+ })
+ mapper(Address, addresses, properties={
+ 'email_address':deferred(addresses.c.email_address)
+ })
+ sess = create_session()
+ u1 = User(name='ed')
+ u1.addresses.append(Address(email_address='ed@bar.com'))
+ sess.save(u1)
+ sess.flush()
+ sess.clear()
+ u1 = sess.query(User).get(u1.id)
+ assert 'name' not in u1.__dict__
+ assert 'addresses' not in u1.__dict__
+
+ u2 = pickle.loads(pickle.dumps(u1))
+ sess2 = create_session()
+ sess2.update(u2)
+ self.assertEquals(u2.name, 'ed')
+ self.assertEquals(u2, User(name='ed', addresses=[Address(email_address='ed@bar.com')]))
+
+ def test_instance_deferred_cols(self):
+ mapper(User, users, properties={
+ 'addresses':relation(Address, backref="user")
+ })
+ mapper(Address, addresses)
+
+ sess = create_session()
+ u1 = User(name='ed')
+ u1.addresses.append(Address(email_address='ed@bar.com'))
+ sess.save(u1)
+ sess.flush()
+ sess.clear()
+
+ u1 = sess.query(User).options(defer('name'), defer('addresses.email_address')).get(u1.id)
+ assert 'name' not in u1.__dict__
+ assert 'addresses' not in u1.__dict__
+
+ u2 = pickle.loads(pickle.dumps(u1))
+ sess2 = create_session()
+ sess2.update(u2)
+ self.assertEquals(u2.name, 'ed')
+ assert 'addresses' not in u1.__dict__
+ ad = u2.addresses[0]
+ assert 'email_address' not in ad.__dict__
+ self.assertEquals(ad.email_address, 'ed@bar.com')
+ self.assertEquals(u2, User(name='ed', addresses=[Address(email_address='ed@bar.com')]))
+
+class PolymorphicDeferredTest(ORMTest):
+ def define_tables(self, metadata):
+ global users, email_users
+ users = Table('users', metadata,
+ Column('id', Integer, primary_key=True),
+ Column('name', String(30)),
+ Column('type', String(30)),
+ )
+ email_users = Table('email_users', metadata,
+ Column('id', Integer, ForeignKey('users.id'), primary_key=True),
+ Column('email_address', String(30))
+ )
+
+ def test_polymorphic_deferred(self):
+ mapper(User, users, polymorphic_identity='user', polymorphic_on=users.c.type, polymorphic_fetch='deferred')
+ mapper(EmailUser, email_users, inherits=User, polymorphic_identity='emailuser')
+
+ eu = EmailUser(name="user1", email_address='foo@bar.com')
+ sess = create_session()
+ sess.save(eu)
+ sess.flush()
+ sess.clear()
+
+ eu = sess.query(User).first()
+ eu2 = pickle.loads(pickle.dumps(eu))
+ sess2 = create_session()
+ sess2.update(eu2)
+ assert 'email_address' not in eu2.__dict__
+ self.assertEquals(eu2.email_address, 'foo@bar.com')
+
+
+
+
+if __name__ == '__main__':
+ testbase.main() \ No newline at end of file