def test_one_to_many_save(self): Node, nodes = self.classes.Node, self.tables.nodes mapper(Node, nodes, properties={'children': relationship(Node)}) sess = create_session() n2, n3 = Node(data='n2'), Node(data='n3') n1 = Node(data='n1', children=[n2, n3]) sess.add(n1) self.assert_sql_execution( testing.db, sess.flush, CompiledSQL( "INSERT INTO nodes (parent_id, data) VALUES " "(:parent_id, :data)", { 'parent_id': None, 'data': 'n1' }), AllOf( CompiledSQL( "INSERT INTO nodes (parent_id, data) VALUES " "(:parent_id, :data)", lambda ctx: { 'parent_id': n1.id, 'data': 'n2' }), CompiledSQL( "INSERT INTO nodes (parent_id, data) VALUES " "(:parent_id, :data)", lambda ctx: { 'parent_id': n1.id, 'data': 'n3' }), ))
def test_one_to_many_delete_parent(self): Node, nodes = self.classes.Node, self.tables.nodes mapper(Node, nodes, properties={'children': relationship(Node)}) sess = create_session() n2, n3 = Node(data='n2', children=[]), Node(data='n3', children=[]) n1 = Node(data='n1', children=[n2, n3]) sess.add(n1) sess.flush() sess.delete(n1) self.assert_sql_execution( testing.db, sess.flush, AllOf( CompiledSQL( "UPDATE nodes SET parent_id=:parent_id " "WHERE nodes.id = :nodes_id", lambda ctx: { 'nodes_id': n3.id, 'parent_id': None }), CompiledSQL( "UPDATE nodes SET parent_id=:parent_id " "WHERE nodes.id = :nodes_id", lambda ctx: { 'nodes_id': n2.id, 'parent_id': None }), ), CompiledSQL("DELETE FROM nodes WHERE nodes.id = :id", lambda ctx: {'id': n1.id}))
def test_one_to_many_delete_all(self): users, Address, addresses, User = (self.tables.users, self.classes.Address, self.tables.addresses, self.classes.User) mapper(User, users, properties={ 'addresses': relationship(Address), }) mapper(Address, addresses) sess = create_session() a1, a2 = Address(email_address='a1'), Address(email_address='a2') u1 = User(name='u1', addresses=[a1, a2]) sess.add(u1) sess.flush() sess.delete(u1) sess.delete(a1) sess.delete(a2) self.assert_sql_execution( testing.db, sess.flush, CompiledSQL("DELETE FROM addresses WHERE addresses.id = :id", [{ 'id': a1.id }, { 'id': a2.id }]), CompiledSQL("DELETE FROM users WHERE users.id = :id", {'id': u1.id}), )
def test_many_to_one_delete_all(self): Node, nodes = self.classes.Node, self.tables.nodes mapper( Node, nodes, properties={'parent': relationship(Node, remote_side=nodes.c.id)}) sess = create_session() n1 = Node(data='n1') n2, n3 = Node(data='n2', parent=n1), Node(data='n3', parent=n1) sess.add_all([n2, n3]) sess.flush() sess.delete(n1) sess.delete(n2) sess.delete(n3) self.assert_sql_execution( testing.db, sess.flush, CompiledSQL("DELETE FROM nodes WHERE nodes.id = :id", lambda ctx: [{ 'id': n2.id }, { 'id': n3.id }]), CompiledSQL("DELETE FROM nodes WHERE nodes.id = :id", lambda ctx: {'id': n1.id}))
def test_one_to_many_save(self): users, Address, addresses, User = (self.tables.users, self.classes.Address, self.tables.addresses, self.classes.User) mapper(User, users, properties={ 'addresses': relationship(Address), }) mapper(Address, addresses) sess = create_session() a1, a2 = Address(email_address='a1'), Address(email_address='a2') u1 = User(name='u1', addresses=[a1, a2]) sess.add(u1) self.assert_sql_execution( testing.db, sess.flush, CompiledSQL("INSERT INTO users (name) VALUES (:name)", {'name': 'u1'}), CompiledSQL( "INSERT INTO addresses (user_id, email_address) " "VALUES (:user_id, :email_address)", lambda ctx: { 'email_address': 'a1', 'user_id': u1.id }), CompiledSQL( "INSERT INTO addresses (user_id, email_address) " "VALUES (:user_id, :email_address)", lambda ctx: { 'email_address': 'a2', 'user_id': u1.id }), )
def test_many_to_one_delete_childonly_unloaded_expired(self): users, Address, addresses, User = (self.tables.users, self.classes.Address, self.tables.addresses, self.classes.User) mapper(User, users) mapper(Address, addresses, properties={'parent': relationship(User)}) parent = User(name='p1') c1, c2 = Address(email_address='c1', parent=parent), \ Address(email_address='c2', parent=parent) session = Session() session.add_all([c1, c2]) session.add(parent) session.flush() pid = parent.id c1id = c1.id c2id = c2.id session.expire(parent) session.expire(c1) session.expire(c2) session.delete(c1) session.delete(c2) self.assert_sql_execution( testing.db, session.flush, AllOf( # the parent User is expired, so it gets loaded here. CompiledSQL( "SELECT addresses.id AS addresses_id, addresses.user_id AS " "addresses_user_id, addresses.email_address AS " "addresses_email_address FROM addresses WHERE addresses.id = " ":param_1", lambda ctx: {'param_1': c1id}), CompiledSQL( "SELECT addresses.id AS addresses_id, addresses.user_id AS " "addresses_user_id, addresses.email_address AS " "addresses_email_address FROM addresses WHERE addresses.id = " ":param_1", lambda ctx: {'param_1': c2id}), ), CompiledSQL("DELETE FROM addresses WHERE addresses.id = :id", lambda ctx: [{ 'id': c1id }, { 'id': c2id }]), )
def test_many_to_many(self): keywords, items, item_keywords, Keyword, Item = ( self.tables.keywords, self.tables.items, self.tables.item_keywords, self.classes.Keyword, self.classes.Item) mapper(Item, items, properties={ 'keywords': relationship(Keyword, secondary=item_keywords) }) mapper(Keyword, keywords) sess = create_session() k1 = Keyword(name='k1') i1 = Item(description='i1', keywords=[k1]) sess.add(i1) self.assert_sql_execution( testing.db, sess.flush, AllOf( CompiledSQL("INSERT INTO keywords (name) VALUES (:name)", {'name': 'k1'}), CompiledSQL( "INSERT INTO items (description) VALUES (:description)", {'description': 'i1'}), ), CompiledSQL( "INSERT INTO item_keywords (item_id, keyword_id) " "VALUES (:item_id, :keyword_id)", lambda ctx: { 'item_id': i1.id, 'keyword_id': k1.id })) # test that keywords collection isn't loaded sess.expire(i1, ['keywords']) i1.description = 'i2' self.assert_sql_execution( testing.db, sess.flush, CompiledSQL( "UPDATE items SET description=:description " "WHERE items.id = :items_id", lambda ctx: { 'description': 'i2', 'items_id': i1.id }))
def test_natural_ordering(self): """test that unconnected items take relationship() into account regardless.""" users, Address, addresses, User = (self.tables.users, self.classes.Address, self.tables.addresses, self.classes.User) mapper(User, users) mapper(Address, addresses, properties={'parent': relationship(User)}) sess = create_session() u1 = User(id=1, name='u1') a1 = Address(id=1, user_id=1, email_address='a2') sess.add_all([u1, a1]) self.assert_sql_execution( testing.db, sess.flush, CompiledSQL("INSERT INTO users (id, name) VALUES (:id, :name)", { 'id': 1, 'name': 'u1' }), CompiledSQL( "INSERT INTO addresses (id, user_id, email_address) " "VALUES (:id, :user_id, :email_address)", { 'email_address': 'a2', 'user_id': 1, 'id': 1 })) sess.delete(u1) sess.delete(a1) self.assert_sql_execution( testing.db, sess.flush, CompiledSQL("DELETE FROM addresses WHERE addresses.id = :id", [{ 'id': 1 }]), CompiledSQL("DELETE FROM users WHERE users.id = :id", [{ 'id': 1 }]))
def test_many_to_one_delete_target(self): users, Address, addresses, User = (self.tables.users, self.classes.Address, self.tables.addresses, self.classes.User) mapper(User, users) mapper(Address, addresses, properties={'user': relationship(User)}) sess = create_session() u1 = User(name='u1') a1, a2 = Address(email_address='a1', user=u1), \ Address(email_address='a2', user=u1) sess.add_all([a1, a2]) sess.flush() sess.delete(u1) a1.user = a2.user = None self.assert_sql_execution( testing.db, sess.flush, CompiledSQL( "UPDATE addresses SET user_id=:user_id WHERE " "addresses.id = :addresses_id", lambda ctx: [{ u'addresses_id': a1.id, 'user_id': None }]), CompiledSQL( "UPDATE addresses SET user_id=:user_id WHERE " "addresses.id = :addresses_id", lambda ctx: [{ u'addresses_id': a2.id, 'user_id': None }]), CompiledSQL("DELETE FROM users WHERE users.id = :id", {'id': u1.id}), )
def test_rowswitch_doesntfire(self): User, Address, users, addresses = (self.classes.User, self.classes.Address, self.tables.users, self.tables.addresses) mapper(User, users) mapper(Address, addresses, properties={'user': relationship(User, passive_updates=True)}) sess = create_session() u1 = User(username='******') a1 = Address(user=u1, email='ed@host1') sess.add(u1) sess.add(a1) sess.flush() sess.delete(u1) sess.delete(a1) u2 = User(username='******') a2 = Address(user=u2, email='ed@host1', etc='foo') sess.add(u2) sess.add(a2) from test.lib.assertsql import CompiledSQL # test that the primary key columns of addresses are not # being updated as well, since this is a row switch. self.assert_sql_execution( testing.db, sess.flush, CompiledSQL( "UPDATE addresses SET etc=:etc WHERE " "addresses.username = :addresses_username AND" " addresses.email = :addresses_email", { 'etc': 'foo', 'addresses_username': '******', 'addresses_email': 'ed@host1' }), )
def test_many_to_one_set_null_unloaded(self): Node, nodes = self.classes.Node, self.tables.nodes mapper( Node, nodes, properties={'parent': relationship(Node, remote_side=nodes.c.id)}) sess = create_session() n1 = Node(data='n1') n2 = Node(data='n2', parent=n1) sess.add_all([n1, n2]) sess.flush() sess.close() n2 = sess.query(Node).filter_by(data='n2').one() n2.parent = None self.assert_sql_execution( testing.db, sess.flush, CompiledSQL( "UPDATE nodes SET parent_id=:parent_id WHERE " "nodes.id = :nodes_id", lambda ctx: { "parent_id": None, "nodes_id": n2.id }))
def test_natural_selfref(self): """test that unconnected items take relationship() into account regardless.""" Node, nodes = self.classes.Node, self.tables.nodes mapper(Node, nodes, properties={'children': relationship(Node)}) sess = create_session() n1 = Node(id=1) n2 = Node(id=2, parent_id=1) n3 = Node(id=3, parent_id=2) # insert order is determined from add order since they # are the same class sess.add_all([n1, n2, n3]) self.assert_sql_execution( testing.db, sess.flush, CompiledSQL( "INSERT INTO nodes (id, parent_id, data) VALUES " "(:id, :parent_id, :data)", [{ 'parent_id': None, 'data': None, 'id': 1 }, { 'parent_id': 1, 'data': None, 'id': 2 }, { 'parent_id': 2, 'data': None, 'id': 3 }]), )
def test_one(self): """Post_update only fires off when needed. This test case used to produce many superfluous update statements, particularly upon delete """ node, Node = self.tables.node, self.classes.Node mapper( Node, node, properties={ 'children': relationship(Node, primaryjoin=node.c.id == node.c.parent_id, cascade="all", backref=backref("parent", remote_side=node.c.id)), 'prev_sibling': relationship(Node, primaryjoin=node.c.prev_sibling_id == node.c.id, remote_side=node.c.id, uselist=False), 'next_sibling': relationship(Node, primaryjoin=node.c.next_sibling_id == node.c.id, remote_side=node.c.id, uselist=False, post_update=True) }) session = create_session() def append_child(parent, child): if parent.children: parent.children[-1].next_sibling = child child.prev_sibling = parent.children[-1] parent.children.append(child) def remove_child(parent, child): child.parent = None node = child.next_sibling node.prev_sibling = child.prev_sibling child.prev_sibling.next_sibling = node session.delete(child) root = Node('root') about = Node('about') cats = Node('cats') stories = Node('stories') bruce = Node('bruce') append_child(root, about) assert (about.prev_sibling is None) append_child(root, cats) assert (cats.prev_sibling is about) assert (cats.next_sibling is None) assert (about.next_sibling is cats) assert (about.prev_sibling is None) append_child(root, stories) append_child(root, bruce) session.add(root) session.flush() remove_child(root, cats) # pre-trigger lazy loader on 'cats' to make the test easier cats.children self.assert_sql_execution( testing.db, session.flush, AllOf( CompiledSQL( "UPDATE node SET prev_sibling_id=:prev_sibling_id " "WHERE node.id = :node_id", lambda ctx: { 'prev_sibling_id': about.id, 'node_id': stories.id }), CompiledSQL( "UPDATE node SET next_sibling_id=:next_sibling_id " "WHERE node.id = :node_id", lambda ctx: { 'next_sibling_id': stories.id, 'node_id': about.id }), CompiledSQL( "UPDATE node SET next_sibling_id=:next_sibling_id " "WHERE node.id = :node_id", lambda ctx: { 'next_sibling_id': None, 'node_id': cats.id }), ), CompiledSQL("DELETE FROM node WHERE node.id = :id", lambda ctx: [{ 'id': cats.id }])) session.delete(root) self.assert_sql_execution( testing.db, session.flush, CompiledSQL( "UPDATE node SET next_sibling_id=:next_sibling_id " "WHERE node.id = :node_id", lambda ctx: [{ 'node_id': about.id, 'next_sibling_id': None }, { 'node_id': stories.id, 'next_sibling_id': None }]), AllOf( CompiledSQL("DELETE FROM node WHERE node.id = :id", lambda ctx: {'id': about.id}), CompiledSQL("DELETE FROM node WHERE node.id = :id", lambda ctx: {'id': stories.id}), CompiledSQL("DELETE FROM node WHERE node.id = :id", lambda ctx: {'id': bruce.id}), ), CompiledSQL("DELETE FROM node WHERE node.id = :id", lambda ctx: {'id': root.id}), ) about = Node('about') cats = Node('cats') about.next_sibling = cats cats.prev_sibling = about session.add(about) session.flush() session.delete(about) cats.prev_sibling = None session.flush()
def test_many_to_many_one(self): nodes, node_to_nodes = self.tables.nodes, self.tables.node_to_nodes class Node(fixtures.ComparableEntity): pass mapper( Node, nodes, properties={ 'children': relationship( Node, secondary=node_to_nodes, primaryjoin=nodes.c.id == node_to_nodes.c.left_node_id, secondaryjoin=nodes.c.id == node_to_nodes.c.right_node_id, backref='parents'), 'favorite': relationship(Node, remote_side=nodes.c.id) }) sess = create_session() n1 = Node(data='n1') n2 = Node(data='n2') n3 = Node(data='n3') n4 = Node(data='n4') n5 = Node(data='n5') n4.favorite = n3 n1.favorite = n5 n5.favorite = n2 n1.children = [n2, n3, n4] n2.children = [n3, n5] n3.children = [n5, n4] sess.add_all([n1, n2, n3, n4, n5]) # can't really assert the SQL on this easily # since there's too many ways to insert the rows. # so check the end result sess.flush() eq_( sess.query(node_to_nodes.c.left_node_id, node_to_nodes.c.right_node_id).\ order_by(node_to_nodes.c.left_node_id, node_to_nodes.c.right_node_id).\ all(), sorted([ (n1.id, n2.id), (n1.id, n3.id), (n1.id, n4.id), (n2.id, n3.id), (n2.id, n5.id), (n3.id, n5.id), (n3.id, n4.id) ]) ) sess.delete(n1) self.assert_sql_execution( testing.db, sess.flush, # this is n1.parents firing off, as it should, since # passive_deletes is False for n1.parents CompiledSQL( "SELECT nodes.id AS nodes_id, nodes.data AS nodes_data, " "nodes.favorite_node_id AS nodes_favorite_node_id FROM " "nodes, node_to_nodes WHERE :param_1 = " "node_to_nodes.right_node_id AND nodes.id = " "node_to_nodes.left_node_id", lambda ctx: {u'param_1': n1.id}, ), CompiledSQL( "DELETE FROM node_to_nodes WHERE " "node_to_nodes.left_node_id = :left_node_id AND " "node_to_nodes.right_node_id = :right_node_id", lambda ctx: [{ 'right_node_id': n2.id, 'left_node_id': n1.id }, { 'right_node_id': n3.id, 'left_node_id': n1.id }, { 'right_node_id': n4.id, 'left_node_id': n1.id }]), CompiledSQL("DELETE FROM nodes WHERE nodes.id = :id", lambda ctx: {'id': n1.id}), ) for n in [n2, n3, n4, n5]: sess.delete(n) # load these collections # outside of the flush() below n4.children n5.children self.assert_sql_execution( testing.db, sess.flush, CompiledSQL( "DELETE FROM node_to_nodes WHERE node_to_nodes.left_node_id " "= :left_node_id AND node_to_nodes.right_node_id = " ":right_node_id", lambda ctx: [{ 'right_node_id': n5.id, 'left_node_id': n3.id }, { 'right_node_id': n4.id, 'left_node_id': n3.id }, { 'right_node_id': n3.id, 'left_node_id': n2.id }, { 'right_node_id': n5.id, 'left_node_id': n2.id }]), CompiledSQL("DELETE FROM nodes WHERE nodes.id = :id", lambda ctx: [{ 'id': n4.id }, { 'id': n5.id }]), CompiledSQL("DELETE FROM nodes WHERE nodes.id = :id", lambda ctx: [{ 'id': n2.id }, { 'id': n3.id }]), )
def test_batch_interaction(self): """test batching groups same-structured, primary key present statements together. """ t = self.tables.t class T(fixtures.ComparableEntity): pass mapper(T, t) sess = Session() sess.add_all([ T(data='t1'), T(data='t2'), T(id=3, data='t3'), T(id=4, data='t4'), T(id=5, data='t5'), T(id=6, data=func.lower('t6')), T(id=7, data='t7'), T(id=8, data='t8'), T(id=9, data='t9', def_='def2'), T(id=10, data='t10', def_='def3'), T(id=11, data='t11'), ]) self.assert_sql_execution( testing.db, sess.flush, CompiledSQL("INSERT INTO t (data) VALUES (:data)", {'data': 't1'}), CompiledSQL("INSERT INTO t (data) VALUES (:data)", {'data': 't2'}), CompiledSQL("INSERT INTO t (id, data) VALUES (:id, :data)", [{ 'data': 't3', 'id': 3 }, { 'data': 't4', 'id': 4 }, { 'data': 't5', 'id': 5 }]), CompiledSQL( "INSERT INTO t (id, data) VALUES (:id, lower(:lower_1))", { 'lower_1': 't6', 'id': 6 }), CompiledSQL("INSERT INTO t (id, data) VALUES (:id, :data)", [{ 'data': 't7', 'id': 7 }, { 'data': 't8', 'id': 8 }]), CompiledSQL( "INSERT INTO t (id, data, def_) VALUES (:id, :data, :def_)", [{ 'data': 't9', 'id': 9, 'def_': 'def2' }, { 'data': 't10', 'id': 10, 'def_': 'def3' }]), CompiledSQL("INSERT INTO t (id, data) VALUES (:id, :data)", { 'data': 't11', 'id': 11 }), )
def test_post_update_o2m(self): """A cycle between two rows, with a post_update on the one-to-many""" person, ball, Ball, Person = (self.tables.person, self.tables.ball, self.classes.Ball, self.classes.Person) mapper(Ball, ball) mapper(Person, person, properties=dict( balls=relationship( Ball, primaryjoin=ball.c.person_id == person.c.id, remote_side=ball.c.person_id, cascade="all, delete-orphan", post_update=True, backref='person'), favorite=relationship( Ball, primaryjoin=person.c.favorite_ball_id == ball.c.id, remote_side=person.c.favorite_ball_id))) b = Ball(data='some data') p = Person(data='some data') p.balls.append(b) b2 = Ball(data='some data') p.balls.append(b2) b3 = Ball(data='some data') p.balls.append(b3) b4 = Ball(data='some data') p.balls.append(b4) p.favorite = b sess = create_session() sess.add_all((b, p, b2, b3, b4)) self.assert_sql_execution( testing.db, sess.flush, CompiledSQL( "INSERT INTO ball (person_id, data) " "VALUES (:person_id, :data)", { 'person_id': None, 'data': 'some data' }), CompiledSQL( "INSERT INTO ball (person_id, data) " "VALUES (:person_id, :data)", { 'person_id': None, 'data': 'some data' }), CompiledSQL( "INSERT INTO ball (person_id, data) " "VALUES (:person_id, :data)", { 'person_id': None, 'data': 'some data' }), CompiledSQL( "INSERT INTO ball (person_id, data) " "VALUES (:person_id, :data)", { 'person_id': None, 'data': 'some data' }), CompiledSQL( "INSERT INTO person (favorite_ball_id, data) " "VALUES (:favorite_ball_id, :data)", lambda ctx: { 'favorite_ball_id': b.id, 'data': 'some data' }), CompiledSQL( "UPDATE ball SET person_id=:person_id " "WHERE ball.id = :ball_id", lambda ctx: [{ 'person_id': p.id, 'ball_id': b.id }, { 'person_id': p.id, 'ball_id': b2.id }, { 'person_id': p.id, 'ball_id': b3.id }, { 'person_id': p.id, 'ball_id': b4.id }]), ) sess.delete(p) self.assert_sql_execution( testing.db, sess.flush, CompiledSQL( "UPDATE ball SET person_id=:person_id " "WHERE ball.id = :ball_id", lambda ctx: [{ 'person_id': None, 'ball_id': b.id }, { 'person_id': None, 'ball_id': b2.id }, { 'person_id': None, 'ball_id': b3.id }, { 'person_id': None, 'ball_id': b4.id }]), CompiledSQL("DELETE FROM person WHERE person.id = :id", lambda ctx: [{ 'id': p.id }]), CompiledSQL( "DELETE FROM ball WHERE ball.id = :id", lambda ctx: [ { 'id': b.id }, { 'id': b2.id }, { 'id': b3.id }, { 'id': b4.id } ]))
def test_bidirectional_multilevel_save(self): Node, nodes = self.classes.Node, self.tables.nodes mapper(Node, nodes, properties={ 'children': relationship(Node, backref=backref('parent', remote_side=nodes.c.id)) }) sess = create_session() n1 = Node(data='n1') n1.children.append(Node(data='n11')) n12 = Node(data='n12') n1.children.append(n12) n1.children.append(Node(data='n13')) n1.children[1].children.append(Node(data='n121')) n1.children[1].children.append(Node(data='n122')) n1.children[1].children.append(Node(data='n123')) sess.add(n1) self.assert_sql_execution( testing.db, sess.flush, CompiledSQL( "INSERT INTO nodes (parent_id, data) VALUES " "(:parent_id, :data)", lambda ctx: { 'parent_id': None, 'data': 'n1' }), CompiledSQL( "INSERT INTO nodes (parent_id, data) VALUES " "(:parent_id, :data)", lambda ctx: { 'parent_id': n1.id, 'data': 'n11' }), CompiledSQL( "INSERT INTO nodes (parent_id, data) VALUES " "(:parent_id, :data)", lambda ctx: { 'parent_id': n1.id, 'data': 'n12' }), CompiledSQL( "INSERT INTO nodes (parent_id, data) VALUES " "(:parent_id, :data)", lambda ctx: { 'parent_id': n1.id, 'data': 'n13' }), CompiledSQL( "INSERT INTO nodes (parent_id, data) VALUES " "(:parent_id, :data)", lambda ctx: { 'parent_id': n12.id, 'data': 'n121' }), CompiledSQL( "INSERT INTO nodes (parent_id, data) VALUES " "(:parent_id, :data)", lambda ctx: { 'parent_id': n12.id, 'data': 'n122' }), CompiledSQL( "INSERT INTO nodes (parent_id, data) VALUES " "(:parent_id, :data)", lambda ctx: { 'parent_id': n12.id, 'data': 'n123' }), )
def test_many_to_one_delete_unloaded(self): users, Address, addresses, User = (self.tables.users, self.classes.Address, self.tables.addresses, self.classes.User) mapper(User, users) mapper(Address, addresses, properties={'parent': relationship(User)}) parent = User(name='p1') c1, c2 = Address(email_address='c1', parent=parent), \ Address(email_address='c2', parent=parent) session = Session() session.add_all([c1, c2]) session.add(parent) session.flush() pid = parent.id c1id = c1.id c2id = c2.id session.expire(parent) session.expire(c1) session.expire(c2) session.delete(c1) session.delete(c2) session.delete(parent) # testing that relationships # are loaded even if all ids/references are # expired self.assert_sql_execution( testing.db, session.flush, AllOf( # [ticket:2002] - ensure the m2os are loaded. # the selects here are in fact unexpiring # each row - the m2o comes from the identity map. # the User row might be handled before or the addresses # are loaded so need to use AllOf CompiledSQL( "SELECT addresses.id AS addresses_id, addresses.user_id AS " "addresses_user_id, addresses.email_address AS " "addresses_email_address FROM addresses WHERE addresses.id = " ":param_1", lambda ctx: {'param_1': c1id}), CompiledSQL( "SELECT addresses.id AS addresses_id, addresses.user_id AS " "addresses_user_id, addresses.email_address AS " "addresses_email_address FROM addresses WHERE addresses.id = " ":param_1", lambda ctx: {'param_1': c2id}), CompiledSQL( "SELECT users.id AS users_id, users.name AS users_name " "FROM users WHERE users.id = :param_1", lambda ctx: {'param_1': pid}), CompiledSQL("DELETE FROM addresses WHERE addresses.id = :id", lambda ctx: [{ 'id': c1id }, { 'id': c2id }]), CompiledSQL("DELETE FROM users WHERE users.id = :id", lambda ctx: {'id': pid}), ), )
def test_delete_unloaded_m2o(self): Node, nodes = self.classes.Node, self.tables.nodes mapper( Node, nodes, properties={'parent': relationship(Node, remote_side=nodes.c.id)}) parent = Node() c1, c2 = Node(parent=parent), Node(parent=parent) session = Session() session.add_all([c1, c2]) session.add(parent) session.flush() pid = parent.id c1id = c1.id c2id = c2.id session.expire(parent) session.expire(c1) session.expire(c2) session.delete(c1) session.delete(c2) session.delete(parent) # testing that relationships # are loaded even if all ids/references are # expired self.assert_sql_execution( testing.db, session.flush, AllOf( # ensure all three m2os are loaded. # the selects here are in fact unexpiring # each row - the m2o comes from the identity map. CompiledSQL( "SELECT nodes.id AS nodes_id, nodes.parent_id AS " "nodes_parent_id, " "nodes.data AS nodes_data FROM nodes " "WHERE nodes.id = :param_1", lambda ctx: {'param_1': pid}), CompiledSQL( "SELECT nodes.id AS nodes_id, nodes.parent_id AS " "nodes_parent_id, " "nodes.data AS nodes_data FROM nodes " "WHERE nodes.id = :param_1", lambda ctx: {'param_1': c1id}), CompiledSQL( "SELECT nodes.id AS nodes_id, nodes.parent_id AS " "nodes_parent_id, " "nodes.data AS nodes_data FROM nodes " "WHERE nodes.id = :param_1", lambda ctx: {'param_1': c2id}), CompiledSQL("DELETE FROM nodes WHERE nodes.id = :id", lambda ctx: [{ 'id': c1id }, { 'id': c2id }]), CompiledSQL("DELETE FROM nodes WHERE nodes.id = :id", lambda ctx: {'id': pid}), ), )
def test_one(self): child1, child2, child3, Parent, parent, Child1, Child2, Child3 = ( self.tables.child1, self.tables.child2, self.tables.child3, self.classes.Parent, self.tables.parent, self.classes.Child1, self.classes.Child2, self.classes.Child3) mapper(Parent, parent, properties={ 'c1s': relationship(Child1, primaryjoin=child1.c.parent_id == parent.c.id), 'c2s': relationship(Child2, primaryjoin=child2.c.parent_id == parent.c.id), 'c3s': relationship(Child3, primaryjoin=child3.c.parent_id == parent.c.id), 'c1': relationship(Child1, primaryjoin=child1.c.id == parent.c.c1_id, post_update=True), 'c2': relationship(Child2, primaryjoin=child2.c.id == parent.c.c2_id, post_update=True), 'c3': relationship(Child3, primaryjoin=child3.c.id == parent.c.c3_id, post_update=True), }) mapper(Child1, child1) mapper(Child2, child2) mapper(Child3, child3) sess = create_session() p1 = Parent('p1') c11, c12, c13 = Child1('c1'), Child1('c2'), Child1('c3') c21, c22, c23 = Child2('c1'), Child2('c2'), Child2('c3') c31, c32, c33 = Child3('c1'), Child3('c2'), Child3('c3') p1.c1s = [c11, c12, c13] p1.c2s = [c21, c22, c23] p1.c3s = [c31, c32, c33] sess.add(p1) sess.flush() p1.c1 = c12 p1.c2 = c23 p1.c3 = c31 self.assert_sql_execution( testing.db, sess.flush, CompiledSQL( "UPDATE parent SET c1_id=:c1_id, c2_id=:c2_id, " "c3_id=:c3_id WHERE parent.id = :parent_id", lambda ctx: { 'c2_id': c23.id, 'parent_id': p1.id, 'c1_id': c12.id, 'c3_id': c31.id })) p1.c1 = p1.c2 = p1.c3 = None self.assert_sql_execution( testing.db, sess.flush, CompiledSQL( "UPDATE parent SET c1_id=:c1_id, c2_id=:c2_id, " "c3_id=:c3_id WHERE parent.id = :parent_id", lambda ctx: { 'c2_id': None, 'parent_id': p1.id, 'c1_id': None, 'c3_id': None }))