Documentation
¶
Overview ¶
Package spanvalue formats Cloud Spanner data from the Go client (cloud.google.com/go/spanner): cloud.google.com/go/spanner.GenericColumnValue values for individual columns and `*spanner.Row` values for full rows (cloud.google.com/go/spanner.Row), into strings for SQL literals, JSON, Spanner CLI–compatible text, and related styles.
Primary API ¶
Configure output with FormatConfig, which holds exactly two fields: the NULL rendering (FormatConfig.NullString) and the ordered plugin chain (FormatConfig.FormatComplexPlugins). Use the constructors LiteralFormatConfig, LiteralFormatConfigWithQuote, LiteralFormatConfigWithSingleQuotedLiterals, LiteralFormatConfigWithOptions, SimpleFormatConfig, SpannerCLICompatibleFormatConfig, and JSONFormatConfig to pick a preset. Literal quote options (LiteralQuoteConfig, WithLiteralQuote) are captured into the literal preset's plugins at construction time.
FormatConfig.FormatColumn tries each FormatComplexFunc plugin in order; a plugin returns ErrFallthrough to defer. When every plugin defers, NULL values of any type render as FormatConfig.NullString, and non-NULL values fail with ErrUnhandledValue — chain coverage is a runtime property. Constructors return a new FormatConfig; call FormatConfig.Clone or FormatConfig.WithComplexPlugin (prepends a plugin, so the most recent addition runs first) before mutating a config you may reuse. After hand-assembling a config, call FormatConfig.Validate to catch an empty FormatConfig.NullString, an empty chain, or nil plugins before the first FormatConfig.FormatRow call. Package writer does not call Validate on [writer.WithFormatter] configs; validate hand-built formatters before passing them to writers.
Convenience entry points include FormatRowLiteral, FormatColumnLiteral, FormatRowJSONObject, and FormatRowSpannerCLICompatible; they use internal singleton configs, so call FormatConfig.FormatRow on your own config when customizing. Identifier quoting helpers are QuoteIdentifier and QuoteQualifiedIdentifier.
Customization: builder and plugins ¶
NewFormatConfig assembles a config from canonical handlers with build-time validation: WithPlugin overrides (most recent first), then WithArrayFormat (PluginForArray), WithStructFormat (PluginForStruct), and the WithScalarFormatter tail (PluginFromNullable). Missing handlers fail at construction (ErrScalarFormatterRequired, ErrArrayFormatRequired, ErrStructFormatRequired) instead of on the first row.
To customize a preset, prepend plugins with FormatConfig.WithComplexPlugin: a prepended plugin runs before the preset handlers, so it can override any type (for tuple STRUCT with Spanner CLI scalars, prepend PluginForStruct(FormatSimpleStructField, FormatTupleStruct); see the README). For per-scalar-type overrides use PluginForNullable (the pre-composed PluginFromNullable + NullableFormatterFor form); values the override defers keep the preset behavior. A prepended PluginFromNullable with a total formatter replaces preset scalar formatting wholesale.
Plugin authors lift the usual type and NULL guards with PluginForType, PluginForTypeCode, and PluginSkippingNull. Callback types are FormatArrayFunc, FormatStructFieldFunc (Formatter-based), FormatStructParenFunc, FormatNullableFunc, and FormatComplexFunc; exported building blocks include FormatTupleStruct, FormatTypedStruct, FormatBracketStruct, FormatUntypedArray, FormatOptionallyTypedArray, FormatCompactArray, and NewJSONObjectStructFormatter.
Related packages ¶
To build cloud.google.com/go/spanner.GenericColumnValue values from Go types, see github.com/apstndb/spanvalue/gcvctor. For streaming row export, see github.com/apstndb/spanvalue/writer. For opt-in descriptor-aware PROTO and ENUM display plugins, see github.com/apstndb/spanvalue/protofmt.
Index ¶
- Variables
- func ColumnNames(fields []*sppb.StructType_Field, namer UnnamedFieldNamer) ([]string, error)
- func FormatBracketStruct(typ *sppb.Type, toplevel bool, fieldStrings []string) (string, error)
- func FormatColumnLiteral(value spanner.GenericColumnValue) (string, error)
- func FormatColumnSpannerCLICompatible(value spanner.GenericColumnValue) (string, error)
- func FormatCompactArray(_ *sppb.Type, _ bool, elemStrings []string) (string, error)
- func FormatEnumAsCast(formatter Formatter, value spanner.GenericColumnValue, toplevel bool) (string, error)
- func FormatJSONSimpleValue(formatter Formatter, value spanner.GenericColumnValue, _ bool) (string, error)
- func FormatNullableSpannerCLICompatible(value NullableValue) (string, error)
- func FormatOptionallyTypedArray(typ *sppb.Type, toplevel bool, elemStrings []string) (string, error)
- func FormatProtoAsCast(formatter Formatter, value spanner.GenericColumnValue, toplevel bool) (string, error)
- func FormatRowColumns(fc *FormatConfig, columnNames []string, values []spanner.GenericColumnValue) ([]string, error)
- func FormatRowJSONObject(fc *FormatConfig, row *spanner.Row, namer UnnamedFieldNamer) (string, error)
- func FormatRowJSONObjectFromColumns(fc *FormatConfig, columnNames []string, values []spanner.GenericColumnValue, ...) (string, error)
- func FormatRowLiteral(value *spanner.Row) ([]string, error)
- func FormatRowSpannerCLICompatible(row *spanner.Row) ([]string, error)
- func FormatSimpleStructField(formatter Formatter, field *sppb.StructType_Field, value *structpb.Value) (string, error)
- func FormatSimpleValue(formatter Formatter, value spanner.GenericColumnValue, _ bool) (string, error)
- func FormatSpannerCLIValue(formatter Formatter, value spanner.GenericColumnValue, _ bool) (string, error)
- func FormatTupleStruct(typ *sppb.Type, toplevel bool, fieldStrings []string) (string, error)
- func FormatTypedStruct(typ *sppb.Type, toplevel bool, fieldStrings []string) (string, error)
- func FormatTypelessStructField(formatter Formatter, field *sppb.StructType_Field, value *structpb.Value) (string, error)
- func FormatUntypedArray(_ *sppb.Type, _ bool, elemStrings []string) (string, error)
- func IndexedUnnamedFieldNamer(index int) string
- func IsNull(gcv spanner.GenericColumnValue) bool
- func QuoteIdentifier(dialect databasepb.DatabaseDialect, name string) string
- func QuoteQualifiedIdentifier(dialect databasepb.DatabaseDialect, name string) string
- type FormatArrayFunc
- type FormatComplexFunc
- func LiteralValuePlugin(opts LiteralFormatOptions) FormatComplexFunc
- func PluginForArray(join FormatArrayFunc) FormatComplexFunc
- func PluginForNullable[T NullableValue](f func(T) (string, error)) FormatComplexFunc
- func PluginForStruct(field FormatStructFieldFunc, paren FormatStructParenFunc) FormatComplexFunc
- func PluginForType(match func(*sppb.Type) bool, plugin FormatComplexFunc) FormatComplexFunc
- func PluginForTypeCode(code sppb.TypeCode, plugin FormatComplexFunc) FormatComplexFunc
- func PluginFromNullable(f FormatNullableFunc) FormatComplexFunc
- func PluginSkippingNull(plugin FormatComplexFunc) FormatComplexFunc
- type FormatConfig
- func JSONFormatConfig() *FormatConfig
- func LiteralFormatConfig() *FormatConfig
- func LiteralFormatConfigWithOptions(opts ...LiteralOption) *FormatConfig
- func LiteralFormatConfigWithQuote(cfg LiteralQuoteConfig) *FormatConfig
- func LiteralFormatConfigWithSingleQuotedLiterals() *FormatConfig
- func NewFormatConfig(opts ...FormatConfigOption) (*FormatConfig, error)
- func SimpleFormatConfig() *FormatConfig
- func SpannerCLICompatibleFormatConfig() *FormatConfig
- func (fc *FormatConfig) Clone() *FormatConfig
- func (fc *FormatConfig) FormatColumn(value spanner.GenericColumnValue, toplevel bool) (string, error)
- func (fc *FormatConfig) FormatRow(row *spanner.Row) ([]string, error)
- func (fc *FormatConfig) FormatToplevelColumn(value spanner.GenericColumnValue) (string, error)
- func (fc *FormatConfig) GetNullString() string
- func (fc *FormatConfig) Validate() error
- func (fc *FormatConfig) WithComplexPlugin(plugin FormatComplexFunc) *FormatConfig
- type FormatConfigOption
- func WithArrayFormat(join FormatArrayFunc) FormatConfigOption
- func WithNullString(s string) FormatConfigOption
- func WithPlugin(p FormatComplexFunc) FormatConfigOption
- func WithScalarFormatter(f FormatNullableFunc) FormatConfigOption
- func WithStructFormat(field FormatStructFieldFunc, paren FormatStructParenFunc) FormatConfigOption
- type FormatNullableFunc
- type FormatStructFieldFunc
- type FormatStructParenFunc
- type Formatter
- type LiteralFormatOptions
- type LiteralOption
- type LiteralQuoteConfig
- type NullBytes
- type NullableValue
- type PreferredQuote
- type QuoteStrategy
- type UnnamedFieldNamer
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( ErrNilRow = errors.New("nil row") ErrNilStructField = errors.New("nil struct field descriptor") // ErrUnknownType is returned when a type code (or, on the Decode path, a Go // value type) is not supported by the formatter. It signals a // configuration/coverage problem: the value may become formattable by adding // a [FormatComplexFunc] plugin or choosing a different preset. For known // types whose wire payload is invalid, see [ErrMalformedWire]. ErrUnknownType = errors.New("unknown type") // ErrMalformedWire is returned when the type code of a value is known but // its wire payload does not match the encoding Spanner uses for that type — // for example a BOOL whose [structpb.Value] kind is a string, a FLOAT64 // string other than "NaN"/"Infinity"/"-Infinity", or a NULL that // unexpectedly reaches the scalar wire validator. Unlike [ErrUnknownType] // (a configuration problem that a plugin or preset change can address), // ErrMalformedWire means the [cloud.google.com/go/spanner.GenericColumnValue] // itself is corrupt: consumers should treat it as a data problem and fail // the export rather than reconfigure formatting. It does not match // [ErrUnknownType] via [errors.Is]. ErrMalformedWire = errors.New("malformed wire value") ErrMismatchedFields = errors.New("mismatched struct value/field count") ErrUnexpectedComplexValueKind = errors.New("unexpected complex value kind") ErrEmptyTypeFQN = errors.New("empty type FQN") // ErrNilFormatConfig is returned by [*FormatConfig.Validate] when the receiver is nil. ErrNilFormatConfig = errors.New("nil format config") // ErrEmptyNullString is returned by [*FormatConfig.Validate] when [FormatConfig.NullString] is empty. ErrEmptyNullString = errors.New("empty null string") // ErrNilFormatComplexPlugin is returned by [*FormatConfig.Validate] when // [FormatConfig.FormatComplexPlugins] contains a nil element. ErrNilFormatComplexPlugin = errors.New("nil format complex plugin") // ErrEmptyFormatComplexPlugins is returned by [*FormatConfig.Validate] when // [FormatConfig.FormatComplexPlugins] is empty: with no plugins, every // non-NULL value fails with [ErrUnhandledValue], so an empty chain is // treated as a construction mistake. ErrEmptyFormatComplexPlugins = errors.New("empty format complex plugins") // ErrUnhandledValue is returned by [*FormatConfig.FormatColumn] when every // plugin in [FormatConfig.FormatComplexPlugins] defers ([ErrFallthrough]) // for a non-NULL value. The wrapped message includes the value's // [sppb.Type]. It signals a coverage problem in the chain: register a // plugin that claims the value (for example [PluginForArray], // [PluginForStruct], or [PluginFromNullable]) or choose a preset that // covers it. NULL values never reach this error; they render as // [FormatConfig.NullString] when no plugin claims them. // // ErrUnhandledValue replaces the pre-v0.8 built-in fallbacks: the // ErrFormatNullableRequired error for scalars, the nil FormatArray / // FormatStruct callback panics, and the built-in path's ErrUnknownType // for unknown scalar type codes. ErrUnhandledValue = errors.New("no plugin handled value") )
var ( // ErrScalarFormatterRequired is returned by [NewFormatConfig] when no // [WithScalarFormatter] option was supplied (or its formatter was nil). ErrScalarFormatterRequired = errors.New("scalar formatter required") // ErrArrayFormatRequired is returned by [NewFormatConfig] when no // [WithArrayFormat] option was supplied (or its join function was nil). ErrArrayFormatRequired = errors.New("array format required") // ErrStructFormatRequired is returned by [NewFormatConfig] when no // [WithStructFormat] option was supplied (or either of its callbacks was nil). ErrStructFormatRequired = errors.New("struct format required") )
var ErrFallthrough = errors.New("fallthrough")
ErrFallthrough tells FormatComplexFunc plugins to defer to the next plugin or built-in path.
Functions ¶
func ColumnNames ¶ added in v0.1.10
func ColumnNames(fields []*sppb.StructType_Field, namer UnnamedFieldNamer) ([]string, error)
ColumnNames returns the names of the provided fields. Unnamed fields are kept as empty strings unless a non-nil namer is provided, in which case the namer is used to generate names for unnamed fields. If a non-nil UnnamedFieldNamer returns an empty string or repeatedly returns colliding names such that a unique column name cannot be chosen, ColumnNames returns a non-nil error describing the contract violation. Explicit duplicate field names from the query schema (for example SELECT 1 AS a, 2 AS a) are preserved as-is; only namer-resolution collisions are errors.
func FormatBracketStruct ¶
func FormatColumnLiteral ¶
func FormatColumnLiteral(value spanner.GenericColumnValue) (string, error)
FormatColumnLiteral formats value using LiteralFormatConfig at top level.
func FormatColumnSpannerCLICompatible ¶
func FormatColumnSpannerCLICompatible(value spanner.GenericColumnValue) (string, error)
FormatColumnSpannerCLICompatible formats value using SpannerCLICompatibleFormatConfig at top level.
func FormatCompactArray ¶ added in v0.1.9
FormatCompactArray formats array elements without spaces between separators. Output: [elem1,elem2,elem3]
func FormatEnumAsCast ¶
func FormatJSONSimpleValue ¶ added in v0.1.9
func FormatJSONSimpleValue(formatter Formatter, value spanner.GenericColumnValue, _ bool) (string, error)
FormatJSONSimpleValue is a FormatComplexFunc that formats scalar types as standalone JSON values. It returns ErrFallthrough for ARRAY, STRUCT, and type codes outside the supported scalar set (the same set as the other preset scalar plugins: BOOL, INT64/ENUM, FLOAT32/64, STRING, BYTES/PROTO, TIMESTAMP, DATE, NUMERIC, JSON, INTERVAL, UUID), so later plugins in the chain can claim unknown codes; with no such plugin, unhandled non-NULL values fail with ErrUnhandledValue instead of emitting invalid JSON. Wire payloads whose kind does not match the type code are rejected (ErrMalformedWire) rather than marshaled blindly.
For most types, structpb.Value.MarshalJSON() produces the correct JSON representation (BOOL→true/false, FLOAT→number, STRING→"quoted", NaN/Inf→"NaN"/"Infinity"). Only INT64, ENUM, and JSON (including PostgreSQL PG_JSONB-annotated JSON) columns need special handling:
- INT64: Spanner encodes as StringValue("42"), MarshalJSON() would produce "42" (quoted), but we want 42 (unquoted number).
- ENUM: Spanner stores proto enum values as INT64; same handling as INT64.
- JSON / PG_JSONB: Spanner encodes as StringValue('{"key":"value"}'), MarshalJSON() would produce escaped quoted string, but we want the raw JSON value passed through.
JSON columns pass the wire string through as-is after validity checking, without re-marshaling — the same wire-as-is contract as NUMERIC (real Spanner wire is already normalized; hand-built GCVs keep their formatting, so key order and whitespace are preserved).
func FormatNullableSpannerCLICompatible ¶
func FormatNullableSpannerCLICompatible(value NullableValue) (string, error)
func FormatOptionallyTypedArray ¶
func FormatOptionallyTypedArray(typ *sppb.Type, toplevel bool, elemStrings []string) (string, error)
FormatOptionallyTypedArray formats ARRAY values for SQL literals. It prefixes the bracket list with an ARRAY<...> type annotation only when toplevel is true and the array element type is complex (STRUCT or nested ARRAY), independent of element count. Scalar element arrays at top level are untyped ([], [1, 2], not ARRAY<INT64>[1, 2]). LiteralFormatConfig wires this through PluginForArray.
func FormatProtoAsCast ¶
func FormatProtoAsCast(formatter Formatter, value spanner.GenericColumnValue, toplevel bool) (string, error)
FormatProtoAsCast formats PROTO values as CAST(b"..." AS `fqn`) with the default (legacy double-quote) bytes-literal quoting. The literal preset constructors install a quote-aware equivalent that follows the constructor-captured LiteralQuoteConfig (LiteralFormatConfigWithQuote and friends), so quote options apply to PROTO casts only through those constructors.
func FormatRowColumns ¶ added in v0.1.10
func FormatRowColumns(fc *FormatConfig, columnNames []string, values []spanner.GenericColumnValue) ([]string, error)
FormatRowColumns formats a row represented as column names plus GCV values. The column names are validated for shape compatibility, but the formatted cell values come from the GCVs themselves.
func FormatRowJSONObject ¶ added in v0.1.9
func FormatRowJSONObject(fc *FormatConfig, row *spanner.Row, namer UnnamedFieldNamer) (string, error)
FormatRowJSONObject formats a spanner.Row as a single JSON object string using the given FormatConfig for value formatting and column names as keys. The FormatConfig must produce standalone JSON values per column (e.g., JSONFormatConfig()). Using a non-JSON config produces syntactically invalid output. Empty column names (e.g., from expressions without aliases like SELECT 1+1) are assigned names by the provided namer function. If namer is nil, empty names are kept as empty-string JSON keys. Returns an error if the namer returns an empty name, or if repeated name collisions prevent choosing a unique name for a field. Output: {"col1":val1,"col2":val2,...}
func FormatRowJSONObjectFromColumns ¶ added in v0.1.10
func FormatRowJSONObjectFromColumns(fc *FormatConfig, columnNames []string, values []spanner.GenericColumnValue, namer UnnamedFieldNamer) (string, error)
FormatRowJSONObjectFromColumns formats a row represented as column names plus GCV values into a JSON object string. The provided FormatConfig must emit standalone JSON values per column (for example, as configured by JSONFormatConfig()), otherwise the assembled object may be syntactically invalid JSON.
func FormatRowLiteral ¶
FormatRowLiteral formats each column of row using LiteralFormatConfig.
func FormatRowSpannerCLICompatible ¶
FormatRowSpannerCLICompatible formats each column of row using SpannerCLICompatibleFormatConfig.
func FormatSimpleStructField ¶
func FormatSimpleStructField(formatter Formatter, field *sppb.StructType_Field, value *structpb.Value) (string, error)
FormatSimpleStructField formats a STRUCT field as the field value alone, recursing through the whole plugin chain with toplevel false.
func FormatSimpleValue ¶ added in v0.4.2
func FormatSimpleValue(formatter Formatter, value spanner.GenericColumnValue, _ bool) (string, error)
FormatSimpleValue is a FormatComplexFunc that formats scalars for SimpleFormatConfig without constructing a NullableValue. It returns ErrFallthrough for ARRAY, STRUCT, and type codes outside the supported scalar set ([isScalarFastPathTypeCode]). NUMERIC uses the string wire payload as-is; canonical wire is the GCV constructor's responsibility (see github.com/apstndb/spanvalue/gcvctor.StringBasedValueFromCode).
func FormatSpannerCLIValue ¶ added in v0.4.2
func FormatSpannerCLIValue(formatter Formatter, value spanner.GenericColumnValue, _ bool) (string, error)
FormatSpannerCLIValue is a FormatComplexFunc that formats scalars for SpannerCLICompatibleFormatConfig. It returns ErrFallthrough for ARRAY, STRUCT, and type codes outside the supported scalar set.
func FormatTupleStruct ¶
FormatTupleStruct renders STRUCT values with parentheses, for example (1, east). SimpleFormatConfig uses it by default. To combine tuple STRUCT with Spanner CLI scalars, see SpannerCLICompatibleFormatConfig and the README tuple STRUCT example.
func FormatTypedStruct ¶
FormatTypedStruct renders STRUCT values with parentheses and, at top level, a verbose STRUCT<...> type prefix, for example STRUCT<id INT64>(1). LiteralFormatConfig uses it as its PluginForStruct paren callback.
func FormatTypelessStructField ¶
func FormatTypelessStructField(formatter Formatter, field *sppb.StructType_Field, value *structpb.Value) (string, error)
FormatTypelessStructField formats a STRUCT field as the field value followed by an " AS name" suffix for named fields. SimpleFormatConfig uses it as its PluginForStruct field callback.
func FormatUntypedArray ¶
func IndexedUnnamedFieldNamer ¶ added in v0.1.9
IndexedUnnamedFieldNamer produces names like "_0", "_1", etc. The underscore prefix minimizes collision with user-defined names. Suitable for row columns (e.g., SELECT 1+1 produces "_0").
func IsNull ¶ added in v0.1.10
func IsNull(gcv spanner.GenericColumnValue) bool
IsNull reports whether gcv represents a NULL value. A nil gcv.Value is treated as NULL.
func QuoteIdentifier ¶ added in v0.3.0
func QuoteIdentifier(dialect databasepb.DatabaseDialect, name string) string
QuoteIdentifier quotes a single identifier for dialect. For GoogleSQL it escapes the identifier with string-literal escape sequences (backslash to \\ and backtick to \`) per the GoogleSQL lexical structure; for PostgreSQL it doubles embedded double quotes. It does not validate the identifier; for example, an empty string becomes an empty quoted identifier (two backticks for GoogleSQL, "" for PostgreSQL), which is invalid SQL in both dialects. DATABASE_DIALECT_UNSPECIFIED follows the Spanner default and uses GoogleSQL quoting.
func QuoteQualifiedIdentifier ¶ added in v0.3.0
func QuoteQualifiedIdentifier(dialect databasepb.DatabaseDialect, name string) string
QuoteQualifiedIdentifier quotes each segment of a dotted identifier path for dialect. It does not validate the path; callers that reject empty segments must do so before calling it.
Types ¶
type FormatArrayFunc ¶
type FormatComplexFunc ¶
type FormatComplexFunc func(formatter Formatter, value spanner.GenericColumnValue, toplevel bool) (string, error)
FormatComplexFunc formats one cloud.google.com/go/spanner.GenericColumnValue as an element of FormatConfig.FormatComplexPlugins. Returning ErrFallthrough defers the value to the next plugin in the chain (and, when every plugin defers, to the built-in NULL handling or ErrUnhandledValue).
func LiteralValuePlugin ¶ added in v0.8.0
func LiteralValuePlugin(opts LiteralFormatOptions) FormatComplexFunc
LiteralValuePlugin returns the literal preset's scalar FormatComplexFunc with quote options captured at construction (invalid enum values are normalized). It returns ErrFallthrough for ARRAY, STRUCT, PROTO, and ENUM — the literal preset handles PROTO/ENUM with FormatProtoAsCast and FormatEnumAsCast earlier in the chain — and for type codes outside the supported scalar set.
LiteralValuePlugin replaces the pre-v0.8 exported plugin value FormatLiteralValue, which read quote options from the removed FormatConfig.Literal field; LiteralValuePlugin(LiteralFormatOptions{}) is the default-quote equivalent.
func PluginForArray ¶ added in v0.7.6
func PluginForArray(join FormatArrayFunc) FormatComplexFunc
PluginForArray lifts a FormatArrayFunc into the plugin chain: for non-NULL ARRAY values the wire list value is extracted (non-list payloads are ErrUnexpectedComplexValueKind), each element is recursively formatted with formatter.FormatColumn(elem, false) so the whole chain applies per element, and the element strings are handed to join. join must be non-nil.
A nil Type, a non-ARRAY type code, and SQL NULL fall through (ErrFallthrough); NULL deferral lets the built-in handling render Formatter.GetNullString. Plugin authors who want typed NULL arrays — for example rendering CAST(NULL AS bigint[]) — should instead write a plain PluginForTypeCode(ARRAY, ...) plugin, which receives NULL values.
func PluginForNullable ¶ added in v0.8.0
func PluginForNullable[T NullableValue](f func(T) (string, error)) FormatComplexFunc
PluginForNullable is the pre-composed combination of PluginFromNullable and NullableFormatterFor: a chain plugin that formats exactly the scalar values decoding to the NullableValue wrapper type T and defers everything else — other scalar types, SQL NULL, ARRAY, STRUCT, and unsupported type codes all fall through (ErrFallthrough). Because the Decode dispatch is annotation-aware, T selects the dialect variant precisely: cloud.google.com/go/spanner.PGNumeric matches only PG_NUMERIC-annotated NUMERIC, cloud.google.com/go/spanner.NullNumeric only the GoogleSQL form.
cfg := spanvalue.SimpleFormatConfig().WithComplexPlugin(
spanvalue.PluginForNullable(func(v spanner.NullNumeric) (string, error) {
return v.Numeric.FloatString(2), nil
}))
Use the two primitives directly when one function should claim several wrapper types.
func PluginForStruct ¶ added in v0.7.6
func PluginForStruct(field FormatStructFieldFunc, paren FormatStructParenFunc) FormatComplexFunc
PluginForStruct lifts STRUCT formatting into the plugin chain: for non-NULL STRUCT values the wire list value is extracted (non-list payloads are ErrUnexpectedComplexValueKind), the value count is checked against the field descriptors (ErrMismatchedFields), each field is formatted with the FormatStructFieldFunc callback (use formatter.FormatColumn(fieldGCV, false) to recurse into the field value), and the field strings are handed to paren. Both callbacks must be non-nil.
A nil Type, a non-STRUCT type code, and SQL NULL fall through (ErrFallthrough); NULL deferral lets the built-in handling render Formatter.GetNullString. For typed NULL STRUCT rendering write a plain PluginForTypeCode(STRUCT, ...) plugin, which receives NULL values.
func PluginForType ¶ added in v0.7.6
func PluginForType(match func(*sppb.Type) bool, plugin FormatComplexFunc) FormatComplexFunc
PluginForType restricts plugin to values whose sppb.Type satisfies match; every other value falls through (ErrFallthrough) to the rest of the plugin chain and the built-in formatting. It lifts the type-guard boilerplate out of FormatComplexFunc authors:
PluginForType(func(t *sppb.Type) bool {
return t.GetCode() == sppb.TypeCode_JSON &&
t.GetTypeAnnotation() == sppb.TypeAnnotationCode_PG_JSONB
}, body)
match must be non-nil. A nil sppb.Type falls through without calling match (the built-in handling classifies such values as malformed wire), so predicates need not be nil-safe. For a bare type-code guard, use PluginForTypeCode; compose with PluginSkippingNull when the body only handles non-NULL values.
func PluginForTypeCode ¶ added in v0.7.6
func PluginForTypeCode(code sppb.TypeCode, plugin FormatComplexFunc) FormatComplexFunc
PluginForTypeCode is PluginForType matching on the type code alone. Note that annotated types share a code with their GoogleSQL base (PG_JSONB is TypeCode_JSON, PG_NUMERIC is TypeCode_NUMERIC); use PluginForType with a predicate when the annotation matters.
func PluginFromNullable ¶ added in v0.7.6
func PluginFromNullable(f FormatNullableFunc) FormatComplexFunc
PluginFromNullable lifts a FormatNullableFunc into the plugin chain: non-NULL scalar values are decoded to their NullableValue wrapper — including the PG-annotated wrappers (cloud.google.com/go/spanner.PGNumeric, cloud.google.com/go/spanner.PGJsonB) — and formatted with f. ARRAY and STRUCT values, SQL NULLs, and type codes outside the scalar set fall through (ErrFallthrough).
f itself may return ErrFallthrough to defer values it does not claim, so per-type overrides compose with NullableFormatterFor and the rest of the chain (preset scalar plugins included) keeps formatting everything the override leaves alone:
cfg := spanvalue.SimpleFormatConfig().WithComplexPlugin(
spanvalue.PluginFromNullable(spanvalue.NullableFormatterFor(
func(v spanner.NullNumeric) (string, error) {
return "NUMERIC:" + v.Numeric.FloatString(2), nil
})))
Like every complex plugin it also runs for ARRAY elements, so an override applies inside ARRAY<T> as well. Decode failures other than the unsupported-type-code class are returned as real errors.
func PluginSkippingNull ¶ added in v0.7.6
func PluginSkippingNull(plugin FormatComplexFunc) FormatComplexFunc
PluginSkippingNull makes SQL NULL values fall through (ErrFallthrough) so plugin only sees non-NULL values. The chain's built-in scalar handling renders NULL via Formatter.GetNullString on every preset, so deferring is output-equivalent to returning the null string from the plugin itself — unless a later plugin in the chain claims NULLs of the same type.
type FormatConfig ¶
type FormatConfig struct {
NullString string
FormatComplexPlugins []FormatComplexFunc
}
FormatConfig controls how Spanner values are formatted. Behavior lives entirely in the two fields: NullString (the global NULL rendering) and FormatComplexPlugins (the ordered FormatComplexFunc chain).
*FormatConfig.FormatColumn tries every plugin in order; a plugin returns ErrFallthrough to defer. When every plugin defers, NULL values (of any type) render as NullString and non-NULL values fail with ErrUnhandledValue. Coverage is therefore a property of the chain: preset constructors (SimpleFormatConfig, LiteralFormatConfig, SpannerCLICompatibleFormatConfig, JSONFormatConfig) install a scalar plugin plus PluginForArray and PluginForStruct handlers, and NewFormatConfig assembles a chain from the same combinators with build-time validation.
Use *FormatConfig.Clone or *FormatConfig.WithComplexPlugin (prepends plugins, so the most recent addition runs first) to customize a preset without mutating shared instances. Call *FormatConfig.Validate after hand-assembling a config to fail fast on an empty NullString, an empty chain, or nil plugins; Validate cannot prove that the chain covers every type — coverage gaps surface at format time as ErrUnhandledValue.
func JSONFormatConfig ¶ added in v0.1.9
func JSONFormatConfig() *FormatConfig
JSONFormatConfig returns a new FormatConfig that produces valid JSON value strings for each Spanner value. Each call returns a fresh instance that the caller may customize.
Each formatted string is a standalone JSON value:
- NULL → null
- BOOL → true / false
- INT64 → 42 (unquoted number)
- FLOAT32/FLOAT64 → 3.14 (NaN/Inf as quoted strings)
- ENUM → 42 (unquoted number, Spanner stores proto enum values as INT64)
INT64 and ENUM emit unquoted JSON numbers. Values beyond 2^53 lose precision in float64-based consumers (JavaScript, encoding/json into any). For lossless export, prepend a FormatComplexFunc plugin (*FormatConfig.WithComplexPlugin) that quotes INT64/ENUM wire strings.
- STRING, BYTES, TIMESTAMP, DATE, NUMERIC, PROTO, INTERVAL, UUID → "quoted string"
- JSON column → raw JSON value (passed through)
- ARRAY → [elem1,elem2,...]
- STRUCT → {"field1":val1,"field2":val2,...}
NULL of any type renders as the JSON literal null via FormatConfig.NullString ("null"); keep NullString JSON-valid when cloning. Scalar type codes outside the supported set fall through the whole chain and fail with ErrUnhandledValue rather than silently emitting non-JSON output; add a plugin (most easily with *FormatConfig.WithComplexPlugin, or appended after FormatJSONSimpleValue on a clone) to support additional codes — the plugin must emit standalone JSON values to keep the output contract.
func LiteralFormatConfig ¶
func LiteralFormatConfig() *FormatConfig
LiteralFormatConfig returns a new FormatConfig that produces parseable SQL literal expressions with type annotations. ARRAY values use FormatOptionallyTypedArray: top-level arrays with scalar elements omit the ARRAY<...> prefix (empty or not); arrays of STRUCT or nested ARRAY include it when toplevel is true (empty or not). The chain is FormatProtoAsCast, FormatEnumAsCast, LiteralValuePlugin for the remaining scalars, PluginForArray, and PluginForStruct with FormatSimpleStructField and FormatTypedStruct. Use LiteralFormatConfigWithQuote or LiteralFormatConfigWithOptions for non-default quote options.
func LiteralFormatConfigWithOptions ¶ added in v0.5.1
func LiteralFormatConfigWithOptions(opts ...LiteralOption) *FormatConfig
LiteralFormatConfigWithOptions returns a LiteralFormatConfig preset with the given options captured into its quote-sensitive plugins (string/bytes scalar literals and PROTO casts).
func LiteralFormatConfigWithQuote ¶ added in v0.5.1
func LiteralFormatConfigWithQuote(cfg LiteralQuoteConfig) *FormatConfig
LiteralFormatConfigWithQuote returns a LiteralFormatConfig preset with the given quote settings.
func LiteralFormatConfigWithSingleQuotedLiterals ¶ added in v0.5.1
func LiteralFormatConfigWithSingleQuotedLiterals() *FormatConfig
LiteralFormatConfigWithSingleQuotedLiterals returns a literal preset that always single-quotes string and bytes literals (SQL INSERT style).
Example ¶
fc := LiteralFormatConfigWithSingleQuotedLiterals()
date, _ := fc.FormatToplevelColumn(gcvctor.DateValue(civil.Date{Year: 2014, Month: 9, Day: 27}))
str, _ := fc.FormatToplevelColumn(gcvctor.StringValue("it's fine"))
fmt.Println(date)
fmt.Println(str)
Output: DATE '2014-09-27' 'it\'s fine'
func NewFormatConfig ¶ added in v0.7.6
func NewFormatConfig(opts ...FormatConfigOption) (*FormatConfig, error)
NewFormatConfig assembles a FormatConfig from the plugin combinators with build-time validation. The chain is built in canonical order:
- WithPlugin overrides, most recent registration first,
- PluginForArray from WithArrayFormat,
- PluginForStruct from WithStructFormat,
- PluginFromNullable from WithScalarFormatter as the tail.
NULL values that no override claims render as the WithNullString value. The returned config passes *FormatConfig.Validate.
Build-time validation: ErrScalarFormatterRequired, ErrArrayFormatRequired, and ErrStructFormatRequired when the respective handler option is missing; ErrEmptyNullString when WithNullString is missing or empty; ErrNilFormatComplexPlugin when a WithPlugin override is nil. Validation does not prove total coverage: a scalar type code outside the PluginFromNullable domain that no override claims surfaces ErrUnhandledValue at format time. Nil options are ignored.
Example ¶
Assemble a config from the canonical handlers plus a per-type override: the prepended PluginFromNullable claims NUMERIC, everything else reaches the WithScalarFormatter tail, and NULLs render as the WithNullString value.
package main
import (
"fmt"
"math/big"
"cloud.google.com/go/spanner"
sppb "cloud.google.com/go/spanner/apiv1/spannerpb"
"github.com/apstndb/spanvalue"
"github.com/apstndb/spanvalue/gcvctor"
)
func main() {
fc, err := spanvalue.NewFormatConfig(
spanvalue.WithNullString("NULL"),
spanvalue.WithPlugin(spanvalue.PluginFromNullable(spanvalue.NullableFormatterFor(
func(v spanner.NullNumeric) (string, error) {
return v.Numeric.FloatString(2), nil
}))),
spanvalue.WithArrayFormat(spanvalue.FormatUntypedArray),
spanvalue.WithStructFormat(spanvalue.FormatSimpleStructField, spanvalue.FormatTupleStruct),
spanvalue.WithScalarFormatter(spanvalue.FormatNullableSpannerCLICompatible),
)
if err != nil {
panic(err)
}
arr, err := gcvctor.ArrayValue(
gcvctor.NumericValue(big.NewRat(3, 2)),
gcvctor.NullFromCode(sppb.TypeCode_NUMERIC),
)
if err != nil {
panic(err)
}
out, err := fc.FormatToplevelColumn(arr)
if err != nil {
panic(err)
}
fmt.Println(out)
}
Output: [1.50, NULL]
func SimpleFormatConfig ¶
func SimpleFormatConfig() *FormatConfig
SimpleFormatConfig returns a new FormatConfig that produces human-readable output using client library conventions. The chain is FormatSimpleValue for scalars, PluginForArray with FormatUntypedArray, and PluginForStruct with FormatTypelessStructField and FormatTupleStruct.
func SpannerCLICompatibleFormatConfig ¶
func SpannerCLICompatibleFormatConfig() *FormatConfig
SpannerCLICompatibleFormatConfig returns a new FormatConfig that matches the output format of the official spanner-cli tool (bracket-style STRUCT fields in arrays, for example [[1, east]] for `ARRAY<STRUCT<...>>`).
Tuple-style STRUCT parentheses such as [(1, east)] are not spanner-cli output. To keep Spanner CLI scalar formatting but render STRUCT with FormatTupleStruct, prepend a PluginForStruct override (it runs before the preset's STRUCT handler and claims non-NULL STRUCT values):
fc := SpannerCLICompatibleFormatConfig().WithComplexPlugin(
PluginForStruct(FormatSimpleStructField, FormatTupleStruct))
See the repository README for a tuple STRUCT example. Application-specific presets (for example spanner-mycli table modes) should compose FormatConfig in the caller rather than adding new constructors here.
Example (TupleStruct) ¶
Tuple-style STRUCT in `ARRAY<STRUCT<...>>` while keeping Spanner CLI scalar formatting. The prepended PluginForStruct override runs before the preset's STRUCT handler.
package main
import (
"fmt"
"cloud.google.com/go/spanner"
"github.com/apstndb/spanvalue"
"github.com/apstndb/spanvalue/gcvctor"
)
func main() {
fc := spanvalue.SpannerCLICompatibleFormatConfig().WithComplexPlugin(
spanvalue.PluginForStruct(spanvalue.FormatSimpleStructField, spanvalue.FormatTupleStruct))
structElem, err := gcvctor.StructValueOf(
[]string{"id", "region"},
[]spanner.GenericColumnValue{gcvctor.Int64Value(1), gcvctor.StringValue("east")},
)
if err != nil {
panic(err)
}
arrayOfStruct, err := gcvctor.ArrayValue(structElem)
if err != nil {
panic(err)
}
out, err := fc.FormatToplevelColumn(arrayOfStruct)
if err != nil {
panic(err)
}
fmt.Println(out)
}
Output: [(1, east)]
func (*FormatConfig) Clone ¶ added in v0.3.2
func (fc *FormatConfig) Clone() *FormatConfig
Clone returns a shallow copy of fc with a copied FormatComplexPlugins slice. The returned config is independent for field assignment and plugin list mutation; callback values themselves are shared with the source. Clone returns nil when fc is nil.
func (*FormatConfig) FormatColumn ¶
func (fc *FormatConfig) FormatColumn(value spanner.GenericColumnValue, toplevel bool) (string, error)
func (*FormatConfig) FormatRow ¶
func (fc *FormatConfig) FormatRow(row *spanner.Row) ([]string, error)
func (*FormatConfig) FormatToplevelColumn ¶
func (fc *FormatConfig) FormatToplevelColumn(value spanner.GenericColumnValue) (string, error)
func (*FormatConfig) GetNullString ¶ added in v0.1.10
func (fc *FormatConfig) GetNullString() string
func (*FormatConfig) Validate ¶ added in v0.6.0
func (fc *FormatConfig) Validate() error
Validate reports invalid hand-built FormatConfig values. Preset constructors and NewFormatConfig return configs that pass *FormatConfig.Validate. Nil fc returns ErrNilFormatConfig.
Static checks: non-empty NullString (ErrEmptyNullString; empty is rejected so NULL output is explicit, not ambiguous with an empty STRING), a non-empty FormatComplexPlugins chain (ErrEmptyFormatComplexPlugins), and non-nil chain elements (ErrNilFormatComplexPlugin).
Validate cannot inspect what a plugin claims, so it does not prove that the chain covers every type: coverage is a runtime property — a non-NULL value that every plugin defers fails with ErrUnhandledValue at format time. NewFormatConfig additionally requires the canonical ARRAY/STRUCT/scalar handlers at build time.
func (*FormatConfig) WithComplexPlugin ¶ added in v0.7.0
func (fc *FormatConfig) WithComplexPlugin(plugin FormatComplexFunc) *FormatConfig
WithComplexPlugin returns a clone of fc with plugin prepended to FormatComplexPlugins so it runs before existing plugins (including preset scalar plugins). This matches the protofmt pattern of prepending descriptor-aware plugins before preset defaults. The original config, including shared preset singletons, is not mutated. Chain further calls on the returned config for additional plugins (each prepends, so the most recent call runs first). Nil fc returns nil. A nil plugin panics so a mistaken nil in a chain fails at the call site instead of collapsing the chain to nil.
type FormatConfigOption ¶ added in v0.7.6
type FormatConfigOption func(*formatConfigBuilder)
FormatConfigOption configures NewFormatConfig.
func WithArrayFormat ¶ added in v0.7.6
func WithArrayFormat(join FormatArrayFunc) FormatConfigOption
WithArrayFormat sets the non-NULL ARRAY handler, installed as PluginForArray(join) after the WithPlugin overrides. NULL ARRAY values render as the WithNullString value unless an override claims them. Required; a nil join is treated as unset (ErrArrayFormatRequired).
func WithNullString ¶ added in v0.7.6
func WithNullString(s string) FormatConfigOption
WithNullString sets FormatConfig.NullString, the string every NULL value renders as unless a WithPlugin override claims it first. Required: NewFormatConfig rejects an empty NullString with ErrEmptyNullString (same rule as *FormatConfig.Validate).
func WithPlugin ¶ added in v0.7.6
func WithPlugin(p FormatComplexFunc) FormatConfigOption
WithPlugin prepends p to the override region of the plugin chain: the most recently registered plugin runs first, matching *FormatConfig.WithComplexPlugin semantics. Overrides run before the WithArrayFormat / WithStructFormat / WithScalarFormatter handlers, so they can claim any value (including SQL NULLs and typed NULL arrays) or defer with ErrFallthrough. A nil p fails NewFormatConfig with ErrNilFormatComplexPlugin.
WithPlugin alone never satisfies the required handler options: even a plugin that covers every value must be accompanied by WithArrayFormat, WithStructFormat, and WithScalarFormatter. Partial, plugin-only configs are built with plain FormatConfig struct literals today.
func WithScalarFormatter ¶ added in v0.7.6
func WithScalarFormatter(f FormatNullableFunc) FormatConfigOption
WithScalarFormatter sets the non-NULL scalar handler, installed as the chain tail PluginFromNullable(f). NULL scalars render as the WithNullString value unless an override claims them. Required; a nil f is treated as unset (ErrScalarFormatterRequired).
func WithStructFormat ¶ added in v0.7.6
func WithStructFormat(field FormatStructFieldFunc, paren FormatStructParenFunc) FormatConfigOption
WithStructFormat sets the non-NULL STRUCT handlers, installed as PluginForStruct(field, paren) after the PluginForArray handler. NULL STRUCT values render as the WithNullString value unless an override claims them. Required; a nil field or paren is treated as unset (ErrStructFormatRequired).
type FormatNullableFunc ¶
type FormatNullableFunc func(value NullableValue) (string, error)
FormatNullableFunc formats one non-NULL scalar value decoded to its NullableValue wrapper. Lift it into the plugin chain with PluginFromNullable (or WithScalarFormatter on NewFormatConfig).
func NullableFormatterFor ¶ added in v0.7.6
func NullableFormatterFor[T NullableValue](f func(T) (string, error)) FormatNullableFunc
NullableFormatterFor restricts a typed formatter to the single NullableValue wrapper type T, deferring every other value with ErrFallthrough. It is meant for composition through PluginFromNullable, which lets the deferral reach the rest of the plugin chain.
type FormatStructFieldFunc ¶
type FormatStructFieldFunc func(formatter Formatter, field *sppb.StructType_Field, value *structpb.Value) (string, error)
FormatStructFieldFunc formats one STRUCT field value for PluginForStruct and WithStructFormat. Use formatter.FormatColumn(fieldGCV, false) to recurse into the field value through the whole plugin chain.
type FormatStructParenFunc ¶
type FormatStructParenFunc func(typ *sppb.Type, toplevel bool, fieldStrings []string) (string, error)
func JSONObjectStructFormat
deprecated
added in
v0.4.0
func JSONObjectStructFormat(namer UnnamedFieldNamer) FormatStructParenFunc
JSONObjectStructFormat returns a FormatStructParenFunc that formats struct fields as a JSON object. When namer is nil, unnamed struct fields produce empty-string keys, matching Spanner's own representation.
Deprecated: use NewJSONObjectStructFormatter instead.
func NewJSONObjectStructFormatter ¶ added in v0.1.9
func NewJSONObjectStructFormatter(namer UnnamedFieldNamer) FormatStructParenFunc
NewJSONObjectStructFormatter creates a FormatStructParenFunc that formats struct fields as a JSON object with field names as keys. Unnamed fields are assigned names by the provided namer function. If namer is nil, unnamed fields keep empty-string keys (which produces duplicate keys — valid per RFC 8259 but may cause issues with parsers that deduplicate keys). Returns an error if the namer returns an empty name, or if repeated name collisions prevent choosing a unique name for a field. Output: {"field1":val1,"field2":val2,...}
type Formatter ¶
type Formatter interface {
FormatColumn(value spanner.GenericColumnValue, toplevel bool) (string, error)
GetNullString() string
}
Formatter is the minimal surface FormatComplexFunc plugins use to recurse into nested values.
type LiteralFormatOptions ¶ added in v0.5.1
type LiteralFormatOptions struct {
// Quote selects the outer delimiter policy for string and bytes SQL-style literals.
// The zero value is legacy adaptive quoting (QuoteLegacy + PreferredDoubleQuote);
// invalid enum values are normalized when options are applied. Escaping uses
// GoogleSQL backslash rules; not PostgreSQL (#126).
Quote LiteralQuoteConfig
}
LiteralFormatOptions holds settings that apply only to the literal preset. It is a constructor input (LiteralFormatConfigWithOptions, LiteralValuePlugin): the options are captured into the literal preset's quote-sensitive plugins at construction time, not stored on FormatConfig.
type LiteralOption ¶ added in v0.5.1
type LiteralOption interface {
// contains filtered or unexported methods
}
LiteralOption configures a literal preset returned by LiteralFormatConfigWithOptions.
func WithLiteralQuote ¶ added in v0.5.1
func WithLiteralQuote(cfg LiteralQuoteConfig) LiteralOption
WithLiteralQuote sets quote policy on a literal preset built with LiteralFormatConfigWithOptions.
type LiteralQuoteConfig ¶ added in v0.5.1
type LiteralQuoteConfig struct {
Strategy QuoteStrategy
PreferredQuote PreferredQuote
}
LiteralQuoteConfig configures string and bytes literal quoting for the literal preset. The zero value is legacy adaptive quoting. Invalid enum values are normalized per axis.
type NullableValue ¶
type NullableValue interface {
spanner.NullableValue
fmt.Stringer
}
NullableValue is the scalar null wrapper type accepted by FormatNullableFunc. It includes cloud.google.com/go/spanner null types and NullBytes for BYTES/PROTO.
type PreferredQuote ¶ added in v0.5.1
type PreferredQuote uint8
PreferredQuote is the default delimiter for QuoteLegacy (with opposite-delimiter escape when the payload contains only that quote character), the fixed delimiter for QuoteAlways, and the tie-breaker for QuoteMinEscape.
const ( // PreferredDoubleQuote uses double quotes as the outer delimiter. PreferredDoubleQuote PreferredQuote = iota // PreferredSingleQuote uses single quotes as the outer delimiter. PreferredSingleQuote )
func (PreferredQuote) String ¶ added in v0.5.1
func (p PreferredQuote) String() string
type QuoteStrategy ¶ added in v0.5.1
type QuoteStrategy uint8
QuoteStrategy selects how the outer string-literal delimiter is chosen for the literal preset.
const ( // QuoteLegacy uses PreferredQuote when the payload needs no opposite-delimiter escape. // When the payload contains only the preferred quote character, the opposite delimiter is used. // PreferredDoubleQuote (the zero value) matches historical suitableQuote byte-for-byte. // When both quote characters appear, Legacy uses presence rules (any opposite quote keeps // the preferred delimiter); [QuoteMinEscape] instead compares quote-character counts. QuoteLegacy QuoteStrategy = iota // QuoteAlways uses PreferredQuote for every string and bytes literal. QuoteAlways // QuoteMinEscape picks the delimiter whose quote character occurs less often in the payload. // On a tie, PreferredQuote wins. Only quote-character counts matter; other escapes are delimiter-independent. // With PreferredSingleQuote it often matches [QuoteLegacy], but when both delimiters appear // MinEscape compares counts (e.g. a”b"c stays single-quoted under Legacy+Single but uses // double under MinEscape+Single because one double escape beats two single escapes). QuoteMinEscape )
func (QuoteStrategy) String ¶ added in v0.5.1
func (s QuoteStrategy) String() string
type UnnamedFieldNamer ¶ added in v0.1.9
UnnamedFieldNamer generates a name for an unnamed field or column. The index argument is a monotonically increasing counter (not necessarily the field's positional index) that may skip values due to collision avoidance. It must return distinct non-empty names for distinct indices. Functions that accept UnnamedFieldNamer (such as NewJSONObjectStructFormatter and FormatRowJSONObject) return an error if the namer violates this contract. Pass nil instead of a namer to keep unnamed fields as empty-string keys.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package dbsqlrows is experimental: APIs may change before a stable release.
|
Package dbsqlrows is experimental: APIs may change before a stable release. |
|
Package gcvctor constructs cloud.google.com/go/spanner.GenericColumnValue values from Go values and explicit cloud.google.com/go/spanner/apiv1/spannerpb.Type metadata, using github.com/apstndb/spantype/typector for type shapes.
|
Package gcvctor constructs cloud.google.com/go/spanner.GenericColumnValue values from Go values and explicit cloud.google.com/go/spanner/apiv1/spannerpb.Type metadata, using github.com/apstndb/spantype/typector for type shapes. |
|
Package protofmt provides descriptor-aware PROTO and ENUM formatting plugins for spanvalue format configs.
|
Package protofmt provides descriptor-aware PROTO and ENUM formatting plugins for spanvalue format configs. |
|
Package writer streams Spanner query results to delimited text, JSONL, or SQL INSERT using github.com/apstndb/spanvalue formatters.
|
Package writer streams Spanner query results to delimited text, JSONL, or SQL INSERT using github.com/apstndb/spanvalue formatters. |