Source code for codegen_database.plugins.index
"""Index plugin for codegen_database dimensions.
:class:`TableIndexPlugin` converts
:class:`~codegen_database.index.CodegenDatabaseIndex`
items into real SQLAlchemy ``Index`` objects on a table.
"""
from __future__ import annotations
from typing import TYPE_CHECKING
from sqlalchemy import Index, text
from codegen_database.index import collect_indices
from codegen_database.plugin import Dynamic, Plugin, requires
from codegen_database.validation import validate_column_references
if TYPE_CHECKING:
from codegen_database.factory.context import FactoryContext
[docs]
@requires(Dynamic("table_key"))
class TableIndexPlugin(Plugin):
"""Materialize index items as table indexes.
Turns :class:`~codegen_database.index.CodegenDatabaseIndex` items
into SQLAlchemy ``Index`` objects.
Reads ``CodegenDatabaseIndex`` items from ``ctx.schema_items``, validates
column names, and creates ``Index`` objects on the target table.
Extra keyword arguments on each ``CodegenDatabaseIndex`` are passed
through to the underlying ``sqlalchemy.Index``.
Args:
table_key: Key in ``ctx`` for the target table
(default ``"primary"``).
"""
def __init__(self, table_key: str = "primary") -> None:
"""Store the context key."""
self.table_key = table_key
[docs]
def run(self, ctx: FactoryContext) -> None:
"""Collect, validate, and create indexes."""
indices = collect_indices(ctx.schema_items)
if not indices:
return
table = ctx[self.table_key]
col_names = {c.name for c in table.columns}
for idx in indices:
validate_column_references(
f"CodegenDatabaseIndex {idx.name!r}",
idx.column_names(),
col_names,
)
resolved = idx.resolve(lambda c: c)
has_expressions = any(expr not in col_names for expr in resolved)
cols = [
table.c[expr] if expr in col_names else text(expr)
for expr in resolved
]
sa_index = Index(
idx.name,
*cols,
unique=idx.unique,
**idx.kw,
)
if has_expressions:
table.append_constraint(sa_index)