Documentation
¶
Overview ¶
Package spanenc converts plain Go values into cloud.google.com/go/spanner.GenericColumnValue (GCV) values and derives column names and Spanner types from Go structs, following the Cloud Spanner Go client library's own encoding semantics — the `spanner` struct tag rules and the Go type coverage of statement parameters and mutations.
The client library keeps its encoding internal (encodeValue, structToMutationParams, and the internal fields cache); this package mirrors those semantics on top of github.com/apstndb/spanvalue/gcvctor constructors so the results compose with the spanvalue formatting and writer stack. The mirrored behavior tracks cloud.google.com/go/spanner v1.91.0.
API overview ¶
- ValueOf: Go value → GCV, mirroring encodeValue (typed NULLs from nil pointers and nil slices, spanner.Null* wrappers, spanner.Encoder, protobuf messages and enums, named variants of base types, Go structs as STRUCT values, spanner.CommitTimestamp).
- TypeFor / TypeFromGoType: Go type → cloud.google.com/go/spanner/apiv1/spannerpb.Type, the type half of ValueOf without a value.
- StructColumns / StructColumnsFromGoType: `spanner`-tagged column names from a struct type, as requested in https://github.com/googleapis/google-cloud-go/issues/13800.
- RowTypeFor / RowTypeFromGoType and ResultSetMetadataFor / ResultSetMetadataFromGoType: row-shaped cloud.google.com/go/spanner/apiv1/spannerpb.StructType / cloud.google.com/go/spanner/apiv1/spannerpb.ResultSetMetadata for writer metadata and client-side virtual result sets.
- StructColumnsAndValues: one struct → column names + GCVs, for GCV-level consumers such as github.com/apstndb/spanvalue/writer.
- RowEncoder (NewRowEncoder): compiled row codec for streaming many rows of one struct type — field listing, column mask, and row type resolved once; per row only RowEncoder.Values runs.
- MutationColumnsAndValues / MutationMap: one struct → cols/vals or map with plain Go values, for the non-Struct mutation constructors (cloud.google.com/go/spanner.Update, cloud.google.com/go/spanner.UpdateMap, ...). An update-mask-style column mask can be written as an include list (WithColumns) or an exclude list (WithoutColumns).
- ParamsMap: one struct → map with plain Go values for cloud.google.com/go/spanner.Statement Params; read-only fields are included (they are ordinary bindable values), and the same column masks apply.
- ValuesFromSlice / ArrayValueFromSlice: homogeneous slices → (element type, wire values) or an ARRAY GCV; heterogeneous-capable (interface) element types are rejected.
Struct field listings ¶
Following the client, there are two different struct field listings:
- Row-shaped helpers (StructColumns, RowTypeFor, StructColumnsAndValues, MutationColumnsAndValues, MutationMap) use the mutation/ToStruct listing: exported fields, embedded struct fields flattened with Go's shadowing rules, `spanner:"-"` skipped, declaration order. Tags split on ";" with the column name first; `spanner:"->"` or a `readonly` part marks the field read-only (since spanner v1.86.0). Read-only fields stay in the read-shaped listings (StructColumns, RowTypeFor, StructColumnsAndValues) and are excluded from the write-shaped ones (MutationColumnsAndValues, MutationMap), mirroring structToMutationParams.
- STRUCT-typed values (ValueOf on a struct, TypeFor) use the encodeStruct listing: declaration order, embedded fields rejected with ErrEmbeddedStructField, and `spanner:""` producing an unnamed field. encodeStruct reads the raw tag, so tag options leak into STRUCT field names verbatim (`spanner:"Name;readonly"` yields a field literally named "Name;readonly"); this mirrors the client.
Divergences from the client library ¶
This package is strict where the client is lenient, so malformed GCVs never enter the spanvalue stack:
- Untyped nil returns ErrUntypedNil; the client sends a NULL without type information.
- A nil pointer to struct passed to MutationColumnsAndValues, MutationMap, or StructColumnsAndValues returns ErrNilStructPointer; the client silently builds an empty mutation.
- cloud.google.com/go/spanner.GenericColumnValue inputs with a nil Type are rejected.
- NUMERIC loss-of-precision handling is an explicit per-call option (WithLossOfPrecisionHandling, reusing the client's cloud.google.com/go/spanner.LossOfPrecisionHandlingOption vocabulary); the package-global cloud.google.com/go/spanner.LossOfPrecisionHandling is never read. The default is cloud.google.com/go/spanner.NumericError (validate), while the client's global defaults to NumericRound (silent rounding).
- Non-finite FLOAT64/FLOAT32 values and JSON payloads use the canonical wire forms produced by github.com/apstndb/spanvalue/gcvctor ("NaN"/"Infinity" strings; compact JSON without HTML escaping); the client sends a raw protobuf NumberValue and HTML-escaped JSON. Both forms are semantically equivalent and accepted by Spanner.
Adoption guide ¶
spanenc pays off where rows carry typed columns, PROTO/ENUM cells, NULL styling, or flow into github.com/apstndb/spanvalue/writer export. If a code path renders rows whose values are already display strings (a SHOW-style key/value listing of pre-formatted text), building GCVs just to format them back into strings adds work for no benefit — keep such paths as plain string rows.
For display cells, pass encoded values to github.com/apstndb/spanvalue.FormatRowColumns instead of writing a per-application GCV-to-string bridge. Prefer RowEncoder.Columns when consumers only need column names; reach for RowEncoder.ResultSetMetadata or RowTypeFor only when they need Spanner types — switching a consumer from names to metadata typically changes how it renders headers.
Formatting of GCVs is owned by github.com/apstndb/spanvalue, so upgrading spanvalue can change rendered output (for example FLOAT64 display); review golden-test diffs from a spanvalue upgrade separately from the spanenc adoption itself. Minimum dependency versions are recorded in the release notes of each version: https://github.com/apstndb/spanenc/releases
The package is experimental: the API may change while encodeValue parity is being proven against client library releases.
Index ¶
- Variables
- func ArrayValueFromSlice[T any](vs []T, opts ...EncodeOption) (spanner.GenericColumnValue, error)
- func MutationColumnsAndValues(v any, opts ...ColumnMaskOption) ([]string, []any, error)
- func MutationMap(v any, opts ...ColumnMaskOption) (map[string]any, error)
- func ParamsMap(v any, opts ...ColumnMaskOption) (map[string]any, error)
- func ResultSetMetadataFor[T any]() (*sppb.ResultSetMetadata, error)
- func ResultSetMetadataFromGoType(t reflect.Type) (*sppb.ResultSetMetadata, error)
- func RowTypeFor[T any]() (*sppb.StructType, error)
- func RowTypeFromGoType(t reflect.Type) (*sppb.StructType, error)
- func StructColumns[T any]() ([]string, error)
- func StructColumnsAndValues(v any, opts ...EncodeOption) ([]string, []spanner.GenericColumnValue, error)
- func StructColumnsFromGoType(t reflect.Type) ([]string, error)
- func TypeFor[T any]() (*sppb.Type, error)
- func TypeFromGoType(t reflect.Type) (*sppb.Type, error)
- func ValueOf(v any, opts ...EncodeOption) (spanner.GenericColumnValue, error)
- func ValuesFromSlice[T any](vs []T, opts ...EncodeOption) (*sppb.Type, []*structpb.Value, error)
- type ColumnMaskOption
- type EncodeOption
- type RowEncoder
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrUnsupportedType is returned when a Go value or type has no Cloud Spanner // client library encoding. It corresponds to the client's // "client doesn't support Go type" errors from encodeValue. ErrUnsupportedType = errors.New("spanenc: unsupported Go type") // ErrUntypedNil is returned by [ValueOf] for an untyped nil input. // This is a deliberate divergence from the client library, which encodes // untyped nil as a NULL value WITHOUT type information; spanvalue/gcvctor // consumers require a well-formed Type in every GenericColumnValue. // Use a typed nil (for example (*int64)(nil)) or // [github.com/apstndb/spanvalue/gcvctor.NullOf] instead. ErrUntypedNil = errors.New("spanenc: untyped nil value") // ErrNotStruct is returned by struct-shaped helpers ([StructColumns], // [RowTypeFor], [StructColumnsAndValues], and variants) when the input is // not a Go struct or pointer to struct. It mirrors the client's // errNotStruct from structToMutationParams. ErrNotStruct = errors.New("spanenc: not a Go struct type") // ErrNilStructPointer is returned by [StructColumnsAndValues] for a nil // pointer to struct. This is a deliberate divergence from the client's // structToMutationParams, which silently returns empty columns and values; // silently producing an empty row is a footgun for export use cases. ErrNilStructPointer = errors.New("spanenc: nil struct pointer") // ErrEmbeddedStructField is returned when a Go struct with embedded // (anonymous) fields is encoded as a Spanner STRUCT value. It mirrors the // client's errUnsupportedEmbeddedStructFields in encodeStruct. Note that // the row-shaped helpers ([StructColumns], [RowTypeFor], // [StructColumnsAndValues]) flatten embedded fields instead, mirroring the // client's mutation/ToStruct field listing. ErrEmbeddedStructField = errors.New("spanenc: embedded struct fields are not supported in STRUCT values") // ErrTypeNotInferable is returned by [TypeFor], [TypeFromGoType], and the // slice helpers when the Spanner type cannot be derived from the Go type // alone: types implementing [cloud.google.com/go/spanner.Encoder], // [cloud.google.com/go/spanner.GenericColumnValue], // [cloud.google.com/go/spanner.NullProtoMessage], // [cloud.google.com/go/spanner.NullProtoEnum], and interface types. The // client library never needs a type-only path because it always encodes // concrete values. ErrTypeNotInferable = errors.New("spanenc: Spanner type is not inferable from the Go type alone") // ErrInvalidSource is returned when a value cannot represent a typed NULL // and is invalid, mirroring the client's errNotValidSrc: NullProtoMessage // and NullProtoEnum with Valid == false. ErrInvalidSource = errors.New("spanenc: invalid (NULL) source value") // ErrNumericOutOfRange is returned when a NUMERIC input exceeds the // precision or scale supported by Cloud Spanner, mirroring the client's // validateNumeric under NumericError loss-of-precision handling — this // package's per-call default; pass // WithLossOfPrecisionHandling(spanner.NumericRound) to round instead. ErrNumericOutOfRange = errors.New("spanenc: NUMERIC value exceeds supported precision or scale") // ErrInvalidColumnMask is returned by [MutationColumnsAndValues] and // [MutationMap] when a [WithColumns] / [WithoutColumns] mask names an // unknown column, includes a read-only column, or combines include and // exclude masks. ErrInvalidColumnMask = errors.New("spanenc: invalid column mask") )
Functions ¶
func ArrayValueFromSlice ¶
func ArrayValueFromSlice[T any](vs []T, opts ...EncodeOption) (spanner.GenericColumnValue, error)
ArrayValueFromSlice converts a homogeneous slice into an ARRAY spanner.GenericColumnValue with the element type inferred statically from T (see ValuesFromSlice for the homogeneity rules). Following the client library's slice handling, a nil slice becomes a typed NULL ARRAY and an empty slice an empty ARRAY.
func MutationColumnsAndValues ¶
func MutationColumnsAndValues(v any, opts ...ColumnMaskOption) ([]string, []any, error)
MutationColumnsAndValues extracts column names and plain Go field values from a struct (or non-nil pointer to struct), mirroring the client's structToMutationParams: read-only fields (`spanner:"->"` or `spanner:"Name;readonly"`, since spanner v1.86.0) are excluded from the results. The results fit the cols/vals form of mutation constructors such as spanner.Insert, spanner.Update, and spanner.Replace, so callers can mask columns by name before building the mutation — something the *Struct constructors cannot do.
Values are returned as-is (no GCV conversion); the client library encodes them when the mutation is applied, so this helper accepts whatever InsertStruct accepts. A nil pointer returns ErrNilStructPointer where the client would silently produce an empty mutation.
An update-mask-style column mask can be written as either an include list (WithColumns) or an exclude list (WithoutColumns); masked output keeps the struct declaration order, and mask mistakes (unknown columns, read-only columns in an include list, or combining both kinds) return ErrInvalidColumnMask.
Example ¶
ExampleMutationColumnsAndValues masks columns by name before building a plain cols/vals mutation, which the *Struct mutation constructors cannot express.
package main
import (
"fmt"
"cloud.google.com/go/spanner"
"github.com/apstndb/spanenc"
)
func main() {
type Singer struct {
SingerID int64 `spanner:"SingerId"`
FirstName string
LastName string
}
// Update only SingerId and LastName; the mask could equally be written
// as an exclude list with WithoutColumns("FirstName").
cols, vals, err := spanenc.MutationColumnsAndValues(
Singer{SingerID: 1, FirstName: "Marc", LastName: "Richards"},
spanenc.WithColumns("SingerId", "LastName"),
)
if err != nil {
fmt.Println(err)
return
}
_ = spanner.Update("Singers", cols, vals)
fmt.Println(cols)
fmt.Println(vals)
}
Output: [SingerId LastName] [1 Richards]
func MutationMap ¶
func MutationMap(v any, opts ...ColumnMaskOption) (map[string]any, error)
MutationMap extracts a column-name-to-Go-value map from a struct (or non-nil pointer to struct) for the *Map mutation constructors (spanner.InsertMap, spanner.UpdateMap, spanner.ReplaceMap, spanner.InsertOrUpdateMap). Read-only fields are excluded and the WithColumns / WithoutColumns masks apply, like MutationColumnsAndValues.
Duplicate column names (possible with explicit duplicate `spanner` tags) return an error rather than silently dropping a value.
func ParamsMap ¶ added in v0.3.0
func ParamsMap(v any, opts ...ColumnMaskOption) (map[string]any, error)
ParamsMap extracts a column-name-to-Go-value map from a struct (or non-nil pointer to struct) for binding as cloud.google.com/go/spanner.Statement Params (parameter names are the `spanner`-tagged column names). Values are returned as-is (no GCV conversion); the client library encodes them when the statement runs.
Unlike the write-shaped MutationMap, read-only fields are included — they are ordinary bindable values in a statement. The WithColumns / WithoutColumns masks apply, and an include mask may name read-only columns.
Duplicate column names (possible with explicit duplicate `spanner` tags) return an error rather than silently dropping a value.
func ResultSetMetadataFor ¶ added in v0.3.0
func ResultSetMetadataFor[T any]() (*sppb.ResultSetMetadata, error)
ResultSetMetadataFor wraps RowTypeFor into a sppb.ResultSetMetadata, the shape expected by result-set consumers such as github.com/apstndb/spanvalue/writer's WithMetadata. It suits client-side virtual result sets (status rows, SHOW-style outputs) whose rows are Go structs rather than server responses.
func ResultSetMetadataFromGoType ¶ added in v0.3.0
func ResultSetMetadataFromGoType(t reflect.Type) (*sppb.ResultSetMetadata, error)
ResultSetMetadataFromGoType is ResultSetMetadataFor for a reflect.Type.
func RowTypeFor ¶
func RowTypeFor[T any]() (*sppb.StructType, error)
RowTypeFor returns the sppb.StructType describing a row of T, pairing StructColumns names (read-only fields included) with statically inferred field types (see TypeFromGoType). It suits writer metadata such as github.com/apstndb/spanvalue/writer's WithRowType, or the row_type of a ResultSetMetadata.
Note that this row-shaped view flattens embedded struct fields, while a STRUCT-typed value of T (TypeFor, ValueOf) rejects them; the client library has the same split between mutations/ToStruct and STRUCT parameters.
func RowTypeFromGoType ¶
func RowTypeFromGoType(t reflect.Type) (*sppb.StructType, error)
RowTypeFromGoType is RowTypeFor for a reflect.Type.
func StructColumns ¶
StructColumns returns the column names derived from T's fields and `spanner` tags, in declaration order, with the same field listing the client library uses for cloud.google.com/go/spanner.Row.ToStruct: exported fields only, embedded struct fields flattened, `spanner:"-"` skipped. Read-only fields (`spanner:"->"` or `spanner:"Name;readonly"`) are included, because they are readable; the write-shaped MutationColumnsAndValues and MutationMap exclude them like the client's mutation constructors do.
It is the spanvalue-side answer to the StructColumns helper requested in https://github.com/googleapis/google-cloud-go/issues/13800, typically used to build the columns argument of Read calls from the same struct passed to ToStruct. T may be a struct or pointer-to-struct type.
Example ¶
ExampleStructColumns derives Read columns from the same struct used with Row.ToStruct, the use case of https://github.com/googleapis/google-cloud-go/issues/13800.
package main
import (
"fmt"
"github.com/apstndb/spanenc"
)
func main() {
type Singer struct {
SingerID int64 `spanner:"SingerId"`
FirstName string
LastName string
Internal string `spanner:"-"`
}
columns, err := spanenc.StructColumns[Singer]()
if err != nil {
fmt.Println(err)
return
}
fmt.Println(columns)
// client.Single().Read(ctx, "Singers", spanner.AllKeys(), columns) ...
Output:
Example (TagOptions) ¶
ExampleStructColumns_tagOptions contrasts the two struct field listings: row-shaped helpers parse `;`-separated tag options, while STRUCT-typed values mirror the client's raw-tag encodeStruct, so options leak into STRUCT field names verbatim (deliberate client parity). Use row-shaped APIs for table rows; reserve struct values for actual STRUCT-typed parameters.
package main
import (
"fmt"
"github.com/apstndb/spanenc"
)
func main() {
type Row struct {
Gen string `spanner:"Name;readonly"`
}
columns, err := spanenc.StructColumns[Row]() // row-shaped: options parsed
if err != nil {
fmt.Println(err)
return
}
fmt.Println(columns)
typ, err := spanenc.TypeFor[Row]() // STRUCT-shaped: raw tag, like the client
if err != nil {
fmt.Println(err)
return
}
fmt.Println(typ.GetStructType().GetFields()[0].GetName())
}
Output: [Name] Name;readonly
func StructColumnsAndValues ¶
func StructColumnsAndValues(v any, opts ...EncodeOption) ([]string, []spanner.GenericColumnValue, error)
StructColumnsAndValues converts a struct (or non-nil pointer to struct) into parallel column-name and spanner.GenericColumnValue slices using the ToStruct-shaped field listing (see StructColumns; read-only fields included) and ValueOf for each field. The result feeds GCV-level consumers such as github.com/apstndb/spanvalue/writer's WriteValues or github.com/apstndb/spanvalue.FormatRowColumns for display cells, and stays aligned with RowTypeFor.
For the client library's own mutation constructors, use MutationColumnsAndValues or MutationMap instead, which keep plain Go values, exclude read-only fields, and let the client encode the values.
Options configure the per-field encoding; see WithLossOfPrecisionHandling.
Example ¶
ExampleStructColumnsAndValues streams Go structs to CSV through spanvalue/writer.
package main
import (
"fmt"
"os"
"github.com/apstndb/spanvalue/writer"
"github.com/apstndb/spanenc"
)
func main() {
type Singer struct {
SingerID int64 `spanner:"SingerId"`
FirstName string
}
names, values, err := spanenc.StructColumnsAndValues(Singer{SingerID: 1, FirstName: "Marc"})
if err != nil {
fmt.Println(err)
return
}
w, err := writer.NewCSVWriter(os.Stdout, writer.WithColumnNames(names))
if err != nil {
fmt.Println(err)
return
}
if err := w.WriteValues(names, values); err != nil {
fmt.Println(err)
return
}
if err := w.Flush(); err != nil {
fmt.Println(err)
return
}
}
Output: SingerId,FirstName 1,Marc
func StructColumnsFromGoType ¶
StructColumnsFromGoType is StructColumns for a reflect.Type.
func TypeFor ¶
TypeFor returns the sppb.Type that ValueOf would produce for a non-NULL value of Go type T, following the Cloud Spanner client library encoding semantics. See TypeFromGoType.
func TypeFromGoType ¶
TypeFromGoType returns the sppb.Type that ValueOf produces for values of the given Go type, following the Cloud Spanner client library encoding semantics (encodeValue in cloud.google.com/go/spanner).
It returns ErrTypeNotInferable for Go types whose Spanner type depends on the value rather than the type: interface types, cloud.google.com/go/spanner.Encoder implementations, cloud.google.com/go/spanner.GenericColumnValue, cloud.google.com/go/spanner.NullProtoMessage, and cloud.google.com/go/spanner.NullProtoEnum. It returns ErrUnsupportedType for Go types the client library cannot encode.
func ValueOf ¶
func ValueOf(v any, opts ...EncodeOption) (spanner.GenericColumnValue, error)
ValueOf converts a Go value into a spanner.GenericColumnValue, following the Cloud Spanner client library encoding semantics (encodeValue in cloud.google.com/go/spanner): the Go types accepted for statement parameters and mutation values, including the typed NULL rules (nil pointers and nil slices become typed NULLs), spanner.Null* wrappers, spanner.Encoder implementations, protobuf messages and enums, named variants of base types, Go structs as STRUCT values, and spanner.CommitTimestamp.
Deliberate divergences from the client library are listed in the package documentation; most notably an untyped nil returns ErrUntypedNil instead of a NULL without type information.
Options configure encoding per call; see WithLossOfPrecisionHandling for the per-call counterpart of the client's package-global loss-of-precision handling.
Example ¶
ExampleValueOf encodes Go values with the client library's parameter semantics and formats them with spanvalue.
package main
import (
"fmt"
"github.com/apstndb/spanvalue"
"github.com/apstndb/spanenc"
)
func main() {
for _, v := range []any{
"foo",
(*int64)(nil),
[]string{"a", "b"},
} {
gcv, err := spanenc.ValueOf(v)
if err != nil {
fmt.Println(err)
return
}
s, err := spanvalue.FormatColumnLiteral(gcv)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(s)
}
}
Output: "foo" NULL ["a", "b"]
func ValuesFromSlice ¶
ValuesFromSlice converts a homogeneous slice into the shared element sppb.Type and one wire structpb.Value per element. Homogeneity is enforced through the static element type: T must have a type-inferable Spanner type (see TypeFromGoType), so interface element types — which could hold heterogeneous values — are rejected with ErrTypeNotInferable before any element is examined. Each encoded element is additionally verified against the inferred type.
A nil slice returns the element type with a nil values slice. To express a typed NULL ARRAY versus an empty ARRAY at the GCV level, use ArrayValueFromSlice.
Types ¶
type ColumnMaskOption ¶ added in v0.3.0
type ColumnMaskOption func(*columnMaskConfig)
ColumnMaskOption configures the column mask of MutationColumnsAndValues, MutationMap, and ParamsMap.
func WithColumns ¶ added in v0.3.0
func WithColumns(columns ...string) ColumnMaskOption
WithColumns restricts the output columns to the listed ones (an include mask). Output keeps the struct declaration order regardless of the argument order. Naming an unknown column returns ErrInvalidColumnMask — as does naming a read-only column in the write-shaped helpers (MutationColumnsAndValues, MutationMap) or combining with WithoutColumns. Multiple WithColumns options accumulate.
func WithoutColumns ¶ added in v0.3.0
func WithoutColumns(columns ...string) ColumnMaskOption
WithoutColumns drops the listed columns from the output (an exclude mask). Naming an unknown column returns ErrInvalidColumnMask (naming a read-only column is allowed: in the write-shaped helpers it is already excluded from writes); combining with WithColumns does too. Multiple WithoutColumns options accumulate.
type EncodeOption ¶ added in v0.3.0
type EncodeOption func(*encodeConfig)
EncodeOption configures value encoding in ValueOf, StructColumnsAndValues, ValuesFromSlice, and ArrayValueFromSlice.
func WithLossOfPrecisionHandling ¶ added in v0.3.0
func WithLossOfPrecisionHandling(handling spanner.LossOfPrecisionHandlingOption) EncodeOption
WithLossOfPrecisionHandling selects the NUMERIC loss-of-precision behavior for this call, using the client's spanner.LossOfPrecisionHandlingOption vocabulary: spanner.NumericError validates precision and scale, returning ErrNumericOutOfRange for values Spanner cannot represent exactly; spanner.NumericRound silently rounds out-of-scale values to Spanner's 9 fractional digits via the canonical wire formatting. Like the client, rounding affects only the fractional part; a whole component exceeding the NUMERIC precision is passed through and rejected by Spanner.
Unlike the client, the behavior is configured per call instead of through the package-global spanner.LossOfPrecisionHandling, which this package never reads; without this option the default is spanner.NumericError (the client's global defaults to NumericRound — pass it explicitly for that behavior).
type RowEncoder ¶ added in v0.3.0
type RowEncoder[T any] struct { // contains filtered or unexported fields }
RowEncoder is a compiled row codec for a struct type T: the field listing, column mask, and row type are resolved once at construction, so encoding many rows avoids re-deriving them per row (and re-validating the mask) the way repeated StructColumnsAndValues calls would.
It uses the read-shaped (ToStruct) field listing like StructColumnsAndValues: read-only fields are included, and an include mask may name them. Construct with NewRowEncoder.
func NewRowEncoder ¶ added in v0.3.0
func NewRowEncoder[T any](opts ...ColumnMaskOption) (*RowEncoder[T], error)
NewRowEncoder compiles a RowEncoder for T, which must be a struct or pointer-to-struct type (ErrNotStruct otherwise). The optional column mask is validated here once (ErrInvalidColumnMask like ParamsMap) and applied to every output, keeping struct declaration order.
func (*RowEncoder[T]) Columns ¶ added in v0.3.0
func (e *RowEncoder[T]) Columns() []string
Columns returns the masked column names in struct declaration order. The returned slice is a copy.
Prefer Columns when consumers only need names (string-only headers); use RowEncoder.ResultSetMetadata only when they need Spanner types — switching a consumer from names to metadata typically changes how it renders headers.
func (*RowEncoder[T]) ResultSetMetadata ¶ added in v0.3.0
func (e *RowEncoder[T]) ResultSetMetadata() (*sppb.ResultSetMetadata, error)
ResultSetMetadata wraps RowEncoder.RowType into a sppb.ResultSetMetadata for result-set consumers such as github.com/apstndb/spanvalue/writer's WithMetadata.
func (*RowEncoder[T]) RowType ¶ added in v0.3.0
func (e *RowEncoder[T]) RowType() (*sppb.StructType, error)
RowType returns the masked row type with statically inferred field types (see TypeFromGoType); fields whose Spanner type is not inferable from the Go type make RowType fail while RowEncoder.Values may still succeed. The returned message is a fresh clone.
func (*RowEncoder[T]) Values ¶ added in v0.3.0
func (e *RowEncoder[T]) Values(v T, opts ...EncodeOption) ([]spanner.GenericColumnValue, error)
Values encodes one row: the masked fields of v as spanner.GenericColumnValue slices aligned with RowEncoder.Columns. A nil pointer v returns ErrNilStructPointer. Options configure the per-field encoding; see WithLossOfPrecisionHandling.
For display cells, pass the result to github.com/apstndb/spanvalue.FormatRowColumns; for file export, pass it to a github.com/apstndb/spanvalue/writer writer.