Documentation
¶
Overview ¶
Package semantic resolves physical columns (a source + collection + set of scanned columns) to the entity fields a project's model says they mean.
Resolve is pure - no I/O, no mutation - so it can be called from anywhere that already has a project's entities in memory: the datatug-cli HTTP resolver behind GET /datatug/semantic/columns (REQ:semantic-resolution-endpoint in datatug/datatug's core-investigation-loop feature), the TUI, or a future `datatug context` verb. Placement note: the resolver lives here in datatug-core rather than in datatug-cli/pkg/semantic (as sketched in the Phase-1 plan's task 5) because datatug-cli currently vendors its own copy of this package's types and a separate stream is restoring its module dependency; the HTTP endpoint itself is still wired in datatug-cli. This is a planner decision, not a founder ruling - open to being moved once the module dependency lands.
Declared EntityField.Mappings always win over an EntityField.NamePatterns match; NamePatterns are tried only for a column with no declared mapping anywhere in the project, and the result is labelled Inferred. See Resolve for the full tie-break rule when more than one field could claim the same column.
RelatedLookups and Applicable build on the same SemanticValue shape a Resolution plus its cell value produces: the former finds every other collection reachable from a selected value (foreign keys in both directions, plus the same field mapped elsewhere); the latter matches the project's library queries against the values on hand and reports a human-readable resolution chain for each bound parameter.
Index ¶
- func Applicable(queries []*datatug.QueryDef, available []SemanticValue) (applicable []ApplicableQuery, notYet []NotYetApplicable)
- func DisplayColumns(entity *datatug.Entity, schema TableSchema, key datatug.PhysicalRef) ([]DisplayColumn, Provenance)
- func ParameterAcceptsKey(parameterType string, kind KeyKind) bool
- type ApplicableQuery
- type Binding
- type Column
- type DisplayColumn
- type KeyKind
- type Lookup
- type LookupKind
- type LookupSource
- type NotYetApplicable
- type ParameterMeaning
- type Provenance
- type Resolution
- type SchemaKey
- type SemanticValue
- type TableSchema
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Applicable ¶ added in v0.19.0
func Applicable(queries []*datatug.QueryDef, available []SemanticValue) (applicable []ApplicableQuery, notYet []NotYetApplicable)
Applicable splits queries into those every required, Meta-tagged parameter of which can be bound from available, and those still missing at least one. A parameter with no Meta is never considered - it stays unbound and never blocks applicability, whether required or not. A Meta-tagged optional parameter (IsRequired == false) is bound when available can satisfy it, but its absence never blocks applicability either; only an unsatisfied *required* Meta-tagged parameter lands a query in notYet.
available is order-sensitive: when more than one entry shares the same Entity+Field (e.g. the Investigation Context holds a stale value and the user's current selection holds a newer one), the last entry for that Entity+Field wins - callers should append newer values after older ones.
Pure: no I/O.
func DisplayColumns ¶ added in v0.74.1
func DisplayColumns(entity *datatug.Entity, schema TableSchema, key datatug.PhysicalRef) ([]DisplayColumn, Provenance)
DisplayColumns returns the columns a lookup picker shows beside the key of the collection key names (backstage parameter-lookup REQ:display-columns).
Declared: each field ID in entity.Display, in order, that has a declared mapping in key's source and collection becomes a column titled with the field's Title (or its ID); at most six. When that yields nothing, up to three columns are inferred: first the entity's other fields mapped in the same collection (field order), then the schema's first text columns (schema order). The key column is never repeated, and when the schema lists its columns every display column must be one of them. entity must not be nil.
func ParameterAcceptsKey ¶ added in v0.74.1
ParameterAcceptsKey reports whether a parameter of parameterType can hold a key of kind: a string parameter takes both kinds (an integer key as decimal text), an integer parameter only integer keys, and no other type takes any.
Types ¶
type ApplicableQuery ¶ added in v0.19.0
type ApplicableQuery struct {
Query *datatug.QueryDef
Bindings []Binding
// Chain is the human-readable resolution chain, one entry per bound
// parameter: "<column> → <entity>.<field> (<declared|inferred>) →
// parameter <parameterID>".
Chain []string
}
ApplicableQuery is a query every required, semantically-tagged parameter of which could be bound from the available values.
type Binding ¶ added in v0.19.0
type Binding struct {
Parameter string
Value interface{}
From SemanticValue
}
Binding is one query parameter bound to a semantic value.
type DisplayColumn ¶ added in v0.74.1
type DisplayColumn struct {
// Column is the physical column name in the lookup source's collection.
Column string
// Field is the entity field the column comes from; empty for a column
// inferred from the schema alone.
Field string
// Label is the field's title, its ID, or (for a schema-only column) the
// column name.
Label string
// Provenance is Declared for a column listed in Entity.Display and
// Inferred for the fallback columns.
Provenance Provenance
}
DisplayColumn is one column shown beside the key in a lookup picker.
type KeyKind ¶ added in v0.74.1
type KeyKind string
KeyKind is the kind of value a lookup source's key column holds. Its values match the contract's TypedValue types, so a picked key can be returned as {type: KeyKind, value: ...}.
func ColumnKeyKind ¶ added in v0.74.1
ColumnKeyKind classifies a declared column type by SQLite-style affinity: a type containing "INT" is an integer key, one containing "CHAR", "CLOB" or "TEXT" (or the DataTug type "string") is a text key. Any other type - decimal, real, date, blob - cannot be a lookup key and yields "".
type Lookup ¶ added in v0.19.0
type Lookup struct {
Source string
Collection string
Column string
Kind LookupKind
Via string
}
Lookup is one related-record path reachable from a SemanticValue: the caller filters Lookup.Collection (in Lookup.Source) where Lookup.Column equals the selected value - RelatedLookups itself performs no such filter, it only says where to look (REQ:related-lookup-execution builds and runs that query server-side).
func RelatedLookups ¶ added in v0.19.0
func RelatedLookups(entities []*datatug.Entity, schemaByCollection map[SchemaKey]TableSchema, selected SemanticValue) []Lookup
RelatedLookups returns every other collection reachable from a selected semantic value: through declared foreign keys in both directions within selected's own source (schemaByCollection must carry that source's scanned schema for this to find anything), and through mappings of the same entity field (selected.Entity + selected.Field) in other sources or collections. A column that is neither part of a foreign-key relationship nor mapped anywhere else yields nothing.
A datatug.ForeignKey names the columns of the referenced table it points to (RefColumns, in the order of its own Columns) when its source reported them, and RelatedLookups uses them: for LookupForeignKey the join column is the referenced column that pairs with selected.Column, for a single-column and a composite key alike. A key without them (read from a source that does not report the referenced column, or stored before projects kept them) does not say which column it targets, so two heuristics fill that gap, both using the referenced table's primary key as the assumed join target:
- LookupForeignKey: selected.Column matches one of the current table's own ForeignKey.Columns: this reports RefTable's primary key (its first column, when the schema for RefTable is known and single-column-keyed; the selected column's own name otherwise) as the join column.
- LookupReferencedBy: selected.Column must be part of the current table's own primary key for a "referenced by" lookup to fire at all, since that is this model's only signal that an incoming foreign key targets this exact column.
Order is deterministic: lookups in selected's own source come first, ordered by target Collection name (ties broken by Kind); then cross-source SameField lookups, ordered by Source then Collection name. Pure: no I/O.
type LookupKind ¶ added in v0.19.0
type LookupKind string
LookupKind identifies how a Lookup was derived.
const ( // LookupForeignKey means the selected value's own column is a foreign // key, pointing at Lookup.Collection. LookupForeignKey LookupKind = "foreignKey" // LookupReferencedBy means Lookup.Collection has a foreign key pointing // back at the selected value's table. LookupReferencedBy LookupKind = "referencedBy" // LookupSameField means Lookup.Collection maps the same semantic field // (the selected value's Entity + Field) in a different source or // collection. LookupSameField LookupKind = "sameField" )
type LookupSource ¶ added in v0.74.1
type LookupSource struct {
Source string
Collection string
KeyColumn string
KeyKind KeyKind
Display []DisplayColumn
// DisplayProvenance is Declared when Display came from Entity.Display and
// Inferred when it was guessed (the picker must say so). It is Declared
// for an empty Display, since nothing was guessed.
DisplayProvenance Provenance
// Meaning is the parameter meaning the source was resolved through: the
// parameter's declared Meta, or a key field inferred from its name
// (ResolveParameterMeaning). The picker must label an Inferred meaning.
Meaning ParameterMeaning
}
LookupSource is one collection a parameter's value can be picked from: its single-column primary key is declared to carry the parameter's meaning.
func LookupSources ¶ added in v0.74.1
func LookupSources(entities []*datatug.Entity, schemaByCollection map[SchemaKey]TableSchema, parameter datatug.ParameterDef, hostSource string) []LookupSource
LookupSources returns the collections the value of parameter can be picked from (backstage parameter-lookup REQ:lookup-source-resolution): every declared mapping (EntityField.Mappings, never a NamePatterns inference) of the field the parameter means (ResolveParameterMeaning: its declared Meta, else the one key field whose NamePatterns match its name), whose collection's schema in schemaByCollection has a primary key of exactly one column equal to the mapped column, with a key kind (ColumnKeyKind of that column's type in TableSchema.Columns, or of the entity field's type when the schema lists no columns) that parameter's type can hold (ParameterAcceptsKey).
A parameter with no meaning, a multi-value parameter, and a parameter of type "record" or "recordset" have no lookup sources. A collection whose schema is unknown is not a source.
Order is deterministic: sources in hostSource first (pass "" when the host has no source of its own), then by Source, then by Collection.
Pure: no I/O, no mutation of its inputs.
type NotYetApplicable ¶ added in v0.19.0
type NotYetApplicable struct {
Query *datatug.QueryDef
// Missing lists each unsatisfied required parameter's semantic field, as
// "<entity>.<field>".
Missing []string
}
NotYetApplicable is a query with at least one required, semantically-tagged parameter the available values could not satisfy.
type ParameterMeaning ¶ added in v0.74.1
type ParameterMeaning struct {
// Ref is the entity field the parameter means.
Ref datatug.EntityFieldRef
// Provenance is Declared when Ref is the parameter's own Meta and
// Inferred when it came from a key field's NamePatterns.
Provenance Provenance
// Rule names the pattern that matched, for an Inferred meaning, in the
// form semantic.Resolve uses ("namePattern:regexp:\\w+CustomerID").
Rule string
}
ParameterMeaning is the meaning a parameter's lookup resolves through (backstage parameter-lookup REQ:inferred-parameter-meaning).
func ResolveParameterMeaning ¶ added in v0.74.1
func ResolveParameterMeaning(entities []*datatug.Entity, parameter datatug.ParameterDef) (meaning ParameterMeaning, ok bool)
ResolveParameterMeaning returns the meaning of parameter: its declared Meta when set (Declared, even when no entity declares that field), else the one key field (EntityField.IsKeyField) whose NamePatterns match the parameter's ID without a leading "@" (Inferred). Patterns are matched as semantic.Resolve matches column names.
ok is false when the parameter has no Meta and no key field matches, or when key fields of more than one entity field match: an ambiguous name gives no meaning, never a guess between entities. A pattern that cannot be evaluated (an invalid regexp, an unknown type) never matches.
Pure: no I/O, no mutation of its inputs.
type Provenance ¶
type Provenance string
Provenance identifies how a Resolution was determined.
const ( // Declared means the column matched an EntityField's declared Mappings. Declared Provenance = "declared" // Inferred means the column matched an EntityField's NamePatterns, with // no declared mapping present for it. Inferred Provenance = "inferred" )
type Resolution ¶
type Resolution struct {
Column string
Entity string
Field string
Provenance Provenance
// Rule documents how the winner was chosen: which name pattern matched
// (for Inferred), and/or a tie-break note when more than one field
// resolved the same column at the same provenance level.
Rule string
// Err is set only when the column had NamePatterns candidates that could
// not be evaluated (e.g. an invalid regexp) and neither a declared
// mapping nor a valid inferred candidate resolved it. When Err is set,
// Entity, Field, Provenance and Rule are zero.
Err error
}
Resolution is what one Column resolved to.
func Resolve ¶
func Resolve(entities []*datatug.Entity, source, collection string, columns []Column) []Resolution
Resolve returns, for each Column, the entity field it maps to in the given source/collection (table): declared EntityField.Mappings win; absent a declared mapping, EntityField.NamePatterns are tried; a column matching neither is simply absent from the result (see REQ:field-mapping-model in datatug/datatug's core-investigation-loop feature).
When more than one field resolves the same column at the same provenance level, the field belonging to the lowest Entity.ID wins (Entity.ID, then EntityField.ID, ascending) and the tie is recorded in the winning Resolution's Rule. This keeps Resolve deterministic without requiring callers to pre-sort entities.
Resolve is pure: it performs no I/O and does not mutate entities. It never panics - a pattern that fails to evaluate (e.g. invalid regexp syntax) yields a Resolution with Err set instead, unless a declared mapping or another, valid pattern already resolved the column.
type SchemaKey ¶ added in v0.19.0
SchemaKey identifies one collection (table or view) within one source.
type SemanticValue ¶ added in v0.19.0
type SemanticValue struct {
Entity string
Field string
Value interface{}
Source string
Collection string
Column string
Provenance Provenance
}
SemanticValue is one resolved cell: a value in a physical column, and the semantic field a resolver (see Resolve) said it means. Provenance is a deliberate addition beyond the field-mapping-model REQ's own sketch of this type: it is needed to render the "(declared)"/"(inferred)" segment of an Applicable resolution Chain (REQ:applicable-queries), so a caller can build one SemanticValue directly from a Resolution and pass it to both RelatedLookups and Applicable.
type TableSchema ¶ added in v0.19.0
type TableSchema struct {
PrimaryKey *datatug.UniqueKey
ForeignKeys datatug.ForeignKeys
ReferencedBy datatug.ReferencedBys
Columns []Column
}
TableSchema is the subset of a scanned table/view's metadata RelatedLookups and LookupSources need: its primary key, its foreign-key graph in both directions (datatug.ForeignKeys/datatug.ReferencedBys, as scanned by the DB driver) and, optionally, its columns in schema order with their declared types (LookupSources uses them for the key's kind and the display columns).