Documentation
¶
Overview ¶
Package semantic is a dependency-light semantic layer for Go: a model (entities, dimensions, metrics, join graph) plus a compiler that turns a semantic Query — "this metric by these dimensions" — into fanout/chasm-safe SQL. It speaks no LLM, opens no database; it only produces SQL strings.
The core technique (the reason this exists): aggregate each measure to its base grain inside a CTE first, THEN join dimensions. That single move makes fan-out and chasm joins impossible by construction.
Index ¶
- type ANSI
- type Compiled
- type Dialect
- type Dimension
- type Entity
- type Filter
- type Join
- type Metric
- type Model
- func (m *Model) Dimension(name string) *Dimension
- func (m *Model) DimensionsFor(metric string) ([]string, error)
- func (m *Model) Entity(name string) *Entity
- func (m *Model) Index() error
- func (m *Model) Metric(name string) *Metric
- func (m *Model) MetricNames() []string
- func (m *Model) ReachableEntities(base string) map[string]bool
- type Postgres
- type Query
- type UnknownMetricError
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type ANSI ¶
type ANSI struct{}
ANSI is a portable fallback (SQLite/DuckDB-ish): ? placeholders, no date_trunc.
func (ANSI) DistinctFrom ¶
func (ANSI) Placeholder ¶
func (ANSI) QuoteIdent ¶
type Compiled ¶
Compiled is the output: SQL plus ordered bind arguments.
func Compile ¶
Compile turns a semantic Query into fanout/chasm-safe SQL for the dialect.
Algorithm: each base metric is aggregated to the requested dimension grain in its OWN CTE (joining only upward via many-to-one edges, so the leaf grain is never multiplied); the CTEs are then null-safe outer-joined on the shared dimensions and combined (derived formulas computed in the outer SELECT). This is what makes fan-out and chasm joins impossible by construction.
type Dialect ¶
type Dialect interface {
Name() string
QuoteIdent(string) string // quote a table/column identifier
DateTrunc(grain, expr string) string // truncate a date/timestamp to a grain
Placeholder(i int) string // bind placeholder for the i-th arg (1-based)
DistinctFrom(left, right string) string // null-safe equality for outer joins
}
Dialect captures the per-engine SQL differences the compiler needs. It only shapes SQL text — it never opens a connection. Postgres ships here; Snowflake/Databricks/DuckDB are added the same way.
type Dimension ¶
type Dimension struct {
Name string `yaml:"name"`
Entity string `yaml:"entity"`
Column string `yaml:"column"`
Type string `yaml:"type"` // categorical | time
Mask string `yaml:"mask"`
}
Dimension is a typed attribute to group/filter by, named in business words. Mask is the SQL expression returned when the caller may not see the raw value.
type Entity ¶
type Entity struct {
Name string `yaml:"name"`
Table string `yaml:"table"`
PrimaryKey string `yaml:"primary_key"`
}
Entity is a real business thing with a primary key the layer joins on — the key is declared, never guessed.
type Filter ¶
type Filter struct {
Dimension string `json:"dimension"`
Op string `json:"op"` // = | != | > | >= | < | <= | in
Values []any `json:"values"` // one value for scalar ops; many for "in"
}
Filter is one predicate against a dimension.
type Join ¶
type Join struct {
From string `yaml:"from"`
To string `yaml:"to"`
FromKey string `yaml:"from_key"`
ToKey string `yaml:"to_key"`
Cardinality string `yaml:"cardinality"` // many_to_one | one_to_many | many_to_many
}
Join is one declared edge of the join graph: keys + cardinality. The compiler only ever traverses declared edges in the safe (many-to-one) direction; a missing edge is refused, never invented.
type Metric ¶
type Metric struct {
Name string `yaml:"name"`
Description string `yaml:"description"`
Synonyms []string `yaml:"synonyms"`
// base metric
Entity string `yaml:"entity"`
Agg string `yaml:"agg"` // sum | count | count_distinct | avg | min | max
Expr string `yaml:"expr"` // SQL expr at base grain, e.g. "quantity * unit_price"
// derived metric
Formula string `yaml:"formula"` // expression over metric names
// time-window metric: a transform of metric Of over the time dimension.
// Window is one of: rolling:N | cumulative | prior:N | delta:N
Of string `yaml:"of"`
Window string `yaml:"window"`
// governance
Roles []string `yaml:"roles"` // if set, only these roles may resolve the metric
}
Metric is an aggregated number with grain + aggregation locked in. A simple metric aggregates Expr over its base Entity; a derived metric is a formula over other metric names (e.g. "total_revenue - refund_total") — which is how chasm traps are avoided: each base metric aggregates in its own CTE.
type Model ¶
type Model struct {
Entities []Entity `yaml:"entities"`
Joins []Join `yaml:"joins"`
Dimensions []Dimension `yaml:"dimensions"`
Metrics []Metric `yaml:"metrics"`
// contains filtered or unexported fields
}
Model is the single source of truth: business meaning compiled to SQL once.
func (*Model) DimensionsFor ¶
DimensionsFor returns the dimensions that can slice the metric WITHOUT a fanout — i.e. dimensions whose entity is reachable from every base metric the metric depends on. (This is why "net_revenue by product_category" is rejected: refunds can't reach product.) Powers the get_dimensions tool so agents self-correct.
func (*Model) MetricNames ¶
MetricNames returns metric names in definition order (for list_metrics tools).
type Postgres ¶
type Postgres struct{}
Postgres dialect.
func (Postgres) DistinctFrom ¶
func (Postgres) Placeholder ¶
func (Postgres) QuoteIdent ¶
type Query ¶
type Query struct {
Metrics []string // metric names to compute
GroupBy []string // dimension names to slice by
Where []Filter // filters expressed against dimensions, not raw columns
TimeGrain string // day | week | month | quarter | year — applied to time dimensions in GroupBy
OrderBy string // a metric or dimension name (presentation only)
Descending bool
Limit int
}
Query is a semantic query: pure intent, zero table names, zero join keywords. "These metrics, by these dimensions, filtered like so, at this time grain."
type UnknownMetricError ¶
type UnknownMetricError struct{ Name string }
UnknownMetricError is returned when a metric name doesn't exist.
func (*UnknownMetricError) Error ¶
func (e *UnknownMetricError) Error() string