Documentation
¶
Overview ¶
Package formula holds the formula language: lexer, parser, function catalog, binder, bytecode, the Go virtual machine and the SQL generator with its SQLite and DuckDB dialects. One compiler, three targets; the browser VM of Phase 7 executes the same bytecode.
Parse turns text into a tree, Bind turns the tree into a Program by the static typing rules of ADR-0019, VM.Run executes a Program over the values of its slots, and GenerateSQL turns a Program into a value and an error expression for a Dialect. The grammar and semantics are fixed by ADR-0019, the query functions by ADR-0020, and the suite under conformance/ is the specification. Composite values and the query functions are not implemented yet.
Index ¶
- Constants
- Variables
- func Classes() map[Class]string
- func Equal(a, b Value) bool
- func IsKeyword(name string) bool
- func NearlyEqual(a, b Value, rel float64) bool
- func ParseCaseDate(s string) (int64, error)
- func ParseCaseDay(s string) (int64, error)
- func ParseExact(s string, t Type) (Value, *EvalError)
- func Render(v Value) string
- func Rescale(v Value, scale int) (Value, *EvalError)
- func SetupSources(db *sql.DB, d Dialect, rows map[*Source][][]Value) error
- func Sexpr(n Node) string
- type Array
- type Binary
- type BindOptions
- type BindingSuite
- type BlankLit
- type BoolLit
- type Call
- type Case
- type CaseContext
- type Class
- type Column
- type Context
- type DecConst
- type Dialect
- type DuckDB
- func (d DuckDB) Call(name string, args []SQLExpr, params *Params) (SQLExpr, error)
- func (DuckDB) ColumnType(k Kind) string
- func (c DuckDB) Cond(e SQLExpr) string
- func (DuckDB) ContextArgs(ctx *Context) []any
- func (DuckDB) False() string
- func (DuckDB) IntLit(m int64) string
- func (d DuckDB) Limits() Limits
- func (DuckDB) Load(column string, k Kind) string
- func (c DuckDB) Mant(e SQLExpr) string
- func (DuckDB) Name() string
- func (DuckDB) Narrow(val string) string
- func (DuckDB) NotFinite(val string) string
- func (c DuckDB) Num(e SQLExpr) string
- func (DuckDB) NumberLit(f float64) string
- func (DuckDB) OverflowErr(val string) string
- func (DuckDB) Param(name string) string
- func (DuckDB) Pow(x, y string) string
- func (c DuckDB) RawMant(e SQLExpr) string
- func (d DuckDB) Render(e SQLExpr) string
- func (DuckDB) Setup() []string
- func (c DuckDB) Text(e SQLExpr) string
- func (DuckDB) TextLit(s string) string
- func (DuckDB) True() string
- func (d DuckDB) WithLimits(l Limits) Dialect
- type Error
- type EvalError
- type Field
- type Function
- type Ident
- type If
- type Instr
- type Kind
- type Limits
- type Member
- type MemoryExecutor
- type Mode
- type Node
- type NumberLit
- type Op
- type Param
- type Params
- type Program
- type QueryExecutor
- type QuerySlot
- type RegisteredFunc
- type RejectCase
- type Rows
- type SQL
- type SQLBinding
- type SQLExpr
- type SQLResult
- type SQLite
- func (d SQLite) Call(name string, args []SQLExpr, params *Params) (SQLExpr, error)
- func (SQLite) ColumnType(k Kind) string
- func (c SQLite) Cond(e SQLExpr) string
- func (SQLite) ContextArgs(ctx *Context) []any
- func (d SQLite) ContextArgsFor(ctx *Context, names []string, dst []any) []any
- func (SQLite) False() string
- func (SQLite) IntLit(m int64) string
- func (d SQLite) Limits() Limits
- func (SQLite) Load(column string, k Kind) string
- func (c SQLite) Mant(e SQLExpr) string
- func (SQLite) Name() string
- func (SQLite) Narrow(val string) string
- func (SQLite) NotFinite(val string) string
- func (c SQLite) Num(e SQLExpr) string
- func (SQLite) NumberLit(f float64) string
- func (SQLite) OverflowErr(val string) string
- func (SQLite) Param(name string) string
- func (SQLite) Pow(x, y string) string
- func (c SQLite) RawMant(e SQLExpr) string
- func (d SQLite) Render(e SQLExpr) string
- func (SQLite) Setup() []string
- func (c SQLite) Text(e SQLExpr) string
- func (SQLite) TextLit(s string) string
- func (SQLite) True() string
- func (d SQLite) WithLimits(l Limits) Dialect
- type Scope
- type Slot
- type Source
- type SourceSet
- type Sources
- type Suite
- type SuiteLimits
- type SuiteSource
- type SyntaxSuite
- type TextLit
- type ThisRef
- type Token
- type TokenKind
- type Type
- type Unary
- type VM
- type Value
- func Blank() Value
- func Bool(b bool) Value
- func Date(days int64) Value
- func DateTime(secs int64) Value
- func Day(year int, month int, day int) Value
- func Decimal(mant int64, scale int) Value
- func ExactFromFloat(f float64, t Type) (Value, bool)
- func JSON(s string) Value
- func Money(mant int64, scale int, currency string) Value
- func Number(f float64) Value
- func ParseCaseValue(raw json.RawMessage, t Type) (Value, error)
- func Ref(s string) Value
- func Text(s string) Value
- func ValueFromDriver(v any, k Kind) Value
- func ValueOfType(v any, t Type, cur any) Value
- func (v Value) Currency() string
- func (v Value) Days() int64
- func (v Value) DriverValue() any
- func (v Value) IsBlank() bool
- func (v Value) Kind() Kind
- func (v Value) Mant() int64
- func (v Value) Num() float64
- func (v Value) Scale() int
- func (v Value) Secs() int64
- func (v Value) Str() string
- func (v Value) String() string
- func (v Value) Truth() bool
- type Variable
Constants ¶
const ( ErrDivByZero = "div_by_zero" ErrNotANumber = "not_a_number" ErrBadText = "bad_text" ErrOutOfRange = "out_of_range" ErrLengthMismatch = "length_mismatch" ErrTooManyElements = "too_many_elements" ErrQueryFailed = "query_failed" ErrOverflow = "overflow" ErrInexact = "inexact" ErrCurrencyMismatch = "currency_mismatch" )
Error codes (ADR-0019, ADR-0020, ADR-0022, ADR-0024).
const CurrencySuffix = "_currency"
CurrencySuffix is appended to a money variable's name for the column that holds its currency.
const DefaultMaxText = 1 << 16
DefaultMaxText is the text limit of a new database: 65,536 code points, room for a long note, and small enough that a vector of 2,048 of them on the analytical engine stays under a gigabyte.
const DivScaleStep = 4
DivScaleStep is how many digits a division adds to the dividend's scale, the rule MySQL uses: 1.00 / 3 is 0.333333 at scale six.
const MaxScale = 18
MaxScale is the most digits after the point an exact value may carry. Eighteen leaves one digit before the point at the top of the range and keeps every power of ten in an int64.
const MinMaxText = 64
MinMaxText is the smallest text limit a database may set: every rendering of a number or a date fits in it.
Variables ¶
var ErrorCodes = map[string]bool{ "div_by_zero": true, "not_a_number": true, "bad_text": true, "out_of_range": true, "length_mismatch": true, "too_many_elements": true, "unknown_source": true, "unknown_column": true, "query_failed": true, "overflow": true, "inexact": true, "currency_mismatch": true, }
ErrorCodes is the closed list of evaluation error codes (ADR-0019, ADR-0020, ADR-0022, ADR-0024). A case may only expect one of these.
var RoundMethods = []string{"half_up", "half_even", "down", "up", "floor", "ceiling"}
RoundMethods lists the names ROUND and DECIMAL accept, in catalog order.
Functions ¶
func Equal ¶
Equal reports whether two values are the same value of the same kind. An exact value compares by mantissa and scale, so 0.3 and 0.30 differ. It is the identity used by tests, not the = operator of the language.
func IsKeyword ¶ added in v0.2.0
IsKeyword reports whether a name, in any case, is a keyword of the language and so can never name a variable, a field, a column or a table (ADR-0019).
func NearlyEqual ¶
NearlyEqual compares two values exactly, except numbers, which may differ by the relative tolerance: the allowance of ADR-0019 for floating-point aggregates across targets.
func ParseCaseDate ¶
ParseCaseDate reads an instant as the suite writes it: YYYY-MM-DD or YYYY-MM-DD HH:MM:SS, UTC, as seconds since the epoch.
func ParseCaseDay ¶ added in v0.2.0
ParseCaseDay reads a calendar day as the suite writes it, YYYY-MM-DD, as days since 1970-01-01.
func ParseExact ¶ added in v0.2.0
ParseExact reads an exact number written as text, "12.30" for a decimal or "12.30 PLN" for a money (ADR-0022), as a value of the type, brought to the type's scale. A digit the scale would drop is the error inexact, a mantissa past int64 is overflow, and anything else is bad_text.
func Render ¶ added in v0.2.0
Render renders a value as the TEXT function does: a decimal with every place, a money with its currency, a date as YYYY-MM-DD, a datetime as YYYY-MM-DD HH:MM:SS, a blank as the empty text (ADR-0019, ADR-0022).
func Rescale ¶ added in v0.2.0
Rescale brings an exact value to another scale: up is exact, down is the error inexact when a dropped digit is not zero. A blank stays blank; a value that is not exact is returned as it is.
func SetupSources ¶ added in v0.2.0
SetupSources creates the tables of the sources in a database, named as the sources are, and fills them: the conformance and property runners' half of LOOKUP on the SQL dialects. Rows are row-major in column order; a money column is its amount and its currency column.
Types ¶
type Array ¶
Array is an array<scalar>, stored column-wise: numbers, dates and booleans in Nums, text, refs and json in Strs, with Nulls marking blank elements. Composite operations arrive with a later change.
type Binary ¶
Binary is an infix operation. Op is one of the arithmetic, text, comparison and logical operator kinds. Const marks a +, - or * of two constant expressions, which the binder folds.
type BindOptions ¶
type BindOptions struct {
Mode Mode
// Sources are the explicit tables LOOKUP may read (ADR-0016); nil
// means none, and every LOOKUP is an unknown source.
Sources Sources
}
BindOptions configures a bind.
type BindingSuite ¶
type BindingSuite struct {
Suite string `json:"suite"`
Description string `json:"description,omitempty"`
Variables map[string]string `json:"variables,omitempty"`
Schemas map[string]map[string]string `json:"schemas,omitempty"`
// Sources declares the tables LOOKUP may read, as in an evaluation
// suite; their rows are not needed to bind.
Sources map[string]*SuiteSource `json:"sources,omitempty"`
// Mode is "any" (the default), "auto" (ADR-0015) or "pure" (ADR-0018).
Mode string `json:"mode,omitempty"`
Accept []string `json:"accept"`
Reject []RejectCase `json:"reject"`
File string `json:"-"`
}
BindingSuite is one file of definition-time cases for the binder: formulas that must bind and formulas it must refuse, in a mode.
func LoadBindingSuites ¶
func LoadBindingSuites(dir string) ([]*BindingSuite, error)
LoadBindingSuites loads every binding suite from dir, sorted by file name.
func (*BindingSuite) BindMode ¶ added in v0.2.0
func (s *BindingSuite) BindMode() Mode
BindMode is the binding mode the suite names.
func (*BindingSuite) Scope ¶ added in v0.2.0
func (s *BindingSuite) Scope() (*Scope, error)
Scope builds the scope of the suite's variables, in name order.
func (*BindingSuite) SourceSet ¶ added in v0.2.0
func (s *BindingSuite) SourceSet() (*SourceSet, error)
SourceSet resolves the suite's sources.
type Call ¶
Call is a function call by canonical name. IF, AND, OR and NOT never appear here: the parser turns them into If, Binary and Unary nodes.
type Case ¶
type Case struct {
Name string `json:"name,omitempty"`
Formula string `json:"formula"`
// Inputs are values for declared variables; an absent variable is blank.
// Dates are written as YYYY-MM-DD or YYYY-MM-DD HH:MM:SS.
Inputs map[string]json.RawMessage `json:"inputs,omitempty"`
// Context sets the context functions: user, groups, now (a date),
// state and id.
Context *CaseContext `json:"context,omitempty"`
// Type is the static type the formula must have, when the case pins it.
// A date result must declare it so that Expected can be written as text.
Type string `json:"type,omitempty"`
// Expected is the value, in the same notation as Inputs. Exactly one of
// Expected and Error is set; Expected may be null for a blank result.
Expected json.RawMessage `json:"expected,omitempty"`
// Error is the error code the evaluation must stop with.
Error string `json:"error,omitempty"`
}
Case is one evaluation case: a formula, its inputs and context, and the value or the error it must produce on every target.
type CaseContext ¶
type CaseContext struct {
User string `json:"user,omitempty"`
Groups []string `json:"groups,omitempty"`
Now string `json:"now,omitempty"`
State string `json:"state,omitempty"`
ID string `json:"id,omitempty"`
}
CaseContext is the context a case runs in.
func (*CaseContext) Context ¶
func (c *CaseContext) Context() (*Context, error)
Context converts the case context to a VM context; nil for none.
type Class ¶
type Class string
Class is the evaluation class of a function (ADR-0015, ADR-0016). It decides where a formula using the function may appear.
type Context ¶
type Context struct {
// User is the id of the user the formula runs for; empty for a system
// recompute.
User string
// Groups are the groups the user belongs to.
Groups []string
// Now is the current time in seconds since the epoch, UTC. Zero means
// the wall clock.
Now int64
// State is the state of the document the formula runs over, for
// STATE(); empty for a class without states and in a preview of a
// stateless application (ADR-0040).
State string
// ID is the id of the document the formula runs over, for ID(); empty
// when there is no document.
ID string
}
Context is what the context functions see (ADR-0015).
type Dialect ¶
type Dialect interface {
Name() string
NumberLit(f float64) string
// IntLit spells an integer literal as the engine's 64-bit integer.
IntLit(m int64) string
TextLit(s string) string
True() string
False() string
// Load references a column holding a variable of the kind, cast to the
// SQL type the dialect computes with.
Load(column string, k Kind) string
// Num, Cond and Text read an expression as a number, a condition or
// text with the blank rules of ADR-0005: a blank is 0, FALSE or "".
Num(e SQLExpr) string
Cond(e SQLExpr) string
Text(e SQLExpr) string
// Mant reads an exact expression's mantissa as a non-null integer in
// the type the dialect does exact arithmetic in: a blank is 0, a bool
// 1 or 0. RawMant reads it with a blank kept NULL, for the functions
// that skip blanks.
Mant(e SQLExpr) string
RawMant(e SQLExpr) string
// Narrow brings an exact arithmetic result back to a 64-bit integer,
// NULL when it does not fit, and OverflowErr is the matching check.
Narrow(val string) string
OverflowErr(val string) string
// NotFinite is the condition that a numeric value is not a finite
// number, the overflow check of ADR-0019.
NotFinite(val string) string
// Pow spells x to the power y as the VM computes it.
Pow(x, y string) string
// Render applies the TEXT rule of ADR-0019 to a scalar.
Render(e SQLExpr) string
// Call translates a builtin by canonical name. Args are translated
// already; the dialect reads their kinds.
Call(name string, args []SQLExpr, params *Params) (SQLExpr, error)
// Param references a context parameter by name.
Param(name string) string
// ColumnType is the SQL type of a column that stores values of the
// kind, as the engine's tables declare it.
ColumnType(k Kind) string
// ContextArgs binds the context parameters for database/sql, in the
// form the dialect's SQL expects.
ContextArgs(ctx *Context) []any
// Setup lists statements to run on a connection before the generated
// SQL can be used: the DuckDB macros, nothing for SQLite.
Setup() []string
// Limits are the size limits the generated SQL enforces (ADR-0021).
Limits() Limits
// WithLimits returns the dialect under other limits.
WithLimits(l Limits) Dialect
}
Dialect spells one SQL engine.
type DuckDB ¶
type DuckDB struct {
// contains filtered or unexported fields
}
DuckDB is the dialect for DuckDB through github.com/duckdb/duckdb-go.
func NewDuckDB ¶
func NewDuckDB() DuckDB
NewDuckDB makes the DuckDB dialect under the default limits.
func (DuckDB) ColumnType ¶ added in v0.2.0
ColumnType implements Dialect: DOUBLE for a number and for the days and seconds of dates, BIGINT for a mantissa, BOOLEAN, VARCHAR.
func (DuckDB) ContextArgs ¶
ContextArgs implements Dialect: groups bind as a list of text.
func (DuckDB) Mant ¶ added in v0.2.0
Mant reads an exact expression's mantissa as a non-null integer in the arithmetic type: a blank is 0, a bool 1 or 0.
func (DuckDB) OverflowErr ¶ added in v0.2.0
OverflowErr implements Dialect: a NULL is a blank, not an overflow.
func (DuckDB) Pow ¶
Pow implements Dialect: DuckDB's pow is the C library's, which the VM's double-double power matches.
func (DuckDB) RawMant ¶ added in v0.2.0
RawMant reads an exact expression's mantissa in the arithmetic type with a blank kept NULL.
func (DuckDB) WithLimits ¶
WithLimits implements Dialect.
type Error ¶
type Error struct {
// Pos is the byte offset of the error in the formula.
Pos int
// Col is the 1-based column in characters, for people.
Col int
Msg string
}
Error is a lexical or syntax error at a position in a formula.
type EvalError ¶
EvalError is an evaluation error: a code from the closed list, the byte offset of the failing operation in the source when known, and a message.
type Function ¶
type Function struct {
Name string `json:"name"`
Aliases []string `json:"aliases,omitempty"`
Class Class `json:"class"`
Category string `json:"category"`
Params []Param `json:"params"`
Returns string `json:"returns"`
Summary string `json:"summary"`
}
Function is one catalog entry.
func Functions ¶
func Functions() []*Function
Functions returns every catalog entry in catalog order.
func LookupFunction ¶
LookupFunction returns the catalog entry for a function name or alias, case-insensitively, or nil when there is none.
type Kind ¶
type Kind uint8
Kind is the kind of a value, static or at run time (ADR-0013, ADR-0022, ADR-0023).
const ( KindNull Kind = iota KindBool KindNumber // float64, Excel arithmetic (ADR-0004) KindDecimal // an exact number: an int64 mantissa at a scale (ADR-0022) KindMoney // a decimal with a currency (ADR-0022) KindText // UTF-8 text KindDate // a calendar day: days since 1970-01-01 (ADR-0023) KindDateTime // an instant: seconds since 1970-01-01 00:00:00 UTC KindRef // a document reference in its Class:id form KindJSON // opaque JSON text KindArray KindRows KindObject // one record of a named schema; static only, never a run-time value (ADR-0031) )
The kinds. KindNull is the blank: the static type of the BLANK literal and the run-time kind of a missing value. The scalar kinds come first so that IsScalar is one comparison.
func (Kind) IsDateLike ¶ added in v0.2.0
IsDateLike reports whether the kind is a calendar day or an instant.
func (Kind) IsExact ¶ added in v0.2.0
IsExact reports whether the kind is an exact number: decimal or money.
type Limits ¶
type Limits struct {
// MaxText is the longest text a formula may produce or a document may
// store, in code points. A longer result is the error out_of_range,
// decided before the text is built.
MaxText int
}
Limits are the size limits a database evaluates under (ADR-0021). They are a property of the database, chosen when it is created and kept with its metadata, so that a formula gives the same result wherever the database is opened and a commit recomputes as it was committed. A server's resource budgets, memory, threads and timeouts, are not limits: they decide whether a recompute runs, never what it returns.
type Member ¶
Member is base.name, or a longer path base.a.b: one column of a rows variable as an array, or a field of an object variable, nested through object fields (ADR-0031).
type MemoryExecutor ¶ added in v0.2.0
type MemoryExecutor struct {
// contains filtered or unexported fields
}
MemoryExecutor is a QueryExecutor over rows held in memory: the in-memory executor of ADR-0020 that the conformance suite runs against, which tests and the formula tool use. It evaluates the condition on every row with a VM of its own, so it is exact and slow; the store has its index and its statements.
func NewMemoryExecutor ¶ added in v0.2.0
func NewMemoryExecutor() *MemoryExecutor
NewMemoryExecutor makes an executor with no tables.
func (*MemoryExecutor) AddTable ¶ added in v0.2.0
func (m *MemoryExecutor) AddTable(src *Source, rows [][]Value)
AddTable adds or replaces a table: rows are row-major in the source's column order and are sorted into the source's key order.
type Mode ¶
type Mode uint8
Mode says where a formula will run, which decides the function classes it may use (ADR-0015).
const ( // ModeAny allows every class: defaults, triggered formulas, guards, // rules, access rules and layouts. ModeAny Mode = iota // ModeAuto allows pure functions and LOOKUP only: the stored value of // an auto variable must be a function of the document itself. ModeAuto // ModePure allows pure functions only: a class title (ADR-0018) and a // schema's presentation formulas (ADR-0032) are computed from the // document's own values and nothing else. ModePure )
The modes.
type Node ¶
type Node interface {
// Pos is the byte offset of the node in the formula: the operator for
// operators, the start otherwise.
Pos() int
}
Node is a node of a parsed formula. The parser produces it; the binder turns it into bytecode. Function names in a Call are canonical upper-case catalog names; variable names are kept as written and resolved case-insensitively by the binder.
func Parse ¶
Parse turns a formula into a syntax tree. It checks the grammar of ADR-0019 and every call against the catalog: the function must exist and the number of arguments must fit. Names, types and function classes are the binder's job.
Precedence from highest to lowest: postfix %, unary -, ^ (right- associative), * / \, + -, &, comparisons, NOT, AND, OR. IF c THEN a ELSE b is an expression whose ELSE branch extends as far right as it can.
type NumberLit ¶
NumberLit is a number literal: its value, its byte offset and its length in the source, from which the binder reads the spelling exactly when the literal meets an exact operand (ADR-0022).
type Op ¶
type Op uint8
Op is an opcode. The numbering is part of the format: append only.
const ( OpNop Op = iota OpConstNum // push Nums[arg] OpConstText // push Texts[arg] OpTrue // push TRUE OpFalse // push FALSE OpBlank // push BLANK OpLoad // push the variable in slot arg OpNeg // -x OpPercent // x% OpNot // NOT x OpAdd OpSub OpMul OpDiv // / and \ : by zero is an error (ADR-0024) OpDivStrict // kept for the numbering: the same as div OpPow OpConcat OpEq OpNe OpLt OpLe OpGt OpGe OpJump // pc = arg OpJumpIfFalse // pop; when FALSE or blank, pc = arg OpAndJump // when the top is FALSE or blank, replace it by FALSE and pc = arg; else pop OpOrJump // when the top is TRUE, pc = arg; else pop OpToBool // replace a blank top by FALSE OpCall // call builtin arg>>8 with arg&0xff arguments from the stack OpLookup // reserved: LOOKUP through query slot arg (ADR-0020) OpQuery // reserved: QUERY through query slot arg (ADR-0020) OpReturn // the top is the result OpConstDec // push Decs[arg] (ADR-0022) OpDecNeg // -x on an exact value; arg is the result's scale and money flag OpDecPercent // x% on an exact value; arg as dec.neg OpDecAdd // exact +; arg as dec.neg OpDecSub // exact -; arg as dec.neg OpDecMul // exact *; arg as dec.neg OpDecDiv // exact /; arg as dec.neg OpDecScale // bring the exact top to the static scale and kind; arg as dec.neg OpTry // on an error before the matching end.try, restore the stack and pc = arg (IFERROR) OpEndTry // leave the innermost try )
The opcodes. Arg is the operand of the instruction.
type Param ¶
type Param struct {
Name string `json:"name"`
// Type names the argument's static type, or a shape such as "numbers"
// (a number or an array of numbers), "source" or "condition" for the
// query functions.
Type string `json:"type"`
// Optional: this argument and every one after it may be left out.
Optional bool `json:"optional,omitempty"`
// Repeat: the argument may be given any number of times.
Repeat bool `json:"repeat,omitempty"`
}
Param is one argument of a function.
type Params ¶
type Params struct {
// contains filtered or unexported fields
}
Params records the context parameters a statement uses.
func NewParams ¶ added in v0.2.0
NewParams makes an empty parameter list for a dialect, for callers that generate fragments with LookupSQL.
type Program ¶
type Program struct {
Nums []float64
Decs []DecConst
Texts []string
Slots []Slot
Code []Instr
Pos []int32 // byte offset in the source per instruction, for messages
Result Type
Classes []Class // function classes used, in catalog order
Queries []QuerySlot
// MaxStack is the stack depth the program needs.
MaxStack int
}
Program is a compiled formula.
func Bind ¶
func Bind(src string, scope *Scope, opts BindOptions) (*Program, error)
Bind parses and binds a formula against a scope.
func BindNode ¶
BindNode binds a parsed formula. src is the source the tree came from, for positions in messages.
func (*Program) ClaimExact ¶ added in v0.2.0
ClaimExact makes a program that is one number constant into the exact constant of the type, when the number is exactly a value at the type's scale: a default of "0" for a decimal(2) variable is 0.00, as a literal meeting an exact operand is read exactly (ADR-0022). It reports whether it did; a program that is not a lone constant, a type that is not a decimal, or a number that does not fit the scale leave the program as it is.
func (*Program) MarshalJSON ¶
MarshalJSON renders the debug form: one line per instruction with the opcode name, the operand, and what the operand refers to.
type QueryExecutor ¶ added in v0.2.0
type QueryExecutor interface {
// Lookup returns the slot's column of the first row of its source, in
// the source's key order, on which the condition holds for the
// arguments, or blank when no row does. A row on which the condition
// stops with an error does not match. ctx is the context the formula
// runs in, for a condition that reads it.
Lookup(q *QuerySlot, args []Value, ctx *Context) (Value, *EvalError)
}
QueryExecutor answers the query functions of a program at run time (ADR-0020). The VM hands it the compiled slot and the values of the document variables the condition reads; nothing crosses the boundary per row.
type QuerySlot ¶
type QuerySlot struct {
Source string
Column string
// Type is the column's type, which is the type of the lookup.
Type Type
// Order lists the source's key columns: "first row" is first in this
// order.
Order []string
// Args are the slots of the enclosing program whose values the
// condition reads as THIS.name, and ArgNames those variables' names,
// so that a slot "THIS.<name>" of Cond or Key maps to Args[i].
Args []int32
ArgNames []string
// Cond is the condition; a row matches when it is TRUE, and a row on
// which it stops with an error does not match.
Cond *Program
// Key is the compared expression of an equality condition, nil for
// any other shape, and IndexColumn the column it is compared with.
Key *Program
IndexColumn string
}
QuerySlot is a compiled LOOKUP call (ADR-0020): the source and the column it returns; the condition as a program of its own over the source's columns, named by column, and the document variables it reads as THIS.name, named "THIS.<variable>"; the slots of the enclosing program those variables live in; and, when the condition is one equality of a column with an expression of the document alone, that expression as a program, so that an index on the column can serve the lookup (ADR-0036). QUERY arrives with Phase 4.
type RegisteredFunc ¶
type RegisteredFunc struct {
// Name is the SQL function name.
Name string
// NArgs is the argument count, the limit included when Limited, or -1
// for variadic.
NArgs int
// Kinds gives the kind expected at each position; the last repeats. A
// KindDecimal position receives a raw mantissa, scale 0.
Kinds []Kind
// Fn is the implementation, the VM's own.
Fn func(vm *VM, args []Value) (Value, *EvalError)
// Limited: the last argument is the text limit, and Fn reads it from
// the VM it is called with.
Limited bool
}
RegisteredFunc describes an engine function a SQL dialect calls back into Go (ADR-0019).
func SQLiteFunctions ¶
func SQLiteFunctions() []RegisteredFunc
SQLiteFunctions lists the engine functions the SQLite dialect expects to be registered, as fado_<name> and fado_<name>_err: the builtins named in sqliteRegistered under their own arguments, then the exact-arithmetic helpers. The sqlitefn package registers them from this list.
func (RegisteredFunc) Kind ¶
func (f RegisteredFunc) Kind(i int) Kind
Kind returns the kind expected at argument position i.
type RejectCase ¶
RejectCase is a formula that must be refused, with the reason for people.
type SQL ¶
type SQL struct {
// Value is the value expression.
Value string
// Error is the error expression, or "" when the formula cannot fail.
Error string
// Currency is the currency expression of a money result, "" otherwise.
Currency string
// Kind is the kind of the value expression.
Kind Kind
// Scale is the scale of an exact value expression.
Scale int8
// Params lists the context parameters the expressions reference, by
// name: now (seconds since the epoch, always bound, never NULL), user
// (the user id or NULL) and groups (the user's groups or NULL, in the
// form the dialect's ContextArgs binds).
Params []string
}
SQL is a generated statement fragment.
func GenerateSQL ¶
GenerateSQL translates a program for a dialect. column gives the column expression that holds each slot's value; for a money slot it is asked again for the currency column, a text slot named with CurrencySuffix. A program with a lookup refers to the source by its quoted name; a caller whose tables are named otherwise uses GenerateSQLWith. Column expressions must be qualified when the program has a lookup, since they are referenced inside its subquery.
func GenerateSQLBound ¶ added in v0.3.0
func GenerateSQLBound(p *Program, d Dialect, b SQLBinding) (SQL, error)
GenerateSQLBound is GenerateSQL with every binding given.
func GenerateSQLWith ¶ added in v0.2.0
func GenerateSQLWith(p *Program, d Dialect, column func(Slot) string, table func(source string) string) (SQL, error)
GenerateSQLWith is GenerateSQL with the table expression of each source a LOOKUP reads given by table.
func (SQL) CurrencyOrNull ¶ added in v0.2.0
CurrencyOrNull returns the currency expression, or NULL when there is none.
func (SQL) ErrorOrNull ¶
ErrorOrNull returns the error expression, or NULL when there is none.
type SQLBinding ¶ added in v0.3.0
type SQLBinding struct {
// Column gives the column expression that holds each slot's value; for
// a money slot it is asked again for the currency column, a text slot
// named with CurrencySuffix. Column expressions must be qualified when
// the program has a lookup, since they are referenced inside its
// subquery.
Column func(Slot) string
// Table gives the table expression of each source a LOOKUP reads; nil
// refers to the source by its quoted name.
Table func(source string) string
// Row gives the column that holds a system value of the document row
// the statement runs over, asked for "state" and "id", which STATE()
// and ID() read (ADR-0040); nil binds them to parameters, as USER().
Row func(name string) string
}
SQLBinding says how a program's references are spelled in a statement.
type SQLExpr ¶
type SQLExpr struct {
// Val is the value expression: the mantissa for an exact kind.
Val string
// Err is the error expression, or "" when the expression cannot fail.
Err string
// Cur is the currency expression of a money value, NULL for a blank.
Cur string
// Kind is the static kind of Val.
Kind Kind
// Scale is the scale of an exact Val.
Scale int8
// Sure reports that Val is never NULL, so no COALESCE is needed.
Sure bool
// IsConst and Const carry a number literal, which a dialect reads for
// an argument that must be written in the formula, such as places.
IsConst bool
Const float64
}
SQLExpr is one translated expression with its static kind.
func LookupSQL ¶ added in v0.2.0
func LookupSQL(q *QuerySlot, d Dialect, arg func(i int, currency bool) string, table func(string) string, params *Params) (SQLExpr, error)
LookupSQL translates one lookup slot into a correlated scalar subquery (ADR-0020): the column of the first row of the source, in key order, on which the condition holds, NULL when none does. A row on which the condition would stop with an error does not match. arg gives the expression of the i-th THIS argument, and of its currency column when currency is set; table the expression of the source. The store's statement path and the generator's lookup instruction share it.
type SQLResult ¶
type SQLResult struct {
// Query is the statement that ran, for messages.
Query string
// Value is the value column as a Value of the program's result kind.
Value Value
// Code is the error column, or "" when NULL.
Code string
}
SQLResult is what RunSQL got back from the engine.
func RunSQL ¶
RunSQL executes one program through database/sql on a dialect: it generates the SQL, binds vars, one value per program slot in slot order, as named parameters over a one-row subselect, a money slot as its amount and its currency column, binds the context, and reads the value, the error and the currency columns. It is the shared half of every SQL conformance and property runner; comparing with the VM is the runner's job.
type SQLite ¶
type SQLite struct {
// contains filtered or unexported fields
}
SQLite is the dialect for SQLite through modernc.org/sqlite.
func NewSQLite ¶
func NewSQLite() SQLite
NewSQLite makes the SQLite dialect under the default limits.
func (SQLite) ColumnType ¶ added in v0.2.0
ColumnType implements Dialect: SQLite's storage classes, a date as INTEGER days and a datetime as INTEGER seconds (ADR-0023), an exact value as its INTEGER mantissa (ADR-0022), a bool as 0 or 1.
func (SQLite) ContextArgs ¶
ContextArgs implements Dialect: now is always bound, user is text or NULL, groups is the text groupsArg makes or NULL.
func (SQLite) ContextArgsFor ¶ added in v0.3.0
ContextArgsFor appends to dst the context parameters a statement uses, by name as SQL.Params lists them, bound as ContextArgs binds them. A statement that reads no context binds nothing, which keeps a lookup inside a commit free of the cost of parameters it never reads.
func (SQLite) Mant ¶ added in v0.2.0
Mant reads an exact expression's mantissa as a non-null integer in the arithmetic type: a blank is 0, a bool 1 or 0.
func (SQLite) Narrow ¶ added in v0.2.0
Narrow implements Dialect: an integer result is already 64-bit.
func (SQLite) NotFinite ¶
NotFinite implements Dialect. SQLite yields NULL for NaN and keeps infinities, so both are checked.
func (SQLite) OverflowErr ¶ added in v0.2.0
OverflowErr implements Dialect: an integer operation that overflows turns REAL in SQLite; a NULL is a blank, not an overflow.
func (SQLite) RawMant ¶ added in v0.2.0
RawMant reads an exact expression's mantissa in the arithmetic type with a blank kept NULL.
func (SQLite) Setup ¶
Setup implements Dialect: the engine functions come from the sqlitefn package's registration, not from statements.
func (SQLite) WithLimits ¶
WithLimits implements Dialect.
type Scope ¶
type Scope struct {
// contains filtered or unexported fields
}
Scope is the set of variables a formula may read. Names resolve case-insensitively (ADR-0013).
type Source ¶ added in v0.2.0
type Source struct {
Name string
Columns []Field
// Key lists the columns that order the source. LOOKUP returns the
// first matching row in this order (ADR-0020).
Key []string
// Binding is sqlite, duckdb or external (ADR-0016); "" is the
// store's default.
Binding string
}
Source is an explicit table a LOOKUP or QUERY may read (ADR-0016, ADR-0020): its columns with their scalar types, the columns whose order is its key order, and the binding that says where its rows live.
func (*Source) ColumnNames ¶ added in v0.2.0
ColumnNames lists the columns in order.
type SourceSet ¶ added in v0.2.0
type SourceSet struct {
// contains filtered or unexported fields
}
SourceSet is a Sources over a list, resolved case-insensitively. A nil SourceSet has no sources.
func NewSourceSet ¶ added in v0.2.0
NewSourceSet makes a set of the sources.
type Suite ¶
type Suite struct {
// Suite is the short name, unique across files.
Suite string `json:"suite"`
Description string `json:"description,omitempty"`
// Variables declares the input variables the cases may set, by type:
// bool, number, text, date, ref, json, array<scalar>, rows, or
// object<Name> for a schema of Schemas.
Variables map[string]string `json:"variables,omitempty"`
// Schemas declares object schemas by name: field name to type, where
// a type may be object<Name> of another schema (ADR-0031). A case sets
// an object's leaf by its path, "shipping.city".
Schemas map[string]map[string]string `json:"schemas,omitempty"`
// Sources declares the explicit tables LOOKUP may read (ADR-0020),
// with their rows.
Sources map[string]*SuiteSource `json:"sources,omitempty"`
// Limits sets the size limits the cases evaluate under (ADR-0021);
// absent, the defaults. A suite at a small limit reaches the boundary
// with short texts.
Limits *SuiteLimits `json:"limits,omitempty"`
Cases []Case `json:"cases"`
// File is where the suite was loaded from, for messages.
File string `json:"-"`
}
Suite is one file of evaluation cases.
func LoadSuites ¶
LoadSuites loads every evaluation suite from dir, sorted by file name.
func (*Suite) EvalLimits ¶
EvalLimits are the limits the suite's cases evaluate under.
func (*Suite) Executor ¶ added in v0.2.0
func (s *Suite) Executor() (*MemoryExecutor, error)
Executor makes the in-memory executor over the suite's sources.
func (*Suite) Scope ¶ added in v0.2.0
Scope builds the scope of the suite's variables, in name order.
func (*Suite) SourceRows ¶ added in v0.2.0
SourceRows parses the rows of every source, row-major in column order.
type SuiteLimits ¶
type SuiteLimits struct {
MaxText int `json:"max_text"`
}
SuiteLimits is the limits field of a suite.
type SuiteSource ¶ added in v0.2.0
type SuiteSource struct {
Columns map[string]string `json:"columns"`
Key []string `json:"key"`
Rows []map[string]json.RawMessage `json:"rows,omitempty"`
}
SuiteSource declares one table a suite's LOOKUP cases read: its columns by scalar type, its key columns, and its rows as objects in the input notation, an absent column blank. Columns are in name order.
type SyntaxSuite ¶
type SyntaxSuite struct {
Suite string `json:"suite"`
Description string `json:"description,omitempty"`
Variables map[string]string `json:"variables,omitempty"`
Accept []string `json:"accept"`
Reject []RejectCase `json:"reject"`
File string `json:"-"`
}
SyntaxSuite is one file of definition-time cases: formulas the parser must accept and formulas it must reject.
func LoadSyntaxSuites ¶
func LoadSyntaxSuites(dir string) ([]*SyntaxSuite, error)
LoadSyntaxSuites loads every syntax suite from dir, sorted by file name.
type Token ¶
type Token struct {
Kind TokenKind
// Text is the name as written for a name, the unescaped value for a
// text literal, and the source text otherwise.
Text string
// Num is the value of a number literal.
Num float64
// Pos is the byte offset of the token in the formula.
Pos int
}
Token is one lexical token with its position in the formula.
type TokenKind ¶
type TokenKind uint8
TokenKind is the kind of a lexical token.
const ( TokEOF TokenKind = iota TokNumber TokText TokIdent TokAnd TokOr TokNot TokIf TokThen TokElse TokTrue TokFalse TokBlank TokThis TokLParen TokRParen TokComma TokDot TokPlus TokMinus TokStar TokSlash TokBackslash TokCaret TokPercent TokAmp TokEq TokNe TokLt TokLe TokGt TokGe )
Token kinds. Keywords are case-insensitive and reserved (ADR-0019).
type Type ¶
type Type struct {
Kind Kind
// Scale is the number of digits after the point of a decimal or money
// type, 0 to MaxScale. For an array it is the element's scale.
Scale int8
// Elem is the element kind of an array.
Elem Kind
// contains filtered or unexported fields
}
Type is a static type: a scalar kind with its scale when it is exact, an array of a scalar kind, rows with a schema, or an object of a named schema. The struct is two words: what only composites and objects carry lives behind a pointer, since the binder passes types by value on every expression.
func DecimalType ¶ added in v0.2.0
DecimalType makes an exact decimal type at the scale.
func ObjectType ¶ added in v0.2.0
ObjectType makes the type of an object of a named schema.
func ParseType ¶
ParseType reads a type as written in class definitions and in the conformance suite: a scalar name, `int`, `decimal(s)`, `money(s)`, `array<scalar>`, or `rows`. `decimal` alone is `decimal(2)` and `money` alone is `money(2)`. It also reads "blank", the static type of a formula that is BLANK, so that every type String writes decodes again; a variable is never declared blank, which is the declaring side's check.
func RowsType ¶ added in v0.2.0
RowsType makes a rows type with the given columns, of a named schema when schema is not empty.
func Scalar ¶
Scalar makes the type of a scalar kind. A decimal or money kind gets scale 0; DecimalType and MoneyType take a scale.
func (Type) Equal ¶
Equal reports whether two types are the same. Exact types compare by scale too; rows compare by schema; objects by schema name and fields.
func (Type) FieldNames ¶ added in v0.2.0
FieldNames lists the field names of an object type, for messages.
func (Type) Fields ¶ added in v0.2.0
Fields are the fields of an object type or the columns of rows, in declared order; nil for anything else.
func (Type) IsExact ¶ added in v0.2.0
IsExact reports whether the type is a decimal or money scalar.
type Unary ¶
Unary is -x, NOT x, or the postfix x%. Op is TokMinus, TokNot or TokPercent. Const marks a minus or a percent of a constant expression, which the binder folds.
type VM ¶
type VM struct {
// Limits are the size limits of the database the programs belong to
// (ADR-0021). NewVM sets the defaults; set others before Run.
Limits Limits
// Executor answers LOOKUP (ADR-0020). A program with a lookup and no
// executor stops with query_failed.
Executor QueryExecutor
// contains filtered or unexported fields
}
VM executes programs. A VM is not safe for concurrent use; make one per goroutine. Its stack is reused across runs.
type Value ¶
type Value struct {
// contains filtered or unexported fields
}
Value is a run-time value. Scalars live in the struct and never allocate: bool, number, date and datetime in num, text, ref and json in str, and an exact number's mantissa in the bits of num with its scale beside it, so that the struct stays four words wide (ADR-0022). Composites (ADR-0013) will hang off pointers added with the composites change; the scalar layout does not move. The zero Value is blank.
func Day ¶ added in v0.2.0
Day makes a date value from a calendar day of the proleptic Gregorian calendar, as DATE(year, month, day) does; the month and the day normalise as time.Date normalises them.
func Decimal ¶ added in v0.2.0
Decimal makes an exact value from a mantissa at a scale: Decimal(1230, 2) is 12.30.
func ExactFromFloat ¶ added in v0.2.0
ExactFromFloat makes a decimal of the type from a float64 that is exactly a value at the type's scale, as a bare literal meeting an exact variable is read (ADR-0022): 0 and 12.3 fit a decimal(2), 0.125 does not. It reports whether the float fit.
func Money ¶ added in v0.2.0
Money makes a money value from a mantissa, a scale and a currency code.
func ParseCaseValue ¶
func ParseCaseValue(raw json.RawMessage, t Type) (Value, error)
ParseCaseValue reads a case value written in the suite notation as a value of the given type. An exact value is written as a JSON number or as text, read exactly and brought to the type's scale, which must not drop a digit; a money value is text such as "12.30 PLN".
func ValueFromDriver ¶
ValueFromDriver converts a value as a database driver delivers it (nil, int64, float64, string or []byte) to a Value of the expected kind. KindNull means "whatever it is": numbers become numbers and text text. KindDecimal reads a raw mantissa at scale 0; ValueOfType reads a typed value with its scale and currency.
func ValueOfType ¶ added in v0.2.0
ValueOfType converts a driver value to a Value of a static type: an exact value gets the type's scale, a money value its currency from cur, and is blank when the currency is.
func (Value) Currency ¶ added in v0.2.0
Currency returns the currency code of a money value, "" otherwise.
func (Value) DriverValue ¶
DriverValue converts a Value to what a database driver takes: nil, float64, int64 or string. A date is REAL days, a datetime REAL seconds, a bool 0 or 1, an exact value its mantissa; a money's currency is bound apart, from Currency.
func (Value) Mant ¶ added in v0.2.0
Mant returns the mantissa of a decimal or money value, and 0 for a blank.
func (Value) Num ¶
Num returns the number of a number, the 1 or 0 of a bool, the days of a date, the seconds of a datetime, and 0 for a blank: the zero of ADR-0005. It is meaningless for a decimal or a money; use Mant.
func (Value) Str ¶
Str returns the text of a text, ref or json value, the currency of a money, and "" for a blank.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package fuzz generates random, well-typed formulas with inputs and runs each one on the Go VM and on a SQL dialect, reporting any divergence.
|
Package fuzz generates random, well-typed formulas with inputs and runs each one on the Go VM and on a SQL dialect, reporting any divergence. |
|
Package sqlitefn registers the formula engine's Go functions into the pure-Go SQLite driver, so that the SQLite dialect of the SQL generator agrees with the Go VM by construction (ADR-0019).
|
Package sqlitefn registers the formula engine's Go functions into the pure-Go SQLite driver, so that the SQLite dialect of the SQL generator agrees with the Go VM by construction (ADR-0019). |