template

package
v0.0.2 Latest Latest
Warning

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

Go to latest
Published: Sep 11, 2026 License: Apache-2.0 Imports: 7 Imported by: 0

Documentation

Overview

Package template implements phase P1: scanning .sql template files into a structured model (constant skeleton + guarded fragments) with exact source spans. See docs/design/01-template-scanner.md.

Index

Constants

View Source
const (
	// MaxGuards: one bit per guard atom in ShapeKey.Guards (uint64).
	MaxGuards = 64
	// MaxOrderKeys: elements pack as key<<1|desc into a uint8, and both
	// shape.orderOptions and runtime.OrderSeq track used keys in a
	// bitmask. 64 keeps the packing well inside uint8 and mirrors
	// MaxGuards.
	MaxOrderKeys = 64
	// MaxChooseOrdinals: ShapeKey.Choices holds one uint8 ordinal per
	// @choose block, counting the @default body.
	MaxChooseOrdinals = 255
	// MaxParams: a bind plan addresses the params struct with
	// runtime.Bind.Idx, an int16. This one bounds the bind plan rather
	// than the shape key, but it is the same kind of limit and the same
	// consequence — codegen would narrow the index silently and bind
	// the wrong value.
	MaxParams = 32767
)

Structural limits of the shape key's encoding (runtime.ShapeKey). They are compiler limits, not policy: past them the encoding decays silently — a truncated @choose ordinal selects a different case's SQL, a truncated @order-by element sorts by a different column — so the scanner refuses the template rather than let an unverified shape reach a database. They are exported so the encoding's other end can pin them: see TestShapeKeyLimitsAgree in internal/codegen.

Variables

This section is empty.

Functions

func Format

func Format(profile dialect.LexerProfile, path string, src []byte) ([]byte, []diagnostics.Diagnostic)

Format canonicalizes a template file: skeleton SQL is preserved byte-for-byte (sqletch never reformats the user's SQL), construct markers are rewritten in canonical layout, and a missing `WHERE TRUE` anchor (R6) is inserted. Files that fail to scan are returned unchanged with their diagnostics. Format is a fixpoint: Format(Format(x)) == Format(x).

Types

type Annotation

type Annotation int
const (
	AnnotationInvalid Annotation = iota
	AnnotationOne
	// AnnotationMaybeOne is :one with "no row" as a normal outcome:
	// the generated method returns Option[Row] and maps the driver's
	// no-rows error to None instead of surfacing it.
	AnnotationMaybeOne
	AnnotationMany
	AnnotationExec
	AnnotationExecRows
)

func (Annotation) String

func (a Annotation) String() string

type Choose

type Choose struct {
	Param   string
	Cases   []ChooseCase // declaration order, excluding default
	Default *ChooseCase  // nil = required parameter
	Slot    Slot
	Span    diagnostics.Span // '@choose' through '@end'
}

func (*Choose) Raw

func (c *Choose) Raw() diagnostics.Span

type ChooseCase

type ChooseCase struct {
	Name string // "" for @default
	Body string // edge-trimmed verbatim; may be empty only for default
	Span diagnostics.Span
}

type FilterTree

type FilterTree struct {
	Param      string
	Required   bool // @filter-tree!: nil tree is an error, Unscoped explicit
	Predicates []Predicate
	// Slot is SlotWhereConjunct or SlotHavingConjunct — the two
	// positions where the empty tree's TRUE rendering is one whole
	// conjunct (enforced by the scanner's anchor checks and R1
	// membership on the empty rendering).
	Slot Slot
	Span diagnostics.Span
}

FilterTree is the @filter-tree construct: a closed predicate vocabulary the caller combines at runtime with AND/OR trees. Predicate parameters are constructor arguments, not struct fields.

func (*FilterTree) Raw

func (f *FilterTree) Raw() diagnostics.Span

type GuardAtom

type GuardAtom struct {
	Param string
	Op    string
	Value string // Go-side literal (unquoted string, number, true/false)
	Kind  ValueKind
	// RawValue is the literal as written in SQL (e.g. `'a'`, `false`),
	// preserved for `sqletch fmt`.
	RawValue string
}

GuardAtom identifies one guard condition: a presence atom (@if-present, Op == "") or a value atom (@when, Op "=" or "!="). Atoms are compared by equality; identical conditions share a shape bit.

func (GuardAtom) IsValue

func (g GuardAtom) IsValue() bool

IsValue reports whether the atom is a @when value condition.

type GuardedItem

type GuardedItem struct {
	Name   string
	Guards []GuardAtom
	Span   diagnostics.Span
}

GuardedItem records one guarded INSERT column/value item for the R7 pairing check. Name is the column name (column items only).

type IfPresent

type IfPresent struct {
	Guards   []GuardAtom
	Sep      Sep
	Body     string // verbatim (edge-trimmed), separator lifted
	Slot     Slot
	Span     diagnostics.Span // '@if-present' through '@endif'
	BodySpan diagnostics.Span
}

func (*IfPresent) Raw

func (i *IfPresent) Raw() diagnostics.Span

type InExpr

type InExpr struct {
	Param string
	Span  diagnostics.Span
}

InExpr is the @in construct: `expr @in(:param)` — dialect-complete variable-arity membership. On PostgreSQL it renders as a single static `= ANY($n)`; expanding dialects (MySQL/SQLite) render per-arity `IN (?, …)` lists.

func (*InExpr) Raw

func (i *InExpr) Raw() diagnostics.Span

type Item

type Item interface {
	// Raw is the full byte range this item occupies in the file
	// (constructs include their @… markers). Item ranges of a query
	// are contiguous: concatenated they reproduce the source section.
	Raw() diagnostics.Span
}

Item is one element of a query template in document order. Exactly one of the concrete types below.

type Occurrence

type Occurrence struct {
	Span         diagnostics.Span
	Guards       []GuardAtom // guard set of the enclosing fragment; nil in skeleton
	InChooseCase bool        // inside a @choose case body (empty guard set, R3)
	InFilterTree bool        // inside a @predicate body (constructor arg)
	InIn         bool        // the parameter of an @in(:param) list occurrence
}

Occurrence is one :name bind appearance of a parameter.

type OrderBy

type OrderBy struct {
	Param   string
	Keys    []OrderKey
	Default *ChooseCase // whole ORDER BY clause; may be empty
	Span    diagnostics.Span
}

OrderBy is the @order-by construct: a closed key set the caller orders at runtime (subset, permutation, per-key direction). The maximal rendering lists all keys in declaration order; the @default body is verified as an extra rendering.

func (*OrderBy) Raw

func (o *OrderBy) Raw() diagnostics.Span

type OrderKey

type OrderKey struct {
	Name string
	Body string // one sort expression
	Span diagnostics.Span
}

type Param

type Param struct {
	Name        string
	Occurrences []Occurrence
	// GuardBit is set iff the param is used as a presence-guard atom;
	// -1 otherwise.
	GuardBit int
	// Optional is filled by the R9 classification (rules.CheckLexical):
	// true iff every bind appearance lies in fragments guarded by this
	// parameter — a pointer field in the generated params struct.
	Optional bool
	// Policy names the policy that wove this parameter in; empty for a
	// parameter the query author wrote. Codegen uses it to tell a value
	// the caller asked for from one the tool injected on their behalf.
	// The latter is a required argument of the generated method rather
	// than a params-struct field, so omitting it cannot compile.
	Policy string
}

type PolicyOptOut

type PolicyOptOut struct {
	Policy string
	Reason string
	Span   diagnostics.Span
}

PolicyOptOut is one `-- @policy-optout` annotation: a deliberate, reviewable exemption from a policy, with a mandatory reason.

type Predicate

type Predicate struct {
	Name   string
	Body   string   // one boolean expression
	Params []string // distinct :params in first-occurrence order
	Span   diagnostics.Span
}

type QueryFile

type QueryFile struct {
	Path    string
	Queries []*QueryTemplate
}

type QueryTemplate

type QueryTemplate struct {
	Name       string
	Annotation Annotation
	HeaderSpan diagnostics.Span
	Items      []Item
	// Params in first-appearance order (deterministic output).
	ParamOrder []string
	Params     map[string]*Param
	// GuardAtoms in bit order: GuardAtoms[i] has bit i.
	GuardAtoms []GuardAtom
	// InsertColGuards / InsertValGuards collect the guarded INSERT
	// column items and, per VALUES row, the guarded value items — the
	// R7 pairing input. Guarded items are restricted to the tail of
	// their clause (checked at scan time), so sequence equality plus
	// the maximal Describe implies positional alignment in every shape.
	InsertColGuards []GuardedItem
	InsertValGuards [][]GuardedItem
	// TypeHints holds `-- @param name: sqltype` directives: explicit
	// parameter types that override (Tier 1) or supply (Tier 2) the
	// oracle's answer. Values are raw SQL type names resolved by the
	// dialect.
	TypeHints map[string]TypeHint
	// ColumnHints holds `-- @column name: sqltype` directives: result
	// column types for dialects whose oracle cannot type expression
	// columns (SQLite decltype is NULL for any expression). Keyed by
	// the result column's output name.
	ColumnHints map[string]TypeHint
	// WhereKwEnd, TailStart, and StmtEnd are template-source offsets
	// recorded for the policy weaver (design 14 §4.2): WhereKwEnd is
	// the offset just past the statement's top-level WHERE keyword (-1
	// when absent); TailStart is where a synthesized WHERE clause would
	// go when the statement has none — the start of the first
	// GROUP BY/HAVING/ORDER BY/tail/RETURNING clause (or `@order-by`
	// construct), -1 when the statement has no such clause; StmtEnd is
	// the end of the last statement token (excluding any terminating
	// semicolon), the fallback insertion point.
	WhereKwEnd int
	TailStart  int
	StmtEnd    int
	// PolicyOptOuts are the query's `-- @policy-optout: name (reason)`
	// annotations in declaration order (a slice so diagnostics never
	// depend on map iteration order).
	PolicyOptOuts []PolicyOptOut
}

type Scanner

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

Scanner turns template source into QueryFiles. It is construct- generic; dialect lexical structure comes from the LexerProfile.

func NewScanner

func NewScanner(profile dialect.LexerProfile) *Scanner

func (*Scanner) ScanFile

func (s *Scanner) ScanFile(path string, src []byte) (*QueryFile, []diagnostics.Diagnostic)

func (*Scanner) ScanFileFrom

func (s *Scanner) ScanFileFrom(path string, src []byte, start int) (*QueryFile, []diagnostics.Diagnostic)

ScanFileFrom is ScanFile that begins scanning at byte offset start, while still treating src as the whole offset-preserving buffer: every emitted span and offset indexes src exactly as ScanFile would, so for any start whose skipped prefix src[:start] is scan-inert trivia the result is byte-identical to ScanFile(path, src).

It exists for gosrc's Go-source views (docs/design/13 §3): a marked const's view is the whole file with everything but that one literal blanked to spaces/newlines. Scanning such a view from 0 re-lexes the blank prefix — and copies it whole as a single whitespace token's Text — once per const, which is O(consts × file size) quadratic CPU (and hangs the LSP on file-open through cli.scanSource). Starting at the literal's own offset skips that inert prefix without moving any span. start is clamped to [0, len(src)].

type Sep

type Sep int

Sep is the composer-owned separator lifted off a fragment body.

const (
	SepNone Sep = iota
	SepAnd
	SepComma // reserved for v0.2 SET/INSERT slots
)

type Skeleton

type Skeleton struct {
	Text string // verbatim bytes, params still :name
	Span diagnostics.Span
	// Synth marks text that exists in no template file (a policy-woven
	// conjunct): Span is zero-width at the insertion offset, and the
	// renderer maps the emission as synthesized text anchored there
	// instead of attributing it to the template bytes that follow.
	Synth bool
}

func (*Skeleton) Raw

func (s *Skeleton) Raw() diagnostics.Span

type Slot

type Slot int

Slot is the grammatical position a construct occupies. The scanner assigns it provisionally from clause context; P2 revalidates against the parsed AST (R1).

const (
	SlotUnknown Slot = iota
	SlotWhereConjunct
	SlotJoinItem
	SlotOrderBy
	SlotSetItem        // v0.2: an UPDATE SET assignment
	SlotInsertColumn   // v0.2: an INSERT column-list item (paired, R7)
	SlotInsertValue    // v0.2: an INSERT VALUES row item (paired, R7)
	SlotGroupBy        // v0.2: @choose over whole GROUP BY clauses
	SlotProjExpr       // v0.2: @choose over one projection expression
	SlotHavingConjunct // v0.3: a HAVING conjunct
)

type TypeHint

type TypeHint struct {
	SQLType string
	Span    diagnostics.Span
}

TypeHint is one `-- @param` / `-- @column` directive.

type ValueKind

type ValueKind int

ValueKind classifies a @when literal (drives the Go type of pure control parameters).

const (
	ValueNone ValueKind = iota
	ValueString
	ValueInt
	ValueBool
)

Jump to

Keyboard shortcuts

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