Source code for codegen_database.ext.refresh.query
"""Query builders for incremental refresh patterns.
:func:`construct_unincorporated_since_query` returns a SELECT for rows in the
source table that have not yet been rolled into an aggregate, based on
a watermark timestamp.
Usage::
# Find orders not yet incorporated into the daily aggregate.
q = construct_unincorporated_since_query(
orders,
watermark_col="created_at",
since="2024-06-01T00:00:00Z",
)
# Without a fixed timestamp: use a subquery as the checkpoint.
q = construct_unincorporated_since_query(
orders,
watermark_col="created_at",
since_subquery="SELECT MIN(day::timestamptz) FROM app.orders_daily_agg",
)
"""
from __future__ import annotations
from typing import TYPE_CHECKING
from sqlalchemy import select, text
from codegen_database.errors import CodegenDatabaseValidationError
if TYPE_CHECKING:
from sqlalchemy import Select
from codegen_database.factory.context import ContextSource
[docs]
def construct_unincorporated_since_query(
source: ContextSource,
*,
watermark_col: str = "created_at",
since: str | None = None,
since_subquery: str | None = None,
table_key: str = "raw_table",
) -> Select:
"""Return rows in *source* not yet incorporated into an aggregate.
Generates::
SELECT * FROM <source_table>
WHERE <watermark_col> >= <since>
where ``<since>`` is either a literal timestamp or the result of a
subquery.
Args:
source: A factory instance or declarative class with a
populated context.
watermark_col: Column in the source table to compare against
the cutoff (default ``"created_at"``).
since: ISO 8601 timestamp string used as the lower bound.
Exactly one of *since* or *since_subquery* must be given.
since_subquery: SQL expression (a scalar subquery) that returns
a ``TIMESTAMPTZ`` cutoff. Exactly one of *since* or
*since_subquery* must be given.
table_key: Key in ``ctx`` for the source table
(default ``"raw_table"``).
Returns:
A SQLAlchemy :class:`~sqlalchemy.Select`.
Raises:
CodegenDatabaseValidationError: If neither or both of *since* and
*since_subquery* are provided.
"""
if (since is None) == (since_subquery is None):
msg = "Exactly one of 'since' or 'since_subquery' must be provided."
raise CodegenDatabaseValidationError(msg)
table = source.ctx[table_key]
if since is not None:
cutoff = text(f"'{since}'::timestamptz")
else:
cutoff = text(f"({since_subquery})")
return select(table).where(table.c[watermark_col] >= cutoff)