check limit as subquery

This commit is contained in:
collerek
2021-03-07 15:47:02 +01:00
parent e8329c0dcd
commit b4350d11f1
2 changed files with 48 additions and 22 deletions

View File

@ -34,6 +34,18 @@ class OrderAction(QueryAction):
def field_alias(self) -> str: def field_alias(self) -> str:
return self.target_model.get_column_alias(self.field_name) return self.target_model.get_column_alias(self.field_name)
def get_field_name_text(self) -> str:
"""
Escapes characters if it's required.
Substitutes values of the models if value is a ormar Model with its pk value.
Compiles the clause.
:return: complied and escaped clause
:rtype: sqlalchemy.sql.elements.TextClause
"""
prefix = f"{self.table_prefix}_" if self.table_prefix else ""
return f"{prefix}{self.table}" f".{self.field_alias}"
def get_text_clause(self) -> sqlalchemy.sql.expression.TextClause: def get_text_clause(self) -> sqlalchemy.sql.expression.TextClause:
""" """
Escapes characters if it's required. Escapes characters if it's required.

View File

@ -137,7 +137,10 @@ class Query:
) = sql_join.build_join() ) = sql_join.build_join()
if self._pagination_query_required(): if self._pagination_query_required():
self._build_pagination_condition() limit_qry, on_clause = self._build_pagination_condition()
self.select_from = sqlalchemy.sql.join(
self.select_from, limit_qry, on_clause
)
expr = sqlalchemy.sql.select(self.columns) expr = sqlalchemy.sql.select(self.columns)
expr = expr.select_from(self.select_from) expr = expr.select_from(self.select_from)
@ -149,7 +152,10 @@ class Query:
return expr return expr
def _build_pagination_condition(self) -> None: def _build_pagination_condition(
self
) -> Tuple[
sqlalchemy.sql.expression.TextClause, sqlalchemy.sql.expression.TextClause]:
""" """
In order to apply limit and offset on main table in join only In order to apply limit and offset on main table in join only
(otherwise you can get only partially constructed main model (otherwise you can get only partially constructed main model
@ -164,22 +170,30 @@ class Query:
primary key values. Whole query is used to determine the values. primary key values. Whole query is used to determine the values.
""" """
pk_alias = self.model_cls.get_column_alias(self.model_cls.Meta.pkname) pk_alias = self.model_cls.get_column_alias(self.model_cls.Meta.pkname)
qry_text = sqlalchemy.text(f"{self.table.name}.{pk_alias}") pk_aliased_name = f"{self.table.name}.{pk_alias}"
limit_qry = sqlalchemy.sql.select([qry_text]) qry_text = sqlalchemy.text(pk_aliased_name)
maxes = dict()
for order in list(self.sorted_orders.keys()):
if order is not None and order.get_field_name_text() != pk_aliased_name:
maxes[order.get_field_name_text()] = sqlalchemy.text(
f"max({order.get_field_name_text()})")
limit_qry = sqlalchemy.sql.select([qry_text]+list(maxes.values()))
limit_qry = limit_qry.select_from(self.select_from) limit_qry = limit_qry.select_from(self.select_from)
limit_qry = self._apply_expression_modifiers(limit_qry) limit_qry = self._apply_expression_modifiers(limit_qry)
limit_qry = FilterQuery(filter_clauses=self.filter_clauses).apply(limit_qry) limit_qry = FilterQuery(filter_clauses=self.filter_clauses).apply(limit_qry)
limit_qry = FilterQuery(filter_clauses=self.exclude_clauses, exclude=True).apply( limit_qry = FilterQuery(filter_clauses=self.exclude_clauses,
exclude=True).apply(
limit_qry limit_qry
) )
limit_qry = limit_qry.group_by(qry_text) limit_qry = limit_qry.group_by(qry_text)
# limit_qry = OrderQuery(sorted_orders=self.sorted_orders).apply(limit_qry) limit_qry = OrderQuery(sorted_orders=self.sorted_orders).apply(limit_qry)
limit_qry = LimitQuery(limit_count=self.limit_count).apply(limit_qry) limit_qry = LimitQuery(limit_count=self.limit_count).apply(limit_qry)
limit_qry = OffsetQuery(query_offset=self.query_offset).apply(limit_qry) limit_qry = OffsetQuery(query_offset=self.query_offset).apply(limit_qry)
limit_action = FilterAction( limit_qry = limit_qry.alias("limit_query")
filter_str=f"{pk_alias}__in", value=limit_qry, model_cls=self.model_cls on_clause = sqlalchemy.text(
) f"limit_query.{pk_alias}={self.table.name}.{pk_alias}")
self.filter_clauses.append(limit_action) return limit_qry, on_clause
def _apply_expression_modifiers( def _apply_expression_modifiers(
self, expr: sqlalchemy.sql.select self, expr: sqlalchemy.sql.select