from unittest.mock import Mock
import sqlalchemy as sa
-from sqlalchemy import and_
from sqlalchemy import cast
-from sqlalchemy import column
from sqlalchemy import desc
from sqlalchemy import event
from sqlalchemy import exc as sa_exc
from sqlalchemy import ForeignKey
from sqlalchemy import func
from sqlalchemy import Integer
-from sqlalchemy import join
-from sqlalchemy import LABEL_STYLE_TABLENAME_PLUS_COL
-from sqlalchemy import lateral
from sqlalchemy import literal_column
from sqlalchemy import MetaData
-from sqlalchemy import or_
from sqlalchemy import select
from sqlalchemy import String
-from sqlalchemy import table
from sqlalchemy import testing
from sqlalchemy import text
from sqlalchemy import true
from sqlalchemy.orm import configure_mappers
from sqlalchemy.orm import contains_alias
from sqlalchemy.orm import contains_eager
-from sqlalchemy.orm import declarative_base
from sqlalchemy.orm import defaultload
from sqlalchemy.orm import defer
from sqlalchemy.orm import deferred
from sqlalchemy.orm import subqueryload
from sqlalchemy.orm import synonym
from sqlalchemy.orm import undefer
-from sqlalchemy.orm import with_loader_criteria
from sqlalchemy.orm import with_parent
from sqlalchemy.orm import with_polymorphic
from sqlalchemy.orm.collections import attribute_mapped_collection
from sqlalchemy.testing import is_
from sqlalchemy.testing import is_true
from sqlalchemy.testing import mock
-from sqlalchemy.testing.assertsql import CompiledSQL
-from sqlalchemy.testing.fixtures import ComparableEntity
from sqlalchemy.testing.fixtures import fixture_session
from sqlalchemy.testing.schema import Column
from sqlalchemy.testing.schema import Table
-from sqlalchemy.testing.util import resolve_lambda
from . import _fixtures
from .inheritance import _poly_fixtures
from .inheritance._poly_fixtures import Manager
query_get_dep = r"The Query.get\(\) method is considered legacy as of the 1.x"
-sef_dep = (
- r"The Query.select_entity_from\(\) method is considered "
- "legacy as of the 1.x"
-)
-
with_polymorphic_dep = (
r"The Query.with_polymorphic\(\) method is considered legacy as of "
r"the 1.x series of SQLAlchemy and will be removed in 2.0"
# this doesn't evaluate anything because it's a net-negative
eq_(q[-2:-5], [])
+ def test_deprecated_select_coercion_join_target(self):
+ User = self.classes.User
+ addresses = self.tables.addresses
+
+ s = addresses.select()
+ sess = fixture_session()
+ with testing.expect_deprecated(
+ "Implicit coercion of SELECT and " "textual SELECT constructs"
+ ):
+ self.assert_compile(
+ sess.query(User).join(s, User.addresses),
+ "SELECT users.id AS users_id, users.name AS users_name "
+ "FROM users JOIN (SELECT addresses.id AS id, "
+ "addresses.user_id AS user_id, addresses.email_address "
+ "AS email_address FROM addresses) AS anon_1 "
+ "ON users.id = anon_1.user_id",
+ )
+
def test_deprecated_negative_slices_compile(self):
User = self.classes.User
],
)
- def test_aliased(self):
- User = self.classes.User
-
- s = fixture_session()
-
- with testing.expect_deprecated_20(join_aliased_dep):
- q1 = s.query(User).join(User.addresses, aliased=True)
-
- self.assert_compile(
- q1,
- "SELECT users.id AS users_id, users.name AS users_name "
- "FROM users JOIN addresses AS addresses_1 "
- "ON users.id = addresses_1.user_id",
- )
-
- def test_from_joinpoint(self):
- User = self.classes.User
- Address = self.classes.Address
-
- s = fixture_session()
-
- u1 = aliased(User)
-
- with testing.expect_deprecated_20(join_aliased_dep):
- q1 = (
- s.query(u1)
- .join(u1.addresses)
- .join(Address.user, from_joinpoint=True)
- )
-
- self.assert_compile(
- q1,
- "SELECT users_1.id AS users_1_id, users_1.name AS users_1_name "
- "FROM users AS users_1 JOIN addresses ON users_1.id = "
- "addresses.user_id JOIN users ON users.id = addresses.user_id",
- )
-
- def test_multiple_joins(self):
- User = self.classes.User
- Address = self.classes.Address
-
- s = fixture_session()
-
- u1 = aliased(User)
-
- with testing.expect_deprecated_20(join_chain_dep):
- q1 = s.query(u1).join(u1.addresses, Address.user)
-
- self.assert_compile(
- q1,
- "SELECT users_1.id AS users_1_id, users_1.name AS users_1_name "
- "FROM users AS users_1 JOIN addresses ON users_1.id = "
- "addresses.user_id JOIN users ON users.id = addresses.user_id",
- )
-
- def test_multiple_entities(self):
- User = self.classes.User
- Address = self.classes.Address
- Dingaling = self.classes.Dingaling
-
- s = fixture_session()
-
- u1 = aliased(User)
-
- with testing.expect_deprecated_20(join_chain_dep):
- q1 = s.query(u1).join(Address, User)
-
- self.assert_compile(
- q1,
- "SELECT users_1.id AS users_1_id, users_1.name AS users_1_name "
- "FROM users AS users_1 JOIN addresses ON users_1.id = "
- "addresses.user_id JOIN users ON users.id = addresses.user_id",
- )
-
- with testing.expect_deprecated_20(join_chain_dep):
- q1 = s.query(u1).join(Address, User, Dingaling)
-
- self.assert_compile(
- q1,
- "SELECT users_1.id AS users_1_id, users_1.name AS users_1_name "
- "FROM users AS users_1 JOIN addresses "
- "ON users_1.id = addresses.user_id "
- "JOIN users ON users.id = addresses.user_id "
- "JOIN dingalings ON addresses.id = dingalings.address_id",
- )
-
def test_invalid_column(self):
User = self.classes.User
"SELECT users.id AS users_id, users.name AS users_name FROM users",
)
- def test_via_textasfrom_select_from(self):
- User = self.classes.User
- s = fixture_session()
-
- with self._expect_implicit_subquery():
- eq_(
- s.query(User)
- .select_entity_from(
- text("select * from users").columns(User.id, User.name)
- )
- .order_by(User.id)
- .all(),
- [User(id=7), User(id=8), User(id=9), User(id=10)],
- )
-
def test_text_as_column(self):
User = self.classes.User
):
s.query(User).as_scalar()
- def test_select_entity_from_crit(self):
- User, users = self.classes.User, self.tables.users
-
- sel = users.select()
- sess = fixture_session()
-
- with self._expect_implicit_subquery():
- eq_(
- sess.query(User)
- .select_entity_from(sel)
- .filter(User.id.in_([7, 8]))
- .all(),
- [User(name="jack", id=7), User(name="ed", id=8)],
- )
-
- def test_select_entity_from_select(self):
- User, users = self.classes.User, self.tables.users
-
- sess = fixture_session()
- with self._expect_implicit_subquery():
- self.assert_compile(
- sess.query(User.name).select_entity_from(
- users.select().where(users.c.id > 5)
- ),
- "SELECT anon_1.name AS anon_1_name FROM "
- "(SELECT users.id AS id, users.name AS name FROM users "
- "WHERE users.id > :id_1) AS anon_1",
- )
-
- def test_select_entity_from_q_statement(self):
- User = self.classes.User
-
- sess = fixture_session()
-
- q = sess.query(User)
- with self._expect_implicit_subquery():
- q = sess.query(User).select_entity_from(q.statement)
- self.assert_compile(
- q.filter(User.name == "ed"),
- "SELECT anon_1.id AS anon_1_id, anon_1.name AS anon_1_name "
- "FROM (SELECT users.id AS id, users.name AS name FROM "
- "users) AS anon_1 WHERE anon_1.name = :name_1",
- )
-
def test_select_from_q_statement_no_aliasing(self):
User = self.classes.User
sess = fixture_session()
"users) AS anon_1 WHERE users.name = :name_1",
)
- def test_from_alias_three(self):
- User, addresses, users = (
- self.classes.User,
- self.tables.addresses,
- self.tables.users,
- )
-
- query = (
- users.select()
- .where(users.c.id == 7)
- .union(users.select().where(users.c.id > 7))
- .alias("ulist")
- .outerjoin(addresses)
- .select()
- .order_by(text("ulist.id"), addresses.c.id)
- )
- sess = fixture_session()
-
- # better way. use select_entity_from()
- def go():
- with self._expect_implicit_subquery():
- result = (
- sess.query(User)
- .select_entity_from(query)
- .options(contains_eager(User.addresses))
- .all()
- )
- assert self.static.user_address_result == result
-
- self.assert_sql_count(testing.db, go, 1)
-
- def test_from_alias_four(self):
- User, addresses, users = (
- self.classes.User,
- self.tables.addresses,
- self.tables.users,
- )
-
- sess = fixture_session()
-
- # same thing, but alias addresses, so that the adapter
- # generated by select_entity_from() is wrapped within
- # the adapter created by contains_eager()
- adalias = addresses.alias()
- query = (
- users.select()
- .where(users.c.id == 7)
- .union(users.select().where(users.c.id > 7))
- .alias("ulist")
- .outerjoin(adalias)
- .select()
- .order_by(text("ulist.id"), adalias.c.id)
- )
-
- def go():
- with self._expect_implicit_subquery():
- result = (
- sess.query(User)
- .select_entity_from(query)
- .options(contains_eager(User.addresses, alias=adalias))
- .all()
- )
- assert self.static.user_address_result == result
-
- self.assert_sql_count(testing.db, go, 1)
-
- def test_select(self):
- users = self.tables.users
-
- sess = fixture_session()
-
- with self._expect_implicit_subquery():
- stmt = sess.query(users).select_entity_from(users.select())
-
- with testing.expect_deprecated_20(r"The Query.with_labels\(\)"):
- stmt = stmt.apply_labels().statement
- self.assert_compile(
- stmt,
- "SELECT users.id AS users_id, users.name AS users_name "
- "FROM users, "
- "(SELECT users.id AS id, users.name AS name FROM users) "
- "AS anon_1",
- )
-
def test_apply_labels(self):
User = self.classes.User
"SELECT users.id AS users_id, users.name AS users_name FROM users",
)
- def test_join(self):
- users, Address, User = (
- self.tables.users,
- self.classes.Address,
- self.classes.User,
- )
-
- # mapper(User, users, properties={"addresses": relationship(Address)})
- # mapper(Address, addresses)
- sel = users.select().where(users.c.id.in_([7, 8]))
- sess = fixture_session()
+class LazyLoadOptSpecificityTest(fixtures.DeclarativeMappedTest):
+ """test for [ticket:3963]"""
- with self._expect_implicit_subquery():
- result = (
- sess.query(User)
- .select_entity_from(sel)
- .join(User.addresses)
- .add_entity(Address)
- .order_by(User.id)
- .order_by(Address.id)
- .all()
- )
+ @classmethod
+ def setup_classes(cls):
+ Base = cls.DeclarativeBasic
- eq_(
- result,
- [
- (
- User(name="jack", id=7),
- Address(user_id=7, email_address="jack@bean.com", id=1),
- ),
- (
- User(name="ed", id=8),
- Address(user_id=8, email_address="ed@wood.com", id=2),
- ),
- (
- User(name="ed", id=8),
- Address(user_id=8, email_address="ed@bettyboop.com", id=3),
- ),
- (
- User(name="ed", id=8),
- Address(user_id=8, email_address="ed@lala.com", id=4),
- ),
- ],
- )
+ class A(Base):
+ __tablename__ = "a"
+ id = Column(Integer, primary_key=True)
+ bs = relationship("B")
- adalias = aliased(Address)
- with self._expect_implicit_subquery():
- result = (
- sess.query(User)
- .select_entity_from(sel)
- .join(adalias, User.addresses)
- .add_entity(adalias)
- .order_by(User.id)
- .order_by(adalias.id)
- .all()
- )
- eq_(
- result,
- [
- (
- User(name="jack", id=7),
- Address(user_id=7, email_address="jack@bean.com", id=1),
- ),
- (
- User(name="ed", id=8),
- Address(user_id=8, email_address="ed@wood.com", id=2),
- ),
- (
- User(name="ed", id=8),
- Address(user_id=8, email_address="ed@bettyboop.com", id=3),
- ),
- (
- User(name="ed", id=8),
- Address(user_id=8, email_address="ed@lala.com", id=4),
- ),
- ],
- )
+ class B(Base):
+ __tablename__ = "b"
+ id = Column(Integer, primary_key=True)
+ a_id = Column(ForeignKey("a.id"))
+ cs = relationship("C")
- def test_more_joins(self):
- (users, Keyword, User) = (
- self.tables.users,
- self.classes.Keyword,
- self.classes.User,
- )
- Order, Item = self.classes("Order", "Item")
+ class C(Base):
+ __tablename__ = "c"
+ id = Column(Integer, primary_key=True)
+ b_id = Column(ForeignKey("b.id"))
- sess = fixture_session()
- sel = users.select().where(users.c.id.in_([7, 8]))
+ @classmethod
+ def insert_data(cls, connection):
+ A, B, C = cls.classes("A", "B", "C")
+ s = Session(connection)
+ s.add(A(id=1, bs=[B(cs=[C()])]))
+ s.add(A(id=2))
+ s.commit()
- with self._expect_implicit_subquery():
- eq_(
- sess.query(User)
- .select_entity_from(sel)
- .join(User.orders)
- .join(Order.items)
- .join(Item.keywords)
- .filter(Keyword.name.in_(["red", "big", "round"]))
- .all(),
- [User(name="jack", id=7)],
- )
+ def _run_tests(self, query, expected):
+ def go():
+ for a, _ in query:
+ for b in a.bs:
+ b.cs
- with self._expect_implicit_subquery():
- eq_(
- sess.query(User)
- .select_entity_from(sel)
- .join(User.orders, aliased=True)
- .join(Order.items, aliased=True)
- .join(Item.keywords, aliased=True)
- .filter(Keyword.name.in_(["red", "big", "round"]))
- .all(),
- [User(name="jack", id=7)],
- )
+ self.assert_sql_count(testing.db, go, expected)
- def test_join_no_order_by(self):
- User, users = self.classes.User, self.tables.users
- sel = users.select().where(users.c.id.in_([7, 8]))
+class DynamicTest(_DynamicFixture, _fixtures.FixtureTest):
+ def test_negative_slice_access_raises(self):
+ User, Address = self._user_address_fixture()
sess = fixture_session()
+ u1 = sess.get(User, 8)
- with self._expect_implicit_subquery():
- eq_(
- sess.query(User).select_entity_from(sel).all(),
- [User(name="jack", id=7), User(name="ed", id=8)],
- )
+ with testing.expect_deprecated_20(
+ "Support for negative indexes for SQL index / slice"
+ ):
+ eq_(u1.addresses[-1], Address(id=4))
- def test_replace_with_eager(self):
- users, Address, User = (
- self.tables.users,
- self.classes.Address,
- self.classes.User,
- )
+ with testing.expect_deprecated_20(
+ "Support for negative indexes for SQL index / slice"
+ ):
+ eq_(u1.addresses[-5:-2], [Address(id=2)])
- sel = users.select().where(users.c.id.in_([7, 8]))
- sess = fixture_session()
+ with testing.expect_deprecated_20(
+ "Support for negative indexes for SQL index / slice"
+ ):
+ eq_(u1.addresses[-2], Address(id=3))
- def go():
- with self._expect_implicit_subquery():
- eq_(
- sess.query(User)
- .options(joinedload(User.addresses))
- .select_entity_from(sel)
- .order_by(User.id)
- .all(),
- [
- User(id=7, addresses=[Address(id=1)]),
- User(
- id=8,
- addresses=[
- Address(id=2),
- Address(id=3),
- Address(id=4),
- ],
- ),
- ],
- )
+ with testing.expect_deprecated_20(
+ "Support for negative indexes for SQL index / slice"
+ ):
+ eq_(u1.addresses[:-2], [Address(id=2)])
- self.assert_sql_count(testing.db, go, 1)
- sess.expunge_all()
- def go():
- with self._expect_implicit_subquery():
+class SessionTest(fixtures.RemovesEvents, _LocalFixture):
+ def test_transaction_attr(self):
+ s1 = Session(testing.db)
+
+ with testing.expect_deprecated_20(
+ "The Session.transaction attribute is considered legacy as "
+ "of the 1.x series"
+ ):
+ s1.transaction
+
+ def test_textual_execute(self, connection):
+ """test that Session.execute() converts to text()"""
+
+ users = self.tables.users
+
+ with Session(bind=connection) as sess:
+ sess.execute(users.insert(), dict(id=7, name="jack"))
+
+ with testing.expect_deprecated_20(
+ "Using plain strings to indicate SQL statements "
+ "without using the text"
+ ):
+ # use :bindparam style
eq_(
- sess.query(User)
- .options(joinedload(User.addresses))
- .select_entity_from(sel)
- .filter(User.id == 8)
- .order_by(User.id)
- .all(),
- [
- User(
- id=8,
- addresses=[
- Address(id=2),
- Address(id=3),
- Address(id=4),
- ],
- )
- ],
+ sess.execute(
+ "select * from users where id=:id", {"id": 7}
+ ).fetchall(),
+ [(7, "jack")],
)
- self.assert_sql_count(testing.db, go, 1)
- sess.expunge_all()
-
- def go():
- with self._expect_implicit_subquery():
+ with testing.expect_deprecated_20(
+ "Using plain strings to indicate SQL statements "
+ "without using the text"
+ ):
+ # use :bindparam style
eq_(
- sess.query(User)
- .options(joinedload(User.addresses))
- .select_entity_from(sel)
- .order_by(User.id)[1],
- User(
- id=8,
- addresses=[
- Address(id=2),
- Address(id=3),
- Address(id=4),
- ],
+ sess.scalar(
+ "select id from users where id=:id", {"id": 7}
),
+ 7,
)
- self.assert_sql_count(testing.db, go, 1)
-
- def test_onclause_conditional_adaption(self):
- Item, Order, orders, order_items, User = (
- self.classes.Item,
- self.classes.Order,
- self.tables.orders,
- self.tables.order_items,
- self.classes.User,
- )
+ def test_session_str(self):
+ s1 = Session(testing.db)
+ str(s1)
- sess = fixture_session()
+ @testing.combinations(
+ {"mapper": None},
+ {"clause": None},
+ {"bind_arguments": {"mapper": None}, "clause": None},
+ {"bind_arguments": {}, "clause": None},
+ )
+ def test_bind_kwarg_deprecated(self, kw):
+ s1 = Session(testing.db)
- oalias = orders.select()
+ for meth in s1.execute, s1.scalar:
+ m1 = mock.Mock(side_effect=s1.get_bind)
+ with mock.patch.object(s1, "get_bind", m1):
+ expr = text("select 1")
- with self._expect_implicit_subquery(), _aliased_join_warning():
- self.assert_compile(
- sess.query(User)
- .join(oalias, User.orders)
- .join(
- Item,
- and_(
- Order.id == order_items.c.order_id,
- order_items.c.item_id == Item.id,
- ),
- from_joinpoint=True,
- ),
- "SELECT users.id AS users_id, users.name AS users_name "
- "FROM users JOIN "
- "(SELECT orders.id AS id, orders.user_id AS user_id, "
- "orders.address_id AS address_id, orders.description "
- "AS description, orders.isopen AS isopen FROM orders) "
- "AS anon_1 ON users.id = anon_1.user_id JOIN items "
- "ON anon_1.id = order_items.order_id "
- "AND order_items.item_id = items.id",
- use_default_dialect=True,
- )
+ with testing.expect_deprecated_20(
+ r"Passing bind arguments to Session.execute\(\) as "
+ "keyword "
+ "arguments is deprecated and will be removed SQLAlchemy "
+ "2.0"
+ ):
+ meth(expr, **kw)
+ bind_arguments = kw.pop("bind_arguments", None)
+ if bind_arguments:
+ bind_arguments.update(kw)
-class SelfRefFromSelfTest(fixtures.MappedTest, AssertsCompiledSQL):
- run_setup_mappers = "once"
- run_inserts = "once"
- run_deletes = None
- __dialect__ = "default"
+ if "clause" not in kw:
+ bind_arguments["clause"] = expr
+ eq_(m1.mock_calls, [call(**bind_arguments)])
+ else:
+ if "clause" not in kw:
+ kw["clause"] = expr
+ eq_(m1.mock_calls, [call(**kw)])
- @classmethod
- def define_tables(cls, metadata):
- Table(
- "nodes",
- metadata,
- Column(
- "id", Integer, primary_key=True, test_needs_autoincrement=True
- ),
- Column("parent_id", Integer, ForeignKey("nodes.id")),
- Column("data", String(30)),
- )
- @classmethod
- def setup_classes(cls):
- class Node(cls.Comparable):
- def append(self, node):
- self.children.append(node)
+class DeprecatedInhTest(_poly_fixtures._Polymorphic):
+ def test_with_polymorphic(self):
+ Person = _poly_fixtures.Person
+ Engineer = _poly_fixtures.Engineer
- @classmethod
- def setup_mappers(cls):
- Node, nodes = cls.classes.Node, cls.tables.nodes
+ with DeprecatedQueryTest._expect_implicit_subquery():
+ p_poly = with_polymorphic(Person, [Engineer], select(Person))
- cls.mapper_registry.map_imperatively(
- Node,
- nodes,
- properties={
- "children": relationship(
- Node,
- lazy="select",
- join_depth=3,
- backref=backref("parent", remote_side=[nodes.c.id]),
- )
- },
+ is_true(
+ sa.inspect(p_poly).selectable.compare(select(Person).subquery())
)
- @classmethod
- def insert_data(cls, connection):
- Node = cls.classes.Node
-
- sess = Session(connection)
- n1 = Node(data="n1")
- n1.append(Node(data="n11"))
- n1.append(Node(data="n12"))
- n1.append(Node(data="n13"))
- n1.children[1].append(Node(data="n121"))
- n1.children[1].append(Node(data="n122"))
- n1.children[1].append(Node(data="n123"))
- sess.add(n1)
- sess.flush()
- sess.close()
-
- def test_from_self_inside_excludes_outside(self):
- """test the propagation of aliased() from inside to outside
- on a from_self()..
- """
- Node = self.classes.Node
+class DeprecatedMapperTest(_fixtures.FixtureTest, AssertsCompiledSQL):
+ __dialect__ = "default"
- sess = fixture_session()
+ def test_deferred_scalar_loader_name_change(self):
+ class Foo:
+ pass
- n1 = aliased(Node)
+ def myloader(*arg, **kw):
+ pass
- # n1 is not inside the from_self(), so all cols must be maintained
- # on the outside
- with self._from_self_deprecated():
- self.assert_compile(
- sess.query(Node)
- .filter(Node.data == "n122")
- .from_self(n1, Node.id),
- "SELECT nodes_1.id AS nodes_1_id, "
- "nodes_1.parent_id AS nodes_1_parent_id, "
- "nodes_1.data AS nodes_1_data, anon_1.nodes_id "
- "AS anon_1_nodes_id "
- "FROM nodes AS nodes_1, (SELECT nodes.id AS nodes_id, "
- "nodes.parent_id AS nodes_parent_id, "
- "nodes.data AS nodes_data FROM "
- "nodes WHERE nodes.data = :data_1) AS anon_1",
- use_default_dialect=True,
- )
+ instrumentation.register_class(Foo)
+ manager = instrumentation.manager_of_class(Foo)
- parent = aliased(Node)
- grandparent = aliased(Node)
- with self._from_self_deprecated():
- q = (
- sess.query(Node, parent, grandparent)
- .join(parent, Node.parent)
- .join(grandparent, parent.parent)
- .filter(Node.data == "n122")
- .filter(parent.data == "n12")
- .filter(grandparent.data == "n1")
- .from_self()
- .limit(1)
- )
+ with testing.expect_deprecated(
+ "The ClassManager.deferred_scalar_loader attribute is now named "
+ "expired_attribute_loader"
+ ):
+ manager.deferred_scalar_loader = myloader
- # parent, grandparent *are* inside the from_self(), so they
- # should get aliased to the outside.
- self.assert_compile(
- q,
- "SELECT anon_1.nodes_id AS anon_1_nodes_id, "
- "anon_1.nodes_parent_id AS anon_1_nodes_parent_id, "
- "anon_1.nodes_data AS anon_1_nodes_data, "
- "anon_1.nodes_1_id AS anon_1_nodes_1_id, "
- "anon_1.nodes_1_parent_id AS anon_1_nodes_1_parent_id, "
- "anon_1.nodes_1_data AS anon_1_nodes_1_data, "
- "anon_1.nodes_2_id AS anon_1_nodes_2_id, "
- "anon_1.nodes_2_parent_id AS anon_1_nodes_2_parent_id, "
- "anon_1.nodes_2_data AS anon_1_nodes_2_data "
- "FROM (SELECT nodes.id AS nodes_id, nodes.parent_id "
- "AS nodes_parent_id, nodes.data AS nodes_data, "
- "nodes_1.id AS nodes_1_id, "
- "nodes_1.parent_id AS nodes_1_parent_id, "
- "nodes_1.data AS nodes_1_data, nodes_2.id AS nodes_2_id, "
- "nodes_2.parent_id AS nodes_2_parent_id, nodes_2.data AS "
- "nodes_2_data FROM nodes JOIN nodes AS nodes_1 ON "
- "nodes_1.id = nodes.parent_id JOIN nodes AS nodes_2 "
- "ON nodes_2.id = nodes_1.parent_id "
- "WHERE nodes.data = :data_1 AND nodes_1.data = :data_2 AND "
- "nodes_2.data = :data_3) AS anon_1 LIMIT :param_1",
- {"param_1": 1},
- use_default_dialect=True,
- )
+ is_(manager.expired_attribute_loader, myloader)
- def test_multiple_explicit_entities_two(self):
- Node = self.classes.Node
+ with testing.expect_deprecated(
+ "The ClassManager.deferred_scalar_loader attribute is now named "
+ "expired_attribute_loader"
+ ):
+ is_(manager.deferred_scalar_loader, myloader)
- sess = fixture_session()
+ def test_polymorphic_union_w_select(self):
+ users, addresses = self.tables.users, self.tables.addresses
- parent = aliased(Node)
- grandparent = aliased(Node)
- with self._from_self_deprecated():
- eq_(
- sess.query(Node, parent, grandparent)
- .join(parent, Node.parent)
- .join(grandparent, parent.parent)
- .filter(Node.data == "n122")
- .filter(parent.data == "n12")
- .filter(grandparent.data == "n1")
- .from_self()
- .first(),
- (Node(data="n122"), Node(data="n12"), Node(data="n1")),
+ with DeprecatedQueryTest._expect_implicit_subquery():
+ dep = polymorphic_union(
+ {"u": users.select(), "a": addresses.select()},
+ "type",
+ "bcjoin",
)
- def test_multiple_explicit_entities_three(self):
- Node = self.classes.Node
-
- sess = fixture_session()
+ subq_version = polymorphic_union(
+ {
+ "u": users.select().subquery(),
+ "a": addresses.select().subquery(),
+ },
+ "type",
+ "bcjoin",
+ )
+ is_true(dep.compare(subq_version))
- parent = aliased(Node)
- grandparent = aliased(Node)
- # same, change order around
- with self._from_self_deprecated():
- eq_(
- sess.query(parent, grandparent, Node)
- .join(parent, Node.parent)
- .join(grandparent, parent.parent)
- .filter(Node.data == "n122")
- .filter(parent.data == "n12")
- .filter(grandparent.data == "n1")
- .from_self()
- .first(),
- (Node(data="n12"), Node(data="n1"), Node(data="n122")),
- )
+ def test_comparable_column(self):
+ users, User = self.tables.users, self.classes.User
- def test_multiple_explicit_entities_five(self):
- Node = self.classes.Node
+ class MyComparator(sa.orm.properties.ColumnProperty.Comparator):
+ __hash__ = None
- sess = fixture_session()
+ def __eq__(self, other):
+ # lower case comparison
+ return func.lower(self.__clause_element__()) == func.lower(
+ other
+ )
- parent = aliased(Node)
- grandparent = aliased(Node)
- with self._from_self_deprecated():
- eq_(
- sess.query(Node, parent, grandparent)
- .join(parent, Node.parent)
- .join(grandparent, parent.parent)
- .filter(Node.data == "n122")
- .filter(parent.data == "n12")
- .filter(grandparent.data == "n1")
- .from_self()
- .options(joinedload(Node.children))
- .first(),
- (Node(data="n122"), Node(data="n12"), Node(data="n1")),
- )
+ def intersects(self, other):
+ # non-standard comparator
+ return self.__clause_element__().op("&=")(other)
- def _from_self_deprecated(self):
- return testing.expect_deprecated_20(r"The Query.from_self\(\) method")
+ self.mapper_registry.map_imperatively(
+ User,
+ users,
+ properties={
+ "name": sa.orm.column_property(
+ users.c.name, comparator_factory=MyComparator
+ )
+ },
+ )
+ assert_raises_message(
+ AttributeError,
+ "Neither 'InstrumentedAttribute' object nor "
+ "'MyComparator' object associated with User.name has "
+ "an attribute 'nonexistent'",
+ getattr,
+ User.name,
+ "nonexistent",
+ )
-class SelfReferentialEagerTest(fixtures.MappedTest):
- @classmethod
- def define_tables(cls, metadata):
- Table(
- "nodes",
- metadata,
- Column(
- "id", Integer, primary_key=True, test_needs_autoincrement=True
+ eq_(
+ str(
+ (User.name == "ed").compile(
+ dialect=sa.engine.default.DefaultDialect()
+ )
),
- Column("parent_id", Integer, ForeignKey("nodes.id")),
- Column("data", String(30)),
+ "lower(users.name) = lower(:lower_1)",
+ )
+ eq_(
+ str(
+ (User.name.intersects("ed")).compile(
+ dialect=sa.engine.default.DefaultDialect()
+ )
+ ),
+ "users.name &= :name_1",
)
+ def test_add_property(self):
+ users = self.tables.users
-class LazyLoadOptSpecificityTest(fixtures.DeclarativeMappedTest):
- """test for [ticket:3963]"""
-
- @classmethod
- def setup_classes(cls):
- Base = cls.DeclarativeBasic
+ assert_col = []
- class A(Base):
- __tablename__ = "a"
- id = Column(Integer, primary_key=True)
- bs = relationship("B")
-
- class B(Base):
- __tablename__ = "b"
- id = Column(Integer, primary_key=True)
- a_id = Column(ForeignKey("a.id"))
- cs = relationship("C")
-
- class C(Base):
- __tablename__ = "c"
- id = Column(Integer, primary_key=True)
- b_id = Column(ForeignKey("b.id"))
+ class User(fixtures.ComparableEntity):
+ def _get_name(self):
+ assert_col.append(("get", self._name))
+ return self._name
- @classmethod
- def insert_data(cls, connection):
- A, B, C = cls.classes("A", "B", "C")
- s = Session(connection)
- s.add(A(id=1, bs=[B(cs=[C()])]))
- s.add(A(id=2))
- s.commit()
+ def _set_name(self, name):
+ assert_col.append(("set", name))
+ self._name = name
- def _run_tests(self, query, expected):
- def go():
- for a, _ in query:
- for b in a.bs:
- b.cs
+ name = property(_get_name, _set_name)
- self.assert_sql_count(testing.db, go, expected)
+ m = self.mapper_registry.map_imperatively(User, users)
+ m.add_property("_name", deferred(users.c.name))
+ m.add_property("name", synonym("_name"))
-class DynamicTest(_DynamicFixture, _fixtures.FixtureTest):
- def test_negative_slice_access_raises(self):
- User, Address = self._user_address_fixture()
sess = fixture_session()
- u1 = sess.get(User, 8)
-
- with testing.expect_deprecated_20(
- "Support for negative indexes for SQL index / slice"
- ):
- eq_(u1.addresses[-1], Address(id=4))
-
- with testing.expect_deprecated_20(
- "Support for negative indexes for SQL index / slice"
- ):
- eq_(u1.addresses[-5:-2], [Address(id=2)])
-
- with testing.expect_deprecated_20(
- "Support for negative indexes for SQL index / slice"
- ):
- eq_(u1.addresses[-2], Address(id=3))
-
- with testing.expect_deprecated_20(
- "Support for negative indexes for SQL index / slice"
- ):
- eq_(u1.addresses[:-2], [Address(id=2)])
-
+ assert sess.get(User, 7)
-class FromSelfTest(QueryTest, AssertsCompiledSQL):
- __dialect__ = "default"
+ u = sess.query(User).filter_by(name="jack").one()
- def _from_self_deprecated(self):
- return testing.expect_deprecated_20(r"The Query.from_self\(\) method")
+ def go():
+ eq_(u.name, "jack")
+ eq_(assert_col, [("get", "jack")], str(assert_col))
- def test_illegal_operations(self):
+ self.sql_count_(1, go)
- User = self.classes.User
- s = fixture_session()
+class DeprecatedOptionAllTest(OptionsPathTest, _fixtures.FixtureTest):
+ run_inserts = "once"
+ run_deletes = None
- with self._from_self_deprecated():
- q = s.query(User).from_self()
- assert_raises_message(
- sa.exc.InvalidRequestError,
- r"Can't call Query.update\(\) or Query.delete\(\)",
- q.update,
- {},
+ def _mapper_fixture_one(self):
+ users, User, addresses, Address, orders, Order = (
+ self.tables.users,
+ self.classes.User,
+ self.tables.addresses,
+ self.classes.Address,
+ self.tables.orders,
+ self.classes.Order,
+ )
+ keywords, items, item_keywords, Keyword, Item = (
+ self.tables.keywords,
+ self.tables.items,
+ self.tables.item_keywords,
+ self.classes.Keyword,
+ self.classes.Item,
+ )
+ self.mapper_registry.map_imperatively(
+ User,
+ users,
+ properties={
+ "addresses": relationship(Address),
+ "orders": relationship(Order),
+ },
+ )
+ self.mapper_registry.map_imperatively(Address, addresses)
+ self.mapper_registry.map_imperatively(
+ Order,
+ orders,
+ properties={
+ "items": relationship(Item, secondary=self.tables.order_items)
+ },
+ )
+ self.mapper_registry.map_imperatively(
+ Keyword,
+ keywords,
+ properties={
+ "keywords": column_property(keywords.c.name + "some keyword")
+ },
+ )
+ self.mapper_registry.map_imperatively(
+ Item,
+ items,
+ properties=dict(
+ keywords=relationship(Keyword, secondary=item_keywords)
+ ),
)
+ def _assert_eager_with_entity_exception(
+ self, entity_list, options, message
+ ):
assert_raises_message(
- sa.exc.InvalidRequestError,
- r"Can't call Query.update\(\) or Query.delete\(\)",
- q.delete,
- {},
+ sa.exc.ArgumentError,
+ message,
+ fixture_session()
+ .query(*entity_list)
+ .options(*options)
+ ._compile_context,
)
- def test_basic_filter_by(self):
- """test #7239"""
-
- User = self.classes.User
-
- s = fixture_session()
-
- with self._from_self_deprecated():
- q = s.query(User).from_self()
-
- self.assert_compile(
- q.filter_by(id=5),
- "SELECT anon_1.users_id AS anon_1_users_id, anon_1.users_name "
- "AS anon_1_users_name FROM (SELECT users.id AS users_id, "
- "users.name AS users_name FROM users) AS anon_1 "
- "WHERE anon_1.users_id = :id_1",
+ def test_defer_addtl_attrs(self):
+ users, User, Address, addresses = (
+ self.tables.users,
+ self.classes.User,
+ self.classes.Address,
+ self.tables.addresses,
)
- def test_columns_augmented_distinct_on(self):
- User, Address = self.classes.User, self.classes.Address
-
- sess = fixture_session()
-
- with self._from_self_deprecated():
- q = (
- sess.query(
- User.id,
- User.name.label("foo"),
- Address.id,
- Address.email_address,
+ self.mapper_registry.map_imperatively(Address, addresses)
+ self.mapper_registry.map_imperatively(
+ User,
+ users,
+ properties={
+ "addresses": relationship(
+ Address, lazy="selectin", order_by=addresses.c.id
)
- .distinct(Address.email_address)
- .order_by(User.id, User.name, Address.email_address)
- .from_self(User.id, User.name.label("foo"), Address.id)
- )
-
- # Address.email_address is added because of DISTINCT,
- # however User.id, User.name are not b.c. they're already there,
- # even though User.name is labeled
- self.assert_compile(
- q,
- "SELECT anon_1.users_id AS anon_1_users_id, anon_1.foo AS foo, "
- "anon_1.addresses_id AS anon_1_addresses_id "
- "FROM ("
- "SELECT DISTINCT ON (addresses.email_address) "
- "users.id AS users_id, users.name AS foo, "
- "addresses.id AS addresses_id, addresses.email_address AS "
- "addresses_email_address FROM users, addresses ORDER BY "
- "users.id, users.name, addresses.email_address"
- ") AS anon_1",
- dialect="postgresql",
+ },
)
- def test_columns_augmented_roundtrip_one_from_self(self):
- """Test workaround for legacy style DISTINCT on extra column.
-
- See #5134
-
- """
- User, Address = self.classes.User, self.classes.Address
-
sess = fixture_session()
- with self._from_self_deprecated():
- q = (
- sess.query(User, Address.email_address)
- .join(User.addresses)
- .distinct()
- .from_self(User)
- .order_by(desc(Address.email_address))
- )
-
- eq_([User(id=7), User(id=9), User(id=8)], q.all())
- def test_columns_augmented_roundtrip_three_from_self(self):
- """Test workaround for legacy style DISTINCT on extra column.
+ with testing.expect_deprecated(undefer_needs_chaining):
+ sess.query(User).options(
+ defer(User.addresses, Address.email_address)
+ )
- See #5134
+ with testing.expect_deprecated(undefer_needs_chaining):
+ sess.query(User).options(
+ undefer(User.addresses, Address.email_address)
+ )
- """
- User, Address = self.classes.User, self.classes.Address
+class InstrumentationTest(fixtures.ORMTest):
+ def test_dict_subclass4(self):
+ # tests #2654
+ with testing.expect_deprecated(
+ r"The collection.converter\(\) handler is deprecated and will "
+ "be removed in a future release. Please refer to the "
+ "AttributeEvents"
+ ):
- sess = fixture_session()
+ class MyDict(collections.MappedCollection):
+ def __init__(self):
+ super(MyDict, self).__init__(lambda value: "k%d" % value)
- with self._from_self_deprecated():
- q = (
- sess.query(
- User.id,
- User.name.label("foo"),
- Address.id,
- Address.email_address,
- )
- .join(Address, true())
- .filter(User.name == "jack")
- .filter(User.id + Address.user_id > 0)
- .distinct()
- .from_self(User.id, User.name.label("foo"), Address.id)
- .order_by(User.id, User.name, Address.email_address)
- )
+ @collection.converter
+ def _convert(self, dictlike):
+ for key, value in dictlike.items():
+ yield value + 5
- eq_(
- q.all(),
- [
- (7, "jack", 3),
- (7, "jack", 4),
- (7, "jack", 2),
- (7, "jack", 5),
- (7, "jack", 1),
- ],
- )
- for row in q:
- eq_(row._mapping.keys(), ["id", "foo", "id"])
+ class Foo:
+ pass
- def test_clause_onclause(self):
- Order, User = (
- self.classes.Order,
- self.classes.User,
+ instrumentation.register_class(Foo)
+ attributes.register_attribute(
+ Foo, "attr", uselist=True, typecallable=MyDict, useobject=True
)
- sess = fixture_session()
- # explicit onclause with from_self(), means
- # the onclause must be aliased against the query's custom
- # FROM object
- with self._from_self_deprecated():
- eq_(
- sess.query(User)
- .order_by(User.id)
- .offset(2)
- .from_self()
- .join(Order, User.id == Order.user_id)
- .all(),
- [User(name="fred")],
- )
+ f = Foo()
+ f.attr = {"k1": 1, "k2": 2}
- def test_from_self_resets_joinpaths(self):
- """test a join from from_self() doesn't confuse joins inside the subquery
- with the outside.
- """
+ eq_(f.attr, {"k7": 7, "k6": 6})
- Item, Keyword = self.classes.Item, self.classes.Keyword
+ def test_name_setup(self):
+ with testing.expect_deprecated(
+ r"The collection.converter\(\) handler is deprecated and will "
+ "be removed in a future release. Please refer to the "
+ "AttributeEvents"
+ ):
- sess = fixture_session()
+ class Base:
+ @collection.iterator
+ def base_iterate(self, x):
+ return "base_iterate"
- with self._from_self_deprecated():
- self.assert_compile(
- sess.query(Item)
- .join(Item.keywords)
- .from_self(Keyword)
- .join(Item.keywords),
- "SELECT keywords.id AS keywords_id, "
- "keywords.name AS keywords_name "
- "FROM (SELECT items.id AS items_id, "
- "items.description AS items_description "
- "FROM items JOIN item_keywords AS item_keywords_1 "
- "ON items.id = "
- "item_keywords_1.item_id JOIN keywords "
- "ON keywords.id = item_keywords_1.keyword_id) "
- "AS anon_1 JOIN item_keywords AS item_keywords_2 ON "
- "anon_1.items_id = item_keywords_2.item_id "
- "JOIN keywords ON "
- "keywords.id = item_keywords_2.keyword_id",
- use_default_dialect=True,
- )
+ @collection.appender
+ def base_append(self, x):
+ return "base_append"
- def test_single_prop_9(self):
- User = self.classes.User
+ @collection.converter
+ def base_convert(self, x):
+ return "base_convert"
- sess = fixture_session()
- with self._from_self_deprecated():
- self.assert_compile(
- sess.query(User)
- .filter(User.name == "ed")
- .from_self()
- .join(User.orders),
- "SELECT anon_1.users_id AS anon_1_users_id, "
- "anon_1.users_name AS anon_1_users_name "
- "FROM (SELECT users.id AS users_id, users.name AS users_name "
- "FROM users "
- "WHERE users.name = :name_1) AS anon_1 JOIN orders "
- "ON anon_1.users_id = orders.user_id",
- )
+ @collection.remover
+ def base_remove(self, x):
+ return "base_remove"
- def test_anonymous_expression_from_self_twice_oldstyle(self):
- # relies upon _orm_only_from_obj_alias setting
+ from sqlalchemy.orm.collections import _instrument_class
- sess = fixture_session()
- c1, c2 = column("c1"), column("c2")
- q1 = sess.query(c1, c2).filter(c1 == "dog")
- with self._from_self_deprecated():
- q1 = q1.from_self().from_self()
- self.assert_compile(
- q1.order_by(c1),
- "SELECT anon_1.anon_2_c1 AS anon_1_anon_2_c1, anon_1.anon_2_c2 AS "
- "anon_1_anon_2_c2 FROM (SELECT anon_2.c1 AS anon_2_c1, anon_2.c2 "
- "AS anon_2_c2 "
- "FROM (SELECT c1, c2 WHERE c1 = :c1_1) AS "
- "anon_2) AS anon_1 ORDER BY anon_1.anon_2_c1",
- )
+ _instrument_class(Base)
- def test_anonymous_expression_plus_flag_aliased_join(self):
- """test that the 'dont alias non-ORM' rule remains for other
- kinds of aliasing when _from_selectable() is used."""
-
- User = self.classes.User
- Address = self.classes.Address
- addresses = self.tables.addresses
+ eq_(Base._sa_remover(Base(), 5), "base_remove")
+ eq_(Base._sa_appender(Base(), 5), "base_append")
+ eq_(Base._sa_iterator(Base(), 5), "base_iterate")
+ eq_(Base._sa_converter(Base(), 5), "base_convert")
- sess = fixture_session()
- q1 = sess.query(User.id).filter(User.id > 5)
- with self._from_self_deprecated():
- q1 = q1.from_self()
+ with testing.expect_deprecated(
+ r"The collection.converter\(\) handler is deprecated and will "
+ "be removed in a future release. Please refer to the "
+ "AttributeEvents"
+ ):
- with testing.expect_deprecated_20(join_aliased_dep):
- q1 = q1.join(User.addresses, aliased=True).order_by(
- User.id, Address.id, addresses.c.id
- )
+ class Sub(Base):
+ @collection.converter
+ def base_convert(self, x):
+ return "sub_convert"
- self.assert_compile(
- q1,
- "SELECT anon_1.users_id AS anon_1_users_id "
- "FROM (SELECT users.id AS users_id FROM users "
- "WHERE users.id > :id_1) AS anon_1 JOIN addresses AS addresses_1 "
- "ON anon_1.users_id = addresses_1.user_id "
- "ORDER BY anon_1.users_id, addresses_1.id, addresses.id",
- )
+ @collection.remover
+ def sub_remove(self, x):
+ return "sub_remove"
- def test_anonymous_expression_plus_explicit_aliased_join(self):
- """test that the 'dont alias non-ORM' rule remains for other
- kinds of aliasing when _from_selectable() is used."""
+ _instrument_class(Sub)
- User = self.classes.User
- Address = self.classes.Address
- addresses = self.tables.addresses
+ eq_(Sub._sa_appender(Sub(), 5), "base_append")
+ eq_(Sub._sa_remover(Sub(), 5), "sub_remove")
+ eq_(Sub._sa_iterator(Sub(), 5), "base_iterate")
+ eq_(Sub._sa_converter(Sub(), 5), "sub_convert")
- sess = fixture_session()
- q1 = sess.query(User.id).filter(User.id > 5)
- with self._from_self_deprecated():
- q1 = q1.from_self()
- aa = aliased(Address)
- q1 = q1.join(aa, User.addresses).order_by(
- User.id, aa.id, addresses.c.id
- )
- self.assert_compile(
- q1,
- "SELECT anon_1.users_id AS anon_1_users_id "
- "FROM (SELECT users.id AS users_id FROM users "
- "WHERE users.id > :id_1) AS anon_1 JOIN addresses AS addresses_1 "
- "ON anon_1.users_id = addresses_1.user_id "
- "ORDER BY anon_1.users_id, addresses_1.id, addresses.id",
- )
+class NonPrimaryRelationshipLoaderTest(_fixtures.FixtureTest):
+ run_inserts = "once"
+ run_deletes = None
- def test_table_anonymous_expression_from_self_twice_oldstyle(self):
- # relies upon _orm_only_from_obj_alias setting
- from sqlalchemy.sql import column
+ def test_selectload(self):
+ """tests lazy loading with two relationships simultaneously,
+ from the same table, using aliases."""
- sess = fixture_session()
- t1 = table("t1", column("c1"), column("c2"))
- q1 = sess.query(t1.c.c1, t1.c.c2).filter(t1.c.c1 == "dog")
- with self._from_self_deprecated():
- q1 = q1.from_self().from_self()
- self.assert_compile(
- q1.order_by(t1.c.c1),
- "SELECT anon_1.anon_2_t1_c1 "
- "AS anon_1_anon_2_t1_c1, anon_1.anon_2_t1_c2 "
- "AS anon_1_anon_2_t1_c2 "
- "FROM (SELECT anon_2.t1_c1 AS anon_2_t1_c1, "
- "anon_2.t1_c2 AS anon_2_t1_c2 FROM (SELECT t1.c1 AS t1_c1, t1.c2 "
- "AS t1_c2 FROM t1 WHERE t1.c1 = :c1_1) AS anon_2) AS anon_1 "
- "ORDER BY anon_1.anon_2_t1_c1",
+ users, orders, User, Address, Order, addresses = (
+ self.tables.users,
+ self.tables.orders,
+ self.classes.User,
+ self.classes.Address,
+ self.classes.Order,
+ self.tables.addresses,
)
- def test_self_referential(self):
- Order = self.classes.Order
-
- sess = fixture_session()
- oalias = aliased(Order)
-
- with self._from_self_deprecated():
- for q in [
- sess.query(Order, oalias)
- .filter(Order.user_id == oalias.user_id)
- .filter(Order.user_id == 7)
- .filter(Order.id > oalias.id)
- .order_by(Order.id, oalias.id),
- sess.query(Order, oalias)
- .filter(Order.id > oalias.id)
- .from_self()
- .filter(Order.user_id == oalias.user_id)
- .filter(Order.user_id == 7)
- .order_by(Order.id, oalias.id),
- # same thing, but reversed.
- sess.query(oalias, Order)
- .filter(Order.id < oalias.id)
- .from_self()
- .filter(oalias.user_id == Order.user_id)
- .filter(oalias.user_id == 7)
- .order_by(oalias.id, Order.id),
- # here we go....two layers of aliasing
- sess.query(Order, oalias)
- .filter(Order.user_id == oalias.user_id)
- .filter(Order.user_id == 7)
- .filter(Order.id > oalias.id)
- .from_self()
- .order_by(Order.id, oalias.id)
- .limit(10)
- .options(joinedload(Order.items)),
- # gratuitous four layers
- sess.query(Order, oalias)
- .filter(Order.user_id == oalias.user_id)
- .filter(Order.user_id == 7)
- .filter(Order.id > oalias.id)
- .from_self()
- .from_self()
- .from_self()
- .order_by(Order.id, oalias.id)
- .limit(10)
- .options(joinedload(Order.items)),
- ]:
-
- eq_(
- q.all(),
- [
- (
- Order(
- address_id=1,
- description="order 3",
- isopen=1,
- user_id=7,
- id=3,
- ),
- Order(
- address_id=1,
- description="order 1",
- isopen=0,
- user_id=7,
- id=1,
- ),
- ),
- (
- Order(
- address_id=None,
- description="order 5",
- isopen=0,
- user_id=7,
- id=5,
- ),
- Order(
- address_id=1,
- description="order 1",
- isopen=0,
- user_id=7,
- id=1,
- ),
- ),
- (
- Order(
- address_id=None,
- description="order 5",
- isopen=0,
- user_id=7,
- id=5,
- ),
- Order(
- address_id=1,
- description="order 3",
- isopen=1,
- user_id=7,
- id=3,
- ),
- ),
- ],
- )
+ openorders = sa.alias(orders, "openorders")
+ closedorders = sa.alias(orders, "closedorders")
- def test_from_self_internal_literals_oldstyle(self):
- # relies upon _orm_only_from_obj_alias setting
- Order = self.classes.Order
+ self.mapper_registry.map_imperatively(Address, addresses)
- sess = fixture_session()
+ self.mapper_registry.map_imperatively(Order, orders)
- # ensure column expressions are taken from inside the subquery, not
- # restated at the top
- with self._from_self_deprecated():
- q = (
- sess.query(
- Order.id,
- Order.description,
- literal_column("'q'").label("foo"),
- )
- .filter(Order.description == "order 3")
- .from_self()
+ with testing.expect_deprecated(
+ "The mapper.non_primary parameter is deprecated"
+ ):
+ open_mapper = self.mapper_registry.map_imperatively(
+ Order, openorders, non_primary=True
)
- self.assert_compile(
- q,
- "SELECT anon_1.orders_id AS "
- "anon_1_orders_id, "
- "anon_1.orders_description AS anon_1_orders_description, "
- "anon_1.foo AS anon_1_foo FROM (SELECT "
- "orders.id AS orders_id, "
- "orders.description AS orders_description, "
- "'q' AS foo FROM orders WHERE "
- "orders.description = :description_1) AS "
- "anon_1",
- )
- eq_(q.all(), [(3, "order 3", "q")])
-
- def test_column_access_from_self(self):
- User = self.classes.User
- sess = fixture_session()
-
- with self._from_self_deprecated():
- q = sess.query(User).from_self()
- self.assert_compile(
- q.filter(User.name == "ed"),
- "SELECT anon_1.users_id AS anon_1_users_id, anon_1.users_name AS "
- "anon_1_users_name FROM (SELECT users.id AS users_id, users.name "
- "AS users_name FROM users) AS anon_1 WHERE anon_1.users_name = "
- ":name_1",
+ closed_mapper = self.mapper_registry.map_imperatively(
+ Order, closedorders, non_primary=True
+ )
+ self.mapper_registry.map_imperatively(
+ User,
+ users,
+ properties=dict(
+ addresses=relationship(Address, lazy=True),
+ open_orders=relationship(
+ open_mapper,
+ primaryjoin=sa.and_(
+ openorders.c.isopen == 1,
+ users.c.id == openorders.c.user_id,
+ ),
+ lazy="select",
+ ),
+ closed_orders=relationship(
+ closed_mapper,
+ primaryjoin=sa.and_(
+ closedorders.c.isopen == 0,
+ users.c.id == closedorders.c.user_id,
+ ),
+ lazy="select",
+ ),
+ ),
)
- def test_column_access_from_self_twice(self):
- User = self.classes.User
- sess = fixture_session()
+ self._run_double_test(10)
- with self._from_self_deprecated():
- q = sess.query(User).from_self(User.id, User.name).from_self()
- self.assert_compile(
- q.filter(User.name == "ed"),
- "SELECT anon_1.anon_2_users_id AS anon_1_anon_2_users_id, "
- "anon_1.anon_2_users_name AS anon_1_anon_2_users_name FROM "
- "(SELECT anon_2.users_id AS anon_2_users_id, anon_2.users_name "
- "AS anon_2_users_name FROM (SELECT users.id AS users_id, "
- "users.name AS users_name FROM users) AS anon_2) AS anon_1 "
- "WHERE anon_1.anon_2_users_name = :name_1",
- )
+ def test_joinedload(self):
+ """Eager loading with two relationships simultaneously,
+ from the same table, using aliases."""
- def test_column_queries_nine(self):
- Address, User = (
- self.classes.Address,
+ users, orders, User, Address, Order, addresses = (
+ self.tables.users,
+ self.tables.orders,
self.classes.User,
+ self.classes.Address,
+ self.classes.Order,
+ self.tables.addresses,
)
- sess = fixture_session()
+ openorders = sa.alias(orders, "openorders")
+ closedorders = sa.alias(orders, "closedorders")
- adalias = aliased(Address)
- # select from aliasing + explicit aliasing
- with self._from_self_deprecated():
- eq_(
- sess.query(User, adalias.email_address, adalias.id)
- .outerjoin(adalias, User.addresses)
- .from_self(User, adalias.email_address)
- .order_by(User.id, adalias.id)
- .all(),
- [
- (User(name="jack", id=7), "jack@bean.com"),
- (User(name="ed", id=8), "ed@wood.com"),
- (User(name="ed", id=8), "ed@bettyboop.com"),
- (User(name="ed", id=8), "ed@lala.com"),
- (User(name="fred", id=9), "fred@fred.com"),
- (User(name="chuck", id=10), None),
- ],
+ self.mapper_registry.map_imperatively(Address, addresses)
+ self.mapper_registry.map_imperatively(Order, orders)
+
+ with testing.expect_deprecated(
+ "The mapper.non_primary parameter is deprecated"
+ ):
+ open_mapper = self.mapper_registry.map_imperatively(
+ Order, openorders, non_primary=True
+ )
+ closed_mapper = self.mapper_registry.map_imperatively(
+ Order, closedorders, non_primary=True
)
- def test_column_queries_ten(self):
- Address, User = (
- self.classes.Address,
- self.classes.User,
+ self.mapper_registry.map_imperatively(
+ User,
+ users,
+ properties=dict(
+ addresses=relationship(
+ Address, lazy="joined", order_by=addresses.c.id
+ ),
+ open_orders=relationship(
+ open_mapper,
+ primaryjoin=sa.and_(
+ openorders.c.isopen == 1,
+ users.c.id == openorders.c.user_id,
+ ),
+ lazy="joined",
+ order_by=openorders.c.id,
+ ),
+ closed_orders=relationship(
+ closed_mapper,
+ primaryjoin=sa.and_(
+ closedorders.c.isopen == 0,
+ users.c.id == closedorders.c.user_id,
+ ),
+ lazy="joined",
+ order_by=closedorders.c.id,
+ ),
+ ),
)
+ self._run_double_test(1)
- sess = fixture_session()
-
- # anon + select from aliasing
- aa = aliased(Address)
- with self._from_self_deprecated():
- eq_(
- sess.query(User)
- .join(aa, User.addresses)
- .filter(aa.email_address.like("%ed%"))
- .from_self()
- .all(),
- [User(name="ed", id=8), User(name="fred", id=9)],
- )
+ def test_selectin(self):
- def test_column_queries_eleven(self):
- Address, User = (
- self.classes.Address,
+ users, orders, User, Address, Order, addresses = (
+ self.tables.users,
+ self.tables.orders,
self.classes.User,
+ self.classes.Address,
+ self.classes.Order,
+ self.tables.addresses,
)
- sess = fixture_session()
-
- adalias = aliased(Address)
- # test eager aliasing, with/without select_entity_from aliasing
- with self._from_self_deprecated():
- for q in [
- sess.query(User, adalias.email_address)
- .outerjoin(adalias, User.addresses)
- .options(joinedload(User.addresses))
- .order_by(User.id, adalias.id)
- .limit(10),
- sess.query(User, adalias.email_address, adalias.id)
- .outerjoin(adalias, User.addresses)
- .from_self(User, adalias.email_address)
- .options(joinedload(User.addresses))
- .order_by(User.id, adalias.id)
- .limit(10),
- ]:
- eq_(
- q.all(),
- [
- (
- User(
- addresses=[
- Address(
- user_id=7,
- email_address="jack@bean.com",
- id=1,
- )
- ],
- name="jack",
- id=7,
- ),
- "jack@bean.com",
- ),
- (
- User(
- addresses=[
- Address(
- user_id=8,
- email_address="ed@wood.com",
- id=2,
- ),
- Address(
- user_id=8,
- email_address="ed@bettyboop.com",
- id=3,
- ),
- Address(
- user_id=8,
- email_address="ed@lala.com",
- id=4,
- ),
- ],
- name="ed",
- id=8,
- ),
- "ed@wood.com",
- ),
- (
- User(
- addresses=[
- Address(
- user_id=8,
- email_address="ed@wood.com",
- id=2,
- ),
- Address(
- user_id=8,
- email_address="ed@bettyboop.com",
- id=3,
- ),
- Address(
- user_id=8,
- email_address="ed@lala.com",
- id=4,
- ),
- ],
- name="ed",
- id=8,
- ),
- "ed@bettyboop.com",
- ),
- (
- User(
- addresses=[
- Address(
- user_id=8,
- email_address="ed@wood.com",
- id=2,
- ),
- Address(
- user_id=8,
- email_address="ed@bettyboop.com",
- id=3,
- ),
- Address(
- user_id=8,
- email_address="ed@lala.com",
- id=4,
- ),
- ],
- name="ed",
- id=8,
- ),
- "ed@lala.com",
- ),
- (
- User(
- addresses=[
- Address(
- user_id=9,
- email_address="fred@fred.com",
- id=5,
- )
- ],
- name="fred",
- id=9,
- ),
- "fred@fred.com",
- ),
- (User(addresses=[], name="chuck", id=10), None),
- ],
- )
+ openorders = sa.alias(orders, "openorders")
+ closedorders = sa.alias(orders, "closedorders")
- def test_filter(self):
- User = self.classes.User
+ self.mapper_registry.map_imperatively(Address, addresses)
+ self.mapper_registry.map_imperatively(Order, orders)
- with self._from_self_deprecated():
- eq_(
- [User(id=8), User(id=9)],
- fixture_session()
- .query(User)
- .filter(User.id.in_([8, 9]))
- .from_self()
- .all(),
+ with testing.expect_deprecated(
+ "The mapper.non_primary parameter is deprecated"
+ ):
+ open_mapper = self.mapper_registry.map_imperatively(
+ Order, openorders, non_primary=True
)
-
- with self._from_self_deprecated():
- eq_(
- [User(id=8), User(id=9)],
- fixture_session()
- .query(User)
- .order_by(User.id)
- .slice(1, 3)
- .from_self()
- .all(),
+ closed_mapper = self.mapper_registry.map_imperatively(
+ Order, closedorders, non_primary=True
)
- with self._from_self_deprecated():
- eq_(
- [User(id=8)],
- list(
- fixture_session()
- .query(User)
- .filter(User.id.in_([8, 9]))
- .from_self()
- .order_by(User.id)[0:1]
+ self.mapper_registry.map_imperatively(
+ User,
+ users,
+ properties=dict(
+ addresses=relationship(
+ Address, lazy="selectin", order_by=addresses.c.id
),
- )
+ open_orders=relationship(
+ open_mapper,
+ primaryjoin=sa.and_(
+ openorders.c.isopen == 1,
+ users.c.id == openorders.c.user_id,
+ ),
+ lazy="selectin",
+ order_by=openorders.c.id,
+ ),
+ closed_orders=relationship(
+ closed_mapper,
+ primaryjoin=sa.and_(
+ closedorders.c.isopen == 0,
+ users.c.id == closedorders.c.user_id,
+ ),
+ lazy="selectin",
+ order_by=closedorders.c.id,
+ ),
+ ),
+ )
- def test_join(self):
- User, Address = self.classes.User, self.classes.Address
+ self._run_double_test(4)
- with self._from_self_deprecated():
- eq_(
- [
- (User(id=8), Address(id=2)),
- (User(id=8), Address(id=3)),
- (User(id=8), Address(id=4)),
- (User(id=9), Address(id=5)),
- ],
- fixture_session()
- .query(User)
- .filter(User.id.in_([8, 9]))
- .from_self()
- .join(User.addresses)
- .add_entity(Address)
- .order_by(User.id, Address.id)
- .all(),
- )
+ def test_subqueryload(self):
- def test_group_by(self):
- Address = self.classes.Address
-
- eq_(
- fixture_session()
- .query(Address.user_id, func.count(Address.id).label("count"))
- .group_by(Address.user_id)
- .order_by(Address.user_id)
- .all(),
- [(7, 1), (8, 3), (9, 1)],
+ users, orders, User, Address, Order, addresses = (
+ self.tables.users,
+ self.tables.orders,
+ self.classes.User,
+ self.classes.Address,
+ self.classes.Order,
+ self.tables.addresses,
)
- with self._from_self_deprecated():
- eq_(
- fixture_session()
- .query(Address.user_id, Address.id)
- .from_self(Address.user_id, func.count(Address.id))
- .group_by(Address.user_id)
- .order_by(Address.user_id)
- .all(),
- [(7, 1), (8, 3), (9, 1)],
- )
-
- def test_having(self):
- User = self.classes.User
+ openorders = sa.alias(orders, "openorders")
+ closedorders = sa.alias(orders, "closedorders")
- s = fixture_session()
+ self.mapper_registry.map_imperatively(Address, addresses)
+ self.mapper_registry.map_imperatively(Order, orders)
- with self._from_self_deprecated():
- self.assert_compile(
- s.query(User.id)
- .group_by(User.id)
- .having(User.id > 5)
- .from_self(),
- "SELECT anon_1.users_id AS anon_1_users_id FROM "
- "(SELECT users.id AS users_id FROM users GROUP "
- "BY users.id HAVING users.id > :id_1) AS anon_1",
+ with testing.expect_deprecated(
+ "The mapper.non_primary parameter is deprecated"
+ ):
+ open_mapper = self.mapper_registry.map_imperatively(
+ Order, openorders, non_primary=True
+ )
+ closed_mapper = self.mapper_registry.map_imperatively(
+ Order, closedorders, non_primary=True
)
- def test_no_joinedload(self):
- """test that joinedloads are pushed outwards and not rendered in
- subqueries."""
-
- User = self.classes.User
-
- s = fixture_session()
-
- with self._from_self_deprecated():
- q = s.query(User).options(joinedload(User.addresses)).from_self()
-
- self.assert_compile(
- q.statement,
- "SELECT anon_1.users_id, anon_1.users_name, addresses_1.id, "
- "addresses_1.user_id, addresses_1.email_address FROM "
- "(SELECT users.id AS users_id, users.name AS "
- "users_name FROM users) AS anon_1 LEFT OUTER JOIN "
- "addresses AS addresses_1 ON anon_1.users_id = "
- "addresses_1.user_id ORDER BY addresses_1.id",
+ self.mapper_registry.map_imperatively(
+ User,
+ users,
+ properties=dict(
+ addresses=relationship(
+ Address, lazy="subquery", order_by=addresses.c.id
+ ),
+ open_orders=relationship(
+ open_mapper,
+ primaryjoin=sa.and_(
+ openorders.c.isopen == 1,
+ users.c.id == openorders.c.user_id,
+ ),
+ lazy="subquery",
+ order_by=openorders.c.id,
+ ),
+ closed_orders=relationship(
+ closed_mapper,
+ primaryjoin=sa.and_(
+ closedorders.c.isopen == 0,
+ users.c.id == closedorders.c.user_id,
+ ),
+ lazy="subquery",
+ order_by=closedorders.c.id,
+ ),
+ ),
)
- def test_aliases(self):
- """test that aliased objects are accessible externally to a from_self()
- call."""
-
- User, Address = self.classes.User, self.classes.Address
-
- s = fixture_session()
-
- ualias = aliased(User)
-
- with self._from_self_deprecated():
- eq_(
- s.query(User, ualias)
- .filter(User.id > ualias.id)
- .from_self(User.name, ualias.name)
- .order_by(User.name, ualias.name)
- .all(),
- [
- ("chuck", "ed"),
- ("chuck", "fred"),
- ("chuck", "jack"),
- ("ed", "jack"),
- ("fred", "ed"),
- ("fred", "jack"),
- ],
- )
+ self._run_double_test(4)
- with self._from_self_deprecated():
- eq_(
- s.query(User, ualias)
- .filter(User.id > ualias.id)
- .from_self(User.name, ualias.name)
- .filter(ualias.name == "ed")
- .order_by(User.name, ualias.name)
- .all(),
- [("chuck", "ed"), ("fred", "ed")],
- )
+ def _run_double_test(self, count):
+ User, Address, Order, Item = self.classes(
+ "User", "Address", "Order", "Item"
+ )
+ q = fixture_session().query(User).order_by(User.id)
- with self._from_self_deprecated():
+ def go():
eq_(
- s.query(User, ualias)
- .filter(User.id > ualias.id)
- .from_self(ualias.name, Address.email_address)
- .join(ualias.addresses)
- .order_by(ualias.name, Address.email_address)
- .all(),
[
- ("ed", "fred@fred.com"),
- ("jack", "ed@bettyboop.com"),
- ("jack", "ed@lala.com"),
- ("jack", "ed@wood.com"),
- ("jack", "fred@fred.com"),
+ User(
+ id=7,
+ addresses=[Address(id=1)],
+ open_orders=[Order(id=3)],
+ closed_orders=[Order(id=1), Order(id=5)],
+ ),
+ User(
+ id=8,
+ addresses=[
+ Address(id=2),
+ Address(id=3),
+ Address(id=4),
+ ],
+ open_orders=[],
+ closed_orders=[],
+ ),
+ User(
+ id=9,
+ addresses=[Address(id=5)],
+ open_orders=[Order(id=4)],
+ closed_orders=[Order(id=2)],
+ ),
+ User(id=10),
],
+ q.all(),
)
- def test_multiple_entities(self):
- User, Address = self.classes.User, self.classes.Address
+ self.assert_sql_count(testing.db, go, count)
sess = fixture_session()
+ user = sess.get(User, 7)
- with self._from_self_deprecated():
- eq_(
- sess.query(User, Address)
- .filter(User.id == Address.user_id)
- .filter(Address.id.in_([2, 5]))
- .from_self()
- .all(),
- [(User(id=8), Address(id=2)), (User(id=9), Address(id=5))],
- )
-
- with self._from_self_deprecated():
- eq_(
- sess.query(User, Address)
- .filter(User.id == Address.user_id)
- .filter(Address.id.in_([2, 5]))
- .from_self()
- .options(joinedload(User.addresses))
- .first(),
- (
- User(id=8, addresses=[Address(), Address(), Address()]),
- Address(id=2),
- ),
- )
+ closed_mapper = User.closed_orders.entity
+ open_mapper = User.open_orders.entity
+ eq_(
+ [Order(id=1), Order(id=5)],
+ fixture_session()
+ .query(closed_mapper)
+ .filter(with_parent(user, User.closed_orders))
+ .all(),
+ )
+ eq_(
+ [Order(id=3)],
+ fixture_session()
+ .query(open_mapper)
+ .filter(with_parent(user, User.open_orders))
+ .all(),
+ )
- def test_multiple_with_column_entities_oldstyle(self):
- # relies upon _orm_only_from_obj_alias setting
- User = self.classes.User
- sess = fixture_session()
+class ViewonlyFlagWarningTest(fixtures.MappedTest):
+ """test for #4993.
- with self._from_self_deprecated():
- eq_(
- sess.query(User.id)
- .from_self()
- .add_columns(func.count().label("foo"))
- .group_by(User.id)
- .order_by(User.id)
- .from_self()
- .all(),
- [(7, 1), (8, 1), (9, 1), (10, 1)],
- )
+ In 1.4, this moves to test/orm/test_cascade, deprecation warnings
+ become errors, will then be for #4994.
+ """
-class SubqRelationsFromSelfTest(fixtures.DeclarativeMappedTest):
- def _from_self_deprecated(self):
- return testing.expect_deprecated_20(r"The Query.from_self\(\) method")
+ @classmethod
+ def define_tables(cls, metadata):
+ Table(
+ "users",
+ metadata,
+ Column("id", Integer, primary_key=True),
+ Column("name", String(30)),
+ )
+ Table(
+ "orders",
+ metadata,
+ Column("id", Integer, primary_key=True),
+ Column("user_id", Integer),
+ Column("description", String(30)),
+ )
@classmethod
def setup_classes(cls):
- Base = cls.DeclarativeBasic
+ class User(cls.Comparable):
+ pass
- class A(Base, ComparableEntity):
- __tablename__ = "a"
+ class Order(cls.Comparable):
+ pass
- id = Column(Integer, primary_key=True)
- cs = relationship("C", order_by="C.id")
+ @testing.combinations(
+ ("passive_deletes", True),
+ ("passive_updates", False),
+ ("enable_typechecks", False),
+ ("active_history", True),
+ ("cascade_backrefs", False),
+ )
+ def test_viewonly_warning(self, flag, value):
+ Order = self.classes.Order
- class B(Base, ComparableEntity):
- __tablename__ = "b"
- id = Column(Integer, primary_key=True)
- a_id = Column(ForeignKey("a.id"))
- a = relationship("A")
- ds = relationship("D", order_by="D.id")
+ with testing.expect_warnings(
+ r"Setting %s on relationship\(\) while also setting "
+ "viewonly=True does not make sense" % flag
+ ):
+ kw = {
+ "viewonly": True,
+ "primaryjoin": self.tables.users.c.id
+ == foreign(self.tables.orders.c.user_id),
+ }
+ kw[flag] = value
+ rel = relationship(Order, **kw)
- class C(Base, ComparableEntity):
- __tablename__ = "c"
- id = Column(Integer, primary_key=True)
- a_id = Column(ForeignKey("a.id"))
+ eq_(getattr(rel, flag), value)
- class D(Base, ComparableEntity):
- __tablename__ = "d"
- id = Column(Integer, primary_key=True)
- b_id = Column(ForeignKey("b.id"))
- @classmethod
- def insert_data(cls, connection):
- A, B, C, D = cls.classes("A", "B", "C", "D")
+class NonPrimaryMapperTest(_fixtures.FixtureTest, AssertsCompiledSQL):
+ __dialect__ = "default"
- s = Session(connection)
+ def teardown_test(self):
+ clear_mappers()
+
+ def test_non_primary_identity_class(self):
+ User = self.classes.User
+ users, addresses = self.tables.users, self.tables.addresses
- as_ = [
- A(
- id=i,
- cs=[C(), C()],
+ class AddressUser(User):
+ pass
+
+ self.mapper_registry.map_imperatively(
+ User, users, polymorphic_identity="user"
+ )
+ m2 = self.mapper_registry.map_imperatively(
+ AddressUser,
+ addresses,
+ inherits=User,
+ polymorphic_identity="address",
+ properties={"address_id": addresses.c.id},
+ )
+ with testing.expect_deprecated(
+ "The mapper.non_primary parameter is deprecated"
+ ):
+ m3 = self.mapper_registry.map_imperatively(
+ AddressUser, addresses, non_primary=True
)
- for i in range(1, 5)
- ]
+ assert m3._identity_class is m2._identity_class
+ eq_(
+ m2.identity_key_from_instance(AddressUser()),
+ m3.identity_key_from_instance(AddressUser()),
+ )
- s.add_all(
- [
- B(a=as_[0], ds=[D()]),
- B(a=as_[1], ds=[D()]),
- B(a=as_[2]),
- B(a=as_[3]),
- ]
+ def test_illegal_non_primary(self):
+ users, Address, addresses, User = (
+ self.tables.users,
+ self.classes.Address,
+ self.tables.addresses,
+ self.classes.User,
)
- s.commit()
+ self.mapper_registry.map_imperatively(User, users)
+ self.mapper_registry.map_imperatively(Address, addresses)
+ with testing.expect_deprecated(
+ "The mapper.non_primary parameter is deprecated"
+ ):
+ m = self.mapper_registry.map_imperatively( # noqa F841
+ User,
+ users,
+ non_primary=True,
+ properties={"addresses": relationship(Address)},
+ )
+ assert_raises_message(
+ sa.exc.ArgumentError,
+ "Attempting to assign a new relationship 'addresses' "
+ "to a non-primary mapper on class 'User'",
+ configure_mappers,
+ )
- def test_subq_w_from_self_one(self):
- A, B, C = self.classes("A", "B", "C")
-
- s = fixture_session()
-
- cache = {}
-
- for i in range(3):
- with self._from_self_deprecated():
- q = (
- s.query(B)
- .execution_options(compiled_cache=cache)
- .join(B.a)
- .filter(B.id < 4)
- .filter(A.id > 1)
- .from_self()
- .options(subqueryload(B.a).subqueryload(A.cs))
- .from_self()
- )
-
- def go():
- results = q.all()
- eq_(
- results,
- [
- B(
- a=A(cs=[C(a_id=2, id=3), C(a_id=2, id=4)], id=2),
- a_id=2,
- id=2,
- ),
- B(
- a=A(cs=[C(a_id=3, id=5), C(a_id=3, id=6)], id=3),
- a_id=3,
- id=3,
- ),
- ],
- )
-
- self.assert_sql_execution(
- testing.db,
- go,
- CompiledSQL(
- "SELECT anon_1.anon_2_b_id AS anon_1_anon_2_b_id, "
- "anon_1.anon_2_b_a_id AS anon_1_anon_2_b_a_id FROM "
- "(SELECT anon_2.b_id AS anon_2_b_id, anon_2.b_a_id "
- "AS anon_2_b_a_id FROM (SELECT b.id AS b_id, b.a_id "
- "AS b_a_id FROM b JOIN a ON a.id = b.a_id "
- "WHERE b.id < :id_1 AND a.id > :id_2) AS anon_2) AS anon_1"
- ),
- CompiledSQL(
- "SELECT a.id AS a_id, anon_1.anon_2_anon_3_b_a_id AS "
- "anon_1_anon_2_anon_3_b_a_id FROM (SELECT DISTINCT "
- "anon_2.anon_3_b_a_id AS anon_2_anon_3_b_a_id FROM "
- "(SELECT anon_3.b_id AS anon_3_b_id, anon_3.b_a_id "
- "AS anon_3_b_a_id FROM (SELECT b.id AS b_id, b.a_id "
- "AS b_a_id FROM b JOIN a ON a.id = b.a_id "
- "WHERE b.id < :id_1 AND a.id > :id_2) AS anon_3) "
- "AS anon_2) AS anon_1 JOIN a "
- "ON a.id = anon_1.anon_2_anon_3_b_a_id"
- ),
- CompiledSQL(
- "SELECT c.id AS c_id, c.a_id AS c_a_id, a_1.id "
- "AS a_1_id FROM (SELECT DISTINCT anon_2.anon_3_b_a_id AS "
- "anon_2_anon_3_b_a_id FROM "
- "(SELECT anon_3.b_id AS anon_3_b_id, anon_3.b_a_id "
- "AS anon_3_b_a_id FROM (SELECT b.id AS b_id, b.a_id "
- "AS b_a_id FROM b JOIN a ON a.id = b.a_id "
- "WHERE b.id < :id_1 AND a.id > :id_2) AS anon_3) "
- "AS anon_2) AS anon_1 JOIN a AS a_1 ON a_1.id = "
- "anon_1.anon_2_anon_3_b_a_id JOIN c ON a_1.id = c.a_id "
- "ORDER BY c.id"
- ),
- )
-
- s.close()
-
- def test_subq_w_from_self_two(self):
-
- A, B, C = self.classes("A", "B", "C")
-
- s = fixture_session()
- cache = {}
-
- for i in range(3):
-
- def go():
- with self._from_self_deprecated():
- q = (
- s.query(B)
- .execution_options(compiled_cache=cache)
- .join(B.a)
- .from_self()
- )
- q = q.options(subqueryload(B.ds))
-
- q.all()
-
- self.assert_sql_execution(
- testing.db,
- go,
- CompiledSQL(
- "SELECT anon_1.b_id AS anon_1_b_id, anon_1.b_a_id AS "
- "anon_1_b_a_id FROM (SELECT b.id AS b_id, b.a_id "
- "AS b_a_id FROM b JOIN a ON a.id = b.a_id) AS anon_1"
- ),
- CompiledSQL(
- "SELECT d.id AS d_id, d.b_id AS d_b_id, "
- "anon_1.anon_2_b_id AS anon_1_anon_2_b_id "
- "FROM (SELECT anon_2.b_id AS anon_2_b_id FROM "
- "(SELECT b.id AS b_id, b.a_id AS b_a_id FROM b "
- "JOIN a ON a.id = b.a_id) AS anon_2) AS anon_1 "
- "JOIN d ON anon_1.anon_2_b_id = d.b_id ORDER BY d.id"
- ),
- )
- s.close()
-
-
-class SessionTest(fixtures.RemovesEvents, _LocalFixture):
- def test_transaction_attr(self):
- s1 = Session(testing.db)
-
- with testing.expect_deprecated_20(
- "The Session.transaction attribute is considered legacy as "
- "of the 1.x series"
- ):
- s1.transaction
-
- def test_textual_execute(self, connection):
- """test that Session.execute() converts to text()"""
-
- users = self.tables.users
-
- with Session(bind=connection) as sess:
- sess.execute(users.insert(), dict(id=7, name="jack"))
-
- with testing.expect_deprecated_20(
- "Using plain strings to indicate SQL statements "
- "without using the text"
- ):
- # use :bindparam style
- eq_(
- sess.execute(
- "select * from users where id=:id", {"id": 7}
- ).fetchall(),
- [(7, "jack")],
- )
-
- with testing.expect_deprecated_20(
- "Using plain strings to indicate SQL statements "
- "without using the text"
- ):
- # use :bindparam style
- eq_(
- sess.scalar(
- "select id from users where id=:id", {"id": 7}
- ),
- 7,
- )
-
- def test_session_str(self):
- s1 = Session(testing.db)
- str(s1)
-
- @testing.combinations(
- {"mapper": None},
- {"clause": None},
- {"bind_arguments": {"mapper": None}, "clause": None},
- {"bind_arguments": {}, "clause": None},
- )
- def test_bind_kwarg_deprecated(self, kw):
- s1 = Session(testing.db)
-
- for meth in s1.execute, s1.scalar:
- m1 = mock.Mock(side_effect=s1.get_bind)
- with mock.patch.object(s1, "get_bind", m1):
- expr = text("select 1")
-
- with testing.expect_deprecated_20(
- r"Passing bind arguments to Session.execute\(\) as "
- "keyword "
- "arguments is deprecated and will be removed SQLAlchemy "
- "2.0"
- ):
- meth(expr, **kw)
-
- bind_arguments = kw.pop("bind_arguments", None)
- if bind_arguments:
- bind_arguments.update(kw)
-
- if "clause" not in kw:
- bind_arguments["clause"] = expr
- eq_(m1.mock_calls, [call(**bind_arguments)])
- else:
- if "clause" not in kw:
- kw["clause"] = expr
- eq_(m1.mock_calls, [call(**kw)])
-
-
-class DeprecatedInhTest(_poly_fixtures._Polymorphic):
- def test_with_polymorphic(self):
- Person = _poly_fixtures.Person
- Engineer = _poly_fixtures.Engineer
-
- with DeprecatedQueryTest._expect_implicit_subquery():
- p_poly = with_polymorphic(Person, [Engineer], select(Person))
+ def test_illegal_non_primary_2(self):
+ User, users = self.classes.User, self.tables.users
- is_true(
- sa.inspect(p_poly).selectable.compare(select(Person).subquery())
+ assert_raises_message(
+ sa.exc.InvalidRequestError,
+ "Configure a primary mapper first",
+ self.mapper_registry.map_imperatively,
+ User,
+ users,
+ non_primary=True,
)
- def test_multiple_adaption(self):
- """test that multiple filter() adapters get chained together "
- and work correctly within a multiple-entry join()."""
-
- Company = _poly_fixtures.Company
- Machine = _poly_fixtures.Machine
- Engineer = _poly_fixtures.Engineer
-
- people = self.tables.people
- engineers = self.tables.engineers
- machines = self.tables.machines
-
- sess = fixture_session()
-
- mach_alias = machines.select()
-
- # note python 2 does not allow parens here; reformat in py3 only
- with DeprecatedQueryTest._expect_implicit_subquery(), _aliased_join_warning( # noqa E501
- r"\[Person\(people\)\]"
- ):
- self.assert_compile(
- sess.query(Company)
- .join(people.join(engineers), Company.employees)
- .join(mach_alias, Engineer.machines, from_joinpoint=True)
- .filter(Engineer.name == "dilbert")
- .filter(Machine.name == "foo"),
- "SELECT companies.company_id AS companies_company_id, "
- "companies.name AS companies_name "
- "FROM companies JOIN (people "
- "JOIN engineers ON people.person_id = "
- "engineers.person_id) ON companies.company_id = "
- "people.company_id JOIN "
- "(SELECT machines.machine_id AS machine_id, "
- "machines.name AS name, "
- "machines.engineer_id AS engineer_id "
- "FROM machines) AS anon_1 "
- "ON engineers.person_id = anon_1.engineer_id "
- "WHERE people.name = :name_1 AND anon_1.name = :name_2",
- use_default_dialect=True,
- )
-
-
-class DeprecatedMapperTest(_fixtures.FixtureTest, AssertsCompiledSQL):
- __dialect__ = "default"
+ def test_illegal_non_primary_3(self):
+ users, addresses = self.tables.users, self.tables.addresses
- def test_deferred_scalar_loader_name_change(self):
- class Foo:
+ class Base:
pass
- def myloader(*arg, **kw):
+ class Sub(Base):
pass
- instrumentation.register_class(Foo)
- manager = instrumentation.manager_of_class(Foo)
+ self.mapper_registry.map_imperatively(Base, users)
+ assert_raises_message(
+ sa.exc.InvalidRequestError,
+ "Configure a primary mapper first",
+ self.mapper_registry.map_imperatively,
+ Sub,
+ addresses,
+ non_primary=True,
+ )
+
+ def test_illegal_non_primary_legacy(self):
+ users, Address, addresses, User = (
+ self.tables.users,
+ self.classes.Address,
+ self.tables.addresses,
+ self.classes.User,
+ )
with testing.expect_deprecated(
- "The ClassManager.deferred_scalar_loader attribute is now named "
- "expired_attribute_loader"
+ "Calling the mapper.* function directly outside of a declarative "
):
- manager.deferred_scalar_loader = myloader
-
- is_(manager.expired_attribute_loader, myloader)
-
+ mapper(User, users)
with testing.expect_deprecated(
- "The ClassManager.deferred_scalar_loader attribute is now named "
- "expired_attribute_loader"
+ "Calling the mapper.* function directly outside of a declarative "
):
- is_(manager.deferred_scalar_loader, myloader)
-
- def test_polymorphic_union_w_select(self):
- users, addresses = self.tables.users, self.tables.addresses
-
- with DeprecatedQueryTest._expect_implicit_subquery():
- dep = polymorphic_union(
- {"u": users.select(), "a": addresses.select()},
- "type",
- "bcjoin",
+ mapper(Address, addresses)
+ with testing.expect_deprecated(
+ "The mapper.non_primary parameter is deprecated"
+ ):
+ m = mapper( # noqa F841
+ User,
+ users,
+ non_primary=True,
+ properties={"addresses": relationship(Address)},
)
-
- subq_version = polymorphic_union(
- {
- "u": users.select().subquery(),
- "a": addresses.select().subquery(),
- },
- "type",
- "bcjoin",
+ assert_raises_message(
+ sa.exc.ArgumentError,
+ "Attempting to assign a new relationship 'addresses' "
+ "to a non-primary mapper on class 'User'",
+ configure_mappers,
)
- is_true(dep.compare(subq_version))
-
- def test_comparable_column(self):
- users, User = self.tables.users, self.classes.User
-
- class MyComparator(sa.orm.properties.ColumnProperty.Comparator):
- __hash__ = None
-
- def __eq__(self, other):
- # lower case comparison
- return func.lower(self.__clause_element__()) == func.lower(
- other
- )
-
- def intersects(self, other):
- # non-standard comparator
- return self.__clause_element__().op("&=")(other)
- self.mapper_registry.map_imperatively(
- User,
- users,
- properties={
- "name": sa.orm.column_property(
- users.c.name, comparator_factory=MyComparator
- )
- },
- )
+ def test_illegal_non_primary_2_legacy(self):
+ User, users = self.classes.User, self.tables.users
- assert_raises_message(
- AttributeError,
- "Neither 'InstrumentedAttribute' object nor "
- "'MyComparator' object associated with User.name has "
- "an attribute 'nonexistent'",
- getattr,
- User.name,
- "nonexistent",
- )
-
- eq_(
- str(
- (User.name == "ed").compile(
- dialect=sa.engine.default.DefaultDialect()
- )
- ),
- "lower(users.name) = lower(:lower_1)",
- )
- eq_(
- str(
- (User.name.intersects("ed")).compile(
- dialect=sa.engine.default.DefaultDialect()
- )
- ),
- "users.name &= :name_1",
- )
-
- def test_add_property(self):
- users = self.tables.users
-
- assert_col = []
-
- class User(fixtures.ComparableEntity):
- def _get_name(self):
- assert_col.append(("get", self._name))
- return self._name
-
- def _set_name(self, name):
- assert_col.append(("set", name))
- self._name = name
-
- name = property(_get_name, _set_name)
-
- m = self.mapper_registry.map_imperatively(User, users)
-
- m.add_property("_name", deferred(users.c.name))
- m.add_property("name", synonym("_name"))
-
- sess = fixture_session()
- assert sess.get(User, 7)
-
- u = sess.query(User).filter_by(name="jack").one()
-
- def go():
- eq_(u.name, "jack")
- eq_(assert_col, [("get", "jack")], str(assert_col))
-
- self.sql_count_(1, go)
-
-
-class DeprecatedOptionAllTest(OptionsPathTest, _fixtures.FixtureTest):
- run_inserts = "once"
- run_deletes = None
-
- def _mapper_fixture_one(self):
- users, User, addresses, Address, orders, Order = (
- self.tables.users,
- self.classes.User,
- self.tables.addresses,
- self.classes.Address,
- self.tables.orders,
- self.classes.Order,
- )
- keywords, items, item_keywords, Keyword, Item = (
- self.tables.keywords,
- self.tables.items,
- self.tables.item_keywords,
- self.classes.Keyword,
- self.classes.Item,
- )
- self.mapper_registry.map_imperatively(
- User,
- users,
- properties={
- "addresses": relationship(Address),
- "orders": relationship(Order),
- },
- )
- self.mapper_registry.map_imperatively(Address, addresses)
- self.mapper_registry.map_imperatively(
- Order,
- orders,
- properties={
- "items": relationship(Item, secondary=self.tables.order_items)
- },
- )
- self.mapper_registry.map_imperatively(
- Keyword,
- keywords,
- properties={
- "keywords": column_property(keywords.c.name + "some keyword")
- },
- )
- self.mapper_registry.map_imperatively(
- Item,
- items,
- properties=dict(
- keywords=relationship(Keyword, secondary=item_keywords)
- ),
- )
-
- def _assert_eager_with_entity_exception(
- self, entity_list, options, message
- ):
- assert_raises_message(
- sa.exc.ArgumentError,
- message,
- fixture_session()
- .query(*entity_list)
- .options(*options)
- ._compile_context,
- )
-
- def test_defer_addtl_attrs(self):
- users, User, Address, addresses = (
- self.tables.users,
- self.classes.User,
- self.classes.Address,
- self.tables.addresses,
- )
-
- self.mapper_registry.map_imperatively(Address, addresses)
- self.mapper_registry.map_imperatively(
- User,
- users,
- properties={
- "addresses": relationship(
- Address, lazy="selectin", order_by=addresses.c.id
- )
- },
- )
-
- sess = fixture_session()
-
- with testing.expect_deprecated(undefer_needs_chaining):
- sess.query(User).options(
- defer(User.addresses, Address.email_address)
- )
-
- with testing.expect_deprecated(undefer_needs_chaining):
- sess.query(User).options(
- undefer(User.addresses, Address.email_address)
- )
-
-
-class InstrumentationTest(fixtures.ORMTest):
- def test_dict_subclass4(self):
- # tests #2654
- with testing.expect_deprecated(
- r"The collection.converter\(\) handler is deprecated and will "
- "be removed in a future release. Please refer to the "
- "AttributeEvents"
- ):
-
- class MyDict(collections.MappedCollection):
- def __init__(self):
- super(MyDict, self).__init__(lambda value: "k%d" % value)
-
- @collection.converter
- def _convert(self, dictlike):
- for key, value in dictlike.items():
- yield value + 5
-
- class Foo:
- pass
-
- instrumentation.register_class(Foo)
- attributes.register_attribute(
- Foo, "attr", uselist=True, typecallable=MyDict, useobject=True
- )
-
- f = Foo()
- f.attr = {"k1": 1, "k2": 2}
-
- eq_(f.attr, {"k7": 7, "k6": 6})
-
- def test_name_setup(self):
- with testing.expect_deprecated(
- r"The collection.converter\(\) handler is deprecated and will "
- "be removed in a future release. Please refer to the "
- "AttributeEvents"
- ):
-
- class Base:
- @collection.iterator
- def base_iterate(self, x):
- return "base_iterate"
-
- @collection.appender
- def base_append(self, x):
- return "base_append"
-
- @collection.converter
- def base_convert(self, x):
- return "base_convert"
-
- @collection.remover
- def base_remove(self, x):
- return "base_remove"
-
- from sqlalchemy.orm.collections import _instrument_class
-
- _instrument_class(Base)
-
- eq_(Base._sa_remover(Base(), 5), "base_remove")
- eq_(Base._sa_appender(Base(), 5), "base_append")
- eq_(Base._sa_iterator(Base(), 5), "base_iterate")
- eq_(Base._sa_converter(Base(), 5), "base_convert")
-
- with testing.expect_deprecated(
- r"The collection.converter\(\) handler is deprecated and will "
- "be removed in a future release. Please refer to the "
- "AttributeEvents"
- ):
-
- class Sub(Base):
- @collection.converter
- def base_convert(self, x):
- return "sub_convert"
-
- @collection.remover
- def sub_remove(self, x):
- return "sub_remove"
-
- _instrument_class(Sub)
-
- eq_(Sub._sa_appender(Sub(), 5), "base_append")
- eq_(Sub._sa_remover(Sub(), 5), "sub_remove")
- eq_(Sub._sa_iterator(Sub(), 5), "base_iterate")
- eq_(Sub._sa_converter(Sub(), 5), "sub_convert")
-
-
-class NonPrimaryRelationshipLoaderTest(_fixtures.FixtureTest):
- run_inserts = "once"
- run_deletes = None
-
- def test_selectload(self):
- """tests lazy loading with two relationships simultaneously,
- from the same table, using aliases."""
-
- users, orders, User, Address, Order, addresses = (
- self.tables.users,
- self.tables.orders,
- self.classes.User,
- self.classes.Address,
- self.classes.Order,
- self.tables.addresses,
- )
-
- openorders = sa.alias(orders, "openorders")
- closedorders = sa.alias(orders, "closedorders")
-
- self.mapper_registry.map_imperatively(Address, addresses)
-
- self.mapper_registry.map_imperatively(Order, orders)
-
- with testing.expect_deprecated(
- "The mapper.non_primary parameter is deprecated"
- ):
- open_mapper = self.mapper_registry.map_imperatively(
- Order, openorders, non_primary=True
- )
- closed_mapper = self.mapper_registry.map_imperatively(
- Order, closedorders, non_primary=True
- )
- self.mapper_registry.map_imperatively(
- User,
- users,
- properties=dict(
- addresses=relationship(Address, lazy=True),
- open_orders=relationship(
- open_mapper,
- primaryjoin=sa.and_(
- openorders.c.isopen == 1,
- users.c.id == openorders.c.user_id,
- ),
- lazy="select",
- ),
- closed_orders=relationship(
- closed_mapper,
- primaryjoin=sa.and_(
- closedorders.c.isopen == 0,
- users.c.id == closedorders.c.user_id,
- ),
- lazy="select",
- ),
- ),
- )
-
- self._run_double_test(10)
-
- def test_joinedload(self):
- """Eager loading with two relationships simultaneously,
- from the same table, using aliases."""
-
- users, orders, User, Address, Order, addresses = (
- self.tables.users,
- self.tables.orders,
- self.classes.User,
- self.classes.Address,
- self.classes.Order,
- self.tables.addresses,
- )
-
- openorders = sa.alias(orders, "openorders")
- closedorders = sa.alias(orders, "closedorders")
-
- self.mapper_registry.map_imperatively(Address, addresses)
- self.mapper_registry.map_imperatively(Order, orders)
-
- with testing.expect_deprecated(
- "The mapper.non_primary parameter is deprecated"
- ):
- open_mapper = self.mapper_registry.map_imperatively(
- Order, openorders, non_primary=True
- )
- closed_mapper = self.mapper_registry.map_imperatively(
- Order, closedorders, non_primary=True
- )
-
- self.mapper_registry.map_imperatively(
- User,
- users,
- properties=dict(
- addresses=relationship(
- Address, lazy="joined", order_by=addresses.c.id
- ),
- open_orders=relationship(
- open_mapper,
- primaryjoin=sa.and_(
- openorders.c.isopen == 1,
- users.c.id == openorders.c.user_id,
- ),
- lazy="joined",
- order_by=openorders.c.id,
- ),
- closed_orders=relationship(
- closed_mapper,
- primaryjoin=sa.and_(
- closedorders.c.isopen == 0,
- users.c.id == closedorders.c.user_id,
- ),
- lazy="joined",
- order_by=closedorders.c.id,
- ),
- ),
- )
- self._run_double_test(1)
-
- def test_selectin(self):
-
- users, orders, User, Address, Order, addresses = (
- self.tables.users,
- self.tables.orders,
- self.classes.User,
- self.classes.Address,
- self.classes.Order,
- self.tables.addresses,
- )
-
- openorders = sa.alias(orders, "openorders")
- closedorders = sa.alias(orders, "closedorders")
-
- self.mapper_registry.map_imperatively(Address, addresses)
- self.mapper_registry.map_imperatively(Order, orders)
-
- with testing.expect_deprecated(
- "The mapper.non_primary parameter is deprecated"
- ):
- open_mapper = self.mapper_registry.map_imperatively(
- Order, openorders, non_primary=True
- )
- closed_mapper = self.mapper_registry.map_imperatively(
- Order, closedorders, non_primary=True
- )
-
- self.mapper_registry.map_imperatively(
- User,
- users,
- properties=dict(
- addresses=relationship(
- Address, lazy="selectin", order_by=addresses.c.id
- ),
- open_orders=relationship(
- open_mapper,
- primaryjoin=sa.and_(
- openorders.c.isopen == 1,
- users.c.id == openorders.c.user_id,
- ),
- lazy="selectin",
- order_by=openorders.c.id,
- ),
- closed_orders=relationship(
- closed_mapper,
- primaryjoin=sa.and_(
- closedorders.c.isopen == 0,
- users.c.id == closedorders.c.user_id,
- ),
- lazy="selectin",
- order_by=closedorders.c.id,
- ),
- ),
- )
-
- self._run_double_test(4)
-
- def test_subqueryload(self):
-
- users, orders, User, Address, Order, addresses = (
- self.tables.users,
- self.tables.orders,
- self.classes.User,
- self.classes.Address,
- self.classes.Order,
- self.tables.addresses,
- )
-
- openorders = sa.alias(orders, "openorders")
- closedorders = sa.alias(orders, "closedorders")
-
- self.mapper_registry.map_imperatively(Address, addresses)
- self.mapper_registry.map_imperatively(Order, orders)
-
- with testing.expect_deprecated(
- "The mapper.non_primary parameter is deprecated"
- ):
- open_mapper = self.mapper_registry.map_imperatively(
- Order, openorders, non_primary=True
- )
- closed_mapper = self.mapper_registry.map_imperatively(
- Order, closedorders, non_primary=True
- )
-
- self.mapper_registry.map_imperatively(
- User,
- users,
- properties=dict(
- addresses=relationship(
- Address, lazy="subquery", order_by=addresses.c.id
- ),
- open_orders=relationship(
- open_mapper,
- primaryjoin=sa.and_(
- openorders.c.isopen == 1,
- users.c.id == openorders.c.user_id,
- ),
- lazy="subquery",
- order_by=openorders.c.id,
- ),
- closed_orders=relationship(
- closed_mapper,
- primaryjoin=sa.and_(
- closedorders.c.isopen == 0,
- users.c.id == closedorders.c.user_id,
- ),
- lazy="subquery",
- order_by=closedorders.c.id,
- ),
- ),
- )
-
- self._run_double_test(4)
-
- def _run_double_test(self, count):
- User, Address, Order, Item = self.classes(
- "User", "Address", "Order", "Item"
- )
- q = fixture_session().query(User).order_by(User.id)
-
- def go():
- eq_(
- [
- User(
- id=7,
- addresses=[Address(id=1)],
- open_orders=[Order(id=3)],
- closed_orders=[Order(id=1), Order(id=5)],
- ),
- User(
- id=8,
- addresses=[
- Address(id=2),
- Address(id=3),
- Address(id=4),
- ],
- open_orders=[],
- closed_orders=[],
- ),
- User(
- id=9,
- addresses=[Address(id=5)],
- open_orders=[Order(id=4)],
- closed_orders=[Order(id=2)],
- ),
- User(id=10),
- ],
- q.all(),
- )
-
- self.assert_sql_count(testing.db, go, count)
-
- sess = fixture_session()
- user = sess.get(User, 7)
-
- closed_mapper = User.closed_orders.entity
- open_mapper = User.open_orders.entity
- eq_(
- [Order(id=1), Order(id=5)],
- fixture_session()
- .query(closed_mapper)
- .filter(with_parent(user, User.closed_orders))
- .all(),
- )
- eq_(
- [Order(id=3)],
- fixture_session()
- .query(open_mapper)
- .filter(with_parent(user, User.open_orders))
- .all(),
- )
-
-
-class ViewonlyFlagWarningTest(fixtures.MappedTest):
- """test for #4993.
-
- In 1.4, this moves to test/orm/test_cascade, deprecation warnings
- become errors, will then be for #4994.
-
- """
-
- @classmethod
- def define_tables(cls, metadata):
- Table(
- "users",
- metadata,
- Column("id", Integer, primary_key=True),
- Column("name", String(30)),
- )
- Table(
- "orders",
- metadata,
- Column("id", Integer, primary_key=True),
- Column("user_id", Integer),
- Column("description", String(30)),
- )
-
- @classmethod
- def setup_classes(cls):
- class User(cls.Comparable):
- pass
-
- class Order(cls.Comparable):
- pass
-
- @testing.combinations(
- ("passive_deletes", True),
- ("passive_updates", False),
- ("enable_typechecks", False),
- ("active_history", True),
- ("cascade_backrefs", False),
- )
- def test_viewonly_warning(self, flag, value):
- Order = self.classes.Order
-
- with testing.expect_warnings(
- r"Setting %s on relationship\(\) while also setting "
- "viewonly=True does not make sense" % flag
- ):
- kw = {
- "viewonly": True,
- "primaryjoin": self.tables.users.c.id
- == foreign(self.tables.orders.c.user_id),
- }
- kw[flag] = value
- rel = relationship(Order, **kw)
-
- eq_(getattr(rel, flag), value)
-
-
-class NonPrimaryMapperTest(_fixtures.FixtureTest, AssertsCompiledSQL):
- __dialect__ = "default"
-
- def teardown_test(self):
- clear_mappers()
-
- def test_non_primary_identity_class(self):
- User = self.classes.User
- users, addresses = self.tables.users, self.tables.addresses
-
- class AddressUser(User):
- pass
-
- self.mapper_registry.map_imperatively(
- User, users, polymorphic_identity="user"
- )
- m2 = self.mapper_registry.map_imperatively(
- AddressUser,
- addresses,
- inherits=User,
- polymorphic_identity="address",
- properties={"address_id": addresses.c.id},
- )
- with testing.expect_deprecated(
- "The mapper.non_primary parameter is deprecated"
- ):
- m3 = self.mapper_registry.map_imperatively(
- AddressUser, addresses, non_primary=True
- )
- assert m3._identity_class is m2._identity_class
- eq_(
- m2.identity_key_from_instance(AddressUser()),
- m3.identity_key_from_instance(AddressUser()),
- )
-
- def test_illegal_non_primary(self):
- users, Address, addresses, User = (
- self.tables.users,
- self.classes.Address,
- self.tables.addresses,
- self.classes.User,
- )
-
- self.mapper_registry.map_imperatively(User, users)
- self.mapper_registry.map_imperatively(Address, addresses)
- with testing.expect_deprecated(
- "The mapper.non_primary parameter is deprecated"
- ):
- m = self.mapper_registry.map_imperatively( # noqa F841
- User,
- users,
- non_primary=True,
- properties={"addresses": relationship(Address)},
- )
- assert_raises_message(
- sa.exc.ArgumentError,
- "Attempting to assign a new relationship 'addresses' "
- "to a non-primary mapper on class 'User'",
- configure_mappers,
- )
-
- def test_illegal_non_primary_2(self):
- User, users = self.classes.User, self.tables.users
-
- assert_raises_message(
- sa.exc.InvalidRequestError,
- "Configure a primary mapper first",
- self.mapper_registry.map_imperatively,
- User,
- users,
- non_primary=True,
- )
-
- def test_illegal_non_primary_3(self):
- users, addresses = self.tables.users, self.tables.addresses
-
- class Base:
- pass
-
- class Sub(Base):
- pass
-
- self.mapper_registry.map_imperatively(Base, users)
- assert_raises_message(
- sa.exc.InvalidRequestError,
- "Configure a primary mapper first",
- self.mapper_registry.map_imperatively,
- Sub,
- addresses,
- non_primary=True,
- )
-
- def test_illegal_non_primary_legacy(self):
- users, Address, addresses, User = (
- self.tables.users,
- self.classes.Address,
- self.tables.addresses,
- self.classes.User,
- )
-
- with testing.expect_deprecated(
- "Calling the mapper.* function directly outside of a declarative "
- ):
- mapper(User, users)
- with testing.expect_deprecated(
- "Calling the mapper.* function directly outside of a declarative "
- ):
- mapper(Address, addresses)
- with testing.expect_deprecated(
- "The mapper.non_primary parameter is deprecated"
- ):
- m = mapper( # noqa F841
- User,
- users,
- non_primary=True,
- properties={"addresses": relationship(Address)},
- )
- assert_raises_message(
- sa.exc.ArgumentError,
- "Attempting to assign a new relationship 'addresses' "
- "to a non-primary mapper on class 'User'",
- configure_mappers,
- )
-
- def test_illegal_non_primary_2_legacy(self):
- User, users = self.classes.User, self.tables.users
-
- with testing.expect_deprecated(
- "The mapper.non_primary parameter is deprecated"
- ):
- assert_raises_message(
- sa.exc.InvalidRequestError,
- "Configure a primary mapper first",
- mapper,
- User,
- users,
- non_primary=True,
- )
-
- def test_illegal_non_primary_3_legacy(self):
- users, addresses = self.tables.users, self.tables.addresses
-
- class Base:
- pass
-
- class Sub(Base):
- pass
-
- with testing.expect_deprecated(
- "Calling the mapper.* function directly outside of a declarative "
- ):
- mapper(Base, users)
- with testing.expect_deprecated(
- "The mapper.non_primary parameter is deprecated",
- ):
- assert_raises_message(
- sa.exc.InvalidRequestError,
- "Configure a primary mapper first",
- mapper,
- Sub,
- addresses,
- non_primary=True,
- )
-
-
-class InstancesTest(QueryTest, AssertsCompiledSQL):
- @testing.fails(
- "ORM refactor not allowing this yet, "
- "we may just abandon this use case"
- )
- def test_from_alias_one(self):
- User, addresses, users = (
- self.classes.User,
- self.tables.addresses,
- self.tables.users,
- )
-
- query = (
- users.select(users.c.id == 7)
- .union(users.select(users.c.id > 7))
- .alias("ulist")
- .outerjoin(addresses)
- .select(order_by=[text("ulist.id"), addresses.c.id])
- )
- sess = fixture_session()
- q = sess.query(User)
-
- # note this has multiple problems because we aren't giving Query
- # the statement where it would be able to create an adapter
- def go():
- with testing.expect_deprecated(
- r"Using the Query.instances\(\) method without a context",
- "Retrieving row values using Column objects with only "
- "matching names",
- ):
- result = list(
- q.options(
- contains_alias("ulist"), contains_eager("addresses")
- ).instances(query.execute())
- )
- assert self.static.user_address_result == result
-
- self.assert_sql_count(testing.db, go, 1)
-
- def test_from_alias_two_old_way(self):
- User, addresses, users = (
- self.classes.User,
- self.tables.addresses,
- self.tables.users,
- )
-
- query = (
- users.select()
- .where(users.c.id == 7)
- .union(users.select().where(users.c.id > 7))
- .alias("ulist")
- .outerjoin(addresses)
- .select()
- .order_by(text("ulist.id"), addresses.c.id)
- )
- sess = fixture_session()
- q = sess.query(User)
-
- def go():
- with testing.expect_deprecated(
- "The AliasOption is not necessary for entities to be "
- "matched up to a query"
- ):
- result = (
- q.options(
- contains_alias("ulist"), contains_eager(User.addresses)
- )
- .from_statement(query)
- .all()
- )
- assert self.static.user_address_result == result
-
- self.assert_sql_count(testing.db, go, 1)
-
- def test_contains_eager(self):
- users, addresses, User = (
- self.tables.users,
- self.tables.addresses,
- self.classes.User,
- )
-
- sess = fixture_session()
-
- selectquery = (
- users.outerjoin(addresses)
- .select()
- .where(users.c.id < 10)
- .order_by(users.c.id, addresses.c.id)
- )
- q = sess.query(User)
-
- def go():
- with testing.expect_deprecated(
- r"Using the Query.instances\(\) method without a context"
- ):
- result = list(
- q.options(contains_eager(User.addresses)).instances(
- sess.execute(selectquery)
- )
- )
- assert self.static.user_address_result[0:3] == result
-
- self.assert_sql_count(testing.db, go, 1)
-
- sess.expunge_all()
-
- def go():
- with testing.expect_deprecated(
- r"Using the Query.instances\(\) method without a context"
- ):
- result = list(
- q.options(contains_eager(User.addresses)).instances(
- sess.connection().execute(selectquery)
- )
- )
- assert self.static.user_address_result[0:3] == result
-
- self.assert_sql_count(testing.db, go, 1)
-
- def test_contains_eager_aliased_instances(self):
- addresses, users, User = (
- self.tables.addresses,
- self.tables.users,
- self.classes.User,
- )
-
- sess = fixture_session()
- q = sess.query(User)
-
- adalias = addresses.alias("adalias")
- selectquery = (
- users.outerjoin(adalias)
- .select()
- .order_by(users.c.id, adalias.c.id)
- )
-
- # note this has multiple problems because we aren't giving Query
- # the statement where it would be able to create an adapter
- def go():
- with testing.expect_deprecated(
- r"Using the Query.instances\(\) method without a context"
- ):
- result = list(
- q.options(
- contains_eager(User.addresses, alias=adalias)
- ).instances(sess.connection().execute(selectquery))
- )
- assert self.static.user_address_result == result
-
- self.assert_sql_count(testing.db, go, 1)
-
- def test_contains_eager_multi_alias(self):
- orders, items, users, order_items, User = (
- self.tables.orders,
- self.tables.items,
- self.tables.users,
- self.tables.order_items,
- self.classes.User,
- )
-
- Order = self.classes.Order
-
- sess = fixture_session()
- q = sess.query(User)
-
- oalias = orders.alias("o1")
- ialias = items.alias("i1")
- query = (
- users.outerjoin(oalias)
- .outerjoin(order_items)
- .outerjoin(ialias)
- .select()
- .order_by(users.c.id, oalias.c.id, ialias.c.id)
- )
-
- # test using Alias with more than one level deep
-
- # new way:
- # from sqlalchemy.orm.strategy_options import Load
- # opt = Load(User).contains_eager('orders', alias=oalias).
- # contains_eager('items', alias=ialias)
-
- def go():
- with testing.expect_deprecated(
- r"Using the Query.instances\(\) method without a context"
- ):
- result = list(
- q.options(
- contains_eager(User.orders, alias=oalias),
- defaultload(User.orders).contains_eager(
- Order.items, alias=ialias
- ),
- ).instances(sess.connection().execute(query))
- )
- assert self.static.user_order_result == result
-
- self.assert_sql_count(testing.db, go, 1)
-
-
-class TextTest(QueryTest):
- def test_via_textasfrom_select_from(self):
- User = self.classes.User
- s = fixture_session()
-
- with assertions.expect_deprecated_20(sef_dep):
- eq_(
- s.query(User)
- .select_entity_from(
- text("select * from users")
- .columns(User.id, User.name)
- .subquery()
- )
- .order_by(User.id)
- .all(),
- [User(id=7), User(id=8), User(id=9), User(id=10)],
- )
-
-
-class TestDeprecation20(QueryTest):
- def test_relation(self):
- User = self.classes.User
- with testing.expect_deprecated_20(".*relationship"):
- relation(User.addresses)
-
- def test_eagerloading(self):
- User = self.classes.User
- with testing.expect_deprecated_20(".*joinedload"):
- eagerload(User.addresses)
-
-
-class DistinctOrderByImplicitTest(QueryTest, AssertsCompiledSQL):
- __dialect__ = "default"
-
- def test_columns_augmented_roundtrip_three(self):
- User, Address = self.classes.User, self.classes.Address
-
- sess = fixture_session()
-
- q = (
- sess.query(User.id, User.name.label("foo"), Address.id)
- .join(Address, true())
- .filter(User.name == "jack")
- .filter(User.id + Address.user_id > 0)
- .distinct()
- .order_by(User.id, User.name, Address.email_address)
- )
-
- # even though columns are added, they aren't in the result
- with testing.expect_deprecated(
- "ORDER BY columns added implicitly due to "
- ):
- eq_(
- q.all(),
- [
- (7, "jack", 3),
- (7, "jack", 4),
- (7, "jack", 2),
- (7, "jack", 5),
- (7, "jack", 1),
- ],
- )
- for row in q:
- eq_(row._mapping.keys(), ["id", "foo", "id"])
-
- def test_columns_augmented_sql_one(self):
- User, Address = self.classes.User, self.classes.Address
-
- sess = fixture_session()
-
- q = (
- sess.query(User.id, User.name.label("foo"), Address.id)
- .distinct()
- .order_by(User.id, User.name, Address.email_address)
- )
-
- # Address.email_address is added because of DISTINCT,
- # however User.id, User.name are not b.c. they're already there,
- # even though User.name is labeled
- with testing.expect_deprecated(
- "ORDER BY columns added implicitly due to "
- ):
- self.assert_compile(
- q,
- "SELECT DISTINCT users.id AS users_id, users.name AS foo, "
- "addresses.id AS addresses_id, addresses.email_address AS "
- "addresses_email_address FROM users, addresses "
- "ORDER BY users.id, users.name, addresses.email_address",
- )
-
-
-class SessionEventsTest(_RemoveListeners, _fixtures.FixtureTest):
- run_inserts = None
-
- def test_on_bulk_update_hook(self):
- User, users = self.classes.User, self.tables.users
-
- sess = fixture_session()
- canary = Mock()
-
- event.listen(sess, "after_bulk_update", canary.after_bulk_update)
-
- def legacy(ses, qry, ctx, res):
- canary.after_bulk_update_legacy(ses, qry, ctx, res)
-
- event.listen(sess, "after_bulk_update", legacy)
-
- self.mapper_registry.map_imperatively(User, users)
-
- with testing.expect_deprecated(
- 'The argument signature for the "SessionEvents.after_bulk_update" '
- "event listener"
- ):
- sess.query(User).update({"name": "foo"})
-
- eq_(canary.after_bulk_update.call_count, 1)
-
- upd = canary.after_bulk_update.mock_calls[0][1][0]
- eq_(upd.session, sess)
- eq_(
- canary.after_bulk_update_legacy.mock_calls,
- [call(sess, upd.query, None, upd.result)],
- )
-
- def test_on_bulk_delete_hook(self):
- User, users = self.classes.User, self.tables.users
-
- sess = fixture_session()
- canary = Mock()
-
- event.listen(sess, "after_bulk_delete", canary.after_bulk_delete)
-
- def legacy(ses, qry, ctx, res):
- canary.after_bulk_delete_legacy(ses, qry, ctx, res)
-
- event.listen(sess, "after_bulk_delete", legacy)
-
- self.mapper_registry.map_imperatively(User, users)
-
- with testing.expect_deprecated(
- 'The argument signature for the "SessionEvents.after_bulk_delete" '
- "event listener"
- ):
- sess.query(User).delete()
-
- eq_(canary.after_bulk_delete.call_count, 1)
-
- upd = canary.after_bulk_delete.mock_calls[0][1][0]
- eq_(upd.session, sess)
- eq_(
- canary.after_bulk_delete_legacy.mock_calls,
- [call(sess, upd.query, None, upd.result)],
- )
-
-
-class ImmediateTest(_fixtures.FixtureTest):
- run_inserts = "once"
- run_deletes = None
-
- @classmethod
- def setup_mappers(cls):
- Address, addresses, users, User = (
- cls.classes.Address,
- cls.tables.addresses,
- cls.tables.users,
- cls.classes.User,
- )
-
- cls.mapper_registry.map_imperatively(Address, addresses)
-
- cls.mapper_registry.map_imperatively(
- User, users, properties=dict(addresses=relationship(Address))
- )
-
- def test_value(self):
- User = self.classes.User
-
- sess = fixture_session()
-
- with testing.expect_deprecated(r"Query.value\(\) is deprecated"):
- eq_(sess.query(User).filter_by(id=7).value(User.id), 7)
- with testing.expect_deprecated(r"Query.value\(\) is deprecated"):
- eq_(
- sess.query(User.id, User.name).filter_by(id=7).value(User.id),
- 7,
- )
- with testing.expect_deprecated(r"Query.value\(\) is deprecated"):
- eq_(sess.query(User).filter_by(id=0).value(User.id), None)
-
- sess.bind = testing.db
- with testing.expect_deprecated(r"Query.value\(\) is deprecated"):
- eq_(sess.query().value(sa.literal_column("1").label("x")), 1)
-
- def test_value_cancels_loader_opts(self):
- User = self.classes.User
-
- sess = fixture_session()
-
- q = (
- sess.query(User)
- .filter(User.name == "ed")
- .options(joinedload(User.addresses))
- )
-
- with testing.expect_deprecated(r"Query.value\(\) is deprecated"):
- q = q.value(func.count(literal_column("*")))
-
-
-class MixedEntitiesTest(QueryTest, AssertsCompiledSQL):
- __dialect__ = "default"
-
- def test_values(self):
- Address, users, User = (
- self.classes.Address,
- self.tables.users,
- self.classes.User,
- )
-
- sess = fixture_session()
-
- with testing.expect_deprecated(r"Query.values?\(\) is deprecated"):
- assert list(sess.query(User).values()) == list()
-
- sel = users.select().where(User.id.in_([7, 8])).alias()
- q = sess.query(User)
- with testing.expect_deprecated(r"Query.values?\(\) is deprecated"):
- q2 = q.select_entity_from(sel).values(User.name)
- eq_(list(q2), [("jack",), ("ed",)])
-
- q = sess.query(User)
-
- with testing.expect_deprecated(r"Query.values?\(\) is deprecated"):
- q2 = q.order_by(User.id).values(
- User.name, User.name + " " + cast(User.id, String(50))
- )
- eq_(
- list(q2),
- [
- ("jack", "jack 7"),
- ("ed", "ed 8"),
- ("fred", "fred 9"),
- ("chuck", "chuck 10"),
- ],
- )
-
- with testing.expect_deprecated(r"Query.values?\(\) is deprecated"):
- q2 = (
- q.join(User.addresses)
- .filter(User.name.like("%e%"))
- .order_by(User.id, Address.id)
- .values(User.name, Address.email_address)
- )
- eq_(
- list(q2),
- [
- ("ed", "ed@wood.com"),
- ("ed", "ed@bettyboop.com"),
- ("ed", "ed@lala.com"),
- ("fred", "fred@fred.com"),
- ],
- )
-
- with testing.expect_deprecated(r"Query.values?\(\) is deprecated"):
- q2 = (
- q.join(User.addresses)
- .filter(User.name.like("%e%"))
- .order_by(desc(Address.email_address))
- .slice(1, 3)
- .values(User.name, Address.email_address)
- )
- eq_(list(q2), [("ed", "ed@wood.com"), ("ed", "ed@lala.com")])
-
- adalias = aliased(Address)
- with testing.expect_deprecated(r"Query.values?\(\) is deprecated"):
- q2 = (
- q.join(adalias, User.addresses)
- .filter(User.name.like("%e%"))
- .order_by(adalias.email_address)
- .values(User.name, adalias.email_address)
- )
- eq_(
- list(q2),
- [
- ("ed", "ed@bettyboop.com"),
- ("ed", "ed@lala.com"),
- ("ed", "ed@wood.com"),
- ("fred", "fred@fred.com"),
- ],
- )
-
- with testing.expect_deprecated(r"Query.values?\(\) is deprecated"):
- q2 = q.values(func.count(User.name))
- assert next(q2) == (4,)
-
- with testing.expect_deprecated(r"Query.values?\(\) is deprecated"):
- q2 = (
- q.select_entity_from(sel)
- .filter(User.id == 8)
- .values(User.name, sel.c.name, User.name)
- )
- eq_(list(q2), [("ed", "ed", "ed")])
-
- # using User.xxx is alised against "sel", so this query returns nothing
- with testing.expect_deprecated(r"Query.values?\(\) is deprecated"):
- q2 = (
- q.select_entity_from(sel)
- .filter(User.id == 8)
- .filter(User.id > sel.c.id)
- .values(User.name, sel.c.name, User.name)
- )
- eq_(list(q2), [])
-
- # whereas this uses users.c.xxx, is not aliased and creates a new join
- with testing.expect_deprecated(r"Query.values?\(\) is deprecated"):
- q2 = (
- q.select_entity_from(sel)
- .filter(users.c.id == 8)
- .filter(users.c.id > sel.c.id)
- .values(users.c.name, sel.c.name, User.name)
- )
- eq_(list(q2), [("ed", "jack", "jack")])
-
- @testing.fails_on("mssql", "FIXME: unknown")
- def test_values_specific_order_by(self):
- users, User = self.tables.users, self.classes.User
-
- sess = fixture_session()
-
- with testing.expect_deprecated(r"Query.values?\(\) is deprecated"):
- assert list(sess.query(User).values()) == list()
-
- sel = users.select().where(User.id.in_([7, 8])).alias()
- q = sess.query(User)
- u2 = aliased(User)
- with testing.expect_deprecated(r"Query.values?\(\) is deprecated"):
- q2 = (
- q.select_entity_from(sel)
- .filter(u2.id > 1)
- .filter(or_(u2.id == User.id, u2.id != User.id))
- .order_by(User.id, sel.c.id, u2.id)
- .values(User.name, sel.c.name, u2.name)
- )
- eq_(
- list(q2),
- [
- ("jack", "jack", "jack"),
- ("jack", "jack", "ed"),
- ("jack", "jack", "fred"),
- ("jack", "jack", "chuck"),
- ("ed", "ed", "jack"),
- ("ed", "ed", "ed"),
- ("ed", "ed", "fred"),
- ("ed", "ed", "chuck"),
- ],
- )
-
- @testing.fails_on("mssql", "FIXME: unknown")
- @testing.fails_on(
- "oracle", "Oracle doesn't support boolean expressions as " "columns"
- )
- @testing.fails_on(
- "postgresql+pg8000",
- "pg8000 parses the SQL itself before passing on "
- "to PG, doesn't parse this",
- )
- @testing.fails_on(
- "postgresql+asyncpg",
- "Asyncpg uses preprated statements that are not compatible with how "
- "sqlalchemy passes the query. Fails with "
- 'ERROR: column "users.name" must appear in the GROUP BY clause'
- " or be used in an aggregate function",
- )
- def test_values_with_boolean_selects(self):
- """Tests a values clause that works with select boolean
- evaluations"""
-
- User = self.classes.User
-
- sess = fixture_session()
-
- q = sess.query(User)
- with testing.expect_deprecated(r"Query.values?\(\) is deprecated"):
- q2 = (
- q.group_by(User.name.like("%j%"))
- .order_by(desc(User.name.like("%j%")))
- .values(
- User.name.like("%j%"), func.count(User.name.like("%j%"))
- )
- )
- eq_(list(q2), [(True, 1), (False, 3)])
-
- with testing.expect_deprecated(r"Query.values?\(\) is deprecated"):
- q2 = q.order_by(desc(User.name.like("%j%"))).values(
- User.name.like("%j%")
- )
- eq_(list(q2), [(True,), (False,), (False,), (False,)])
-
-
-class JoinTest(QueryTest, AssertsCompiledSQL):
- __dialect__ = "default"
-
- def test_orderby_arg_bug(self):
- User, users, Order = (
- self.classes.User,
- self.tables.users,
- self.classes.Order,
- )
-
- sess = fixture_session()
- # no arg error
- with testing.expect_deprecated_20(join_aliased_dep):
- (
- sess.query(User)
- .join(User.orders, aliased=True)
- .order_by(Order.id)
- .reset_joinpoint()
- .order_by(users.c.id)
- .all()
- )
-
- def test_does_filter_aliasing_work(self):
- User, Address = self.classes("User", "Address")
-
- s = fixture_session()
-
- # aliased=True is to be deprecated, other filter lambdas
- # that go into effect include polymorphic filtering.
- with testing.expect_deprecated(join_aliased_dep):
- q = (
- s.query(lambda: User)
- .join(lambda: User.addresses, aliased=True)
- .filter(lambda: Address.email_address == "foo")
- )
- self.assert_compile(
- q,
- "SELECT users.id AS users_id, users.name AS users_name "
- "FROM users JOIN addresses AS addresses_1 "
- "ON users.id = addresses_1.user_id "
- "WHERE addresses_1.email_address = :email_address_1",
- )
-
- def test_multi_tuple_form_legacy_one(self):
- """test the 'tuple' form of join, now superseded
- by the two-element join() form.
-
-
- """
-
- Order, User = (
- self.classes.Order,
- self.classes.User,
- )
-
- sess = fixture_session()
-
- with testing.expect_deprecated(join_tuple_form):
- q = (
- sess.query(User)
- .join((Order, User.id == Order.user_id))
- .filter_by(description="foo")
- )
- self.assert_compile(
- q,
- "SELECT users.id AS users_id, users.name AS users_name "
- "FROM users JOIN orders ON users.id = orders.user_id "
- "WHERE orders.description = :description_1",
- )
-
- def test_multi_tuple_form_legacy_two(self):
- """test the 'tuple' form of join, now superseded
- by the two-element join() form.
-
-
- """
-
- Item, Order, User = (
- self.classes.Item,
- self.classes.Order,
- self.classes.User,
- )
-
- sess = fixture_session()
-
- with testing.expect_deprecated_20(join_tuple_form):
- q = (
- sess.query(User)
- .join((Order, User.id == Order.user_id), (Item, Order.items))
- .filter_by(description="foo")
- )
- self.assert_compile(
- q,
- "SELECT users.id AS users_id, users.name AS users_name "
- "FROM users JOIN orders ON users.id = orders.user_id "
- "JOIN order_items AS order_items_1 ON orders.id = "
- "order_items_1.order_id JOIN items ON items.id = "
- "order_items_1.item_id WHERE items.description = :description_1",
- )
-
- def test_single_prop_5(self):
- (
- Order,
- User,
- ) = (self.classes.Order, self.classes.User)
-
- sess = fixture_session()
- with testing.expect_deprecated_20(join_chain_dep):
- self.assert_compile(
- sess.query(User).join(User.orders, Order.items),
- "SELECT users.id AS users_id, users.name AS users_name "
- "FROM users "
- "JOIN orders ON users.id = orders.user_id "
- "JOIN order_items AS order_items_1 "
- "ON orders.id = order_items_1.order_id JOIN items "
- "ON items.id = order_items_1.item_id",
- )
-
- def test_single_prop_7(self):
- Order, User = (self.classes.Order, self.classes.User)
-
- sess = fixture_session()
- # this query is somewhat nonsensical. the old system didn't render a
- # correct query for this. In this case its the most faithful to what
- # was asked - there's no linkage between User.orders and "oalias",
- # so two FROM elements are generated.
- oalias = aliased(Order)
- with testing.expect_deprecated_20(join_chain_dep):
- self.assert_compile(
- sess.query(User).join(User.orders, oalias.items),
- "SELECT users.id AS users_id, users.name AS users_name "
- "FROM users "
- "JOIN orders ON users.id = orders.user_id, "
- "orders AS orders_1 JOIN order_items AS order_items_1 "
- "ON orders_1.id = order_items_1.order_id "
- "JOIN items ON items.id = order_items_1.item_id",
- )
-
- def test_single_prop_8(self):
- (
- Order,
- User,
- ) = (self.classes.Order, self.classes.User)
-
- sess = fixture_session()
- # same as before using an aliased() for User as well
- ualias = aliased(User)
- oalias = aliased(Order)
- with testing.expect_deprecated_20(join_chain_dep):
- self.assert_compile(
- sess.query(ualias).join(ualias.orders, oalias.items),
- "SELECT users_1.id AS users_1_id, users_1.name "
- "AS users_1_name "
- "FROM users AS users_1 "
- "JOIN orders ON users_1.id = orders.user_id, "
- "orders AS orders_1 JOIN order_items AS order_items_1 "
- "ON orders_1.id = order_items_1.order_id "
- "JOIN items ON items.id = order_items_1.item_id",
- )
-
- def test_single_prop_10(self):
- User, Address = (self.classes.User, self.classes.Address)
-
- sess = fixture_session()
- with testing.expect_deprecated_20(join_aliased_dep):
- self.assert_compile(
- sess.query(User)
- .join(User.addresses, aliased=True)
- .filter(Address.email_address == "foo"),
- "SELECT users.id AS users_id, users.name AS users_name "
- "FROM users JOIN addresses AS addresses_1 "
- "ON users.id = addresses_1.user_id "
- "WHERE addresses_1.email_address = :email_address_1",
- )
-
- def test_single_prop_11(self):
- Item, Order, User, = (
- self.classes.Item,
- self.classes.Order,
- self.classes.User,
- )
-
- sess = fixture_session()
- with testing.expect_deprecated_20(join_aliased_dep, join_chain_dep):
- self.assert_compile(
- sess.query(User)
- .join(User.orders, Order.items, aliased=True)
- .filter(Item.id == 10),
- "SELECT users.id AS users_id, users.name AS users_name "
- "FROM users JOIN orders AS orders_1 "
- "ON users.id = orders_1.user_id "
- "JOIN order_items AS order_items_1 "
- "ON orders_1.id = order_items_1.order_id "
- "JOIN items AS items_1 ON items_1.id = order_items_1.item_id "
- "WHERE items_1.id = :id_1",
- )
-
- def test_multiple_adaption(self):
- Item, Order, User = (
- self.classes.Item,
- self.classes.Order,
- self.classes.User,
- )
-
- sess = fixture_session()
-
- with testing.expect_deprecated_20(join_chain_dep, join_aliased_dep):
- self.assert_compile(
- sess.query(User)
- .join(User.orders, Order.items, aliased=True)
- .filter(Order.id == 7)
- .filter(Item.id == 8),
- "SELECT users.id AS users_id, users.name AS users_name "
- "FROM users "
- "JOIN orders AS orders_1 "
- "ON users.id = orders_1.user_id JOIN order_items AS "
- "order_items_1 "
- "ON orders_1.id = order_items_1.order_id "
- "JOIN items AS items_1 ON items_1.id = order_items_1.item_id "
- "WHERE orders_1.id = :id_1 AND items_1.id = :id_2",
- use_default_dialect=True,
- )
-
- def test_onclause_conditional_adaption(self):
- Item, Order, orders, order_items, User = (
- self.classes.Item,
- self.classes.Order,
- self.tables.orders,
- self.tables.order_items,
- self.classes.User,
- )
-
- sess = fixture_session()
-
- # this is now a very weird test, nobody should really
- # be using the aliased flag in this way.
- with testing.expect_deprecated_20(join_aliased_dep):
- self.assert_compile(
- sess.query(User)
- .join(User.orders, aliased=True)
- .join(
- Item,
- and_(
- Order.id == order_items.c.order_id,
- order_items.c.item_id == Item.id,
- ),
- from_joinpoint=True,
- aliased=True,
- ),
- "SELECT users.id AS users_id, users.name AS users_name "
- "FROM users "
- "JOIN orders AS orders_1 ON users.id = orders_1.user_id "
- "JOIN items AS items_1 "
- "ON orders_1.id = order_items.order_id "
- "AND order_items.item_id = items_1.id",
- use_default_dialect=True,
- )
-
- # nothing is deprecated here but it is comparing to the above
- # that nothing is adapted.
- oalias = aliased(Order, orders.select().subquery())
- self.assert_compile(
- sess.query(User)
- .join(oalias, User.orders)
- .join(
- Item,
- and_(
- oalias.id == order_items.c.order_id,
- order_items.c.item_id == Item.id,
- ),
- ),
- "SELECT users.id AS users_id, users.name AS users_name "
- "FROM users JOIN "
- "(SELECT orders.id AS id, orders.user_id AS user_id, "
- "orders.address_id AS address_id, orders.description "
- "AS description, orders.isopen AS isopen FROM orders) AS anon_1 "
- "ON users.id = anon_1.user_id JOIN items "
- "ON anon_1.id = order_items.order_id "
- "AND order_items.item_id = items.id",
- use_default_dialect=True,
- )
-
- # query.join(<stuff>, aliased=True).join(target, sql_expression)
- # or: query.join(path_to_some_joined_table_mapper).join(target,
- # sql_expression)
-
-
-class AliasFromCorrectLeftTest(
- fixtures.DeclarativeMappedTest, AssertsCompiledSQL
-):
- run_create_tables = None
- __dialect__ = "default"
-
- @classmethod
- def setup_classes(cls):
- Base = cls.DeclarativeBasic
-
- class Object(Base):
- __tablename__ = "object"
-
- type = Column(String(30))
- __mapper_args__ = {
- "polymorphic_identity": "object",
- "polymorphic_on": type,
- }
-
- id = Column(Integer, primary_key=True)
- name = Column(String(256))
-
- class A(Object):
- __tablename__ = "a"
-
- __mapper_args__ = {"polymorphic_identity": "a"}
-
- id = Column(Integer, ForeignKey("object.id"), primary_key=True)
-
- b_list = relationship(
- "B", secondary="a_b_association", backref="a_list"
- )
-
- class B(Object):
- __tablename__ = "b"
-
- __mapper_args__ = {"polymorphic_identity": "b"}
-
- id = Column(Integer, ForeignKey("object.id"), primary_key=True)
-
- class ABAssociation(Base):
- __tablename__ = "a_b_association"
-
- a_id = Column(Integer, ForeignKey("a.id"), primary_key=True)
- b_id = Column(Integer, ForeignKey("b.id"), primary_key=True)
-
- class X(Base):
- __tablename__ = "x"
-
- id = Column(Integer, primary_key=True)
- name = Column(String(30))
-
- obj_id = Column(Integer, ForeignKey("object.id"))
- obj = relationship("Object", backref="x_list")
-
- def test_join_prop_to_prop(self):
- A, B, X = self.classes("A", "B", "X")
-
- s = fixture_session()
-
- # B -> A, but both are Object. So when we say A.x_list, make sure
- # we pick the correct right side
- with testing.expect_deprecated_20(join_chain_dep):
- q = s.query(B).join(B.a_list, A.x_list).filter(X.name == "x1")
-
- with _aliased_join_warning():
- self.assert_compile(
- q,
- "SELECT object.type AS object_type, b.id AS b_id, "
- "object.id AS object_id, object.name AS object_name "
- "FROM object JOIN b ON object.id = b.id "
- "JOIN a_b_association AS a_b_association_1 "
- "ON b.id = a_b_association_1.b_id "
- "JOIN ("
- "object AS object_1 "
- "JOIN a AS a_1 ON object_1.id = a_1.id"
- ") ON a_1.id = a_b_association_1.a_id "
- "JOIN x ON object_1.id = x.obj_id WHERE x.name = :name_1",
- )
-
-
-class SelfReferentialTest(fixtures.MappedTest, AssertsCompiledSQL):
- run_setup_mappers = "once"
- run_inserts = "once"
- run_deletes = None
- __dialect__ = "default"
-
- @classmethod
- def define_tables(cls, metadata):
- Table(
- "nodes",
- metadata,
- Column(
- "id", Integer, primary_key=True, test_needs_autoincrement=True
- ),
- Column("parent_id", Integer, ForeignKey("nodes.id")),
- Column("data", String(30)),
- )
-
- @classmethod
- def setup_classes(cls):
- class Node(cls.Comparable):
- def append(self, node):
- self.children.append(node)
-
- @classmethod
- def setup_mappers(cls):
- Node, nodes = cls.classes.Node, cls.tables.nodes
-
- cls.mapper_registry.map_imperatively(
- Node,
- nodes,
- properties={
- "children": relationship(
- Node,
- lazy="select",
- join_depth=3,
- backref=backref("parent", remote_side=[nodes.c.id]),
- )
- },
- )
-
- @classmethod
- def insert_data(cls, connection):
- Node = cls.classes.Node
-
- sess = Session(connection)
- n1 = Node(data="n1")
- n1.append(Node(data="n11"))
- n1.append(Node(data="n12"))
- n1.append(Node(data="n13"))
- n1.children[1].append(Node(data="n121"))
- n1.children[1].append(Node(data="n122"))
- n1.children[1].append(Node(data="n123"))
- sess.add(n1)
- sess.flush()
- sess.close()
-
- def test_join_2(self):
- Node = self.classes.Node
- sess = fixture_session()
- with testing.expect_deprecated_20(join_aliased_dep):
- ret = (
- sess.query(Node.data)
- .join(Node.children, aliased=True)
- .filter_by(data="n122")
- .all()
- )
- assert ret == [("n12",)]
-
-
-class InheritedJoinTest(
- fixtures.NoCache,
- _poly_fixtures._Polymorphic,
- _poly_fixtures._PolymorphicFixtureBase,
- AssertsCompiledSQL,
-):
- run_setup_mappers = "once"
- __dialect__ = "default"
-
- def test_join_to_selectable(self):
- people, Company, engineers, Engineer = (
- self.tables.people,
- self.classes.Company,
- self.tables.engineers,
- self.classes.Engineer,
- )
-
- sess = fixture_session()
-
- with _aliased_join_deprecation():
- self.assert_compile(
- sess.query(Company)
- .join(people.join(engineers), Company.employees)
- .filter(Engineer.name == "dilbert"),
- "SELECT companies.company_id AS companies_company_id, "
- "companies.name AS companies_name "
- "FROM companies JOIN (people "
- "JOIN engineers ON people.person_id = "
- "engineers.person_id) ON companies.company_id = "
- "people.company_id WHERE people.name = :name_1",
- use_default_dialect=True,
- )
-
- def test_multiple_adaption(self):
- """test that multiple filter() adapters get chained together "
- and work correctly within a multiple-entry join()."""
-
- people, Company, Machine, engineers, machines, Engineer = (
- self.tables.people,
- self.classes.Company,
- self.classes.Machine,
- self.tables.engineers,
- self.tables.machines,
- self.classes.Engineer,
- )
-
- sess = fixture_session()
-
- mach_alias = aliased(Machine, machines.select().subquery())
-
- with testing.expect_deprecated_20(
- join_aliased_dep
- ), _aliased_join_deprecation():
- self.assert_compile(
- sess.query(Company)
- .join(people.join(engineers), Company.employees)
- .join(mach_alias, Engineer.machines, from_joinpoint=True)
- .filter(Engineer.name == "dilbert")
- .filter(mach_alias.name == "foo"),
- "SELECT companies.company_id AS companies_company_id, "
- "companies.name AS companies_name "
- "FROM companies JOIN (people "
- "JOIN engineers ON people.person_id = "
- "engineers.person_id) ON companies.company_id = "
- "people.company_id JOIN "
- "(SELECT machines.machine_id AS machine_id, "
- "machines.name AS name, "
- "machines.engineer_id AS engineer_id "
- "FROM machines) AS anon_1 "
- "ON engineers.person_id = anon_1.engineer_id "
- "WHERE people.name = :name_1 AND anon_1.name = :name_2",
- use_default_dialect=True,
- )
-
- def test_with_poly_loader_criteria_warning(self):
- Person, Manager = (
- self.classes.Person,
- self.classes.Manager,
- )
-
- sess = fixture_session()
-
- with testing.expect_deprecated_20(w_polymorphic_dep):
- q = (
- sess.query(Person)
- .with_polymorphic(Manager)
- .options(with_loader_criteria(Person, Person.person_id == 1))
- )
-
- with testing.expect_warnings(
- r"The with_loader_criteria\(\) function may not work "
- r"correctly with the legacy Query.with_polymorphic\(\)"
+ with testing.expect_deprecated(
+ "The mapper.non_primary parameter is deprecated"
):
- str(q)
-
- def test_join_to_subclass_selectable_auto_alias(self):
- Company, Engineer = self.classes("Company", "Engineer")
- people, engineers = self.tables("people", "engineers")
-
- sess = fixture_session()
-
- with _aliased_join_deprecation():
- eq_(
- sess.query(Company)
- .join(people.join(engineers), Company.employees)
- .filter(Engineer.primary_language == "java")
- .all(),
- [self.c1],
- )
-
- # occurs for 2.0 style query also
- with _aliased_join_deprecation():
- stmt = (
- select(Company)
- .join(people.join(engineers), Company.employees)
- .filter(Engineer.primary_language == "java")
- )
- results = sess.scalars(stmt)
- eq_(results.all(), [self.c1])
-
- def test_join_to_subclass_two(self):
- Company, Engineer = self.classes("Company", "Engineer")
- people, engineers = self.tables("people", "engineers")
-
- sess = fixture_session()
-
- with _aliased_join_deprecation():
- eq_(
- sess.query(Company)
- .join(people.join(engineers), Company.employees)
- .filter(Engineer.primary_language == "java")
- .all(),
- [self.c1],
- )
-
- def test_join_to_subclass_six_selectable_auto_alias(self):
- Company, Engineer = self.classes("Company", "Engineer")
- people, engineers = self.tables("people", "engineers")
-
- sess = fixture_session()
-
- with _aliased_join_deprecation():
- eq_(
- sess.query(Company)
- .join(people.join(engineers), Company.employees)
- .join(Engineer.machines)
- .all(),
- [self.c1, self.c2],
- )
-
- def test_join_to_subclass_six_point_five_selectable_auto_alias(self):
- Company, Engineer = self.classes("Company", "Engineer")
- people, engineers = self.tables("people", "engineers")
-
- sess = fixture_session()
-
- with _aliased_join_deprecation():
- eq_(
- sess.query(Company)
- .join(people.join(engineers), Company.employees)
- .join(Engineer.machines)
- .filter(Engineer.name == "dilbert")
- .all(),
- [self.c1],
- )
-
- def test_join_to_subclass_seven_selectable_auto_alias(self):
- Company, Engineer, Machine = self.classes(
- "Company", "Engineer", "Machine"
- )
- people, engineers = self.tables("people", "engineers")
-
- sess = fixture_session()
-
- with _aliased_join_deprecation():
- eq_(
- sess.query(Company)
- .join(people.join(engineers), Company.employees)
- .join(Engineer.machines)
- .filter(Machine.name.ilike("%thinkpad%"))
- .all(),
- [self.c1],
- )
-
-
-class JoinFromSelectableTest(fixtures.MappedTest, AssertsCompiledSQL):
- __dialect__ = "default"
- run_setup_mappers = "once"
-
- @classmethod
- def define_tables(cls, metadata):
- Table("table1", metadata, Column("id", Integer, primary_key=True))
- Table(
- "table2",
- metadata,
- Column("id", Integer, primary_key=True),
- Column("t1_id", Integer),
- )
-
- @classmethod
- def setup_classes(cls):
- class T1(cls.Comparable):
- pass
-
- class T2(cls.Comparable):
- pass
-
- @classmethod
- def setup_mappers(cls):
- T1, T2 = cls.classes("T1", "T2")
- table1, table2 = cls.tables.table1, cls.tables.table2
- cls.mapper_registry.map_imperatively(T1, table1)
- cls.mapper_registry.map_imperatively(T2, table2)
-
- def test_mapped_to_select_implicit_left_w_aliased(self):
- T1, T2 = self.classes.T1, self.classes.T2
-
- sess = fixture_session()
- subq = (
- sess.query(T2.t1_id, func.count(T2.id).label("count"))
- .group_by(T2.t1_id)
- .subquery()
- )
-
- with testing.expect_deprecated_20(join_aliased_dep):
assert_raises_message(
- sa_exc.InvalidRequestError,
- r"The aliased=True parameter on query.join\(\) only works "
- "with "
- "an ORM entity, not a plain selectable, as the target.",
- # this doesn't work, so have it raise an error
- sess.query(T1.id)
- .join(subq, subq.c.t1_id == T1.id, aliased=True)
- ._compile_context,
- )
-
-
-class MultiplePathTest(fixtures.MappedTest, AssertsCompiledSQL):
- @classmethod
- def define_tables(cls, metadata):
- Table(
- "t1",
- metadata,
- Column(
- "id", Integer, primary_key=True, test_needs_autoincrement=True
- ),
- Column("data", String(30)),
- )
- Table(
- "t2",
- metadata,
- Column(
- "id", Integer, primary_key=True, test_needs_autoincrement=True
- ),
- Column("data", String(30)),
- )
-
- Table(
- "t1t2_1",
- metadata,
- Column("t1id", Integer, ForeignKey("t1.id")),
- Column("t2id", Integer, ForeignKey("t2.id")),
- )
-
- Table(
- "t1t2_2",
- metadata,
- Column("t1id", Integer, ForeignKey("t1.id")),
- Column("t2id", Integer, ForeignKey("t2.id")),
- )
-
-
-class BindSensitiveStringifyTest(fixtures.MappedTest):
- def _fixture(self):
- # building a totally separate metadata /mapping here
- # because we need to control if the MetaData is bound or not
-
- class User:
- pass
-
- m = MetaData()
- user_table = Table(
- "users",
- m,
- Column("id", Integer, primary_key=True),
- Column("name", String(50)),
- )
-
- clear_mappers()
- self.mapper_registry.map_imperatively(User, user_table)
- return User
-
- def _dialect_fixture(self):
- class MyDialect(default.DefaultDialect):
- default_paramstyle = "qmark"
+ sa.exc.InvalidRequestError,
+ "Configure a primary mapper first",
+ mapper,
+ User,
+ users,
+ non_primary=True,
+ )
- from sqlalchemy.engine import base
+ def test_illegal_non_primary_3_legacy(self):
+ users, addresses = self.tables.users, self.tables.addresses
- return base.Engine(mock.Mock(), MyDialect(), mock.Mock())
+ class Base:
+ pass
- def _test(self, bound_session, session_present, expect_bound):
- if bound_session:
- eng = self._dialect_fixture()
- else:
- eng = None
+ class Sub(Base):
+ pass
- User = self._fixture()
+ with testing.expect_deprecated(
+ "Calling the mapper.* function directly outside of a declarative "
+ ):
+ mapper(Base, users)
+ with testing.expect_deprecated(
+ "The mapper.non_primary parameter is deprecated",
+ ):
+ assert_raises_message(
+ sa.exc.InvalidRequestError,
+ "Configure a primary mapper first",
+ mapper,
+ Sub,
+ addresses,
+ non_primary=True,
+ )
- s = Session(eng if bound_session else None)
- q = s.query(User).filter(User.id == 7)
- if not session_present:
- q = q.with_session(None)
- eq_ignore_whitespace(
- str(q),
- "SELECT users.id AS users_id, users.name AS users_name "
- "FROM users WHERE users.id = ?"
- if expect_bound
- else "SELECT users.id AS users_id, users.name AS users_name "
- "FROM users WHERE users.id = :id_1",
+class InstancesTest(QueryTest, AssertsCompiledSQL):
+ @testing.fails(
+ "ORM refactor not allowing this yet, "
+ "we may just abandon this use case"
+ )
+ def test_from_alias_one(self):
+ User, addresses, users = (
+ self.classes.User,
+ self.tables.addresses,
+ self.tables.users,
)
- def test_query_bound_session(self):
- self._test(True, True, True)
+ query = (
+ users.select(users.c.id == 7)
+ .union(users.select(users.c.id > 7))
+ .alias("ulist")
+ .outerjoin(addresses)
+ .select(order_by=[text("ulist.id"), addresses.c.id])
+ )
+ sess = fixture_session()
+ q = sess.query(User)
- def test_query_no_session(self):
- self._test(False, False, False)
+ # note this has multiple problems because we aren't giving Query
+ # the statement where it would be able to create an adapter
+ def go():
+ with testing.expect_deprecated(
+ r"Using the Query.instances\(\) method without a context",
+ "Retrieving row values using Column objects with only "
+ "matching names",
+ ):
+ result = list(
+ q.options(
+ contains_alias("ulist"), contains_eager("addresses")
+ ).instances(query.execute())
+ )
+ assert self.static.user_address_result == result
- def test_query_unbound_session(self):
- self._test(False, True, False)
+ self.assert_sql_count(testing.db, go, 1)
+ def test_from_alias_two_old_way(self):
+ User, addresses, users = (
+ self.classes.User,
+ self.tables.addresses,
+ self.tables.users,
+ )
-class DeprecationScopedSessionTest(fixtures.MappedTest):
- def test_config_errors(self):
- sm = sessionmaker()
+ query = (
+ users.select()
+ .where(users.c.id == 7)
+ .union(users.select().where(users.c.id > 7))
+ .alias("ulist")
+ .outerjoin(addresses)
+ .select()
+ .order_by(text("ulist.id"), addresses.c.id)
+ )
+ sess = fixture_session()
+ q = sess.query(User)
def go():
- s = sm()
- s._is_asyncio = True
- return s
+ with testing.expect_deprecated(
+ "The AliasOption is not necessary for entities to be "
+ "matched up to a query"
+ ):
+ result = (
+ q.options(
+ contains_alias("ulist"), contains_eager(User.addresses)
+ )
+ .from_statement(query)
+ .all()
+ )
+ assert self.static.user_address_result == result
- Session = scoped_session(go)
+ self.assert_sql_count(testing.db, go, 1)
- with expect_deprecated(
- "Using `scoped_session` with asyncio is deprecated and "
- "will raise an error in a future version. "
- "Please use `async_scoped_session` instead."
- ):
- Session()
- Session.remove()
+ def test_contains_eager(self):
+ users, addresses, User = (
+ self.tables.users,
+ self.tables.addresses,
+ self.classes.User,
+ )
+ sess = fixture_session()
-@testing.combinations(
- (
- "inline",
- True,
- ),
- (
- "separate",
- False,
- ),
- argnames="inline",
- id_="sa",
-)
-@testing.combinations(
- (
- "string",
- True,
- ),
- (
- "literal",
- False,
- ),
- argnames="stringbased",
- id_="sa",
-)
-class ExplicitJoinTest(fixtures.MappedTest):
- @classmethod
- def define_tables(cls, metadata):
- global User, Address
- Base = declarative_base(metadata=metadata)
+ selectquery = (
+ users.outerjoin(addresses)
+ .select()
+ .where(users.c.id < 10)
+ .order_by(users.c.id, addresses.c.id)
+ )
+ q = sess.query(User)
- class User(Base, fixtures.ComparableEntity):
+ def go():
+ with testing.expect_deprecated(
+ r"Using the Query.instances\(\) method without a context"
+ ):
+ result = list(
+ q.options(contains_eager(User.addresses)).instances(
+ sess.execute(selectquery)
+ )
+ )
+ assert self.static.user_address_result[0:3] == result
- __tablename__ = "users"
- id = Column(
- Integer, primary_key=True, test_needs_autoincrement=True
- )
- name = Column(String(50))
+ self.assert_sql_count(testing.db, go, 1)
- class Address(Base, fixtures.ComparableEntity):
+ sess.expunge_all()
- __tablename__ = "addresses"
- id = Column(
- Integer, primary_key=True, test_needs_autoincrement=True
- )
- email = Column(String(50))
- user_id = Column(Integer, ForeignKey("users.id"))
- if cls.inline:
- if cls.stringbased:
- user = relationship(
- "User",
- primaryjoin="User.id==Address.user_id",
- backref="addresses",
- )
- else:
- user = relationship(
- User,
- primaryjoin=User.id == user_id,
- backref="addresses",
+ def go():
+ with testing.expect_deprecated(
+ r"Using the Query.instances\(\) method without a context"
+ ):
+ result = list(
+ q.options(contains_eager(User.addresses)).instances(
+ sess.connection().execute(selectquery)
)
-
- if not cls.inline:
- configure_mappers()
- if cls.stringbased:
- Address.user = relationship(
- "User",
- primaryjoin="User.id==Address.user_id",
- backref="addresses",
- )
- else:
- Address.user = relationship(
- User,
- primaryjoin=User.id == Address.user_id,
- backref="addresses",
)
+ assert self.static.user_address_result[0:3] == result
- @classmethod
- def insert_data(cls, connection):
- params = [
- dict(list(zip(("id", "name"), column_values)))
- for column_values in [
- (7, "jack"),
- (8, "ed"),
- (9, "fred"),
- (10, "chuck"),
- ]
- ]
-
- connection.execute(User.__table__.insert(), params)
- connection.execute(
- Address.__table__.insert(),
- [
- dict(list(zip(("id", "user_id", "email"), column_values)))
- for column_values in [
- (1, 7, "jack@bean.com"),
- (2, 8, "ed@wood.com"),
- (3, 8, "ed@bettyboop.com"),
- (4, 8, "ed@lala.com"),
- (5, 9, "fred@fred.com"),
- ]
- ],
- )
-
- def test_aliased_join(self):
+ self.assert_sql_count(testing.db, go, 1)
- # this query will screw up if the aliasing enabled in
- # query.join() gets applied to the right half of the join
- # condition inside the any(). the join condition inside of
- # any() comes from the "primaryjoin" of the relationship,
- # and should not be annotated with _orm_adapt.
- # PropertyLoader.Comparator will annotate the left side with
- # _orm_adapt, though.
+ def test_contains_eager_aliased_instances(self):
+ addresses, users, User = (
+ self.tables.addresses,
+ self.tables.users,
+ self.classes.User,
+ )
sess = fixture_session()
+ q = sess.query(User)
- with testing.expect_deprecated_20(join_aliased_dep):
- eq_(
- sess.query(User)
- .join(User.addresses, aliased=True)
- .filter(Address.email == "ed@wood.com")
- .filter(User.addresses.any(Address.email == "jack@bean.com"))
- .all(),
- [],
- )
-
-
-class RequirementsTest(fixtures.MappedTest):
-
- """Tests the contract for user classes."""
-
- @classmethod
- def define_tables(cls, metadata):
- Table(
- "ht1",
- metadata,
- Column(
- "id", Integer, primary_key=True, test_needs_autoincrement=True
- ),
- Column("value", String(10)),
- )
- Table(
- "ht2",
- metadata,
- Column(
- "id", Integer, primary_key=True, test_needs_autoincrement=True
- ),
- Column("ht1_id", Integer, ForeignKey("ht1.id")),
- Column("value", String(10)),
- )
- Table(
- "ht3",
- metadata,
- Column(
- "id", Integer, primary_key=True, test_needs_autoincrement=True
- ),
- Column("value", String(10)),
- )
- Table(
- "ht4",
- metadata,
- Column("ht1_id", Integer, ForeignKey("ht1.id"), primary_key=True),
- Column("ht3_id", Integer, ForeignKey("ht3.id"), primary_key=True),
- )
- Table(
- "ht5",
- metadata,
- Column("ht1_id", Integer, ForeignKey("ht1.id"), primary_key=True),
- )
- Table(
- "ht6",
- metadata,
- Column("ht1a_id", Integer, ForeignKey("ht1.id"), primary_key=True),
- Column("ht1b_id", Integer, ForeignKey("ht1.id"), primary_key=True),
- Column("value", String(10)),
+ adalias = addresses.alias("adalias")
+ selectquery = (
+ users.outerjoin(adalias)
+ .select()
+ .order_by(users.c.id, adalias.c.id)
)
+ # note this has multiple problems because we aren't giving Query
+ # the statement where it would be able to create an adapter
+ def go():
+ with testing.expect_deprecated(
+ r"Using the Query.instances\(\) method without a context"
+ ):
+ result = list(
+ q.options(
+ contains_eager(User.addresses, alias=adalias)
+ ).instances(sess.connection().execute(selectquery))
+ )
+ assert self.static.user_address_result == result
-class DeferredOptionsTest(AssertsCompiledSQL, _fixtures.FixtureTest):
- __dialect__ = "default"
+ self.assert_sql_count(testing.db, go, 1)
- def test_deep_options(self):
- users, items, order_items, Order, Item, User, orders = (
- self.tables.users,
+ def test_contains_eager_multi_alias(self):
+ orders, items, users, order_items, User = (
+ self.tables.orders,
self.tables.items,
+ self.tables.users,
self.tables.order_items,
- self.classes.Order,
- self.classes.Item,
self.classes.User,
- self.tables.orders,
)
- self.mapper_registry.map_imperatively(
- Item,
- items,
- properties=dict(description=deferred(items.c.description)),
- )
- self.mapper_registry.map_imperatively(
- Order,
- orders,
- properties=dict(items=relationship(Item, secondary=order_items)),
- )
- self.mapper_registry.map_imperatively(
- User,
- users,
- properties=dict(orders=relationship(Order, order_by=orders.c.id)),
- )
+ Order = self.classes.Order
sess = fixture_session()
- q = sess.query(User).order_by(User.id)
- result = q.all()
- item = result[0].orders[1].items[1]
+ q = sess.query(User)
- def go():
- eq_(item.description, "item 4")
+ oalias = orders.alias("o1")
+ ialias = items.alias("i1")
+ query = (
+ users.outerjoin(oalias)
+ .outerjoin(order_items)
+ .outerjoin(ialias)
+ .select()
+ .order_by(users.c.id, oalias.c.id, ialias.c.id)
+ )
- self.sql_count_(1, go)
- eq_(item.description, "item 4")
+ # test using Alias with more than one level deep
- sess.expunge_all()
- with assertions.expect_deprecated(undefer_needs_chaining):
- result = q.options(
- undefer(User.orders, Order.items, Item.description)
- ).all()
- item = result[0].orders[1].items[1]
+ # new way:
+ # from sqlalchemy.orm.strategy_options import Load
+ # opt = Load(User).contains_eager('orders', alias=oalias).
+ # contains_eager('items', alias=ialias)
def go():
- eq_(item.description, "item 4")
+ with testing.expect_deprecated(
+ r"Using the Query.instances\(\) method without a context"
+ ):
+ result = list(
+ q.options(
+ contains_eager(User.orders, alias=oalias),
+ defaultload(User.orders).contains_eager(
+ Order.items, alias=ialias
+ ),
+ ).instances(sess.connection().execute(query))
+ )
+ assert self.static.user_order_result == result
- self.sql_count_(0, go)
- eq_(item.description, "item 4")
+ self.assert_sql_count(testing.db, go, 1)
-class SubOptionsTest(PathTest, OptionsQueryTest):
- run_create_tables = False
- run_inserts = None
- run_deletes = None
+class TestDeprecation20(QueryTest):
+ def test_relation(self):
+ User = self.classes.User
+ with testing.expect_deprecated_20(".*relationship"):
+ relation(User.addresses)
- def _assert_opts(self, q, sub_opt, non_sub_opts):
- attr_a = {}
+ def test_eagerloading(self):
+ User = self.classes.User
+ with testing.expect_deprecated_20(".*joinedload"):
+ eagerload(User.addresses)
- for val in sub_opt._to_bind:
- val._bind_loader(
+
+class DistinctOrderByImplicitTest(QueryTest, AssertsCompiledSQL):
+ __dialect__ = "default"
+
+ def test_columns_augmented_roundtrip_three(self):
+ User, Address = self.classes.User, self.classes.Address
+
+ sess = fixture_session()
+
+ q = (
+ sess.query(User.id, User.name.label("foo"), Address.id)
+ .join(Address, true())
+ .filter(User.name == "jack")
+ .filter(User.id + Address.user_id > 0)
+ .distinct()
+ .order_by(User.id, User.name, Address.email_address)
+ )
+
+ # even though columns are added, they aren't in the result
+ with testing.expect_deprecated(
+ "ORDER BY columns added implicitly due to "
+ ):
+ eq_(
+ q.all(),
[
- ent.entity_zero
- for ent in q._compile_state()._lead_mapper_entities
+ (7, "jack", 3),
+ (7, "jack", 4),
+ (7, "jack", 2),
+ (7, "jack", 5),
+ (7, "jack", 1),
],
- q._compile_options._current_path,
- attr_a,
- False,
)
+ for row in q:
+ eq_(row._mapping.keys(), ["id", "foo", "id"])
- attr_b = {}
+ def test_columns_augmented_sql_one(self):
+ User, Address = self.classes.User, self.classes.Address
- for opt in non_sub_opts:
- for val in opt._to_bind:
- val._bind_loader(
- [
- ent.entity_zero
- for ent in q._compile_state()._lead_mapper_entities
- ],
- q._compile_options._current_path,
- attr_b,
- False,
- )
+ sess = fixture_session()
- for k, l in attr_b.items():
- if not l.strategy:
- del attr_b[k]
+ q = (
+ sess.query(User.id, User.name.label("foo"), Address.id)
+ .distinct()
+ .order_by(User.id, User.name, Address.email_address)
+ )
- def strat_as_tuple(strat):
- return (
- strat.strategy,
- strat.local_opts,
- strat.propagate_to_loaders,
- strat._of_type,
- strat.is_class_strategy,
- strat.is_opts_only,
+ # Address.email_address is added because of DISTINCT,
+ # however User.id, User.name are not b.c. they're already there,
+ # even though User.name is labeled
+ with testing.expect_deprecated(
+ "ORDER BY columns added implicitly due to "
+ ):
+ self.assert_compile(
+ q,
+ "SELECT DISTINCT users.id AS users_id, users.name AS foo, "
+ "addresses.id AS addresses_id, addresses.email_address AS "
+ "addresses_email_address FROM users, addresses "
+ "ORDER BY users.id, users.name, addresses.email_address",
)
- eq_(
- {path: strat_as_tuple(load) for path, load in attr_a.items()},
- {path: strat_as_tuple(load) for path, load in attr_b.items()},
- )
-
-class PolyCacheKeyTest(CacheKeyFixture, _poly_fixtures._Polymorphic):
- run_setup_mappers = "once"
+class SessionEventsTest(_RemoveListeners, _fixtures.FixtureTest):
run_inserts = None
- run_deletes = None
- def _stmt_20(self, *elements):
- return tuple(
- elem._statement_20() if isinstance(elem, sa.orm.Query) else elem
- for elem in elements
- )
+ def test_on_bulk_update_hook(self):
+ User, users = self.classes.User, self.tables.users
- def test_wp_queries(self):
- Person, Manager, Engineer, Boss = self.classes(
- "Person", "Manager", "Engineer", "Boss"
- )
+ sess = fixture_session()
+ canary = Mock()
- def one():
- with assertions.expect_deprecated_20(w_polymorphic_dep):
- return (
- fixture_session()
- .query(Person)
- .with_polymorphic([Manager, Engineer])
- )
+ event.listen(sess, "after_bulk_update", canary.after_bulk_update)
- def two():
- wp = with_polymorphic(Person, [Manager, Engineer])
+ def legacy(ses, qry, ctx, res):
+ canary.after_bulk_update_legacy(ses, qry, ctx, res)
- return fixture_session().query(wp)
+ event.listen(sess, "after_bulk_update", legacy)
- def three():
- wp = with_polymorphic(Person, [Manager, Engineer])
+ self.mapper_registry.map_imperatively(User, users)
- return fixture_session().query(wp).filter(wp.name == "asdfo")
+ with testing.expect_deprecated(
+ 'The argument signature for the "SessionEvents.after_bulk_update" '
+ "event listener"
+ ):
+ sess.query(User).update({"name": "foo"})
- def three_a():
- wp = with_polymorphic(Person, [Manager, Engineer], flat=True)
+ eq_(canary.after_bulk_update.call_count, 1)
- return fixture_session().query(wp).filter(wp.name == "asdfo")
+ upd = canary.after_bulk_update.mock_calls[0][1][0]
+ eq_(upd.session, sess)
+ eq_(
+ canary.after_bulk_update_legacy.mock_calls,
+ [call(sess, upd.query, None, upd.result)],
+ )
- def four():
- with assertions.expect_deprecated_20(w_polymorphic_dep):
- return (
- fixture_session()
- .query(Person)
- .with_polymorphic([Manager, Engineer])
- .filter(Person.name == "asdf")
- )
+ def test_on_bulk_delete_hook(self):
+ User, users = self.classes.User, self.tables.users
- def five():
- subq = (
- select(Person)
- .outerjoin(Manager)
- .outerjoin(Engineer)
- .subquery()
- )
- wp = with_polymorphic(Person, [Manager, Engineer], subq)
+ sess = fixture_session()
+ canary = Mock()
- return fixture_session().query(wp).filter(wp.name == "asdfo")
+ event.listen(sess, "after_bulk_delete", canary.after_bulk_delete)
- def six():
- subq = (
- select(Person)
- .outerjoin(Manager)
- .outerjoin(Engineer)
- .subquery()
- )
+ def legacy(ses, qry, ctx, res):
+ canary.after_bulk_delete_legacy(ses, qry, ctx, res)
+
+ event.listen(sess, "after_bulk_delete", legacy)
+
+ self.mapper_registry.map_imperatively(User, users)
+
+ with testing.expect_deprecated(
+ 'The argument signature for the "SessionEvents.after_bulk_delete" '
+ "event listener"
+ ):
+ sess.query(User).delete()
- with assertions.expect_deprecated_20(w_polymorphic_dep):
- return (
- fixture_session()
- .query(Person)
- .with_polymorphic([Manager, Engineer], subq)
- .filter(Person.name == "asdfo")
- )
+ eq_(canary.after_bulk_delete.call_count, 1)
- self._run_cache_key_fixture(
- lambda: self._stmt_20(
- one(), two(), three(), three_a(), four(), five(), six()
- ),
- compare_values=True,
+ upd = canary.after_bulk_delete.mock_calls[0][1][0]
+ eq_(upd.session, sess)
+ eq_(
+ canary.after_bulk_delete_legacy.mock_calls,
+ [call(sess, upd.query, None, upd.result)],
)
-class ColumnAccessTest(QueryTest, AssertsCompiledSQL):
- """test access of columns after _from_selectable has been applied"""
+class ImmediateTest(_fixtures.FixtureTest):
+ run_inserts = "once"
+ run_deletes = None
- __dialect__ = "default"
+ @classmethod
+ def setup_mappers(cls):
+ Address, addresses, users, User = (
+ cls.classes.Address,
+ cls.tables.addresses,
+ cls.tables.users,
+ cls.classes.User,
+ )
- def test_select_entity_from(self):
- User = self.classes.User
- sess = fixture_session()
+ cls.mapper_registry.map_imperatively(Address, addresses)
- q = sess.query(User)
- with assertions.expect_deprecated_20(sef_dep):
- q = sess.query(User).select_entity_from(q.statement.subquery())
- self.assert_compile(
- q.filter(User.name == "ed"),
- "SELECT anon_1.id AS anon_1_id, anon_1.name AS anon_1_name "
- "FROM (SELECT users.id AS id, users.name AS name FROM "
- "users) AS anon_1 WHERE anon_1.name = :name_1",
+ cls.mapper_registry.map_imperatively(
+ User, users, properties=dict(addresses=relationship(Address))
)
- def test_select_entity_from_no_entities(self):
+ def test_value(self):
User = self.classes.User
+
sess = fixture_session()
- with assertions.expect_deprecated_20(sef_dep):
- assert_raises_message(
- sa.exc.ArgumentError,
- r"A selectable \(FromClause\) instance is "
- "expected when the base alias is being set",
- sess.query(User).select_entity_from(User)._compile_context,
+ with testing.expect_deprecated(r"Query.value\(\) is deprecated"):
+ eq_(sess.query(User).filter_by(id=7).value(User.id), 7)
+ with testing.expect_deprecated(r"Query.value\(\) is deprecated"):
+ eq_(
+ sess.query(User.id, User.name).filter_by(id=7).value(User.id),
+ 7,
)
+ with testing.expect_deprecated(r"Query.value\(\) is deprecated"):
+ eq_(sess.query(User).filter_by(id=0).value(User.id), None)
+ sess.bind = testing.db
+ with testing.expect_deprecated(r"Query.value\(\) is deprecated"):
+ eq_(sess.query().value(sa.literal_column("1").label("x")), 1)
-class SelectFromTest(QueryTest, AssertsCompiledSQL):
- run_setup_mappers = None
- __dialect__ = "default"
-
- def test_aliased_class_vs_nonaliased(self):
- User, users = self.classes.User, self.tables.users
- self.mapper_registry.map_imperatively(User, users)
+ def test_value_cancels_loader_opts(self):
+ User = self.classes.User
sess = fixture_session()
- with assertions.expect_deprecated_20(sef_dep):
- self.assert_compile(
- sess.query(User.name).select_entity_from(
- users.select().where(users.c.id > 5).subquery()
- ),
- "SELECT anon_1.name AS anon_1_name FROM "
- "(SELECT users.id AS id, "
- "users.name AS name FROM users WHERE users.id > :id_1) "
- "AS anon_1",
- )
- @testing.combinations(
- (
- lambda users: users.select().where(users.c.id.in_([7, 8])),
- "SELECT anon_1.id AS anon_1_id, anon_1.name AS anon_1_name "
- "FROM (SELECT users.id AS id, users.name AS name "
- "FROM users WHERE users.id IN (__[POSTCOMPILE_id_1])) AS anon_1 "
- "WHERE anon_1.name = :name_1",
- ),
- (
- lambda users: users.select()
- .where(users.c.id.in_([7, 8]))
- .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL),
- "SELECT anon_1.users_id AS anon_1_users_id, anon_1.users_name "
- "AS anon_1_users_name FROM (SELECT users.id AS users_id, "
- "users.name AS users_name FROM users "
- "WHERE users.id IN (__[POSTCOMPILE_id_1])) AS anon_1 "
- "WHERE anon_1.users_name = :name_1",
- ),
- (
- lambda User, sess: sess.query(User).where(User.id.in_([7, 8])),
- "SELECT anon_1.id AS anon_1_id, anon_1.name AS anon_1_name "
- "FROM (SELECT users.id AS id, users.name AS name "
- "FROM users WHERE users.id IN (__[POSTCOMPILE_id_1])) AS anon_1 "
- "WHERE anon_1.name = :name_1",
- ),
- )
- def test_filter_by(self, query_fn, expected):
- """test #7239"""
+ q = (
+ sess.query(User)
+ .filter(User.name == "ed")
+ .options(joinedload(User.addresses))
+ )
- User = self.classes.User
- sess = fixture_session()
+ with testing.expect_deprecated(r"Query.value\(\) is deprecated"):
+ q = q.value(func.count(literal_column("*")))
- User, users = self.classes.User, self.tables.users
- self.mapper_registry.map_imperatively(User, users)
+class MixedEntitiesTest(QueryTest, AssertsCompiledSQL):
+ __dialect__ = "default"
- sel = resolve_lambda(query_fn, User=User, users=users, sess=sess)
+ def test_values(self):
+ Address, User = (
+ self.classes.Address,
+ self.classes.User,
+ )
sess = fixture_session()
- with assertions.expect_deprecated_20(sef_dep):
- q = sess.query(User).select_entity_from(sel.subquery())
-
- self.assert_compile(q.filter_by(name="ed"), expected)
- eq_(q.filter_by(name="ed").all(), [User(name="ed")])
+ with testing.expect_deprecated(r"Query.values?\(\) is deprecated"):
+ assert list(sess.query(User).values()) == list()
- def test_join_no_order_by(self):
- User, users = self.classes.User, self.tables.users
+ q = sess.query(User)
- self.mapper_registry.map_imperatively(User, users)
+ with testing.expect_deprecated(r"Query.values?\(\) is deprecated"):
+ q2 = q.order_by(User.id).values(
+ User.name, User.name + " " + cast(User.id, String(50))
+ )
+ eq_(
+ list(q2),
+ [
+ ("jack", "jack 7"),
+ ("ed", "ed 8"),
+ ("fred", "fred 9"),
+ ("chuck", "chuck 10"),
+ ],
+ )
- sel = users.select().where(users.c.id.in_([7, 8]))
- sess = fixture_session()
+ with testing.expect_deprecated(r"Query.values?\(\) is deprecated"):
+ q2 = (
+ q.join(User.addresses)
+ .filter(User.name.like("%e%"))
+ .order_by(User.id, Address.id)
+ .values(User.name, Address.email_address)
+ )
+ eq_(
+ list(q2),
+ [
+ ("ed", "ed@wood.com"),
+ ("ed", "ed@bettyboop.com"),
+ ("ed", "ed@lala.com"),
+ ("fred", "fred@fred.com"),
+ ],
+ )
- with assertions.expect_deprecated_20(sef_dep):
- eq_(
- sess.query(User).select_entity_from(sel.subquery()).all(),
- [User(name="jack", id=7), User(name="ed", id=8)],
+ with testing.expect_deprecated(r"Query.values?\(\) is deprecated"):
+ q2 = (
+ q.join(User.addresses)
+ .filter(User.name.like("%e%"))
+ .order_by(desc(Address.email_address))
+ .slice(1, 3)
+ .values(User.name, Address.email_address)
)
+ eq_(list(q2), [("ed", "ed@wood.com"), ("ed", "ed@lala.com")])
- def test_join(self):
- users, Address, addresses, User = (
- self.tables.users,
- self.classes.Address,
- self.tables.addresses,
- self.classes.User,
+ adalias = aliased(Address)
+ with testing.expect_deprecated(r"Query.values?\(\) is deprecated"):
+ q2 = (
+ q.join(adalias, User.addresses)
+ .filter(User.name.like("%e%"))
+ .order_by(adalias.email_address)
+ .values(User.name, adalias.email_address)
+ )
+ eq_(
+ list(q2),
+ [
+ ("ed", "ed@bettyboop.com"),
+ ("ed", "ed@lala.com"),
+ ("ed", "ed@wood.com"),
+ ("fred", "fred@fred.com"),
+ ],
)
- self.mapper_registry.map_imperatively(
- User, users, properties={"addresses": relationship(Address)}
- )
- self.mapper_registry.map_imperatively(Address, addresses)
+ with testing.expect_deprecated(r"Query.values?\(\) is deprecated"):
+ q2 = q.values(func.count(User.name))
+ assert next(q2) == (4,)
+
+ @testing.fails_on("mssql", "FIXME: unknown")
+ def test_values_specific_order_by(self):
+ User = self.classes.User
- sel = users.select().where(users.c.id.in_([7, 8]))
sess = fixture_session()
- with assertions.expect_deprecated_20(sef_dep):
- eq_(
- sess.query(User)
- .select_entity_from(sel.subquery())
- .join(User.addresses)
- .add_entity(Address)
- .order_by(User.id)
- .order_by(Address.id)
- .all(),
- [
- (
- User(name="jack", id=7),
- Address(
- user_id=7, email_address="jack@bean.com", id=1
- ),
- ),
- (
- User(name="ed", id=8),
- Address(user_id=8, email_address="ed@wood.com", id=2),
- ),
- (
- User(name="ed", id=8),
- Address(
- user_id=8, email_address="ed@bettyboop.com", id=3
- ),
- ),
- (
- User(name="ed", id=8),
- Address(user_id=8, email_address="ed@lala.com", id=4),
- ),
- ],
- )
+ with testing.expect_deprecated(r"Query.values?\(\) is deprecated"):
+ assert list(sess.query(User).values()) == list()
- adalias = aliased(Address)
- with assertions.expect_deprecated_20(sef_dep):
- eq_(
- sess.query(User)
- .select_entity_from(sel.subquery())
- .join(adalias, User.addresses)
- .add_entity(adalias)
- .order_by(User.id)
- .order_by(adalias.id)
- .all(),
- [
- (
- User(name="jack", id=7),
- Address(
- user_id=7, email_address="jack@bean.com", id=1
- ),
- ),
- (
- User(name="ed", id=8),
- Address(user_id=8, email_address="ed@wood.com", id=2),
- ),
- (
- User(name="ed", id=8),
- Address(
- user_id=8, email_address="ed@bettyboop.com", id=3
- ),
- ),
- (
- User(name="ed", id=8),
- Address(user_id=8, email_address="ed@lala.com", id=4),
- ),
- ],
- )
+ @testing.fails_on("mssql", "FIXME: unknown")
+ @testing.fails_on(
+ "oracle", "Oracle doesn't support boolean expressions as " "columns"
+ )
+ @testing.fails_on(
+ "postgresql+pg8000",
+ "pg8000 parses the SQL itself before passing on "
+ "to PG, doesn't parse this",
+ )
+ @testing.fails_on(
+ "postgresql+asyncpg",
+ "Asyncpg uses preprated statements that are not compatible with how "
+ "sqlalchemy passes the query. Fails with "
+ 'ERROR: column "users.name" must appear in the GROUP BY clause'
+ " or be used in an aggregate function",
+ )
+ def test_values_with_boolean_selects(self):
+ """Tests a values clause that works with select boolean
+ evaluations"""
- def test_more_joins(self):
- (
- users,
- Keyword,
- orders,
- items,
- order_items,
- Order,
- Item,
- User,
- keywords,
- item_keywords,
- ) = (
- self.tables.users,
- self.classes.Keyword,
- self.tables.orders,
- self.tables.items,
- self.tables.order_items,
- self.classes.Order,
- self.classes.Item,
- self.classes.User,
- self.tables.keywords,
- self.tables.item_keywords,
- )
+ User = self.classes.User
- self.mapper_registry.map_imperatively(
- User,
- users,
- properties={"orders": relationship(Order, backref="user")},
- ) # o2m, m2o
- self.mapper_registry.map_imperatively(
- Order,
- orders,
- properties={
- "items": relationship(
- Item, secondary=order_items, order_by=items.c.id
- )
- },
- ) # m2m
+ sess = fixture_session()
- self.mapper_registry.map_imperatively(
- Item,
- items,
- properties={
- "keywords": relationship(
- Keyword, secondary=item_keywords, order_by=keywords.c.id
+ q = sess.query(User)
+ with testing.expect_deprecated(r"Query.values?\(\) is deprecated"):
+ q2 = (
+ q.group_by(User.name.like("%j%"))
+ .order_by(desc(User.name.like("%j%")))
+ .values(
+ User.name.like("%j%"), func.count(User.name.like("%j%"))
)
- },
- ) # m2m
- self.mapper_registry.map_imperatively(Keyword, keywords)
-
- sess = fixture_session()
- sel = users.select().where(users.c.id.in_([7, 8]))
+ )
+ eq_(list(q2), [(True, 1), (False, 3)])
- with assertions.expect_deprecated_20(sef_dep):
- eq_(
- sess.query(User)
- .select_entity_from(sel.subquery())
- .join(User.orders, Order.items, Item.keywords)
- .filter(Keyword.name.in_(["red", "big", "round"]))
- .all(),
- [User(name="jack", id=7)],
+ with testing.expect_deprecated(r"Query.values?\(\) is deprecated"):
+ q2 = q.order_by(desc(User.name.like("%j%"))).values(
+ User.name.like("%j%")
)
+ eq_(list(q2), [(True,), (False,), (False,), (False,)])
- def test_very_nested_joins_with_joinedload(self):
- (
- users,
- Keyword,
- orders,
- items,
- order_items,
- Order,
- Item,
- User,
- keywords,
- item_keywords,
- ) = (
- self.tables.users,
- self.classes.Keyword,
- self.tables.orders,
- self.tables.items,
- self.tables.order_items,
- self.classes.Order,
- self.classes.Item,
- self.classes.User,
- self.tables.keywords,
- self.tables.item_keywords,
- )
- self.mapper_registry.map_imperatively(
- User,
- users,
- properties={"orders": relationship(Order, backref="user")},
- ) # o2m, m2o
- self.mapper_registry.map_imperatively(
- Order,
- orders,
- properties={
- "items": relationship(
- Item, secondary=order_items, order_by=items.c.id
- )
- },
- ) # m2m
- self.mapper_registry.map_imperatively(
- Item,
- items,
- properties={
- "keywords": relationship(
- Keyword, secondary=item_keywords, order_by=keywords.c.id
- )
- },
- ) # m2m
- self.mapper_registry.map_imperatively(Keyword, keywords)
+class InheritedJoinTest(
+ fixtures.NoCache,
+ _poly_fixtures._Polymorphic,
+ _poly_fixtures._PolymorphicFixtureBase,
+ AssertsCompiledSQL,
+):
+ run_setup_mappers = "once"
+ __dialect__ = "default"
+
+ def test_join_to_selectable(self):
+ people, Company, engineers, Engineer = (
+ self.tables.people,
+ self.classes.Company,
+ self.tables.engineers,
+ self.classes.Engineer,
+ )
sess = fixture_session()
- sel = users.select().where(users.c.id.in_([7, 8]))
+ with _aliased_join_deprecation():
+ self.assert_compile(
+ sess.query(Company)
+ .join(people.join(engineers), Company.employees)
+ .filter(Engineer.name == "dilbert"),
+ "SELECT companies.company_id AS companies_company_id, "
+ "companies.name AS companies_name "
+ "FROM companies JOIN (people "
+ "JOIN engineers ON people.person_id = "
+ "engineers.person_id) ON companies.company_id = "
+ "people.company_id WHERE people.name = :name_1",
+ use_default_dialect=True,
+ )
- def go():
- with assertions.expect_deprecated_20(sef_dep):
- eq_(
- sess.query(User)
- .select_entity_from(sel.subquery())
- .options(
- joinedload(User.orders)
- .joinedload(Order.items)
- .joinedload(Item.keywords)
- )
- .join(User.orders, Order.items, Item.keywords)
- .filter(Keyword.name.in_(["red", "big", "round"]))
- .all(),
- [
- User(
- name="jack",
- orders=[
- Order(
- description="order 1",
- items=[
- Item(
- description="item 1",
- keywords=[
- Keyword(name="red"),
- Keyword(name="big"),
- Keyword(name="round"),
- ],
- ),
- Item(
- description="item 2",
- keywords=[
- Keyword(name="red", id=2),
- Keyword(name="small", id=5),
- Keyword(name="square"),
- ],
- ),
- Item(
- description="item 3",
- keywords=[
- Keyword(name="green", id=3),
- Keyword(name="big", id=4),
- Keyword(name="round", id=6),
- ],
- ),
- ],
- ),
- Order(
- description="order 3",
- items=[
- Item(
- description="item 3",
- keywords=[
- Keyword(name="green", id=3),
- Keyword(name="big", id=4),
- Keyword(name="round", id=6),
- ],
- ),
- Item(
- description="item 4",
- keywords=[],
- id=4,
- ),
- Item(
- description="item 5",
- keywords=[],
- id=5,
- ),
- ],
- ),
- Order(
- description="order 5",
- items=[
- Item(description="item 5", keywords=[])
- ],
- ),
- ],
- )
- ],
- )
+ def test_join_to_subclass_selectable_auto_alias(self):
+ Company, Engineer = self.classes("Company", "Engineer")
+ people, engineers = self.tables("people", "engineers")
- self.assert_sql_count(testing.db, go, 1)
+ sess = fixture_session()
- sess.expunge_all()
- sel2 = orders.select().where(orders.c.id.in_([1, 2, 3]))
- with assertions.expect_deprecated_20(sef_dep):
+ with _aliased_join_deprecation():
eq_(
- sess.query(Order)
- .select_entity_from(sel2.subquery())
- .join(Order.items)
- .join(Item.keywords)
- .filter(Keyword.name == "red")
- .order_by(Order.id)
+ sess.query(Company)
+ .join(people.join(engineers), Company.employees)
+ .filter(Engineer.primary_language == "java")
.all(),
- [
- Order(description="order 1", id=1),
- Order(description="order 2", id=2),
- ],
+ [self.c1],
)
- def test_replace_with_eager(self):
- users, Address, addresses, User = (
- self.tables.users,
- self.classes.Address,
- self.tables.addresses,
- self.classes.User,
- )
+ # occurs for 2.0 style query also
+ with _aliased_join_deprecation():
+ stmt = (
+ select(Company)
+ .join(people.join(engineers), Company.employees)
+ .filter(Engineer.primary_language == "java")
+ )
+ results = sess.scalars(stmt)
+ eq_(results.all(), [self.c1])
- self.mapper_registry.map_imperatively(
- User,
- users,
- properties={
- "addresses": relationship(Address, order_by=addresses.c.id)
- },
- )
- self.mapper_registry.map_imperatively(Address, addresses)
+ def test_join_to_subclass_two(self):
+ Company, Engineer = self.classes("Company", "Engineer")
+ people, engineers = self.tables("people", "engineers")
- sel = users.select().where(users.c.id.in_([7, 8]))
sess = fixture_session()
- def go():
- with assertions.expect_deprecated_20(sef_dep):
- eq_(
- sess.query(User)
- .options(joinedload(User.addresses))
- .select_entity_from(sel.subquery())
- .order_by(User.id)
- .all(),
- [
- User(id=7, addresses=[Address(id=1)]),
- User(
- id=8,
- addresses=[
- Address(id=2),
- Address(id=3),
- Address(id=4),
- ],
- ),
- ],
- )
+ with _aliased_join_deprecation():
+ eq_(
+ sess.query(Company)
+ .join(people.join(engineers), Company.employees)
+ .filter(Engineer.primary_language == "java")
+ .all(),
+ [self.c1],
+ )
- self.assert_sql_count(testing.db, go, 1)
- sess.expunge_all()
+ def test_join_to_subclass_six_selectable_auto_alias(self):
+ Company, Engineer = self.classes("Company", "Engineer")
+ people, engineers = self.tables("people", "engineers")
- def go():
- with assertions.expect_deprecated_20(sef_dep):
- eq_(
- sess.query(User)
- .options(joinedload(User.addresses))
- .select_entity_from(sel.subquery())
- .filter(User.id == 8)
- .order_by(User.id)
- .all(),
- [
- User(
- id=8,
- addresses=[
- Address(id=2),
- Address(id=3),
- Address(id=4),
- ],
- )
- ],
- )
+ sess = fixture_session()
- self.assert_sql_count(testing.db, go, 1)
- sess.expunge_all()
+ with _aliased_join_deprecation():
+ eq_(
+ sess.query(Company)
+ .join(people.join(engineers), Company.employees)
+ .join(Engineer.machines)
+ .all(),
+ [self.c1, self.c2],
+ )
- def go():
- with assertions.expect_deprecated_20(sef_dep):
- eq_(
- sess.query(User)
- .options(joinedload(User.addresses))
- .select_entity_from(sel.subquery())
- .order_by(User.id)[1],
- User(
- id=8,
- addresses=[
- Address(id=2),
- Address(id=3),
- Address(id=4),
- ],
- ),
- )
+ def test_join_to_subclass_six_point_five_selectable_auto_alias(self):
+ Company, Engineer = self.classes("Company", "Engineer")
+ people, engineers = self.tables("people", "engineers")
- self.assert_sql_count(testing.db, go, 1)
+ sess = fixture_session()
- def test_select_from_aliased_one(self):
- User, users = self.classes.User, self.tables.users
+ with _aliased_join_deprecation():
+ eq_(
+ sess.query(Company)
+ .join(people.join(engineers), Company.employees)
+ .join(Engineer.machines)
+ .filter(Engineer.name == "dilbert")
+ .all(),
+ [self.c1],
+ )
- self.mapper_registry.map_imperatively(User, users)
+ def test_join_to_subclass_seven_selectable_auto_alias(self):
+ Company, Engineer, Machine = self.classes(
+ "Company", "Engineer", "Machine"
+ )
+ people, engineers = self.tables("people", "engineers")
sess = fixture_session()
- not_users = table("users", column("id"), column("name"))
- ua = aliased(User, select(not_users).alias(), adapt_on_names=True)
-
- with assertions.expect_deprecated_20(sef_dep):
- q = (
- sess.query(User.name)
- .select_entity_from(ua)
- .order_by(User.name)
+ with _aliased_join_deprecation():
+ eq_(
+ sess.query(Company)
+ .join(people.join(engineers), Company.employees)
+ .join(Engineer.machines)
+ .filter(Machine.name.ilike("%thinkpad%"))
+ .all(),
+ [self.c1],
)
- self.assert_compile(
- q,
- "SELECT anon_1.name AS anon_1_name FROM (SELECT users.id AS id, "
- "users.name AS name FROM users) AS anon_1 ORDER BY anon_1.name",
+
+
+class MultiplePathTest(fixtures.MappedTest, AssertsCompiledSQL):
+ @classmethod
+ def define_tables(cls, metadata):
+ Table(
+ "t1",
+ metadata,
+ Column(
+ "id", Integer, primary_key=True, test_needs_autoincrement=True
+ ),
+ Column("data", String(30)),
+ )
+ Table(
+ "t2",
+ metadata,
+ Column(
+ "id", Integer, primary_key=True, test_needs_autoincrement=True
+ ),
+ Column("data", String(30)),
)
- eq_(q.all(), [("chuck",), ("ed",), ("fred",), ("jack",)])
- def test_select_from_aliased_two(self):
- User, users = self.classes.User, self.tables.users
+ Table(
+ "t1t2_1",
+ metadata,
+ Column("t1id", Integer, ForeignKey("t1.id")),
+ Column("t2id", Integer, ForeignKey("t2.id")),
+ )
- self.mapper_registry.map_imperatively(User, users)
+ Table(
+ "t1t2_2",
+ metadata,
+ Column("t1id", Integer, ForeignKey("t1.id")),
+ Column("t2id", Integer, ForeignKey("t2.id")),
+ )
- sess = fixture_session()
- ua = aliased(User)
+class BindSensitiveStringifyTest(fixtures.MappedTest):
+ def _fixture(self):
+ # building a totally separate metadata /mapping here
+ # because we need to control if the MetaData is bound or not
- with assertions.expect_deprecated_20(sef_dep):
- q = (
- sess.query(User.name)
- .select_entity_from(ua)
- .order_by(User.name)
- )
- self.assert_compile(
- q,
- "SELECT users_1.name AS users_1_name FROM users AS users_1 "
- "ORDER BY users_1.name",
+ class User:
+ pass
+
+ m = MetaData()
+ user_table = Table(
+ "users",
+ m,
+ Column("id", Integer, primary_key=True),
+ Column("name", String(50)),
)
- eq_(q.all(), [("chuck",), ("ed",), ("fred",), ("jack",)])
- def test_select_from_core_alias_one(self):
- User, users = self.classes.User, self.tables.users
+ clear_mappers()
+ self.mapper_registry.map_imperatively(User, user_table)
+ return User
- self.mapper_registry.map_imperatively(User, users)
+ def _dialect_fixture(self):
+ class MyDialect(default.DefaultDialect):
+ default_paramstyle = "qmark"
- sess = fixture_session()
+ from sqlalchemy.engine import base
- ua = users.alias()
+ return base.Engine(mock.Mock(), MyDialect(), mock.Mock())
- with assertions.expect_deprecated_20(sef_dep):
- q = (
- sess.query(User.name)
- .select_entity_from(ua)
- .order_by(User.name)
- )
- self.assert_compile(
- q,
- "SELECT users_1.name AS users_1_name FROM users AS users_1 "
- "ORDER BY users_1.name",
- )
- eq_(q.all(), [("chuck",), ("ed",), ("fred",), ("jack",)])
+ def _test(self, bound_session, session_present, expect_bound):
+ if bound_session:
+ eng = self._dialect_fixture()
+ else:
+ eng = None
- def test_differentiate_self_external(self):
- """test some different combinations of joining a table to a subquery of
- itself."""
+ User = self._fixture()
- users, User = self.tables.users, self.classes.User
+ s = Session(eng if bound_session else None)
+ q = s.query(User).filter(User.id == 7)
+ if not session_present:
+ q = q.with_session(None)
- self.mapper_registry.map_imperatively(User, users)
+ eq_ignore_whitespace(
+ str(q),
+ "SELECT users.id AS users_id, users.name AS users_name "
+ "FROM users WHERE users.id = ?"
+ if expect_bound
+ else "SELECT users.id AS users_id, users.name AS users_name "
+ "FROM users WHERE users.id = :id_1",
+ )
- sess = fixture_session()
+ def test_query_bound_session(self):
+ self._test(True, True, True)
- sel = sess.query(User).filter(User.id.in_([7, 8])).subquery()
- ualias = aliased(User)
+ def test_query_no_session(self):
+ self._test(False, False, False)
- with assertions.expect_deprecated_20(sef_dep):
- self.assert_compile(
- sess.query(ualias)
- .select_entity_from(sel)
- .filter(ualias.id > sel.c.id),
- "SELECT users_1.id AS users_1_id, "
- "users_1.name AS users_1_name "
- "FROM users AS users_1, ("
- "SELECT users.id AS id, users.name AS name FROM users "
- "WHERE users.id IN (__[POSTCOMPILE_id_1])) AS anon_1 "
- "WHERE users_1.id > anon_1.id",
- check_post_param={"id_1": [7, 8]},
- )
+ def test_query_unbound_session(self):
+ self._test(False, True, False)
- with assertions.expect_deprecated_20(sef_dep):
- self.assert_compile(
- sess.query(ualias)
- .select_entity_from(sel)
- .join(ualias, ualias.id > sel.c.id),
- "SELECT users_1.id AS users_1_id, "
- "users_1.name AS users_1_name "
- "FROM (SELECT users.id AS id, users.name AS name "
- "FROM users WHERE users.id IN "
- "(__[POSTCOMPILE_id_1])) AS anon_1 "
- "JOIN users AS users_1 ON users_1.id > anon_1.id",
- check_post_param={"id_1": [7, 8]},
- )
- with assertions.expect_deprecated_20(sef_dep):
- self.assert_compile(
- sess.query(ualias)
- .select_entity_from(sel)
- .join(ualias, ualias.id > User.id),
- "SELECT users_1.id AS users_1_id, "
- "users_1.name AS users_1_name "
- "FROM (SELECT users.id AS id, users.name AS name FROM "
- "users WHERE users.id IN (__[POSTCOMPILE_id_1])) AS anon_1 "
- "JOIN users AS users_1 ON users_1.id > anon_1.id",
- check_post_param={"id_1": [7, 8]},
- )
+class DeprecationScopedSessionTest(fixtures.MappedTest):
+ def test_config_errors(self):
+ sm = sessionmaker()
- with assertions.expect_deprecated_20(sef_dep):
- self.assert_compile(
- sess.query(ualias).select_entity_from(
- join(sel, ualias, ualias.id > sel.c.id)
- ),
- "SELECT users_1.id AS users_1_id, "
- "users_1.name AS users_1_name "
- "FROM "
- "(SELECT users.id AS id, users.name AS name "
- "FROM users WHERE users.id "
- "IN (__[POSTCOMPILE_id_1])) AS anon_1 "
- "JOIN users AS users_1 ON users_1.id > anon_1.id",
- check_post_param={"id_1": [7, 8]},
- )
+ def go():
+ s = sm()
+ s._is_asyncio = True
+ return s
+
+ Session = scoped_session(go)
+ with expect_deprecated(
+ "Using `scoped_session` with asyncio is deprecated and "
+ "will raise an error in a future version. "
+ "Please use `async_scoped_session` instead."
+ ):
+ Session()
+ Session.remove()
-class JoinLateralTest(fixtures.MappedTest, AssertsCompiledSQL):
- __dialect__ = default.DefaultDialect(supports_native_boolean=True)
- run_setup_bind = None
- run_setup_mappers = "once"
+class RequirementsTest(fixtures.MappedTest):
- run_create_tables = None
+ """Tests the contract for user classes."""
@classmethod
def define_tables(cls, metadata):
Table(
- "people",
+ "ht1",
metadata,
- Column("people_id", Integer, primary_key=True),
- Column("age", Integer),
- Column("name", String(30)),
+ Column(
+ "id", Integer, primary_key=True, test_needs_autoincrement=True
+ ),
+ Column("value", String(10)),
)
Table(
- "bookcases",
+ "ht2",
metadata,
- Column("bookcase_id", Integer, primary_key=True),
Column(
- "bookcase_owner_id", Integer, ForeignKey("people.people_id")
+ "id", Integer, primary_key=True, test_needs_autoincrement=True
),
- Column("bookcase_shelves", Integer),
- Column("bookcase_width", Integer),
+ Column("ht1_id", Integer, ForeignKey("ht1.id")),
+ Column("value", String(10)),
)
Table(
- "books",
+ "ht3",
metadata,
- Column("book_id", Integer, primary_key=True),
Column(
- "bookcase_id", Integer, ForeignKey("bookcases.bookcase_id")
+ "id", Integer, primary_key=True, test_needs_autoincrement=True
),
- Column("book_owner_id", Integer, ForeignKey("people.people_id")),
- Column("book_weight", Integer),
+ Column("value", String(10)),
+ )
+ Table(
+ "ht4",
+ metadata,
+ Column("ht1_id", Integer, ForeignKey("ht1.id"), primary_key=True),
+ Column("ht3_id", Integer, ForeignKey("ht3.id"), primary_key=True),
+ )
+ Table(
+ "ht5",
+ metadata,
+ Column("ht1_id", Integer, ForeignKey("ht1.id"), primary_key=True),
+ )
+ Table(
+ "ht6",
+ metadata,
+ Column("ht1a_id", Integer, ForeignKey("ht1.id"), primary_key=True),
+ Column("ht1b_id", Integer, ForeignKey("ht1.id"), primary_key=True),
+ Column("value", String(10)),
)
- @classmethod
- def setup_classes(cls):
- class Person(cls.Comparable):
- pass
-
- class Bookcase(cls.Comparable):
- pass
- class Book(cls.Comparable):
- pass
+class DeferredOptionsTest(AssertsCompiledSQL, _fixtures.FixtureTest):
+ __dialect__ = "default"
- @classmethod
- def setup_mappers(cls):
- Person, Bookcase, Book = cls.classes("Person", "Bookcase", "Book")
- people, bookcases, books = cls.tables("people", "bookcases", "books")
- cls.mapper_registry.map_imperatively(Person, people)
- cls.mapper_registry.map_imperatively(
- Bookcase,
- bookcases,
- properties={
- "owner": relationship(Person),
- "books": relationship(Book),
- },
+ def test_deep_options(self):
+ users, items, order_items, Order, Item, User, orders = (
+ self.tables.users,
+ self.tables.items,
+ self.tables.order_items,
+ self.classes.Order,
+ self.classes.Item,
+ self.classes.User,
+ self.tables.orders,
)
- cls.mapper_registry.map_imperatively(Book, books)
- # "sef" == "select entity from"
- def test_select_subquery_sef_implicit_correlate(self):
- Person, Book = self.classes("Person", "Book")
+ self.mapper_registry.map_imperatively(
+ Item,
+ items,
+ properties=dict(description=deferred(items.c.description)),
+ )
+ self.mapper_registry.map_imperatively(
+ Order,
+ orders,
+ properties=dict(items=relationship(Item, secondary=order_items)),
+ )
+ self.mapper_registry.map_imperatively(
+ User,
+ users,
+ properties=dict(orders=relationship(Order, order_by=orders.c.id)),
+ )
- s = fixture_session()
+ sess = fixture_session()
+ q = sess.query(User).order_by(User.id)
+ result = q.all()
+ item = result[0].orders[1].items[1]
- stmt = s.query(Person).subquery()
+ def go():
+ eq_(item.description, "item 4")
- subq = (
- s.query(Book.book_id)
- .filter(Person.people_id == Book.book_owner_id)
- .subquery()
- .lateral()
- )
+ self.sql_count_(1, go)
+ eq_(item.description, "item 4")
- with assertions.expect_deprecated_20(sef_dep):
- stmt = (
- s.query(Person, subq.c.book_id)
- .select_entity_from(stmt)
- .join(subq, true())
- )
+ sess.expunge_all()
+ with assertions.expect_deprecated(undefer_needs_chaining):
+ result = q.options(
+ undefer(User.orders, Order.items, Item.description)
+ ).all()
+ item = result[0].orders[1].items[1]
- self.assert_compile(
- stmt,
- "SELECT anon_1.people_id AS anon_1_people_id, "
- "anon_1.age AS anon_1_age, anon_1.name AS anon_1_name, "
- "anon_2.book_id AS anon_2_book_id "
- "FROM "
- "(SELECT people.people_id AS people_id, people.age AS age, "
- "people.name AS name FROM people) AS anon_1 "
- "JOIN LATERAL "
- "(SELECT books.book_id AS book_id FROM books "
- "WHERE anon_1.people_id = books.book_owner_id) AS anon_2 ON true",
- )
+ def go():
+ eq_(item.description, "item 4")
- def test_select_subquery_sef_implicit_correlate_coreonly(self):
- Person, Book = self.classes("Person", "Book")
+ self.sql_count_(0, go)
+ eq_(item.description, "item 4")
- s = fixture_session()
- stmt = s.query(Person).subquery()
+class SubOptionsTest(PathTest, OptionsQueryTest):
+ run_create_tables = False
+ run_inserts = None
+ run_deletes = None
- subq = (
- select(Book.book_id)
- .where(Person.people_id == Book.book_owner_id)
- .subquery()
- .lateral()
- )
+ def _assert_opts(self, q, sub_opt, non_sub_opts):
+ attr_a = {}
- with assertions.expect_deprecated_20(sef_dep):
- stmt = (
- s.query(Person, subq.c.book_id)
- .select_entity_from(stmt)
- .join(subq, true())
+ for val in sub_opt._to_bind:
+ val._bind_loader(
+ [
+ ent.entity_zero
+ for ent in q._compile_state()._lead_mapper_entities
+ ],
+ q._compile_options._current_path,
+ attr_a,
+ False,
)
- self.assert_compile(
- stmt,
- "SELECT anon_1.people_id AS anon_1_people_id, "
- "anon_1.age AS anon_1_age, anon_1.name AS anon_1_name, "
- "anon_2.book_id AS anon_2_book_id "
- "FROM "
- "(SELECT people.people_id AS people_id, people.age AS age, "
- "people.name AS name FROM people) AS anon_1 "
- "JOIN LATERAL "
- "(SELECT books.book_id AS book_id FROM books "
- "WHERE anon_1.people_id = books.book_owner_id) AS anon_2 ON true",
- )
-
- def test_select_subquery_sef_explicit_correlate_coreonly(self):
- Person, Book = self.classes("Person", "Book")
-
- s = fixture_session()
+ attr_b = {}
- stmt = s.query(Person).subquery()
+ for opt in non_sub_opts:
+ for val in opt._to_bind:
+ val._bind_loader(
+ [
+ ent.entity_zero
+ for ent in q._compile_state()._lead_mapper_entities
+ ],
+ q._compile_options._current_path,
+ attr_b,
+ False,
+ )
- subq = (
- select(Book.book_id)
- .correlate(Person)
- .where(Person.people_id == Book.book_owner_id)
- .subquery()
- .lateral()
- )
+ for k, l in attr_b.items():
+ if not l.strategy:
+ del attr_b[k]
- with assertions.expect_deprecated_20(sef_dep):
- stmt = (
- s.query(Person, subq.c.book_id)
- .select_entity_from(stmt)
- .join(subq, true())
+ def strat_as_tuple(strat):
+ return (
+ strat.strategy,
+ strat.local_opts,
+ strat.propagate_to_loaders,
+ strat._of_type,
+ strat.is_class_strategy,
+ strat.is_opts_only,
)
- self.assert_compile(
- stmt,
- "SELECT anon_1.people_id AS anon_1_people_id, "
- "anon_1.age AS anon_1_age, anon_1.name AS anon_1_name, "
- "anon_2.book_id AS anon_2_book_id "
- "FROM "
- "(SELECT people.people_id AS people_id, people.age AS age, "
- "people.name AS name FROM people) AS anon_1 "
- "JOIN LATERAL "
- "(SELECT books.book_id AS book_id FROM books "
- "WHERE anon_1.people_id = books.book_owner_id) AS anon_2 ON true",
+ eq_(
+ {path: strat_as_tuple(load) for path, load in attr_a.items()},
+ {path: strat_as_tuple(load) for path, load in attr_b.items()},
)
- def test_select_subquery_sef_explicit_correlate(self):
- Person, Book = self.classes("Person", "Book")
- s = fixture_session()
+class PolyCacheKeyTest(CacheKeyFixture, _poly_fixtures._Polymorphic):
+ run_setup_mappers = "once"
+ run_inserts = None
+ run_deletes = None
- stmt = s.query(Person).subquery()
+ def _stmt_20(self, *elements):
+ return tuple(
+ elem._statement_20() if isinstance(elem, sa.orm.Query) else elem
+ for elem in elements
+ )
- subq = (
- s.query(Book.book_id)
- .correlate(Person)
- .filter(Person.people_id == Book.book_owner_id)
- .subquery()
- .lateral()
+ def test_wp_queries(self):
+ Person, Manager, Engineer, Boss = self.classes(
+ "Person", "Manager", "Engineer", "Boss"
)
- with assertions.expect_deprecated_20(sef_dep):
- stmt = (
- s.query(Person, subq.c.book_id)
- .select_entity_from(stmt)
- .join(subq, true())
- )
+ def two():
+ wp = with_polymorphic(Person, [Manager, Engineer])
- self.assert_compile(
- stmt,
- "SELECT anon_1.people_id AS anon_1_people_id, "
- "anon_1.age AS anon_1_age, anon_1.name AS anon_1_name, "
- "anon_2.book_id AS anon_2_book_id "
- "FROM "
- "(SELECT people.people_id AS people_id, people.age AS age, "
- "people.name AS name FROM people) AS anon_1 "
- "JOIN LATERAL "
- "(SELECT books.book_id AS book_id FROM books "
- "WHERE anon_1.people_id = books.book_owner_id) AS anon_2 ON true",
- )
+ return fixture_session().query(wp)
+
+ def three():
+ wp = with_polymorphic(Person, [Manager, Engineer])
- def test_from_function_sef(self):
- Bookcase = self.classes.Bookcase
+ return fixture_session().query(wp).filter(wp.name == "asdfo")
- s = fixture_session()
+ def three_a():
+ wp = with_polymorphic(Person, [Manager, Engineer], flat=True)
- subq = s.query(Bookcase).subquery()
+ return fixture_session().query(wp).filter(wp.name == "asdfo")
- srf = lateral(func.generate_series(1, Bookcase.bookcase_shelves))
+ def five():
+ subq = (
+ select(Person)
+ .outerjoin(Manager)
+ .outerjoin(Engineer)
+ .subquery()
+ )
+ wp = with_polymorphic(Person, [Manager, Engineer], subq)
- with assertions.expect_deprecated_20(sef_dep):
- q = s.query(Bookcase).select_entity_from(subq).join(srf, true())
+ return fixture_session().query(wp).filter(wp.name == "asdfo")
- self.assert_compile(
- q,
- "SELECT anon_1.bookcase_id AS anon_1_bookcase_id, "
- "anon_1.bookcase_owner_id AS anon_1_bookcase_owner_id, "
- "anon_1.bookcase_shelves AS anon_1_bookcase_shelves, "
- "anon_1.bookcase_width AS anon_1_bookcase_width "
- "FROM (SELECT bookcases.bookcase_id AS bookcase_id, "
- "bookcases.bookcase_owner_id AS bookcase_owner_id, "
- "bookcases.bookcase_shelves AS bookcase_shelves, "
- "bookcases.bookcase_width AS bookcase_width FROM bookcases) "
- "AS anon_1 "
- "JOIN LATERAL "
- "generate_series(:generate_series_1, anon_1.bookcase_shelves) "
- "AS anon_2 ON true",
+ self._run_cache_key_fixture(
+ lambda: self._stmt_20(two(), three(), three_a(), five()),
+ compare_values=True,
)