Skip to content

tdfs4ds.genai.deep_tables

tdfs4ds.genai.deep_tables

Deep (historian) source tables: documenting the table as if it were pivoted.

A deep table stores one row per (id columns, timestamp, tag) with the value in a payload column - a historian, an entity-attribute-value table. What a reader needs documented is each tag (each value of the tag column: a sensor, a signal), as if it were a column of the pivoted table.

Nothing here adds a table or alters one:

  • the layout - which columns are the id columns, the tag, the payload and the timestamp, and the timestamp's time zone - is a reserved section DEEP_LAYOUT of the table in the business dictionary (JSON), like the agent's FEATURE_GROUPS;
  • each tag is a FS_BUSINESS_DICTIONARY_COLUMNS row of the table whose COLUMN_NAME is the tag value. A row is a tag when the table has a layout and the name is not a physical column. Provenance (IMPORTED / MANUAL), the log, the index and protection from LLM runs apply as to any column.

A table without a layout behaves exactly as before everywhere.

The LLM documenting a process that reads a deep table receives only the tags the process's SQL names (its string and number literals), never the whole tag list: see :func:scope_deep_context.

DEEP_LAYOUT_SECTION module-attribute

DEEP_LAYOUT_SECTION = 'DEEP_LAYOUT'

RESERVED_SECTION_NAMES module-attribute

RESERVED_SECTION_NAMES = ('FEATURE_GROUPS', DEEP_LAYOUT_SECTION, 'EXPOSES', 'ATTACHED')

_COLUMN_NAME_MAX module-attribute

_COLUMN_NAME_MAX = 128

_ROLES module-attribute

_ROLES = ('id_columns', 'tag_column', 'payload_column', 'timestamp_column')

_COMMENT_RE module-attribute

_COMMENT_RE = compile('--[^\\n]*|/\\*.*?\\*/', S)

_STRING_RE module-attribute

_STRING_RE = compile("'((?:[^']|'')*)'")

_NUMBER_RE module-attribute

_NUMBER_RE = compile('(?<![\\w.])(\\d+(?:\\.\\d+)?)(?![\\w.])')

logger_safe

logger_safe(level, message, *args, **kwargs)

Wrapper around the global logger that only emits logs when tdfs4ds.DISPLAY_LOGS is True. level is a string like "info", "error", etc.

qualified

qualified(database, object_name, force=False)

Build db.obj with each part quoted only as needed.

qualified('TDB', 'FS_X') == 'TDB.FS_X' (unchanged for ordinary names); qualified('SVC@CORP', 'FS_X') == '"SVC@CORP".FS_X'. An empty/None database yields the bare object name, so unqualified callers keep working.

force=True quotes both parts unconditionally — only for the sites that have always emitted quotes and whose exact text is already persisted (dataset view DDL, returned volatile-table names).

sql_literal

sql_literal(value)

Escape value for use inside a single-quoted SQL string literal.

For the DBC probes and catalog predicates that compare a name as data (WHERE DatabaseName = '…'). The caller supplies the surrounding quotes.

reserved_sections_sql

reserved_sections_sql() -> str

'FEATURE_GROUPS', 'DEEP_LAYOUT' for a SECTION_NAME NOT IN (...) predicate.

_names

_names(v) -> List[str]

build_layout

build_layout(physical: Iterable[str], *, existing: Optional[dict] = None, id_columns=None, tag_column=None, payload_column=None, timestamp_column=None, timestamp_timezone: Optional[str] = None) -> dict

The layout of a deep table, checked against its physical columns.

Values not given are taken from existing (a later call can change one role). The tag, payload and timestamp columns are required; the id columns may be empty. Column names are returned with the table's own spelling.

render_layout

render_layout(layout: dict) -> str

parse_layout

parse_layout(text) -> Optional[dict]

The layout stored in the DEEP_LAYOUT section, or None (absent / unreadable).

describe_layout

describe_layout(layout: dict, table_label: str = '') -> str

One sentence for a reader or an LLM: the grain, where the value is, the time zone.

tag_name_problem

tag_name_problem(name: str, physical: Iterable[str]) -> Optional[str]

Why name cannot be stored as a tag, or None.

tags_from_input

tags_from_input(tags, tag_name_column=None, tag_text_column=None, unit_column=None) -> Dict[str, str]

{tag: text} from a dict or a DataFrame (tag, description [, unit]).

sql_literals

sql_literals(sql: str) -> Set[str]

Every string literal and bare number of sql, upper-cased, comments removed.

This is deliberately shape-blind: a tag can be named in a CASE, an IN list, a PIVOT, a join condition or a QUALIFY - the literal is what they share.

tags_named

tags_named(sql: str, tag_names: Iterable[str]) -> List[str]

The documented tags that sql names, in the documented spelling.

scope_deep_context

scope_deep_context(ctx: dict, consumer_sql: str, layout: dict, physical: Iterable[str], max_tags: Optional[int] = None) -> dict

The upstream context of a deep table, reduced to what consumer_sql uses.

Physical columns keep their documentation; tags are kept only when the SQL names them. When it names none (tags chosen through a join, or the tag kept as a row), at most max_tags tags are kept so the LLM sees the shape without the whole list. Returns a new dict with deep set; the input is unchanged.

undocumented_tags_named

undocumented_tags_named(consumer_sql: str, layout: dict, documented: Iterable[str]) -> List[str]

String literals compared with the tag column (=, <>, IN (...)) that have no documentation.

Best effort, for a log line telling the user which tags to document next; it never decides what the LLM receives.

format_deep_context_lines

format_deep_context_lines(ctx: dict) -> List[str]

Prompt lines for a deep table (used by _format_upstream_context).

read_layout

read_layout(db: str, obj: str) -> Optional[dict]

The stored layout of db.obj, or None. Fail-open (None) on any error.

physical_columns

physical_columns(db: str, obj: str) -> List[str]

The table's columns (DBC), in order. Raises when the object does not exist.

deep_context

deep_context(ctx: Optional[dict], consumer_sql: str) -> Optional[dict]

ctx scoped for consumer_sql when its object is a deep table; else ctx unchanged.

deep_table_tags

deep_table_tags(database: str, table: str, *, since=None, until=None, documented: Optional[bool] = None)

The tags present in a deep table, with their row counts and first/last timestamps.

One GROUP BY over the table, bounded by since / until on the timestamp column when given (interpreted in the layout's time zone, UTC by default). This reads the table: on a large historian, give a window. It is never run by tdfs4ds on its own.

documented=False keeps the tags without documentation, True the documented ones; None keeps all, with a DOCUMENTED column.