v0.8.0
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-composedPluginFromNullable(NullableFormatterFor(f))for the dominant single-scalar-type override; annotation-aware via the Decode dispatch (PGNumericmatches only PG_NUMERIC).ExampleNewFormatConfigand 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:
PostgreSQLLiteralFormatConfigmoves toNewFormatConfig(WithPlugin×2 preserving plugin order,WithArrayFormat,WithStructFormatwith the field callback retyped toFormatter,WithScalarFormatter); its nested integration module needs no changes. - No consumer used the other removed identifiers; the alias→defined-type change was transparent everywhere.