summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/ext/baked.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/ext/baked.py')
-rw-r--r--lib/sqlalchemy/ext/baked.py93
1 files changed, 58 insertions, 35 deletions
diff --git a/lib/sqlalchemy/ext/baked.py b/lib/sqlalchemy/ext/baked.py
index a9c79d6bd..24af454b6 100644
--- a/lib/sqlalchemy/ext/baked.py
+++ b/lib/sqlalchemy/ext/baked.py
@@ -13,19 +13,18 @@ compiled result to be fully cached.
"""
-import copy
import logging
from .. import exc as sa_exc
from .. import util
from ..orm import exc as orm_exc
from ..orm import strategy_options
+from ..orm.context import QueryContext
from ..orm.query import Query
from ..orm.session import Session
from ..sql import func
from ..sql import literal_column
from ..sql import util as sql_util
-from ..sql.selectable import LABEL_STYLE_TABLENAME_PLUS_COL
from ..util import collections_abc
@@ -209,9 +208,7 @@ class BakedQuery(object):
key += cache_key
self.add_criteria(
- lambda q: q._with_current_path(
- effective_path
- )._conditional_options(*options),
+ lambda q: q._with_current_path(effective_path).options(*options),
cache_path.path,
key,
)
@@ -228,14 +225,21 @@ class BakedQuery(object):
def _bake(self, session):
query = self._as_query(session)
- context = query._compile_context()
+ compile_state = query._compile_state()
- self._bake_subquery_loaders(session, context)
- context.session = None
- context.query = query = context.query.with_session(None)
+ self._bake_subquery_loaders(session, compile_state)
+
+ # TODO: compile_state clearly needs to be simplified here.
+ # if the session remains, fails memusage test
+ compile_state.orm_query = (
+ query
+ ) = (
+ compile_state.select_statement
+ ) = compile_state.query = compile_state.orm_query.with_session(None)
query._execution_options = query._execution_options.union(
{"compiled_cache": self._bakery}
)
+
# we'll be holding onto the query for some of its state,
# so delete some compilation-use-only attributes that can take up
# space
@@ -251,10 +255,10 @@ class BakedQuery(object):
# if the query is not safe to cache, we still do everything as though
# we did cache it, since the receiver of _bake() assumes subqueryload
# context was set up, etc.
- if context.query._bake_ok:
- self._bakery[self._effective_key(session)] = context
+ if compile_state.compile_options._bake_ok:
+ self._bakery[self._effective_key(session)] = compile_state
- return context
+ return compile_state
def to_query(self, query_or_session):
"""Return the :class:`_query.Query` object for use as a subquery.
@@ -314,9 +318,10 @@ class BakedQuery(object):
for step in self.steps[1:]:
query = step(query)
+
return query
- def _bake_subquery_loaders(self, session, context):
+ def _bake_subquery_loaders(self, session, compile_state):
"""convert subquery eager loaders in the cache into baked queries.
For subquery eager loading to work, all we need here is that the
@@ -325,28 +330,30 @@ class BakedQuery(object):
a "baked" query so that we save on performance too.
"""
- context.attributes["baked_queries"] = baked_queries = []
- for k, v in list(context.attributes.items()):
- if isinstance(v, Query):
- if "subquery" in k:
- bk = BakedQuery(self._bakery, lambda *args: v)
+ compile_state.attributes["baked_queries"] = baked_queries = []
+ for k, v in list(compile_state.attributes.items()):
+ if isinstance(v, dict) and "query" in v:
+ if "subqueryload_data" in k:
+ query = v["query"]
+ bk = BakedQuery(self._bakery, lambda *args: query)
bk._cache_key = self._cache_key + k
bk._bake(session)
baked_queries.append((k, bk._cache_key, v))
- del context.attributes[k]
+ del compile_state.attributes[k]
def _unbake_subquery_loaders(
- self, session, context, params, post_criteria
+ self, session, compile_state, context, params, post_criteria
):
"""Retrieve subquery eager loaders stored by _bake_subquery_loaders
and turn them back into Result objects that will iterate just
like a Query object.
"""
- if "baked_queries" not in context.attributes:
+ if "baked_queries" not in compile_state.attributes:
return
- for k, cache_key, query in context.attributes["baked_queries"]:
+ for k, cache_key, v in compile_state.attributes["baked_queries"]:
+ query = v["query"]
bk = BakedQuery(
self._bakery, lambda sess, q=query: q.with_session(sess)
)
@@ -354,7 +361,9 @@ class BakedQuery(object):
q = bk.for_session(session)
for fn in post_criteria:
q = q.with_post_criteria(fn)
- context.attributes[k] = q.params(**params)
+ v = dict(v)
+ v["query"] = q.params(**params)
+ context.attributes[k] = v
class Result(object):
@@ -432,26 +441,37 @@ class Result(object):
if not self.session.enable_baked_queries or bq._spoiled:
return self._as_query()._iter()
- baked_context = bq._bakery.get(bq._effective_key(self.session), None)
- if baked_context is None:
- baked_context = bq._bake(self.session)
+ baked_compile_state = bq._bakery.get(
+ bq._effective_key(self.session), None
+ )
+ if baked_compile_state is None:
+ baked_compile_state = bq._bake(self.session)
- context = copy.copy(baked_context)
+ context = QueryContext(baked_compile_state, self.session)
context.session = self.session
- context.attributes = context.attributes.copy()
bq._unbake_subquery_loaders(
- self.session, context, self._params, self._post_criteria
+ self.session,
+ baked_compile_state,
+ context,
+ self._params,
+ self._post_criteria,
)
- context.statement._label_style = LABEL_STYLE_TABLENAME_PLUS_COL
+ # asserts true
+ # if isinstance(baked_compile_state.statement, expression.Select):
+ # assert baked_compile_state.statement._label_style == \
+ # LABEL_STYLE_TABLENAME_PLUS_COL
+
if context.autoflush and not context.populate_existing:
self.session._autoflush()
- q = context.query.params(self._params).with_session(self.session)
+ q = context.orm_query.params(self._params).with_session(self.session)
for fn in self._post_criteria:
q = fn(q)
- return q._execute_and_instances(context)
+ params = q.load_options._params
+
+ return q._execute_and_instances(context, params=params)
def count(self):
"""return the 'count'.
@@ -566,7 +586,7 @@ class Result(object):
def _load_on_pk_identity(self, query, primary_key_identity):
"""Load the given primary key identity from the database."""
- mapper = query._mapper_zero()
+ mapper = query._only_full_mapper_zero("load_on_pk_identity")
_get_clause, _get_params = mapper._get_clause
@@ -592,8 +612,11 @@ class Result(object):
_lcl_get_clause, nones
)
- _lcl_get_clause = q._adapt_clause(_lcl_get_clause, True, False)
- q._criterion = _lcl_get_clause
+ # TODO: can mapper._get_clause be pre-adapted?
+ q._where_criteria = (
+ sql_util._deep_annotate(_lcl_get_clause, {"_orm_adapt": True}),
+ )
+
for fn in self._post_criteria:
q = fn(q)
return q