Documentation
¶
Overview ¶
Package build translates a *spec.Spec into a *plan.DAG.
The package lives separately from `plan` because the translator imports `plan/nodes` (which already imports `plan` itself) — Go disallows the resulting import cycle. Splitting Build into its own package keeps `plan` dependency-free of the concrete node implementations while still giving callers a single entry point.
Translation rules:
- Each declared dataset (top-level `data` + each `datasets[name]`) becomes one leaf node: SourceNode for `data.source`, InlineNode for `data.values`. Name-only datasets register as aliases for the already-registered dataset they point at.
- Each transform[] entry becomes one node, chained on top of the previous transform's output (or the active dataset's leaf).
- If the leaf encoding declares an aggregate on any channel, a synthetic GroupAggregateNode is injected at the tail.
- The tail node is marked as the DAG's sole sink and its id is returned alongside the DAG so the encode stage knows which table to consume. P03's synthetic SinkNode (D030) was retired in P05 — see D040.
Out of scope for P03 (raise PRISM_PLAN_002):
- Composition primitives (layer, concat, hconcat, vconcat, facet, repeat) — P08/P09.
- Selections — P13.
Validator-gate failures (PRISM_SPEC_*) are NOT re-checked here; the builder trusts that callers have already validated the spec. The builder only emits codes that belong to plan-time concerns: PRISM_PLAN_001 (cycle, via TopoLevels), PRISM_PLAN_002 (out of scope feature), PRISM_PLAN_003 (missing dataset reference).
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Build ¶
Build translates a *spec.Spec into a *plan.DAG. The returned NodeID is the tip — the table the encode stage consumes. The builder marks this node as the DAG's sole sink so existing renderers (DOT / JSON / text) and the executor continue to find it via DAG.Sinks() without a code change.
func BuildComposite ¶
BuildComposite translates a composite *spec.Spec (layer / concat / hconcat / vconcat / facet / repeat) into a *plan.CompositeDAG. Layer + concat / hconcat / vconcat have each child build its own sub-plan + tip (P08). Facet builds the parent's shared upstream pipeline once and returns a single ChildDAG (D054); the encoder fans out into per-partition SceneCells. Repeat builds one sub-plan per cell after applying the field-name substitution (D055 / D056). The executor runs every child independently via plan.Execute and the encoder assembles a SceneDoc from the collected per-child tables.
Nested composition: layer / concat children stay flat (D050); facet / repeat children may themselves be composite, and the encoder recurses through EncodeComposite per cell (D058).
Per D049, children inherit the parent's `datasets` block (and top-level `data` when the child has none) via mergeParentDatasets; per-child `data` overrides win.
func IsComposite ¶
IsComposite reports whether s carries any of the six composition primitives (layer / concat / hconcat / vconcat / facet / repeat). Callers route composite specs through BuildComposite; flat specs continue through Build.
Types ¶
type Options ¶
type Options struct {
FS afero.Fs
Resolver resolve.Resolver
Backend plan.Backend
DatasetRegistry resolve.DatasetRegistry
// DataResolver handles the `{data: {ref: "<name>"}}` spec variant.
// Nil means refs are unresolvable (any ref-form dataset surfaces
// PRISM_RESOLVE_REF_UNRESOLVED at build time). Sync only — callers
// expecting async resolution must pre-resolve the dataset and
// register a synchronous getter that returns the cached value.
DataResolver resolve.DataResolver
}
Options carries the runtime knobs the builder needs to build leaf nodes (Source needs an afero.Fs + Resolver) and to wire the compile backend that every linear node's Execute routes through. FS defaults to afero.NewOsFs(); Resolver defaults to resolve.New(nil); Backend is left nil so callers that don't care about execution (e.g. `prism plan`) skip the dependency on compile/. The CLI `execute` subcommand passes `inmem.New()`. See D033.
DatasetRegistry (P07, optional) resolves name-only dataset references like `{"data": {"name": "current"}}` through the server-side / env- loaded alias map (see resolve/registry_dataset.go). Nil = no registry; the builder behaviour reverts to P03–P06 (name-only ref raises PRISM_PLAN_003 when the alias is undeclared inline).