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
- func Format(profile dialect.LexerProfile, path string, src []byte) ([]byte, []diagnostics.Diagnostic)
- type Annotation
- type Choose
- type ChooseCase
- type FilterTree
- type GuardAtom
- type GuardedItem
- type IfPresent
- type InExpr
- type Item
- type Occurrence
- type OrderBy
- type OrderKey
- type Param
- type PolicyOptOut
- type Predicate
- type QueryFile
- type QueryTemplate
- type Scanner
- type Sep
- type Skeleton
- type Slot
- type TypeHint
- type ValueKind
Constants ¶
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.
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 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.