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 ¶
- func ComposeVariant(segments []Segment, p Presence) string
- func EmitGoBuilder(segments []Segment, params []Param, opts BuilderOptions) (string, error)
- func FormatPlanVariants(entries []PlanQueryVariant) string
- func VerifyBuilderRoundTrip(segments []Segment, variants []Variant) error
- type BuilderOptions
- type Mode
- type Param
- type PlanQueryVariant
- type Presence
- type Segment
- type SegmentKind
- type Variant
- type VerifyResult
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ComposeVariant ¶
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 ¶
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 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).
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 ¶
EnumerateVariants returns every product point: each on/off combination for omit/empty segments crossed with every choice for orderby segments.
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.