mirror of
https://github.com/sqlalchemy/sqlalchemy.git
synced 2026-06-04 06:48:27 -04:00
4769ea895b
- renamed SessionTransaction autoflush to reentrant_flush to more clearly state its purpose - added _enable_transaction_accounting, flag for Mike Bernson which disables the whole 0.5 transaction state management; the system depends on expiry on rollback in order to function.
385 lines
14 KiB
Python
385 lines
14 KiB
Python
import testenv; testenv.configure_for_tests()
|
|
import operator
|
|
from sqlalchemy.orm import dynamic_loader, backref
|
|
from testlib import testing
|
|
from testlib.sa import Table, Column, Integer, String, ForeignKey, desc
|
|
from testlib.sa.orm import mapper, relation, create_session
|
|
from testlib.testing import eq_
|
|
from testlib.compat import _function_named
|
|
from orm import _base, _fixtures
|
|
|
|
|
|
class DynamicTest(_fixtures.FixtureTest):
|
|
@testing.resolve_artifact_names
|
|
def test_basic(self):
|
|
mapper(User, users, properties={
|
|
'addresses':dynamic_loader(mapper(Address, addresses))
|
|
})
|
|
sess = create_session()
|
|
q = sess.query(User)
|
|
|
|
u = q.filter(User.id==7).first()
|
|
eq_([User(id=7,
|
|
addresses=[Address(id=1, email_address='jack@bean.com')])],
|
|
q.filter(User.id==7).all())
|
|
eq_(self.static.user_address_result, q.all())
|
|
|
|
@testing.resolve_artifact_names
|
|
def test_order_by(self):
|
|
mapper(User, users, properties={
|
|
'addresses':dynamic_loader(mapper(Address, addresses))
|
|
})
|
|
sess = create_session()
|
|
u = sess.query(User).get(8)
|
|
eq_(list(u.addresses.order_by(desc(Address.email_address))), [Address(email_address=u'ed@wood.com'), Address(email_address=u'ed@lala.com'), Address(email_address=u'ed@bettyboop.com')])
|
|
|
|
@testing.resolve_artifact_names
|
|
def test_configured_order_by(self):
|
|
mapper(User, users, properties={
|
|
'addresses':dynamic_loader(mapper(Address, addresses), order_by=desc(Address.email_address))
|
|
})
|
|
sess = create_session()
|
|
u = sess.query(User).get(8)
|
|
eq_(list(u.addresses), [Address(email_address=u'ed@wood.com'), Address(email_address=u'ed@lala.com'), Address(email_address=u'ed@bettyboop.com')])
|
|
|
|
@testing.resolve_artifact_names
|
|
def test_count(self):
|
|
mapper(User, users, properties={
|
|
'addresses':dynamic_loader(mapper(Address, addresses))
|
|
})
|
|
sess = create_session()
|
|
u = sess.query(User).first()
|
|
eq_(u.addresses.count(), 1)
|
|
|
|
@testing.resolve_artifact_names
|
|
def test_backref(self):
|
|
mapper(Address, addresses, properties={
|
|
'user':relation(User, backref=backref('addresses', lazy='dynamic'))
|
|
})
|
|
mapper(User, users)
|
|
|
|
sess = create_session()
|
|
ad = sess.query(Address).get(1)
|
|
def go():
|
|
ad.user = None
|
|
self.assert_sql_count(testing.db, go, 1)
|
|
sess.flush()
|
|
u = sess.query(User).get(7)
|
|
assert ad not in u.addresses
|
|
|
|
@testing.resolve_artifact_names
|
|
def test_no_count(self):
|
|
mapper(User, users, properties={
|
|
'addresses':dynamic_loader(mapper(Address, addresses))
|
|
})
|
|
sess = create_session()
|
|
q = sess.query(User)
|
|
|
|
# dynamic collection cannot implement __len__() (at least one that
|
|
# returns a live database result), else additional count() queries are
|
|
# issued when evaluating in a list context
|
|
def go():
|
|
eq_([User(id=7,
|
|
addresses=[Address(id=1,
|
|
email_address='jack@bean.com')])],
|
|
q.filter(User.id==7).all())
|
|
self.assert_sql_count(testing.db, go, 2)
|
|
|
|
@testing.resolve_artifact_names
|
|
def test_m2m(self):
|
|
mapper(Order, orders, properties={
|
|
'items':relation(Item, secondary=order_items, lazy="dynamic",
|
|
backref=backref('orders', lazy="dynamic"))
|
|
})
|
|
mapper(Item, items)
|
|
|
|
sess = create_session()
|
|
o1 = Order(id=15, description="order 10")
|
|
i1 = Item(id=10, description="item 8")
|
|
o1.items.append(i1)
|
|
sess.add(o1)
|
|
sess.flush()
|
|
|
|
assert o1 in i1.orders.all()
|
|
assert i1 in o1.items.all()
|
|
|
|
@testing.resolve_artifact_names
|
|
def test_transient_detached(self):
|
|
mapper(User, users, properties={
|
|
'addresses':dynamic_loader(mapper(Address, addresses))
|
|
})
|
|
sess = create_session()
|
|
u1 = User()
|
|
u1.addresses.append(Address())
|
|
assert u1.addresses.count() == 1
|
|
assert u1.addresses[0] == Address()
|
|
|
|
class FlushTest(_fixtures.FixtureTest):
|
|
run_inserts = None
|
|
|
|
@testing.resolve_artifact_names
|
|
def test_basic(self):
|
|
mapper(User, users, properties={
|
|
'addresses':dynamic_loader(mapper(Address, addresses))
|
|
})
|
|
sess = create_session()
|
|
u1 = User(name='jack')
|
|
u2 = User(name='ed')
|
|
u2.addresses.append(Address(email_address='foo@bar.com'))
|
|
u1.addresses.append(Address(email_address='lala@hoho.com'))
|
|
sess.add_all((u1, u2))
|
|
sess.flush()
|
|
|
|
from sqlalchemy.orm import attributes
|
|
self.assertEquals(attributes.get_history(attributes.instance_state(u1), 'addresses'), ([], [Address(email_address='lala@hoho.com')], []))
|
|
|
|
sess.clear()
|
|
|
|
# test the test fixture a little bit
|
|
assert User(name='jack', addresses=[Address(email_address='wrong')]) != sess.query(User).first()
|
|
assert User(name='jack', addresses=[Address(email_address='lala@hoho.com')]) == sess.query(User).first()
|
|
|
|
assert [
|
|
User(name='jack', addresses=[Address(email_address='lala@hoho.com')]),
|
|
User(name='ed', addresses=[Address(email_address='foo@bar.com')])
|
|
] == sess.query(User).all()
|
|
|
|
@testing.resolve_artifact_names
|
|
def test_hasattr(self):
|
|
mapper(User, users, properties={
|
|
'addresses':dynamic_loader(mapper(Address, addresses))
|
|
})
|
|
u1 = User(name='jack')
|
|
|
|
assert 'addresses' not in u1.__dict__.keys()
|
|
u1.addresses = [Address(email_address='test')]
|
|
assert 'addresses' in dir(u1)
|
|
|
|
@testing.resolve_artifact_names
|
|
def test_rollback(self):
|
|
mapper(User, users, properties={
|
|
'addresses':dynamic_loader(mapper(Address, addresses))
|
|
})
|
|
sess = create_session(expire_on_commit=False, autocommit=False, autoflush=True)
|
|
u1 = User(name='jack')
|
|
u1.addresses.append(Address(email_address='lala@hoho.com'))
|
|
sess.add(u1)
|
|
sess.flush()
|
|
sess.commit()
|
|
u1.addresses.append(Address(email_address='foo@bar.com'))
|
|
eq_(u1.addresses.all(), [Address(email_address='lala@hoho.com'), Address(email_address='foo@bar.com')])
|
|
sess.rollback()
|
|
eq_(u1.addresses.all(), [Address(email_address='lala@hoho.com')])
|
|
|
|
@testing.fails_on('maxdb')
|
|
@testing.resolve_artifact_names
|
|
def test_delete_nocascade(self):
|
|
mapper(User, users, properties={
|
|
'addresses':dynamic_loader(mapper(Address, addresses), backref='user')
|
|
})
|
|
sess = create_session(autoflush=True)
|
|
u = User(name='ed')
|
|
u.addresses.append(Address(email_address='a'))
|
|
u.addresses.append(Address(email_address='b'))
|
|
u.addresses.append(Address(email_address='c'))
|
|
u.addresses.append(Address(email_address='d'))
|
|
u.addresses.append(Address(email_address='e'))
|
|
u.addresses.append(Address(email_address='f'))
|
|
sess.add(u)
|
|
|
|
assert Address(email_address='c') == u.addresses[2]
|
|
sess.delete(u.addresses[2])
|
|
sess.delete(u.addresses[4])
|
|
sess.delete(u.addresses[3])
|
|
assert [Address(email_address='a'), Address(email_address='b'), Address(email_address='d')] == list(u.addresses)
|
|
|
|
sess.clear()
|
|
u = sess.query(User).get(u.id)
|
|
|
|
sess.delete(u)
|
|
|
|
# u.addresses relation will have to force the load
|
|
# of all addresses so that they can be updated
|
|
sess.flush()
|
|
sess.close()
|
|
|
|
assert testing.db.scalar(addresses.count(addresses.c.user_id != None)) ==0
|
|
|
|
@testing.fails_on('maxdb')
|
|
@testing.resolve_artifact_names
|
|
def test_delete_cascade(self):
|
|
mapper(User, users, properties={
|
|
'addresses':dynamic_loader(mapper(Address, addresses), backref='user', cascade="all, delete-orphan")
|
|
})
|
|
sess = create_session(autoflush=True)
|
|
u = User(name='ed')
|
|
u.addresses.append(Address(email_address='a'))
|
|
u.addresses.append(Address(email_address='b'))
|
|
u.addresses.append(Address(email_address='c'))
|
|
u.addresses.append(Address(email_address='d'))
|
|
u.addresses.append(Address(email_address='e'))
|
|
u.addresses.append(Address(email_address='f'))
|
|
sess.add(u)
|
|
|
|
assert Address(email_address='c') == u.addresses[2]
|
|
sess.delete(u.addresses[2])
|
|
sess.delete(u.addresses[4])
|
|
sess.delete(u.addresses[3])
|
|
assert [Address(email_address='a'), Address(email_address='b'), Address(email_address='d')] == list(u.addresses)
|
|
|
|
sess.clear()
|
|
u = sess.query(User).get(u.id)
|
|
|
|
sess.delete(u)
|
|
|
|
# u.addresses relation will have to force the load
|
|
# of all addresses so that they can be updated
|
|
sess.flush()
|
|
sess.close()
|
|
|
|
assert testing.db.scalar(addresses.count()) ==0
|
|
|
|
@testing.fails_on('maxdb')
|
|
@testing.resolve_artifact_names
|
|
def test_remove_orphans(self):
|
|
mapper(User, users, properties={
|
|
'addresses':dynamic_loader(mapper(Address, addresses), cascade="all, delete-orphan", backref='user')
|
|
})
|
|
sess = create_session(autoflush=True)
|
|
u = User(name='ed')
|
|
u.addresses.append(Address(email_address='a'))
|
|
u.addresses.append(Address(email_address='b'))
|
|
u.addresses.append(Address(email_address='c'))
|
|
u.addresses.append(Address(email_address='d'))
|
|
u.addresses.append(Address(email_address='e'))
|
|
u.addresses.append(Address(email_address='f'))
|
|
sess.add(u)
|
|
|
|
assert [Address(email_address='a'), Address(email_address='b'), Address(email_address='c'),
|
|
Address(email_address='d'), Address(email_address='e'), Address(email_address='f')] == sess.query(Address).all()
|
|
|
|
assert Address(email_address='c') == u.addresses[2]
|
|
|
|
try:
|
|
del u.addresses[3]
|
|
assert False
|
|
except TypeError, e:
|
|
assert "doesn't support item deletion" in str(e), str(e)
|
|
|
|
for a in u.addresses.filter(Address.email_address.in_(['c', 'e', 'f'])):
|
|
u.addresses.remove(a)
|
|
|
|
assert [Address(email_address='a'), Address(email_address='b'), Address(email_address='d')] == list(u.addresses)
|
|
|
|
assert [Address(email_address='a'), Address(email_address='b'), Address(email_address='d')] == sess.query(Address).all()
|
|
|
|
sess.delete(u)
|
|
sess.close()
|
|
|
|
|
|
def create_backref_test(autoflush, saveuser):
|
|
|
|
@testing.resolve_artifact_names
|
|
def test_backref(self):
|
|
mapper(User, users, properties={
|
|
'addresses':dynamic_loader(mapper(Address, addresses), backref='user')
|
|
})
|
|
sess = create_session(autoflush=autoflush)
|
|
|
|
u = User(name='buffy')
|
|
|
|
a = Address(email_address='foo@bar.com')
|
|
a.user = u
|
|
|
|
if saveuser:
|
|
sess.add(u)
|
|
else:
|
|
sess.add(a)
|
|
|
|
if not autoflush:
|
|
sess.flush()
|
|
|
|
assert u in sess
|
|
assert a in sess
|
|
|
|
self.assert_(list(u.addresses) == [a])
|
|
|
|
a.user = None
|
|
if not autoflush:
|
|
self.assert_(list(u.addresses) == [a])
|
|
|
|
if not autoflush:
|
|
sess.flush()
|
|
self.assert_(list(u.addresses) == [])
|
|
|
|
test_backref = _function_named(
|
|
test_backref, "test%s%s" % ((autoflush and "_autoflush" or ""),
|
|
(saveuser and "_saveuser" or "_savead")))
|
|
setattr(FlushTest, test_backref.__name__, test_backref)
|
|
|
|
for autoflush in (False, True):
|
|
for saveuser in (False, True):
|
|
create_backref_test(autoflush, saveuser)
|
|
|
|
class DontDereferenceTest(_base.MappedTest):
|
|
def define_tables(self, metadata):
|
|
Table('users', metadata,
|
|
Column('id', Integer, primary_key=True),
|
|
Column('name', String(40)),
|
|
Column('fullname', String(100)),
|
|
Column('password', String(15)))
|
|
|
|
Table('addresses', metadata,
|
|
Column('id', Integer, primary_key=True),
|
|
Column('email_address', String(100), nullable=False),
|
|
Column('user_id', Integer, ForeignKey('users.id')))
|
|
|
|
@testing.resolve_artifact_names
|
|
def setup_mappers(self):
|
|
class User(_base.ComparableEntity):
|
|
pass
|
|
|
|
class Address(_base.ComparableEntity):
|
|
pass
|
|
|
|
mapper(User, users, properties={
|
|
'addresses': relation(Address, backref='user', lazy='dynamic')
|
|
})
|
|
mapper(Address, addresses)
|
|
|
|
@testing.resolve_artifact_names
|
|
def test_no_deref(self):
|
|
session = create_session()
|
|
user = User()
|
|
user.name = 'joe'
|
|
user.fullname = 'Joe User'
|
|
user.password = 'Joe\'s secret'
|
|
address = Address()
|
|
address.email_address = 'joe@joesdomain.example'
|
|
address.user = user
|
|
session.add(user)
|
|
session.flush()
|
|
session.clear()
|
|
|
|
def query1():
|
|
session = create_session(testing.db)
|
|
user = session.query(User).first()
|
|
return user.addresses.all()
|
|
|
|
def query2():
|
|
session = create_session(testing.db)
|
|
return session.query(User).first().addresses.all()
|
|
|
|
def query3():
|
|
session = create_session(testing.db)
|
|
user = session.query(User).first()
|
|
return session.query(User).first().addresses.all()
|
|
|
|
eq_(query1(), [Address(email_address='joe@joesdomain.example')])
|
|
eq_(query2(), [Address(email_address='joe@joesdomain.example')])
|
|
eq_(query3(), [Address(email_address='joe@joesdomain.example')])
|
|
|
|
|
|
if __name__ == '__main__':
|
|
testenv.main()
|