9
9
from sqlalchemy.test.schema import Column
10
10
from sqlalchemy.orm import mapper, relationship, create_session, \
11
11
attributes, deferred, exc as orm_exc, defer, undefer,\
12
strategies, state, lazyload, backref
12
strategies, state, lazyload, backref, Session
13
13
from test.orm import _base, _fixtures
89
89
assert s.query(User).get(10) is None
90
90
assert u not in s # and expunges
92
# trick the "deleted" flag so we can re-add for the sake
94
del attributes.instance_state(u).deleted
94
98
# nope, raises ObjectDeletedError
108
112
@testing.resolve_artifact_names
109
113
def test_deferred(self):
110
114
"""test that unloaded, deferred attributes aren't included in the expiry list."""
112
116
mapper(Order, orders, properties={'description':deferred(orders.c.description)})
114
118
s = create_session()
115
119
o1 = s.query(Order).first()
116
120
assert 'description' not in o1.__dict__
118
122
assert o1.isopen is not None
119
123
assert 'description' not in o1.__dict__
120
124
assert o1.description
122
126
@testing.resolve_artifact_names
123
127
def test_lazyload_autoflushes(self):
124
128
mapper(User, users, properties={
145
149
@testing.resolve_artifact_names
146
150
def test_refresh_collection_exception(self):
147
"""test graceful failure for currently unsupported immediate refresh of a collection"""
151
"""test graceful failure for currently unsupported
152
immediate refresh of a collection"""
149
154
mapper(User, users, properties={
150
155
'addresses':relationship(Address, order_by=addresses.c.email_address)
152
157
mapper(Address, addresses)
153
158
s = create_session(autoflush=True, autocommit=False)
154
159
u = s.query(User).get(8)
155
assert_raises_message(sa_exc.InvalidRequestError, "properties specified for refresh", s.refresh, u, ['addresses'])
160
assert_raises_message(sa_exc.InvalidRequestError,
161
"properties specified for refresh",
162
s.refresh, u, ['addresses'])
157
164
# in contrast to a regular query with no columns
158
assert_raises_message(sa_exc.InvalidRequestError, "no columns with which to SELECT", s.query().all)
165
assert_raises_message(sa_exc.InvalidRequestError,
166
"no columns with which to SELECT", s.query().all)
160
168
@testing.resolve_artifact_names
161
169
def test_refresh_cancels_expire(self):
162
170
mapper(User, users)
221
229
assert 'name' not in u.__dict__
223
231
assert u.name == 'jack'
225
233
@testing.resolve_artifact_names
226
234
def test_no_instance_key_no_pk(self):
227
235
# same as test_no_instance_key, but the PK columns
236
244
assert 'name' not in u.__dict__
238
246
assert_raises(sa_exc.InvalidRequestError, getattr, u, 'name')
241
249
@testing.resolve_artifact_names
242
250
def test_expire_preserves_changes(self):
243
251
"""test that the expire load operation doesn't revert post-expire changes"""
342
350
def test_refresh_cascade_pending(self):
343
351
cascade = 'save-update, refresh-expire'
344
352
self._test_cascade_to_pending(cascade, False)
346
354
@testing.resolve_artifact_names
347
355
def _test_cascade_to_pending(self, cascade, expire_or_refresh):
348
356
mapper(User, users, properties={
728
736
@testing.resolve_artifact_names
729
737
def test_expire_all(self):
730
738
mapper(User, users, properties={
731
'addresses':relationship(Address, backref='user', lazy='joined'),
739
'addresses':relationship(Address, backref='user', lazy='joined',
740
order_by=addresses.c.id),
733
742
mapper(Address, addresses)
760
769
attributes.instance_state(u1).callables['name'],
761
770
strategies.LoadDeferredColumns
764
773
# expire the attr, it gets the InstanceState callable
765
774
sess.expire(u1, ['name'])
766
775
assert isinstance(
767
776
attributes.instance_state(u1).callables['name'],
768
777
state.InstanceState
771
780
# load it, callable is gone
773
782
assert 'name' not in attributes.instance_state(u1).callables
780
789
attributes.instance_state(u1).callables['name'],
781
790
state.InstanceState
784
793
# load over it. everything normal.
785
794
sess.query(User).first()
786
795
assert 'name' not in attributes.instance_state(u1).callables
788
797
sess.expunge_all()
789
798
u1 = sess.query(User).first()
790
799
# for non present, still expires the same way
793
802
assert 'name' in attributes.instance_state(u1).callables
795
804
@testing.resolve_artifact_names
796
805
def test_state_deferred_to_col(self):
797
806
"""Behavioral test to verify the current activity of loader callables."""
799
808
mapper(User, users, properties={'name':deferred(users.c.name)})
801
810
sess = create_session()
802
811
u1 = sess.query(User).options(undefer(User.name)).first()
803
812
assert 'name' not in attributes.instance_state(u1).callables
805
814
# mass expire, the attribute was loaded,
806
815
# the attribute gets the callable
813
822
# load it, callable is gone
815
824
assert 'name' not in attributes.instance_state(u1).callables
817
826
# mass expire, attribute was loaded but then deleted,
818
827
# the callable goes away - the state wants to flip
819
828
# it back to its "deferred" loader.
839
848
mapper(User, users, properties={'addresses':relationship(Address, lazy='noload')})
840
849
mapper(Address, addresses)
842
851
sess = create_session()
843
852
u1 = sess.query(User).options(lazyload(User.addresses)).first()
844
853
assert isinstance(
851
860
attributes.instance_state(u1).callables['addresses'],
852
861
strategies.LoadLazyAttribute
855
864
# load over it. callable goes away.
856
865
sess.query(User).first()
857
866
assert 'addresses' not in attributes.instance_state(u1).callables
859
868
sess.expunge_all()
860
869
u1 = sess.query(User).options(lazyload(User.addresses)).first()
861
870
sess.expire(u1, ['addresses'])
863
872
attributes.instance_state(u1).callables['addresses'],
864
873
strategies.LoadLazyAttribute
867
876
# load the attr, goes away
869
878
assert 'addresses' not in attributes.instance_state(u1).callables
873
882
class PolymorphicExpireTest(_base.MappedTest):
874
883
run_inserts = 'once'
875
884
run_deletes = None
882
891
Column('person_id', Integer, primary_key=True,
883
892
test_needs_autoincrement=True),
884
893
Column('name', String(50)),
885
Column('type', String(30)))
894
Column('type', String(30)),
887
897
engineers = Table('engineers', metadata,
888
898
Column('person_id', Integer, ForeignKey('people.person_id'),
910
920
{'person_id':3, 'status':'old engineer'},
913
924
@testing.resolve_artifact_names
914
def test_poly_deferred(self):
925
def setup_mappers(cls):
915
926
mapper(Person, people, polymorphic_on=people.c.type, polymorphic_identity='person')
916
927
mapper(Engineer, engineers, inherits=Person, polymorphic_identity='engineer')
929
@testing.resolve_artifact_names
930
def test_poly_deferred(self):
918
932
sess = create_session()
919
933
[p1, e1, e2] = sess.query(Person).order_by(people.c.person_id).all()
949
963
self.assert_sql_count(testing.db, go, 2)
950
964
eq_(Engineer.name.get_history(e1), (['new engineer name'],(), ['engineer1']))
966
@testing.resolve_artifact_names
967
def test_no_instance_key(self):
969
sess = create_session()
970
e1 = sess.query(Engineer).get(2)
972
sess.expire(e1, attribute_names=['name'])
974
attributes.instance_state(e1).key = None
975
assert 'name' not in e1.__dict__
977
assert e1.name == 'engineer1'
979
@testing.resolve_artifact_names
980
def test_no_instance_key(self):
981
# same as test_no_instance_key, but the PK columns
982
# are absent. ensure an error is raised.
983
sess = create_session()
984
e1 = sess.query(Engineer).get(2)
986
sess.expire(e1, attribute_names=['name', 'person_id'])
988
attributes.instance_state(e1).key = None
989
assert 'name' not in e1.__dict__
991
assert_raises(sa_exc.InvalidRequestError, getattr, e1, 'name')
952
994
class ExpiredPendingTest(_fixtures.FixtureTest):
953
995
run_define_tables = 'once'
954
996
run_setup_classes = 'once'
955
997
run_setup_mappers = None
956
998
run_inserts = None
958
1000
@testing.resolve_artifact_names
959
1001
def test_expired_pending(self):
960
1002
mapper(User, users, properties={
983
1025
# expire u1.addresses again. this expires
984
1026
# "pending" as well.
985
1027
sess.expire(u1, ['addresses'])
987
1029
# insert a new row
988
1030
sess.execute(addresses.insert(), dict(email_address='a3', user_id=u1.id))
990
1032
# only two addresses pulled from the DB, no "pending"
991
1033
assert len(u1.addresses) == 2
994
1036
sess.expire_all()
995
1037
assert len(u1.addresses) == 3
998
1040
class RefreshTest(_fixtures.FixtureTest):