Source code for loom.core.model.scoped
"""Marker and descriptors for tables whose rows are scoped by a column value."""
from __future__ import annotations
from collections.abc import Iterable, Mapping
from dataclasses import dataclass
from typing import ClassVar
from loom.core.model.field import Reach
from loom.core.model.privilege import READ_WRITE, Privilege
[docs]
class RowScoped:
"""Mark a model as row-scoped; adds no column.
The product names the scope on one of the model's columns with
``ColumnField(scope=...)``. A read-only scoped table narrows
``__scope_privileges__`` to ``{Privilege.SELECT}``.
"""
__row_scoped__: ClassVar[bool] = True
__scope_privileges__: ClassVar[frozenset[Privilege]] = READ_WRITE
[docs]
@dataclass(frozen=True, slots=True)
class ScopeColumn:
"""One scoped column: which scope, which column, and how far it reaches."""
scope: str
column: str
on: Reach
elevable: bool
@property
def is_boundary(self) -> bool:
return self.on == "both" and not self.elevable
[docs]
@dataclass(frozen=True, slots=True)
class ScopedTable:
"""A compiled scoped table: its scopes, the privileges it grants and its partition column.
``partition_by`` names the column a range-partitioned table is partitioned
by, ``None`` for a plain table.
"""
schema: str | None
name: str
scopes: tuple[ScopeColumn, ...]
privileges: frozenset[Privilege]
partition_by: str | None = None
@property
def boundary(self) -> ScopeColumn:
return next(scope for scope in self.scopes if scope.is_boundary)
[docs]
def registered_model_tables(
registered: Mapping[str, str | None], scoped: Iterable[ScopedTable]
) -> frozenset[str]:
"""The registered tables that stand for a model table.
``registered`` maps each table the guard registered to the table it is a
partition of, or ``None``. A partition of a partitioned scoped table is
not in the model and stands for its parent, so it is left out; every
other registered table is kept.
"""
partitioned = {table.name for table in scoped if table.partition_by is not None}
return frozenset(name for name, parent in registered.items() if parent not in partitioned)