From 6948bad36d02e16c9c1781062aabe050b40fb38e Mon Sep 17 00:00:00 2001 From: apstndb <803393+apstndb@users.noreply.github.com> Date: Wed, 3 Jun 2026 03:57:11 +0900 Subject: [PATCH] Bump spanvalue to v0.5.0 for experimental CSV export. Handle NewCSVWriter construction errors and regolden NUMERIC output to wire-as-is (99.5). Co-authored-by: Cursor --- csv_test.go | 16 +++++++++++++--- go.mod | 2 +- go.sum | 4 ++-- main.go | 12 +++++++++--- testdata/experimental_csv/numeric.golden | 2 +- 5 files changed, 26 insertions(+), 10 deletions(-) diff --git a/csv_test.go b/csv_test.go index 190308f..f6b337c 100644 --- a/csv_test.go +++ b/csv_test.go @@ -88,7 +88,11 @@ func TestExperimentalCsvBehavior(t *testing.T) { if err := writeCsvFromResultSet(&bytes.Buffer{}, nil); err == nil { t.Fatal("writeCsvFromResultSet(nil) expected error") } - if err := prepareCsvRowType(svwriter.NewCSVWriter(&bytes.Buffer{}), nil); err == nil { + w, err := svwriter.NewCSVWriter(&bytes.Buffer{}) + if err != nil { + t.Fatalf("NewCSVWriter() error = %v", err) + } + if err := prepareCsvRowType(w, nil); err == nil { t.Fatal("prepareCsvRowType(nil metadata) expected error") } }) @@ -139,7 +143,10 @@ func TestExperimentalCsvDumpFixtures(t *testing.T) { // experimentalCsvViaSpanvalueWriter is the reference path for ResultSet-shaped fixtures. func experimentalCsvViaSpanvalueWriter(out *bytes.Buffer, rs *sppb.ResultSet) error { - csvWriter := svwriter.NewCSVWriter(out, svwriter.WithMetadata(rs.GetMetadata())) + csvWriter, err := svwriter.NewCSVWriter(out, svwriter.WithMetadata(rs.GetMetadata())) + if err != nil { + return err + } for _, row := range rs.GetRows() { if err := csvWriter.WriteStructValues(row.GetValues()); err != nil { return err @@ -150,7 +157,10 @@ func experimentalCsvViaSpanvalueWriter(out *bytes.Buffer, rs *sppb.ResultSet) er // writeCsvFromPreparedRows exercises the WriteRow path after PrepareRowType, matching production. func writeCsvFromPreparedRows(w io.Writer, metadata *sppb.ResultSetMetadata, rows []*spanner.Row) error { - csvWriter := svwriter.NewCSVWriter(w) + csvWriter, err := svwriter.NewCSVWriter(w) + if err != nil { + return err + } if err := prepareCsvRowType(csvWriter, metadata); err != nil { return err } diff --git a/go.mod b/go.mod index 68d1fd7..c7ed853 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/apstndb/memebridge v0.6.0 github.com/apstndb/spanemuboost v0.0.0-20241212215948-d4eb945c8f10 github.com/apstndb/spannerotel v0.0.0-20220113012943-45b1c9cc5afb - github.com/apstndb/spanvalue v0.4.1 + github.com/apstndb/spanvalue v0.5.0 github.com/cloudspannerecosystem/memefish v0.6.2 github.com/google/go-cmp v0.7.0 github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 diff --git a/go.sum b/go.sum index de74a78..f16e0ae 100644 --- a/go.sum +++ b/go.sum @@ -674,8 +674,8 @@ github.com/apstndb/spannerotel v0.0.0-20220113012943-45b1c9cc5afb h1:wop6M8ZQWhV github.com/apstndb/spannerotel v0.0.0-20220113012943-45b1c9cc5afb/go.mod h1:H9relGptAtWqSNrJy+V1jiYPeBIk8KYh6lACV3VZrqU= github.com/apstndb/spantype v0.3.11 h1:wKue4WLYGT82MH3B3TRSFn8tWIbk1Geczs+5BAEtnK4= github.com/apstndb/spantype v0.3.11/go.mod h1:9eHowE7LcJ155ukCYUyuNzVAw9Ne0GXPXpHmu+iaMyk= -github.com/apstndb/spanvalue v0.4.1 h1:5G4TzCb5KPovcx8dsmRu81dKOyKydMaJlWgJdomTutI= -github.com/apstndb/spanvalue v0.4.1/go.mod h1:xKnvCW0eC+EtZfICvyesMpr/PJTY8tXjcWR+i0x0dZw= +github.com/apstndb/spanvalue v0.5.0 h1:91RfaKX6WRDNDQrNmo9lO6O0sUS0x+4YxRBylDfS0xM= +github.com/apstndb/spanvalue v0.5.0/go.mod h1:xKnvCW0eC+EtZfICvyesMpr/PJTY8tXjcWR+i0x0dZw= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= diff --git a/main.go b/main.go index a142329..545781e 100644 --- a/main.go +++ b/main.go @@ -379,12 +379,15 @@ func runAndWriteCsv(ctx context.Context, client *spanner.Client, stmt spanner.St } // writeCsvFromRowIter streams query rows to CSV without materializing a ResultSet. -// It follows spanvalue v0.4.1 RowIterator guidance: PrepareRowType after the first Next +// It follows spanvalue RowIterator guidance: PrepareRowType after the first Next // (including iterator.Done), WriteRow in the loop, return Flush (not defer Flush). func writeCsvFromRowIter(writer io.Writer, rowIter *spanner.RowIterator, redactRows bool) error { defer rowIter.Stop() - csvWriter := svwriter.NewCSVWriter(writer) + csvWriter, err := svwriter.NewCSVWriter(writer) + if err != nil { + return err + } if redactRows { if err := skipRowIter(rowIter); err != nil { @@ -432,7 +435,10 @@ func writeCsvFromResultSet(writer io.Writer, rs *sppb.ResultSet) error { return errors.New("result set metadata is missing or invalid") } - csvWriter := svwriter.NewCSVWriter(writer, svwriter.WithMetadata(rs.GetMetadata())) + csvWriter, err := svwriter.NewCSVWriter(writer, svwriter.WithMetadata(rs.GetMetadata())) + if err != nil { + return err + } for _, row := range rs.GetRows() { if row == nil { return fmt.Errorf("nil row in result set") diff --git a/testdata/experimental_csv/numeric.golden b/testdata/experimental_csv/numeric.golden index 6ad683c..7d8a15d 100644 --- a/testdata/experimental_csv/numeric.golden +++ b/testdata/experimental_csv/numeric.golden @@ -1,2 +1,2 @@ v -99.500000000 +99.5