def test_merge_load(self): Parent = self.classes.Parent sess = sessionmaker()() sess2 = sessionmaker()() p1 = sess.query(Parent).get(1) p1.children # preloading of collection took this down from 1728 to 1192 # using sqlite3 the C extension took it back up to approx. 1257 # (py2.6) @profiling.function_call_count(variance=0.10) def go(): sess2.merge(p1) go() # one more time, count the SQL def go2(): sess2.merge(p1) sess2 = sessionmaker(testing.db)() self.assert_sql_count(testing.db, go2, 2)
def test_baked_mix(self): sess = self._fixture_data() tokyo = sess.query(WeatherLocation).filter_by(city="Tokyo").one() tokyo.city sess.expunge_all() from sqlalchemy_1_3.ext.baked import BakedQuery bakery = BakedQuery.bakery() def get_tokyo(sess): bq = bakery(lambda session: session.query(WeatherLocation)) t = bq(sess).get(tokyo.id) return t Sess = sessionmaker( class_=Session, bind=db2, autoflush=True, autocommit=False ) sess2 = Sess() t = get_tokyo(sess) eq_(t.city, tokyo.city) t = get_tokyo(sess2) eq_(t.city, tokyo.city)
def test_collection_move_preloaded(self): User, Address = self.classes.User, self.classes.Address sess = sessionmaker()() a1 = Address(email_address="address1") u1 = User(name="jack", address=a1) u2 = User(name="ed") sess.add_all([u1, u2]) sess.commit() # everything is expired # load u1.address u1.address # reassign u2.address = a1 assert u2.address is a1 # backref fires assert a1.user is u2 # doesn't extend to the previous attribute tho. # flushing at this point means its anyone's guess. assert u1.address is a1 assert u2.address is a1
def test_collection_move_commitfirst(self): User, Address = self.classes.User, self.classes.Address sess = sessionmaker()() a1 = Address(email_address="address1") u1 = User(name="jack", address=a1) u2 = User(name="ed") sess.add_all([u1, u2]) sess.commit() # everything is expired # load u1.address u1.address # reassign u2.address = a1 assert u2.address is a1 # backref fires assert a1.user is u2 # the commit cancels out u1.addresses # being loaded, on next access its fine. sess.commit() assert u1.address is None assert u2.address is a1
def test_scalar_move_commitfirst(self): User, Address = self.classes.User, self.classes.Address sess = sessionmaker()() a1 = Address(email_address="address1") a2 = Address(email_address="address2") u1 = User(name="jack", address=a1) sess.add_all([u1, a1, a2]) sess.commit() # everything is expired # load assert a1.user is u1 # reassign a2.user = u1 # backref fires assert u1.address is a2 # didn't work this way tho assert a1.user is u1 # moves appropriately after commit sess.commit() assert u1.address is a2 assert a1.user is None assert a2.user is u1
def test_deserailize_colprop(self): TestTable = self.classes.TestTable s = scoped_session(sessionmaker()) expr = s.query(TestTable).filter(TestTable.some_primary_id == 123456) expr2 = serializer.loads(serializer.dumps(expr), TestTable.metadata, s) # note in the original, the same bound parameter is used twice self.assert_compile( expr, "SELECT test.some_id AS test_some_id, " "CAST(left(test.some_id, :left_1) AS INTEGER) AS anon_1, " "test.id AS test_id FROM test WHERE " "CAST(left(test.some_id, :left_1) AS INTEGER) = :param_1", checkparams={"left_1": 6, "param_1": 123456}, ) # in the deserialized, it's two separate parameter objects which # need to have different anonymous names. they still have # the same value however self.assert_compile( expr2, "SELECT test.some_id AS test_some_id, " "CAST(left(test.some_id, :left_1) AS INTEGER) AS anon_1, " "test.id AS test_id FROM test WHERE " "CAST(left(test.some_id, :left_2) AS INTEGER) = :param_1", checkparams={"left_1": 6, "left_2": 6, "param_1": 123456}, )
def go(): sessmaker = sessionmaker(bind=self.engine) sess = sessmaker() r = sess.execute(select([1])) r.close() sess.close() del sess del sessmaker
def test_table_binds(self): Address, addresses, users, User = ( self.classes.Address, self.tables.addresses, self.tables.users, self.classes.User, ) # ensure tables are unbound m2 = sa.MetaData() users_unbound = users.tometadata(m2) addresses_unbound = addresses.tometadata(m2) mapper(Address, addresses_unbound) mapper( User, users_unbound, properties={ "addresses": relationship( Address, backref=backref("user", cascade="all"), cascade="all", ) }, ) Session = sessionmaker( binds={ users_unbound: self.metadata.bind, addresses_unbound: self.metadata.bind, }) sess = Session() u1 = User(id=1, name="ed") sess.add(u1) eq_( sess.query(User).filter(User.id == 1).all(), [User(id=1, name="ed")], ) sess.execute(users_unbound.insert(), params=dict(id=2, name="jack")) eq_( sess.execute( users_unbound.select(users_unbound.c.id == 2)).fetchall(), [(2, "jack")], ) eq_( sess.execute(users_unbound.select(User.id == 2)).fetchall(), [(2, "jack")], ) sess.execute(users_unbound.delete()) eq_(sess.execute(users_unbound.select()).fetchall(), []) sess.close()
def test_inheriting(self): A, B, b_table, a_table, Dest, dest_table = ( self.classes.A, self.classes.B, self.tables.b_table, self.tables.a_table, self.classes.Dest, self.tables.dest_table, ) mapper( A, a_table, properties={ "some_dest": relationship(Dest, back_populates="many_a") }, ) mapper( B, b_table, inherits=A, concrete=True, properties={ "some_dest": relationship(Dest, back_populates="many_b") }, ) mapper( Dest, dest_table, properties={ "many_a": relationship(A, back_populates="some_dest"), "many_b": relationship(B, back_populates="some_dest"), }, ) sess = sessionmaker()() dest1 = Dest(name="c1") dest2 = Dest(name="c2") a1 = A(some_dest=dest1, aname="a1") a2 = A(some_dest=dest2, aname="a2") b1 = B(some_dest=dest1, bname="b1") b2 = B(some_dest=dest1, bname="b2") assert_raises(AttributeError, setattr, b1, "aname", "foo") assert_raises(AttributeError, getattr, A, "bname") assert dest2.many_a == [a2] assert dest1.many_a == [a1] assert dest1.many_b == [b1, b2] sess.add_all([dest1, dest2]) sess.commit() assert sess.query(Dest).filter(Dest.many_a.contains(a2)).one() is dest2 assert dest2.many_a == [a2] assert dest1.many_a == [a1] assert dest1.many_b == [b1, b2] assert sess.query(B).filter(B.bname == "b1").one() is b1
def setup_session(cls): global create_session shard_lookup = { "North America": "north_america", "Asia": "asia", "Europe": "europe", "South America": "south_america", } def shard_chooser(mapper, instance, clause=None): if isinstance(instance, WeatherLocation): return shard_lookup[instance.continent] else: return shard_chooser(mapper, instance.location) def id_chooser(query, ident): return ["north_america", "asia", "europe", "south_america"] def query_chooser(query): ids = [] class FindContinent(sql.ClauseVisitor): def visit_binary(self, binary): if binary.left.shares_lineage( weather_locations.c.continent ): if binary.operator == operators.eq: ids.append(shard_lookup[binary.right.value]) elif binary.operator == operators.in_op: for bind in binary.right.clauses: ids.append(shard_lookup[bind.value]) if query._criterion is not None: FindContinent().traverse(query._criterion) if len(ids) == 0: return ["north_america", "asia", "europe", "south_america"] else: return ids create_session = sessionmaker( class_=ShardedSession, autoflush=True, autocommit=False ) create_session.configure( shards={ "north_america": db1, "asia": db2, "europe": db3, "south_america": db4, }, shard_chooser=shard_chooser, id_chooser=id_chooser, query_chooser=query_chooser, )
def test_stale_conditions(self): Place, Transition, place_input, place, transition = ( self.classes.Place, self.classes.Transition, self.tables.place_input, self.tables.place, self.tables.transition, ) mapper( Place, place, properties={ "transitions": relationship(Transition, secondary=place_input, passive_updates=False) }, ) mapper(Transition, transition) p1 = Place("place1") t1 = Transition("t1") p1.transitions.append(t1) sess = sessionmaker()() sess.add_all([p1, t1]) sess.commit() p1.place_id p1.transitions sess.execute("delete from place_input", mapper=Place) p1.place_id = 7 assert_raises_message( orm_exc.StaleDataError, r"UPDATE statement on table 'place_input' expected to " r"update 1 row\(s\); Only 0 were matched.", sess.commit, ) sess.rollback() p1.place_id p1.transitions sess.execute("delete from place_input", mapper=Place) p1.transitions.remove(t1) assert_raises_message( orm_exc.StaleDataError, r"DELETE statement on table 'place_input' expected to " r"delete 1 row\(s\); Only 0 were matched.", sess.commit, )
def test_selective_relationships(self): sub, base_mtom, Related, Base, related, sub_mtom, base, Sub = ( self.tables.sub, self.tables.base_mtom, self.classes.Related, self.classes.Base, self.tables.related, self.tables.sub_mtom, self.tables.base, self.classes.Sub, ) mapper( Base, base, properties={ "related": relationship( Related, secondary=base_mtom, backref="bases", order_by=related.c.id, ) }, ) mapper( Sub, sub, inherits=Base, concrete=True, properties={ "related": relationship( Related, secondary=sub_mtom, backref="subs", order_by=related.c.id, ) }, ) mapper(Related, related) sess = sessionmaker()() b1, s1, r1, r2, r3 = Base(), Sub(), Related(), Related(), Related() b1.related.append(r1) b1.related.append(r2) s1.related.append(r2) s1.related.append(r3) sess.add_all([b1, s1]) sess.commit() eq_(s1.related, [r2, r3]) eq_(b1.related, [r1, r2])
def setup_mappers(cls): global Session Session = scoped_session(sessionmaker()) mapper( User, users, properties={ "addresses": relationship( Address, backref="user", order_by=addresses.c.id ) }, ) mapper(Address, addresses) configure_mappers()
def test_merge_no_load(self): Parent = self.classes.Parent sess = sessionmaker()() sess2 = sessionmaker()() p1 = sess.query(Parent).get(1) p1.children # down from 185 on this this is a small slice of a usually # bigger operation so using a small variance @profiling.function_call_count(variance=0.20) def go1(): return sess2.merge(p1, load=False) p2 = go1() # third call, merge object already present. almost no calls. @profiling.function_call_count(variance=0.20, warmup=1) def go2(): return sess2.merge(p2, load=False) go2()
def test_m2o_event(self): User, Address = self.classes.User, self.classes.Address sess = sessionmaker()() a1 = Address(email_address="address1") u1 = User(name="jack", address=a1) sess.add(u1) sess.commit() sess.expunge(u1) u2 = User(name="ed") # the _SingleParent extension sets the backref get to "active" ! # u1 gets loaded and deleted u2.address = a1 sess.commit() assert sess.query(User).count() == 1
def test_set_none(self): User, Address = self.classes.User, self.classes.Address sess = sessionmaker()() u1 = User(name="jack") a1 = Address(email_address="a1") a1.user = u1 sess.add_all([u1, a1]) sess.commit() # works for None too def go(): a1.user = None self.assert_sql_count(testing.db, go, 0) assert a1 not in u1.addresses
def test_join_cache(self): metadata = MetaData(self.engine) table1 = Table( "table1", metadata, Column("id", Integer, primary_key=True, test_needs_autoincrement=True), Column("data", String(30)), ) table2 = Table( "table2", metadata, Column("id", Integer, primary_key=True, test_needs_autoincrement=True), Column("data", String(30)), Column("t1id", Integer, ForeignKey("table1.id")), ) class Foo(object): pass class Bar(object): pass mapper(Foo, table1, properties={"bars": relationship(mapper(Bar, table2))}) metadata.create_all() session = sessionmaker() @profile_memory() def go(): s = table2.select() sess = session() sess.query(Foo).join((s, Foo.bars)).all() sess.rollback() try: go() finally: metadata.drop_all()
def test_collection_move_notloaded(self): Item, Keyword = self.classes.Item, self.classes.Keyword sess = sessionmaker()() k1 = Keyword(name="k1") i1 = Item(description="i1", keyword=k1) i2 = Item(description="i2") sess.add_all([i1, i2, k1]) sess.commit() # everything is expired i2.keyword = k1 assert k1.item is i2 assert i1.keyword is None assert i2.keyword is k1
def test_scalar_move_notloaded(self): User, Address = self.classes.User, self.classes.Address sess = sessionmaker()() u1 = User(name="jack") u2 = User(name="ed") a1 = Address(email_address="a1") a1.user = u1 sess.add_all([u1, u2, a1]) sess.commit() # direct set - the fetching of the # "old" u1 here allows the backref # to remove it from the addresses collection a1.user = u2 assert a1 not in u1.addresses assert a1 in u2.addresses
def test_collection_move_notloaded(self): User, Address = self.classes.User, self.classes.Address sess = sessionmaker()() a1 = Address(email_address="address1") u1 = User(name="jack", addresses=[a1]) u2 = User(name="ed") sess.add_all([u1, u2]) sess.commit() # everything is expired u2.addresses.append(a1) # backref fires assert a1.user is u2 # u1.addresses wasn't loaded, # so when it loads its correct assert a1 not in u1.addresses assert a1 in u2.addresses
def test_collection_move_hitslazy(self): User, Address = self.classes.User, self.classes.Address sess = sessionmaker()() a1 = Address(email_address="address1") a2 = Address(email_address="address2") a3 = Address(email_address="address3") u1 = User(name="jack", addresses=[a1, a2, a3]) u2 = User(name="ed") sess.add_all([u1, a1, a2, a3]) sess.commit() # u1.addresses def go(): u2.addresses.append(a1) u2.addresses.append(a2) u2.addresses.append(a3) self.assert_sql_count(testing.db, go, 0)
def test_scalar_move_notloaded(self): User, Address = self.classes.User, self.classes.Address sess = sessionmaker()() a1 = Address(email_address="address1") a2 = Address(email_address="address1") u1 = User(name="jack", address=a1) sess.add_all([u1, a1, a2]) sess.commit() # everything is expired # reassign a2.user = u1 # backref fires assert u1.address is a2 # stays on both sides assert a1.user is u1 assert a2.user is u1
def test_collection_move_notloaded(self): User, Address = self.classes.User, self.classes.Address sess = sessionmaker()() a1 = Address(email_address="address1") u1 = User(name="jack", address=a1) u2 = User(name="ed") sess.add_all([u1, u2]) sess.commit() # everything is expired # reassign u2.address = a1 assert u2.address is a1 # backref fires assert a1.user is u2 # u1.address loads now after a flush assert u1.address is None assert u2.address is a1
def test_pickle_protocols(self): users, addresses = (self.tables.users, self.tables.addresses) mapper( User, users, properties={"addresses": relationship(Address, backref="user")}, ) mapper(Address, addresses) sess = sessionmaker()() u1 = User(name="ed") u1.addresses.append(Address(email_address="*****@*****.**")) sess.add(u1) sess.commit() u1 = sess.query(User).first() u1.addresses for loads, dumps in picklers(): u2 = loads(dumps(u1)) eq_(u1, u2)
def test_collection_move_preloaded(self): User, Address = self.classes.User, self.classes.Address sess = sessionmaker()() a1 = Address(email_address="address1") u1 = User(name="jack", addresses=[a1]) u2 = User(name="ed") sess.add_all([u1, u2]) sess.commit() # everything is expired # load u1.addresses collection u1.addresses u2.addresses.append(a1) # backref fires assert a1.user is u2 # a1 removed from u1.addresses as of [ticket:2789] assert a1 not in u1.addresses assert a1 in u2.addresses
def test_plain_load_passive(self): """test that many-to-one set doesn't load the old value.""" User, Address = self.classes.User, self.classes.Address sess = sessionmaker()() u1 = User(name="jack") u2 = User(name="ed") a1 = Address(email_address="a1") a1.user = u1 sess.add_all([u1, u2, a1]) sess.commit() # in this case, a lazyload would # ordinarily occur except for the # PASSIVE_NO_FETCH flag. def go(): a1.user = u2 self.assert_sql_count(testing.db, go, 0) assert a1 not in u1.addresses assert a1 in u2.addresses
def test_collection_move_commitfirst(self): User, Address = self.classes.User, self.classes.Address sess = sessionmaker()() a1 = Address(email_address="address1") u1 = User(name="jack", addresses=[a1]) u2 = User(name="ed") sess.add_all([u1, u2]) sess.commit() # everything is expired # load u1.addresses collection u1.addresses u2.addresses.append(a1) # backref fires assert a1.user is u2 # everything expires, no changes in # u1.addresses, so all is fine sess.commit() assert a1 not in u1.addresses assert a1 in u2.addresses
def test_scalar_move_preloaded(self): User, Address = self.classes.User, self.classes.Address sess = sessionmaker()() u1 = User(name="jack") u2 = User(name="ed") a1 = Address(email_address="a1") a1.user = u1 sess.add_all([u1, u2, a1]) sess.commit() # u1.addresses is loaded u1.addresses # direct set - the "old" is "fetched", # but only from the local session - not the # database, due to the PASSIVE_NO_FETCH flag. # this is a more fine grained behavior introduced # in 0.6 a1.user = u2 assert a1 not in u1.addresses assert a1 in u2.addresses
def test_merge_w_relationship(self): A, C, B, c_table, b_table, a_table, Dest, dest_table = ( self.classes.A, self.classes.C, self.classes.B, self.tables.c_table, self.tables.b_table, self.tables.a_table, self.classes.Dest, self.tables.dest_table, ) ajoin = polymorphic_union({ "a": a_table, "b": b_table, "c": c_table }, "type", "ajoin") mapper( A, a_table, with_polymorphic=("*", ajoin), polymorphic_on=ajoin.c.type, polymorphic_identity="a", properties={ "some_dest": relationship(Dest, back_populates="many_a") }, ) mapper( B, b_table, inherits=A, concrete=True, polymorphic_identity="b", properties={ "some_dest": relationship(Dest, back_populates="many_a") }, ) mapper( C, c_table, inherits=A, concrete=True, polymorphic_identity="c", properties={ "some_dest": relationship(Dest, back_populates="many_a") }, ) mapper( Dest, dest_table, properties={ "many_a": relationship(A, back_populates="some_dest", order_by=ajoin.c.id) }, ) assert C.some_dest.property.parent is class_mapper(C) assert B.some_dest.property.parent is class_mapper(B) assert A.some_dest.property.parent is class_mapper(A) sess = sessionmaker()() dest1 = Dest(name="d1") dest2 = Dest(name="d2") a1 = A(some_dest=dest2, aname="a1") b1 = B(some_dest=dest1, bname="b1") c1 = C(some_dest=dest2, cname="c1") sess.add_all([dest1, dest2, c1, a1, b1]) sess.commit() sess2 = sessionmaker()() merged_c1 = sess2.merge(c1) eq_(merged_c1.some_dest.name, "d2") eq_(merged_c1.some_dest_id, c1.some_dest_id)
def test_polymorphic_backref(self): """test multiple backrefs to the same polymorphically-loading attribute.""" A, C, B, c_table, b_table, a_table, Dest, dest_table = ( self.classes.A, self.classes.C, self.classes.B, self.tables.c_table, self.tables.b_table, self.tables.a_table, self.classes.Dest, self.tables.dest_table, ) ajoin = polymorphic_union({ "a": a_table, "b": b_table, "c": c_table }, "type", "ajoin") mapper( A, a_table, with_polymorphic=("*", ajoin), polymorphic_on=ajoin.c.type, polymorphic_identity="a", properties={ "some_dest": relationship(Dest, back_populates="many_a") }, ) mapper( B, b_table, inherits=A, concrete=True, polymorphic_identity="b", properties={ "some_dest": relationship(Dest, back_populates="many_a") }, ) mapper( C, c_table, inherits=A, concrete=True, polymorphic_identity="c", properties={ "some_dest": relationship(Dest, back_populates="many_a") }, ) mapper( Dest, dest_table, properties={ "many_a": relationship(A, back_populates="some_dest", order_by=ajoin.c.id) }, ) sess = sessionmaker()() dest1 = Dest(name="c1") dest2 = Dest(name="c2") a1 = A(some_dest=dest1, aname="a1", id=1) a2 = A(some_dest=dest2, aname="a2", id=2) b1 = B(some_dest=dest1, bname="b1", id=3) b2 = B(some_dest=dest1, bname="b2", id=4) c1 = C(some_dest=dest1, cname="c1", id=5) c2 = C(some_dest=dest2, cname="c2", id=6) eq_([a2, c2], dest2.many_a) eq_([a1, b1, b2, c1], dest1.many_a) sess.add_all([dest1, dest2]) sess.commit() assert sess.query(Dest).filter(Dest.many_a.contains(a2)).one() is dest2 assert sess.query(Dest).filter(Dest.many_a.contains(b1)).one() is dest1 assert sess.query(Dest).filter(Dest.many_a.contains(c2)).one() is dest2 eq_(dest2.many_a, [a2, c2]) eq_(dest1.many_a, [a1, b1, b2, c1]) sess.expire_all() def go(): eq_( [ Dest(many_a=[ A(aname="a1"), B(bname="b1"), B(bname="b2"), C(cname="c1"), ]), Dest(many_a=[A(aname="a2"), C(cname="c2")]), ], sess.query(Dest).options(joinedload(Dest.many_a)).order_by( Dest.id).all(), ) self.assert_sql_count(testing.db, go, 1)