from sqlalchemy.testing import assert_raises_message from sqlalchemy import MetaData, Integer, ForeignKey from sqlalchemy.testing.schema import Table from sqlalchemy.testing.schema import Column from sqlalchemy.orm import mapper, create_session import sqlalchemy as sa from sqlalchemy import testing from sqlalchemy.testing import fixtures, eq_, engines, is_ from sqlalchemy.orm import relationship, Session, backref, sessionmaker from test.orm import _fixtures from sqlalchemy.testing.mock import Mock class BindIntegrationTest(_fixtures.FixtureTest): run_inserts = None def test_mapped_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")}) sess = Session(binds={User: self.metadata.bind, Address: self.metadata.bind}) u1 = User(id=1, name='ed') sess.add(u1) eq_(sess.query(User).filter(User.id == 1).all(), [User(id=1, name='ed')]) # test expression binding 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_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_bind_from_metadata(self): users, User = self.tables.users, self.classes.User mapper(User, users) session = create_session() session.execute(users.insert(), dict(name='Johnny')) assert len(session.query(User).filter_by(name='Johnny').all()) == 1 session.execute(users.delete()) assert len(session.query(User).filter_by(name='Johnny').all()) == 0 session.close() def test_bind_arguments(self): users, Address, addresses, User = (self.tables.users, self.classes.Address, self.tables.addresses, self.classes.User) mapper(User, users) mapper(Address, addresses) e1 = engines.testing_engine() e2 = engines.testing_engine() e3 = engines.testing_engine() sess = Session(e3) sess.bind_mapper(User, e1) sess.bind_mapper(Address, e2) assert sess.connection().engine is e3 assert sess.connection(bind=e1).engine is e1 assert sess.connection(mapper=Address, bind=e1).engine is e1 assert sess.connection(mapper=Address).engine is e2 assert sess.connection(clause=addresses.select()).engine is e2 assert sess.connection(mapper=User, clause=addresses.select()).engine is e1 assert sess.connection(mapper=User, clause=addresses.select(), bind=e2).engine is e2 sess.close() def test_bind_arg(self): sess = Session() assert_raises_message( sa.exc.ArgumentError, "Not an acceptable bind target: foobar", sess.bind_mapper, "foobar", testing.db ) mapper(self.classes.User, self.tables.users) u_object = self.classes.User() assert_raises_message( sa.exc.ArgumentError, "Not an acceptable bind target: User()", sess.bind_mapper, u_object, testing.db ) @engines.close_open_connections def test_bound_connection(self): users, User = self.tables.users, self.classes.User mapper(User, users) c = testing.db.connect() sess = create_session(bind=c) sess.begin() transaction = sess.transaction u = User(name='u1') sess.add(u) sess.flush() assert transaction._connection_for_bind(testing.db, None) \ is transaction._connection_for_bind(c, None) is c assert_raises_message(sa.exc.InvalidRequestError, 'Session already has a Connection ' 'associated', transaction._connection_for_bind, testing.db.connect(), None) transaction.rollback() assert len(sess.query(User).all()) == 0 sess.close() def test_bound_connection_transactional(self): User, users = self.classes.User, self.tables.users mapper(User, users) c = testing.db.connect() sess = create_session(bind=c, autocommit=False) u = User(name='u1') sess.add(u) sess.flush() sess.close() assert not c.in_transaction() assert c.scalar("select count(1) from users") == 0 sess = create_session(bind=c, autocommit=False) u = User(name='u2') sess.add(u) sess.flush() sess.commit() assert not c.in_transaction() assert c.scalar("select count(1) from users") == 1 c.execute("delete from users") assert c.scalar("select count(1) from users") == 0 c = testing.db.connect() trans = c.begin() sess = create_session(bind=c, autocommit=True) u = User(name='u3') sess.add(u) sess.flush() assert c.in_transaction() trans.commit() assert not c.in_transaction() assert c.scalar("select count(1) from users") == 1 class SessionBindTest(fixtures.MappedTest): @classmethod def define_tables(cls, metadata): Table('test_table', metadata, Column('id', Integer, primary_key=True, test_needs_autoincrement=True), Column('data', Integer)) @classmethod def setup_classes(cls): class Foo(cls.Basic): pass @classmethod def setup_mappers(cls): test_table, Foo = cls.tables.test_table, cls.classes.Foo meta = MetaData() test_table.tometadata(meta) assert meta.tables['test_table'].bind is None mapper(Foo, meta.tables['test_table']) def test_session_bind(self): Foo = self.classes.Foo engine = self.metadata.bind for bind in (engine, engine.connect()): try: sess = create_session(bind=bind) assert sess.bind is bind f = Foo() sess.add(f) sess.flush() assert sess.query(Foo).get(f.id) is f finally: if hasattr(bind, 'close'): bind.close() def test_session_unbound(self): Foo = self.classes.Foo sess = create_session() sess.add(Foo()) assert_raises_message( sa.exc.UnboundExecutionError, ('Could not locate a bind configured on Mapper|Foo|test_table ' 'or this Session'), sess.flush) class GetBindTest(fixtures.MappedTest): @classmethod def define_tables(cls, metadata): Table( 'base_table', metadata, Column('id', Integer, primary_key=True) ) Table( 'w_mixin_table', metadata, Column('id', Integer, primary_key=True) ) Table( 'joined_sub_table', metadata, Column('id', ForeignKey('base_table.id'), primary_key=True) ) Table( 'concrete_sub_table', metadata, Column('id', Integer, primary_key=True) ) @classmethod def setup_classes(cls): class MixinOne(cls.Basic): pass class BaseClass(cls.Basic): pass class ClassWMixin(MixinOne, cls.Basic): pass class JoinedSubClass(BaseClass): pass class ConcreteSubClass(BaseClass): pass @classmethod def setup_mappers(cls): mapper(cls.classes.ClassWMixin, cls.tables.w_mixin_table) mapper(cls.classes.BaseClass, cls.tables.base_table) mapper( cls.classes.JoinedSubClass, cls.tables.joined_sub_table, inherits=cls.classes.BaseClass) mapper( cls.classes.ConcreteSubClass, cls.tables.concrete_sub_table, inherits=cls.classes.BaseClass, concrete=True) def _fixture(self, binds): return Session(binds=binds) def test_fallback_table_metadata(self): session = self._fixture({}) is_( session.get_bind(self.classes.BaseClass), testing.db ) def test_bind_base_table_base_class(self): base_class_bind = Mock() session = self._fixture({ self.tables.base_table: base_class_bind }) is_( session.get_bind(self.classes.BaseClass), base_class_bind ) def test_bind_base_table_joined_sub_class(self): base_class_bind = Mock() session = self._fixture({ self.tables.base_table: base_class_bind }) is_( session.get_bind(self.classes.BaseClass), base_class_bind ) is_( session.get_bind(self.classes.JoinedSubClass), base_class_bind ) def test_bind_joined_sub_table_joined_sub_class(self): base_class_bind = Mock(name='base') joined_class_bind = Mock(name='joined') session = self._fixture({ self.tables.base_table: base_class_bind, self.tables.joined_sub_table: joined_class_bind }) is_( session.get_bind(self.classes.BaseClass), base_class_bind ) # joined table inheritance has to query based on the base # table, so this is what we expect is_( session.get_bind(self.classes.JoinedSubClass), base_class_bind ) def test_bind_base_table_concrete_sub_class(self): base_class_bind = Mock() session = self._fixture({ self.tables.base_table: base_class_bind }) is_( session.get_bind(self.classes.ConcreteSubClass), testing.db ) def test_bind_sub_table_concrete_sub_class(self): base_class_bind = Mock(name='base') concrete_sub_bind = Mock(name='concrete') session = self._fixture({ self.tables.base_table: base_class_bind, self.tables.concrete_sub_table: concrete_sub_bind }) is_( session.get_bind(self.classes.BaseClass), base_class_bind ) is_( session.get_bind(self.classes.ConcreteSubClass), concrete_sub_bind ) def test_bind_base_class_base_class(self): base_class_bind = Mock() session = self._fixture({ self.classes.BaseClass: base_class_bind }) is_( session.get_bind(self.classes.BaseClass), base_class_bind ) def test_bind_mixin_class_simple_class(self): base_class_bind = Mock() session = self._fixture({ self.classes.MixinOne: base_class_bind }) is_( session.get_bind(self.classes.ClassWMixin), base_class_bind ) def test_bind_base_class_joined_sub_class(self): base_class_bind = Mock() session = self._fixture({ self.classes.BaseClass: base_class_bind }) is_( session.get_bind(self.classes.JoinedSubClass), base_class_bind ) def test_bind_joined_sub_class_joined_sub_class(self): base_class_bind = Mock(name='base') joined_class_bind = Mock(name='joined') session = self._fixture({ self.classes.BaseClass: base_class_bind, self.classes.JoinedSubClass: joined_class_bind }) is_( session.get_bind(self.classes.BaseClass), base_class_bind ) is_( session.get_bind(self.classes.JoinedSubClass), joined_class_bind ) def test_bind_base_class_concrete_sub_class(self): base_class_bind = Mock() session = self._fixture({ self.classes.BaseClass: base_class_bind }) is_( session.get_bind(self.classes.ConcreteSubClass), base_class_bind ) def test_bind_sub_class_concrete_sub_class(self): base_class_bind = Mock(name='base') concrete_sub_bind = Mock(name='concrete') session = self._fixture({ self.classes.BaseClass: base_class_bind, self.classes.ConcreteSubClass: concrete_sub_bind }) is_( session.get_bind(self.classes.BaseClass), base_class_bind ) is_( session.get_bind(self.classes.ConcreteSubClass), concrete_sub_bind )