Skip to content

v0.8.0

Choose a tag to compare

@apstndb apstndb released this 12 Jun 09:14
591721f

Breaking release. FormatConfig collapses to two fields — NullString and the ordered FormatComplexPlugins chain — completing the #250#253 redesign: every formatting concern is now a plugin, assembled by hand or through the validating NewFormatConfig builder. Preset outputs are byte-identical to v0.7.6 (pinned by the golden batteries). Closes #252, #253, #217, #185, #205, #219, #221, #250. Minimum Go remains 1.24.


Removed → replacement

Removed (deprecated in v0.7.6) Replacement
FormatConfig.FormatNullable append PluginFromNullable(f) last in the chain / NewFormatConfig(WithScalarFormatter(f), …)
FormatConfig.FormatArray PluginForArray / WithArrayFormat
FormatConfig.FormatStruct (+ the FormatStruct type, TypedStructFormat()) PluginForStruct / WithStructFormat; FormatTypedStruct is the exported paren function
FormatConfig.Literal literal quote options are constructor-captured plugin state (LiteralFormatConfigWithOptions / WithLiteralQuote signatures unchanged)
FormatLiteralValue (plugin value) LiteralValuePlugin(opts LiteralFormatOptions) constructor
FormatConfigWithoutScalarPlugins prepend a total PluginFromNullable(f) via WithComplexPlugin, or build with NewFormatConfig
ErrFormatNullableRequired, ErrNilFormatArray, ErrNilFormatStructField, ErrNilFormatStructParen, nil-callback panics, built-in ErrUnknownType for unknown codes one sentinel ErrUnhandledValue wrapping the type (coverage is a runtime property; Validate checks NullString + a non-empty, nil-free chain)
writer DelimitedWriter.Header / .UnnamedFieldNamer, JSONLWriter.UnnamedFieldNamer fields constructor-only WithHeader / WithUnnamedFieldNamer (#221)

Signature changes: FormatStructFieldFunc now takes Formatter instead of *FormatConfig; FormatComplexFunc and FormatNullableFunc are defined types instead of aliases (plain functions remain assignable). Formatter.GetNullString keeps its name (rename considered, declined — plugin-facing churn without payoff).

Internals deleted (#217 closed)

The function-pointer identity machinery (scalarFastPathActive, nullableFuncsEqual, the slow-path literal-quote interception) is gone: preset scalar plugins are unconditional chain members, and custom behavior enters the chain at an explicit position instead of replacing a field the framework then has to sniff.

JSON preset contract (#205 closed)

FormatJSONSimpleValue now gates on the supported scalar set, validates wire payloads, and falls through for unknown codes; stripped/escape-hatch configs error (ErrUnhandledValue) instead of silently emitting invalid JSON. JSON wire-as-is is documented as the contract and pinned with a denormalized-wire test; NULL renders via NullString: "null" as before.

New since v0.7.6

  • PluginForNullable[T] — the pre-composed PluginFromNullable(NullableFormatterFor(f)) for the dominant single-scalar-type override; annotation-aware via the Decode dispatch (PGNumeric matches only PG_NUMERIC).
  • ExampleNewFormatConfig and rewritten customization docs (doc.go).

Downstream impact (verified against all four consumers via local replaces before release)

  • spanner-mycli, execspansql: no changes required; builds and test suites pass unmodified.
  • spannersh: one line — the tuple-STRUCT recipe becomes SpannerCLICompatibleFormatConfig().WithComplexPlugin(PluginForStruct(FormatSimpleStructField, FormatTupleStruct)).
  • spanpg: PostgreSQLLiteralFormatConfig moves to NewFormatConfig (WithPlugin×2 preserving plugin order, WithArrayFormat, WithStructFormat with the field callback retyped to Formatter, WithScalarFormatter); its nested integration module needs no changes.
  • No consumer used the other removed identifiers; the alias→defined-type change was transparent everywhere.

Full changelog

v0.7.6...v0.8.0