optparam

package
v0.2.1 Latest Latest
Warning

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

Go to latest
Published: Jun 12, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Overview

Package optparam models optional query parameters that drive dynamic SQL generation at codegen time.

It is intentionally isolated from internal/querygen so the marker grammar, variant enumeration, and runtime builder generation remain reusable and easy to test apart from the v1alpha config shape.

Four optional shapes are modeled by per-segment markers in the SQL template:

  • ModeRequired: parameter is always supplied; no SQL variation.

  • ModeNullIsNull (marker /*?null_is_null:NAME*/ ... = @NAME ... /*?end*/): the body must contain "= @NAME" which is rewritten to "IS NOT DISTINCT FROM @NAME" at codegen time. A single SQL is produced; the caller passes a nullable wrapper at runtime.

  • ModeOmitWhenNull (marker /*?optional:NAME*/ ... /*?end*/): when the caller leaves the *T pointer nil, the whole marker block is removed from the SQL. Multiplies the variant count by 2.

  • ModeOmitWhenEmpty (marker /*?empty:NAME*/ ... IN UNNEST(@NAME) ... /*?end*/): when len([]T) is 0 the block is removed. Multiplies the variant count by 2. SQL-wise indistinguishable from OmitWhenNull; the difference is the runtime gating condition and Go type.

  • ModeOrderByChoice (marker /*?orderby:NAME*/ <default> /*?end*/): the body of the marker is replaced wholesale by one of the declared Choices. Multiplies the variant count by len(Choices).

EnumerateVariants takes the Cartesian product across every kind of segment. VerifyVariants confirms every product point analyzes to the same row type. EmitGoBuilder generates a Go function that walks the segment list linearly at runtime and is byte-equal to whichever verified variant matches the call-site inputs.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ComposeVariant

func ComposeVariant(segments []Segment, p Presence) string

ComposeVariant assembles SQL from segments. The output is byte-identical to the verified variant EnumerateVariants would produce for the same inputs — this invariant is what the runtime composer in EmitGoBuilder relies on.

func EmitGoBuilder

func EmitGoBuilder(segments []Segment, params []Param, opts BuilderOptions) (string, error)

EmitGoBuilder generates Go code that composes the SQL at runtime from the segment list. The returned source is gofmt'd.

The generated function signature is:

func <FuncName>(p <FuncName>Params) (sql string, args map[string]interface{}, variant string)

For every kind of segment the output SQL equals the variant EnumerateVariants would produce for the same call-site inputs.

func FormatPlanVariants

func FormatPlanVariants(entries []PlanQueryVariant) string

FormatPlanVariants renders a human-readable summary of the plan-contract entries; useful for test output and for confirming what lands in the plan contract.

func VerifyBuilderRoundTrip

func VerifyBuilderRoundTrip(segments []Segment, variants []Variant) error

VerifyBuilderRoundTrip asserts every verified variant can be reproduced byte-for-byte by composing segments with that variant's presence and choice sets. Callers should invoke this at codegen time before writing the generated builder file.

Types

type BuilderOptions

type BuilderOptions struct {
	// Package is the package clause emitted at the top of the file.
	Package string
	// FuncName is the name of the generated builder function. The
	// params struct is named "<FuncName>Params".
	FuncName string
	// ParamsTypeName overrides the generated params struct name. If
	// empty, "<FuncName>Params" is used.
	ParamsTypeName string
	// Fragment omits package and import declarations. The returned
	// declarations are intended to be embedded in a larger generated
	// Go file that will be gofmt'd by the caller.
	Fragment bool
}

BuilderOptions configures EmitGoBuilder.

type Mode

type Mode int

Mode describes how an optional parameter shapes the generated SQL.

const (
	ModeRequired Mode = iota
	ModeNullIsNull
	ModeOmitWhenNull
	ModeOmitWhenEmpty
	ModeOrderByChoice
)

func (Mode) String

func (m Mode) String() string

type Param

type Param struct {
	Name string
	// Type is the GoogleSQL type spec, e.g. "STRING", "INT64",
	// "ARRAY<STRING>". For ModeOrderByChoice this is ignored.
	Type string
	Mode Mode
	// Choices is the set of allowed ORDER BY clauses for an
	// ModeOrderByChoice param, keyed by an identifier the runtime
	// caller selects. Each value is a full ORDER BY ... clause.
	Choices map[string]string
	// Default is the choice key used when the caller does not specify
	// one. Must match a key in Choices.
	Default string
}

Param describes one named query parameter.

type PlanQueryVariant

type PlanQueryVariant struct {
	// Label is a stable identifier for the variant. It is the same value as
	// Variant.Key (alphabetized concatenation of present OmitWhenNull
	// params, joined with '+', or "(none)" when every block is omitted).
	Label string `json:"label" yaml:"label"`
	// SQL is the rewritten statement.
	SQL string `json:"sql" yaml:"sql"`
	// SQLSHA256 is the SHA-256 of SQL, hex-encoded, so plan contracts can
	// pin per-variant execution plans without re-running the generator.
	SQLSHA256 string `json:"sql_sha256" yaml:"sql_sha256"`
	// PresentParams lists the OmitWhenNull params kept in this variant.
	PresentParams []string `json:"present_params,omitempty" yaml:"present_params,omitempty"`
	// AbsentParams lists the OmitWhenNull params dropped in this variant.
	AbsentParams []string `json:"absent_params,omitempty" yaml:"absent_params,omitempty"`
}

PlanQueryVariant is the per-variant plan-contract entry. It is shaped to be emitted into QueryCodegenPlanQuery.Variants so downstream tools (e.g. spanner-query-plan-shape) can produce one execution plan per SQL variant.

func BuildPlanVariants

func BuildPlanVariants(result *VerifyResult) []PlanQueryVariant

BuildPlanVariants turns a VerifyResult into plan-contract entries. It does not interpret the row type; that is shared across every variant and lives at the parent QueryCodegenPlanQuery level.

type Presence

type Presence struct {
	// Present[name] == true means the omit/empty block for `name` is kept.
	Present map[string]bool
	// Choices[name] is the choice key picked for the orderby segment
	// keyed by `name`.
	Choices map[string]string
}

Presence carries the per-variant inputs to ComposeVariant.

type Segment

type Segment struct {
	Kind SegmentKind
	// Text is the segment body, with marker tokens already stripped.
	Text string
	// Param is the parameter that gates or selects the segment. Empty
	// for SegFixed.
	Param string
	// Choices is populated for SegOrderByChoice with the same map as
	// Param.Choices, snapshotted at parse time.
	Choices map[string]string
	// Default is populated for SegOrderByChoice with the default choice
	// key.
	Default string
}

Segment is the unit of the parsed SQL template. The template is a flat slice of segments shared by EnumerateVariants (build-time verification) and EmitGoBuilder (runtime composition).

func SegmentTemplate

func SegmentTemplate(sql string, params []Param) ([]Segment, error)

SegmentTemplate splits sql at every recognized marker pair, validating each block against params. The returned slice preserves source order.

type SegmentKind

type SegmentKind int

SegmentKind classifies how a Segment contributes to the rendered SQL.

const (
	// SegFixed unconditionally emits Text.
	SegFixed SegmentKind = iota
	// SegOmitWhenNull emits Text iff the caller's *T pointer is non-nil.
	SegOmitWhenNull
	// SegOmitWhenEmpty emits Text iff len([]T) > 0.
	SegOmitWhenEmpty
	// SegOrderByChoice emits one of Choices keyed by the caller's
	// choice string. Text holds the default-choice body (used when
	// the SQL is interpreted without the framework).
	SegOrderByChoice
)

type Variant

type Variant struct {
	SQL string
	// PresentParams names omit/empty params whose block is kept.
	PresentParams []string
	// AbsentParams names omit/empty params whose block is removed.
	AbsentParams []string
	// ChoiceAssignments records the choice picked for each
	// ModeOrderByChoice param, keyed by param name.
	ChoiceAssignments map[string]string
}

Variant is one concrete SQL produced by EnumerateVariants.

func EnumerateVariants

func EnumerateVariants(sql string, params []Param) ([]Variant, error)

EnumerateVariants returns every product point: each on/off combination for omit/empty segments crossed with every choice for orderby segments.

func (Variant) Key

func (v Variant) Key() string

Key returns a stable key suitable for indexing into a result map.

type VerifyResult

type VerifyResult struct {
	// Variants is the enumerated set (preserves the order returned by
	// EnumerateVariants).
	Variants []Variant
	// RowType is the agreed result row type. Pointer-shared across variants
	// since they were proven equal.
	RowType *spannerpb.StructType
}

VerifyResult is what VerifyVariants returns when every variant agrees on the result row type.

func VerifyVariants

func VerifyVariants(ddlPath, ddlSQL, sql string, params []Param) (*VerifyResult, error)

VerifyVariants enumerates SQL variants for the given query and runs the GoogleSQL analyzer against each one. The function fails if any variant fails to analyze or if two variants produce different result row types.

The analyzer is rebuilt per variant because AnalyzerOptions track per-call state (parameter declarations). All declared params are added to every variant, even ones whose predicate block is omitted, so the analyzer can resolve identifiers without surprise.

Jump to

Keyboard shortcuts

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