model

package
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 9, 2026 License: MIT Imports: 8 Imported by: 0

Documentation

Overview

Package model defines document classes: the class definition as JSON, its validation into a compiled Class, the named schemas and the predefined vocabulary, and the diagnostics a definition earns.

A Definition is the class as written (docs/architecture.md, ADR-0013, ADR-0018, ADR-0022, ADR-0023, ADR-0031 to ADR-0034). Compile checks every name, type and property, binds every formula against the class's variables with the function classes its mode allows (ADR-0015), builds the dependency graph of the computed variables and refuses a cycle, and lays the variables out as the typed columns and child tables of ADR-0014. Everything it refuses, it refuses at definition time, as a list of Diagnostics: a stable code, the JSON pointer of the element, the position inside a formula, a message and, where there is one, a fix. A caller that drives the engine without a person watching reads the code and the path; a person reads the message.

The statechart (Phase 3), rules and actions (Phase 4) and access rules and rights (Phase 5) are part of the class format already. Compile checks their structure and binds their formulas so that a definition is valid as a whole, and the engine runs them when their phase arrives.

Index

Constants

View Source
const (
	// CodeBadJSON: the definition is not the JSON the class format expects.
	CodeBadJSON = "bad_json"
	// CodeMissing: a required element is absent or empty.
	CodeMissing = "missing"
	// CodeBadName: a name is not an identifier, or uses the reserved
	// separator or suffix.
	CodeBadName = "bad_name"
	// CodeReservedName: a name the generated tables use, or a keyword.
	CodeReservedName = "reserved_name"
	// CodeDuplicate: a name declared twice, in any case.
	CodeDuplicate = "duplicate"
	// CodeUnknownType: a type the type system does not have.
	CodeUnknownType = "unknown_type"
	// CodeUnknownSchema: an object or rows type names a schema that is not
	// defined.
	CodeUnknownSchema = "unknown_schema"
	// CodeSchemaCycle: a schema contains itself.
	CodeSchemaCycle = "schema_cycle"
	// CodeTooDeep: objects nest more than MaxObjectDepth deep.
	CodeTooDeep = "too_deep"
	// CodeNotAllowed: a property that this kind of variable, field or
	// element may not have.
	CodeNotAllowed = "not_allowed"
	// CodeBadFormula: a formula does not parse or bind; Pos says where.
	CodeBadFormula = "bad_formula"
	// CodeTypeMismatch: a formula's type is not the variable's.
	CodeTypeMismatch = "type_mismatch"
	// CodeNotACondition: a guard, rule condition or access rule is not
	// bool.
	CodeNotACondition = "not_a_condition"
	// CodeCycle: computed variables depend on each other in a loop.
	CodeCycle = "cycle"
	// CodeUnknownState, CodeUnknownVariable, CodeUnknownTransition: a
	// reference to a state, variable or transition the class lacks.
	CodeUnknownState      = "unknown_state"
	CodeUnknownVariable   = "unknown_variable"
	CodeUnknownTransition = "unknown_transition"
	// CodeBadTrigger: a trigger of a triggered variable is malformed.
	CodeBadTrigger = "bad_trigger"
	// CodeBadValue: an enum value, a range bound or a literal is wrong.
	CodeBadValue = "bad_value"
	// CodeTooManyColumns: a generated table would exceed MaxColumns.
	CodeTooManyColumns = "too_many_columns"
	// CodeNotSupported: a construct the format allows that the engine
	// does not implement yet.
	CodeNotSupported = "not_supported"
)

The diagnostic codes. The list is a contract once the validate command ships (ADR-0025): a new code is added, never renamed.

View Source
const MaxColumns = 1000

MaxColumns is the most columns a generated table may hold (ADR-0031).

View Source
const MaxObjectDepth = 4

MaxObjectDepth is how deep objects may nest below a variable: a schema of scalars is one deep, a schema with an object field two (ADR-0031).

View Source
const PathSeparator = "__"

PathSeparator joins the parts of a field path in a column name (ADR-0031); it is reserved in every name.

Variables

This section is empty.

Functions

func Compile

func Compile(def *Definition, schemas *SchemaSet) (*Class, Diagnostics)

Compile validates and compiles a definition against the schemas and no tables.

func CompileIn

func CompileIn(def *Definition, env Env) (*Class, Diagnostics)

CompileIn validates a definition against the environment and compiles it. It reports every finding it can, not the first: a class with three wrong formulas earns three diagnostics.

func CompileTable

func CompileTable(def *TableDef) (*Table, Diagnostics)

CompileTable checks a table definition and lays it out.

func Define

func Define(data []byte, schemas *SchemaSet) (*Class, Diagnostics)

Define parses and compiles a class definition in one step, against the schemas and no tables.

func DefineIn

func DefineIn(data []byte, env Env) (*Class, Diagnostics)

DefineIn parses and compiles a class definition against an environment.

func DefineTable

func DefineTable(data []byte) (*Table, Diagnostics)

DefineTable parses and compiles a table definition in one step.

func Parse

func Parse(data []byte) (*Definition, Diagnostics)

Parse decodes a class definition. Unknown properties are findings, so that a misspelt property never passes as an absent one.

func ParseSchema

func ParseSchema(data []byte) (*SchemaDef, Diagnostics)

ParseSchema decodes a schema definition, keeping the field order.

func ParseTable

func ParseTable(data []byte) (*TableDef, Diagnostics)

ParseTable decodes a table definition. Unknown properties are findings.

func VocabularyNames

func VocabularyNames() []string

VocabularyNames lists the predefined schemas in their order.

Types

type Access

type Access struct {
	Read, Create, Update, Delete *formula.Program
	Transition                   map[string]*formula.Program
}

Access holds the compiled class-level access rules.

type AccessDef

type AccessDef struct {
	Read       string            `json:"read,omitempty"`
	Create     string            `json:"create,omitempty"`
	Update     string            `json:"update,omitempty"`
	Delete     string            `json:"delete,omitempty"`
	Transition map[string]string `json:"transition,omitempty"`
}

AccessDef holds the class-level access rules (ADR-0010).

type Change

type Change struct {
	Kind ChangeKind
	// Name is the variable or the state the change is about, "" for the
	// class as a whole.
	Name string
	// Path is the JSON pointer of the element in the new definition, or
	// in the old one for a removal.
	Path string
}

Change is one difference between two versions of a class.

func Diff

func Diff(old, new *Class) []Change

Diff lists what a new version of a class changes against the old one, variables first in the new definition's order, then states, then the rest. Two identical definitions give no change.

type ChangeKind

type ChangeKind string

ChangeKind is what a redefinition does to one element of a class (ADR-0039).

const (
	// ChangeAddVariable: a variable the old version lacked.
	ChangeAddVariable ChangeKind = "add_variable"
	// ChangeRemoveVariable: a variable the new version lacks.
	ChangeRemoveVariable ChangeKind = "remove_variable"
	// ChangeRetypeVariable: the same variable with another type, scale or
	// shape.
	ChangeRetypeVariable ChangeKind = "retype_variable"
	// ChangeFormula: another formula, default, mode or triggers, or the
	// class title.
	ChangeFormula ChangeKind = "change_formula"
	// ChangeConstraints: another required, values, min, max, index or ref
	// class.
	ChangeConstraints ChangeKind = "change_constraints"
	// ChangeRemoveState: a state the new version lacks.
	ChangeRemoveState ChangeKind = "remove_state"
	// ChangeUnfinalState: a state that was terminal and is not.
	ChangeUnfinalState ChangeKind = "unfinal_state"
	// ChangeBehaviour: states added or made terminal, transitions, rules,
	// access, rights, or the header.
	ChangeBehaviour ChangeKind = "change_behaviour"
)

The kinds of change. The store decides which are allowed against the documents it holds; the model only names them.

type ChildTable

type ChildTable struct {
	Variable string
	Columns  []Column
}

ChildTable is the per-version table of a composite variable (ADR-0014): the schema's columns, or value for an array, after doc_id, version and idx.

type Class

type Class struct {
	Name        string
	Version     int
	Label       string
	Plural      string
	Description string
	Icon        string
	Color       string
	// Title is the compiled title formula, nil when TITLE is ID.
	Title *formula.Program
	// Variables in declaration order.
	Variables []*Variable

	// Order lists the auto computed variables, and "title" when there is
	// a title formula, in an order where every one comes after what it
	// reads: the full recalculation order of ADR-0015.
	Order []string
	// DefaultOrder lists the inputs with defaults in dependency order.
	DefaultOrder []string
	// Columns are the typed columns of the current and history tables
	// after the system columns, in variable order; Children the child
	// tables of composite variables.
	Columns  []Column
	Children []ChildTable
	// Schemas are the schemas the class uses, resolved at definition.
	Schemas     []*Schema
	States      *States
	Transitions []*Transition
	Rules       []*Rule
	Access      *Access
	// Rights is the rights table by state, then variable, "*" included
	// (ADR-0028); nil when the class declares none.
	Rights map[string]map[string]*Right
	Def    *Definition
	// contains filtered or unexported fields
}

Class is a compiled class definition: every formula bound, every reference checked, the computed variables in evaluation order, and the variables laid out as the columns and child tables of ADR-0014.

func (*Class) ReadRule added in v0.3.0

func (c *Class) ReadRule(state, variable string) *RightRule

ReadRule resolves the read right that governs a variable in a state (ADR-0028, ADR-0041): the cell of the named state and variable, then the state's "*", then the "*" state's cell of the variable, then its "*"; the first cell declaring a read rule decides. nil means the class rules alone apply and the variable is readable. A state of "" reads the "*" row alone.

func (*Class) Variable

func (c *Class) Variable(name string) (*Variable, bool)

Variable finds a variable by name, case-insensitively.

func (*Class) WriteRule added in v0.3.0

func (c *Class) WriteRule(state, variable string) *RightRule

WriteRule resolves the write right of a variable in a state the way ReadRule resolves the read right.

type Column

type Column struct {
	// Name is the column name: the variable, a flattened field path, or a
	// money column's currency twin.
	Name string
	Type formula.Type
	// Variable is the variable the column belongs to; Path the dotted
	// field path for an object leaf, the variable name for a scalar.
	Variable string
	Path     string
	Index    bool
}

Column is one storage column of the current and history tables.

type ComputeMode

type ComputeMode string

ComputeMode is how a computed variable recalculates (ADR-0015).

const (
	ModeAuto      ComputeMode = "auto"
	ModeTriggered ComputeMode = "triggered"
)

The modes.

type Definition

type Definition struct {
	Name        string `json:"name"`
	Version     int    `json:"version,omitempty"`
	Label       string `json:"label,omitempty"`
	Plural      string `json:"plural,omitempty"`
	Description string `json:"description,omitempty"`
	Icon        string `json:"icon,omitempty"`
	Color       string `json:"color,omitempty"`
	// Title is a formula over pure functions and the document's own
	// variables (ADR-0018); empty means TITLE equals ID.
	Title       string                          `json:"title,omitempty"`
	Variables   map[string]*VariableDef         `json:"variables"`
	States      *StatesDef                      `json:"states,omitempty"`
	Transitions []TransitionDef                 `json:"transitions,omitempty"`
	Rules       []RuleDef                       `json:"rules,omitempty"`
	Access      *AccessDef                      `json:"access,omitempty"`
	Rights      map[string]map[string]*RightDef `json:"rights,omitempty"`
	// VariableOrder lists the variables in the order they were written.
	VariableOrder []string `json:"-"`
	// RightsOrder lists the states of the rights table, then per state its
	// variables, in the order they were written.
	RightsOrder map[string][]string `json:"-"`
	// contains filtered or unexported fields
}

Definition is a class as written in JSON (docs/architecture.md). Maps keep JSON's lack of order, so the order of declaration, which decides column order and messages, is recorded apart in VariableOrder and RightsOrder by Parse.

type Diagnostic

type Diagnostic struct {
	// Code is a stable identifier of the kind of finding, one of the
	// Code constants. A caller branches on it.
	Code string `json:"code"`
	// Path is the JSON pointer of the element the finding is about,
	// such as /variables/total/formula or /transitions/1/guard.
	Path string `json:"path"`
	// Pos is the byte offset inside the formula at Path when the finding
	// is about a place in a formula, and -1 otherwise.
	Pos int `json:"pos"`
	// Message says what is wrong, for a person.
	Message string `json:"message"`
	// Hint says what to write instead, when the engine knows.
	Hint string `json:"hint,omitempty"`
}

Diagnostic is one definition-time finding.

func (Diagnostic) String

func (d Diagnostic) String() string

type Diagnostics

type Diagnostics []Diagnostic

Diagnostics is the list of findings of one definition. It is an error when it is not empty.

func (Diagnostics) Err

func (ds Diagnostics) Err() error

Err returns the diagnostics as an error, or nil when there are none.

func (Diagnostics) Error

func (ds Diagnostics) Error() string

func (Diagnostics) Has

func (ds Diagnostics) Has(code string) bool

Has reports whether a finding with the code is in the list.

type Env

type Env struct {
	Schemas *SchemaSet
	Sources formula.Sources
}

Env is what a definition compiles against: the schemas its objects name and the explicit tables its formulas may read (ADR-0016). A nil Schemas is the vocabulary alone; nil Sources are none.

type Leaf

type Leaf struct {
	// Path is the dotted field path from the variable, "shipping.city",
	// which is also the slot name the binder gives it.
	Path string
	// Column is the column name, the path joined with the separator.
	Column string
	Type   formula.Type
}

Leaf is one scalar column an object flattens to (ADR-0031).

type Presentation

type Presentation struct {
	Title, Subtitle *formula.Program
	Avatar          string
	Icon, Color     string
}

Presentation is a compiled presentation block.

type PresentationDef

type PresentationDef struct {
	Title    string `json:"title,omitempty"`
	Subtitle string `json:"subtitle,omitempty"`
	Avatar   string `json:"avatar,omitempty"`
	Icon     string `json:"icon,omitempty"`
	Color    string `json:"color,omitempty"`
}

PresentationDef says how a frontend shows an object of the schema (ADR-0032): Title and Subtitle are formulas over the fields, pure functions only; Avatar names a text field holding an image URL or a file hash; Icon and Color are as in the class header.

type Right struct {
	Read, Write *RightRule
}

Right is one cell of the rights table: a formula, or a list of groups meaning INGROUP of any of them. A nil Right in a cell means the rule was not declared and the class-level rules alone apply.

type RightDef

type RightDef struct {
	Read  json.RawMessage `json:"read,omitempty"`
	Write json.RawMessage `json:"write,omitempty"`
}

RightDef is one cell of the rights table (ADR-0028): a formula as text or a list of group names, for reading and for writing.

type RightRule

type RightRule struct {
	Formula *formula.Program
	Groups  []string
	Src     string
}

RightRule is a formula or a group list; Src is the rule as written, for the hint of a refusal.

type Rule

type Rule struct {
	On        string
	State     string
	Name      string
	Variables []string
	If        *formula.Program
	Actions   []json.RawMessage
}

Rule is one compiled rule; its actions are kept as written until Phase 4 gives them their meaning.

type RuleDef

type RuleDef struct {
	On        string            `json:"on"`
	State     string            `json:"state,omitempty"`
	Name      string            `json:"name,omitempty"`
	Variables []string          `json:"variables,omitempty"`
	If        string            `json:"if,omitempty"`
	Do        []json.RawMessage `json:"do"`
}

RuleDef is one event-condition-action rule (ADR-0009). The actions are kept as written; Phase 4 gives them their meaning.

type Schema

type Schema struct {
	Name string
	// Version counts the definitions of a user schema; a predefined one
	// is versioned with the engine.
	Version    int
	Predefined bool
	Extends    string
	// Type is the object type, fields in order, base fields first.
	Type formula.Type
	// Depth is 1 for a schema of scalars and one more per level of
	// object fields.
	Depth        int
	Presentation *Presentation
	Def          *SchemaDef
}

Schema is a resolved schema: its object type with every field's type in place, how deep it nests, and its compiled presentation.

type SchemaDef

type SchemaDef struct {
	Name         string            `json:"name"`
	Extends      string            `json:"extends,omitempty"`
	Fields       map[string]string `json:"fields"`
	Presentation *PresentationDef  `json:"presentation,omitempty"`
	// FieldOrder lists the fields in the order written; ParseSchema fills
	// it, and a caller building a SchemaDef in code may.
	FieldOrder []string `json:"-"`
}

SchemaDef is a schema as written: a named list of fields, each a scalar type other than json or object<Name> of another schema, with an optional base to extend and a presentation block (ADR-0031, ADR-0032).

type SchemaSet

type SchemaSet struct {
	// contains filtered or unexported fields
}

SchemaSet holds the schemas a database knows: the vocabulary and the user's. Names are unique in any case.

func NewSchemaSet

func NewSchemaSet() *SchemaSet

NewSchemaSet makes a set holding the predefined vocabulary.

func (*SchemaSet) Define

func (s *SchemaSet) Define(def *SchemaDef) (*Schema, Diagnostics)

Define adds a user schema, or a new version of one. A predefined name is refused. The schema is resolved when it is defined: a later change to a schema it extends or embeds does not reach it until it is defined again (ADR-0031, ADR-0032).

func (*SchemaSet) Lookup

func (s *SchemaSet) Lookup(name string) (*Schema, bool)

Lookup finds a schema by name, case-insensitively.

func (*SchemaSet) Names

func (s *SchemaSet) Names() []string

Names lists the schemas in definition order.

type States

type States struct {
	Initial string
	List    []string
	Final   []string
}

States is the compiled states block.

func (*States) Has

func (s *States) Has(state string) bool

Has reports whether the state is one of the class's.

func (*States) IsFinal

func (s *States) IsFinal(state string) bool

IsFinal reports whether the state is terminal (ADR-0039).

type StatesDef

type StatesDef struct {
	Initial string   `json:"initial"`
	List    []string `json:"list"`
	Final   []string `json:"final,omitempty"`
}

StatesDef is the statechart's states (ADR-0008).

type Table

type Table struct {
	Name        string
	Version     int
	Label       string
	Description string
	Binding     string
	// Fields are the logical columns in order; Columns the storage
	// columns, a money field as two.
	Fields  []formula.Field
	Columns []Column
	Key     []string
	Indexes [][]string
	Def     *TableDef
}

Table is a compiled table definition.

func (*Table) Field

func (t *Table) Field(name string) (formula.Field, bool)

Field finds a logical column by name, case-insensitively.

func (*Table) Source

func (t *Table) Source() *formula.Source

Source is the table as the binder sees it.

type TableDef

type TableDef struct {
	Name        string `json:"name"`
	Version     int    `json:"version,omitempty"`
	Label       string `json:"label,omitempty"`
	Description string `json:"description,omitempty"`
	// Columns maps a column name to its type: a scalar type other than
	// object; money is stored as two columns.
	Columns map[string]string `json:"columns"`
	// Key lists the columns that identify a row and order the table; a
	// LOOKUP returns the first matching row in this order (ADR-0020).
	Key []string `json:"key"`
	// Indexes lists further column sets to index.
	Indexes [][]string `json:"indexes,omitempty"`
	// Binding is sqlite (the default), duckdb or external (ADR-0016).
	Binding string `json:"binding,omitempty"`
	// ColumnOrder lists the columns in the order written.
	ColumnOrder []string `json:"-"`
}

TableDef is an explicit table as written (ADR-0016, ADR-0037): a name, its columns by scalar type, the key columns that order it and identify a row, optional secondary indexes, and the storage binding its rows live in.

type Transition

type Transition struct {
	Name  string
	From  []string
	To    string
	Guard *formula.Program
	// GuardSrc is the guard as written, for the hint of a refusal.
	GuardSrc string
}

Transition is one compiled transition; Guard is nil when there is none.

type TransitionDef

type TransitionDef struct {
	Name  string          `json:"name,omitempty"`
	From  json.RawMessage `json:"from"`
	To    string          `json:"to"`
	Guard string          `json:"guard,omitempty"`
}

TransitionDef is one transition. From is one state as text or a list of states. A transition without a name is eventless and needs a guard.

type Trigger

type Trigger struct {
	Kind string
	Arg  string
}

Trigger is one trigger of a triggered variable: refresh, enter:<state>, exit:<state>, transition:<name>, table:<name> or schedule:<spec>.

type Variable

type Variable struct {
	Name string
	// Computed is true for a variable with a formula, false for an input.
	Computed bool
	Type     formula.Type
	// RefClass is the class a ref variable points at.
	RefClass string
	Required bool
	// Default is the compiled default of an input, nil when none.
	Default *formula.Program
	// Formula and Mode belong to a computed variable; Triggers to a
	// triggered one.
	Formula  *formula.Program
	Mode     ComputeMode
	Triggers []Trigger
	// Values is the enum list of a text variable (ADR-0023).
	Values []string
	// Min and Max bound a numeric variable (ADR-0034); HasMin and HasMax
	// say which are set.
	Min, Max       formula.Value
	HasMin, HasMax bool
	Index          bool
	// Deps are the variables the formula or default reads, by declared
	// name, an object by its variable name whichever leaf was read.
	Deps []string
	// Sources are the explicit tables the formula or default reads
	// through LOOKUP, by name.
	Sources []string
	Def     *VariableDef
}

Variable is one compiled variable.

type VariableDef

type VariableDef struct {
	// Type is the type as written: a scalar name, int, decimal(s),
	// money(s), array<scalar>, object or rows. decimal and money without
	// a scale take Scale, or the default of two places.
	Type  string `json:"type"`
	Scale *int   `json:"scale,omitempty"`
	// Class names the class a ref points at.
	Class string `json:"class,omitempty"`
	// Schema is the schema of an object or rows variable: a schema name
	// as text, or for rows an inline object of column name to type.
	Schema json.RawMessage `json:"schema,omitempty"`
	// Input variables.
	Required bool   `json:"required,omitempty"`
	Default  string `json:"default,omitempty"`
	// Computed variables (ADR-0015).
	Formula string   `json:"formula,omitempty"`
	Mode    string   `json:"mode,omitempty"`
	On      []string `json:"on,omitempty"`
	// Values makes a text variable an enum (ADR-0023).
	Values []string `json:"values,omitempty"`
	// Min and Max bound a numeric variable (ADR-0034), as literals of its
	// type: a number, or text for an exact value.
	Min json.RawMessage `json:"min,omitempty"`
	Max json.RawMessage `json:"max,omitempty"`
	// Index asks for a B-tree index on the column.
	Index bool `json:"index,omitempty"`
	// contains filtered or unexported fields
}

VariableDef is one variable as written.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL