Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions pkg-py/src/commons/_data_dictionary.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@

Prose fields stay as authored markdown, because they reach the model verbatim.

Reading a dictionary also type-checks any ``definitions:`` blocks against
data-dict's expression language, so an unusable definition raises here,
before any source exists. Only the lowering to SQL waits for a dialect.

The three channels are methods rather than separate structures.
``pkg-r`` spreads the same rendering across ``R/data-dictionary.R``,
``R/prompt.R`` and ``R/context-layer.R``; here the dictionary owns it and the
Expand Down Expand Up @@ -128,6 +132,12 @@ class DataDictionary(_Permissive):
tables: dict[str, Table] = {}
relationships: list[Relationship] = []
glossary: dict[str, str] = {}
# Phase 1 of the compiler, keyed by table name. Source-independent, so it
# is produced here; the SQL needs a dialect and waits for `data_source()`.
# Values map each definition name to its
# `_definitions._export.DefinitionExport`, typed loosely so this module
# need not import the compiler's types.
definition_exports: dict[str, Any] = {}

@model_validator(mode="before")
@classmethod
Expand All @@ -136,6 +146,14 @@ def _normalize(cls, data: Any) -> Any:
return data
data = dict(data)
data["tables"] = _key_by_name(data.get("tables"), "table")
# Type-checked here rather than at `data_source()` so an unusable
# definition is reported when the dictionary is read, before any
# source exists. Only the lowering to SQL needs a dialect.
from ._definitions._export import export_spec

data["definition_exports"] = {
name: table.definitions for name, table in export_spec(data).items()
}
for field in ("name", "description", "details"):
data[field] = _prose(data.get(field))
relationships = data.get("relationships") or []
Expand Down Expand Up @@ -235,9 +253,7 @@ def _relationships_text(self, table: str) -> str | None:
lines = []
for relationship in self.relationships:
text = " ".join(
part
for part in (relationship.join, relationship.description)
if part
part for part in (relationship.join, relationship.description) if part
)
if not _word_pattern(table).search(text):
continue
Expand Down
10 changes: 10 additions & 0 deletions pkg-py/src/commons/_data_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,11 @@ def data_source(
tables of the engine and board forms; `dictionary` attaches a data
dictionary to any form. To use either as a frame name, call
`DataSource.from_frames()` directly.

A dictionary's governed definitions are compiled for the source's
dialect here, so construction raises if the dialect has no emitter
(only DuckDB does today), if a definition sits on a table the source
does not expose, or if a metric mixes row and aggregate grain.
"""
from ._data_dictionary import as_data_dictionary

Expand All @@ -272,6 +277,11 @@ def data_source(
source = DataSource.from_frames(**frames)

source.dictionary = resolved
if resolved is not None:
# The dialect is only known now, which is why lowering waits for it.
from ._definitions import attach_compiled_definitions

attach_compiled_definitions(resolved, source.dialect(), set(source.tables))
return source


Expand Down
5 changes: 4 additions & 1 deletion pkg-py/src/commons/_definitions/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Governed definitions: the registry, and the compiler that will feed it.
"""Governed definitions: the registry, and the compiler that feeds it.

Definitions are authored in data-dict's expression language, not in the SQL
dialect of the attached source, so they are type-checked against the
Expand All @@ -12,6 +12,7 @@
authority, not this code.
"""

from ._compile import attach_compiled_definitions, mixed_grain
from ._registry import (
ExportRecord,
Registry,
Expand All @@ -28,10 +29,12 @@
"ExportRecord",
"Registry",
"applied_text",
"attach_compiled_definitions",
"build_registry",
"context_chunks",
"entry_text",
"expand_tokens",
"index_overflows",
"index_text",
"mixed_grain",
]
Loading
Loading