From 4e2c4f24c1a63355749bc515218464218b8c8e23 Mon Sep 17 00:00:00 2001 From: Chris Masone Date: Wed, 10 Feb 2016 11:27:31 -0800 Subject: [PATCH] Change csv.Write() signature to broaden uses The old csv.Write() signature required passing in a Dataset whose Head() contained a List of structs. Not all data that we want to export as CSV will be the Head of a Dataset, so this patch makes the function a bit more flexible. --- clients/csv/common.go | 2 +- clients/csv/exporter/.gitignore | 1 + clients/csv/exporter/exporter.go | 3 ++- clients/csv/write.go | 46 +++++++++++++++----------------- 4 files changed, 26 insertions(+), 26 deletions(-) create mode 100644 clients/csv/exporter/.gitignore diff --git a/clients/csv/common.go b/clients/csv/common.go index 84e36b5bea..861494061c 100644 --- a/clients/csv/common.go +++ b/clients/csv/common.go @@ -5,7 +5,7 @@ import ( "unicode/utf8" ) -// Returns the rune contained in delimiter or an error. +// StringToRune returns the rune contained in delimiter or an error. func StringToRune(delimiter string) (rune, error) { dlimLen := len(delimiter) if dlimLen == 0 { diff --git a/clients/csv/exporter/.gitignore b/clients/csv/exporter/.gitignore new file mode 100644 index 0000000000..9cfaec5af1 --- /dev/null +++ b/clients/csv/exporter/.gitignore @@ -0,0 +1 @@ +exporter diff --git a/clients/csv/exporter/exporter.go b/clients/csv/exporter/exporter.go index fd12323838..666968ef4c 100644 --- a/clients/csv/exporter/exporter.go +++ b/clients/csv/exporter/exporter.go @@ -44,7 +44,8 @@ func main() { } err = d.Try(func() { - csv.Write(ds, comma, *p, os.Stdout) + nomsList, structDesc := csv.ValueToListAndElemDesc(ds.Head().Value(), ds.Store()) + csv.Write(nomsList, structDesc, comma, *p, os.Stdout) }) if err != nil { fmt.Println("Failed to export dataset as CSV:") diff --git a/clients/csv/write.go b/clients/csv/write.go index cc1c921b18..95b380488c 100644 --- a/clients/csv/write.go +++ b/clients/csv/write.go @@ -5,22 +5,13 @@ import ( "fmt" "io" + "github.com/attic-labs/noms/chunks" "github.com/attic-labs/noms/d" - "github.com/attic-labs/noms/dataset" "github.com/attic-labs/noms/types" ) -func getFieldNamesFromStruct(structDesc types.StructDesc) (fieldNames []string) { - for _, f := range structDesc.Fields { - d.Exp.Equal(true, types.IsPrimitiveKind(f.T.Desc.Kind()), - "Non-primitive CSV export not supported:", f.T.Desc.Describe()) - fieldNames = append(fieldNames, f.Name) - } - return -} - -func datasetToHeaderAndList(ds *dataset.Dataset) (fieldNames []string, nomsList types.List) { - v := ds.Head().Value() +// ValueToListAndElemDesc ensures that v is a types.List of structs, pulls the types.StructDesc that describes the elements of v out of cs, and returns the List and related StructDesc. +func ValueToListAndElemDesc(v types.Value, cs chunks.ChunkSource) (types.List, types.StructDesc) { d.Exp.Equal(types.ListKind, v.Type().Desc.Kind(), "Dataset must be List<>, found: %s", v.Type().Desc.Describe()) @@ -28,29 +19,27 @@ func datasetToHeaderAndList(ds *dataset.Dataset) (fieldNames []string, nomsList d.Exp.Equal(types.UnresolvedKind, u.Desc.Kind(), "List<> must be UnresolvedKind, found: %s", u.Desc.Describe()) - pkg := types.ReadPackage(u.PackageRef(), ds.Store()) + pkg := types.ReadPackage(u.PackageRef(), cs) d.Exp.Equal(types.PackageKind, pkg.Type().Desc.Kind(), "Failed to read package: %s", pkg.Type().Desc.Describe()) - structDesc := pkg.Types()[u.Ordinal()].Desc - d.Exp.Equal(types.StructKind, structDesc.Kind(), - "Did not find Struct: %s", structDesc.Describe()) - - fieldNames = getFieldNamesFromStruct(structDesc.(types.StructDesc)) - nomsList = v.(types.List) - return + desc := pkg.Types()[u.Ordinal()].Desc + d.Exp.Equal(types.StructKind, desc.Kind(), "Did not find Struct: %s", desc.Describe()) + return v.(types.List), desc.(types.StructDesc) } -func Write(ds *dataset.Dataset, comma rune, concurrency int, output io.Writer) { - fieldNames, nomsList := datasetToHeaderAndList(ds) +// Write takes a types.List l of structs (described by sd) and writes it to output as comma-delineated values. +func Write(l types.List, sd types.StructDesc, comma rune, concurrency int, output io.Writer) { + d.Exp.Equal(types.StructKind, sd.Kind(), "Did not find Struct: %s", sd.Describe()) + fieldNames := getFieldNamesFromStruct(sd) csvWriter := csv.NewWriter(output) csvWriter.Comma = comma - records := make([][]string, nomsList.Len()+1) + records := make([][]string, l.Len()+1) records[0] = fieldNames // Write header - nomsList.IterAllP(concurrency, func(v types.Value, index uint64) { + l.IterAllP(concurrency, func(v types.Value, index uint64) { for _, f := range fieldNames { records[index+1] = append( records[index+1], @@ -63,3 +52,12 @@ func Write(ds *dataset.Dataset, comma rune, concurrency int, output io.Writer) { err := csvWriter.Error() d.Exp.Equal(nil, err, "error flushing csv:", err) } + +func getFieldNamesFromStruct(structDesc types.StructDesc) (fieldNames []string) { + for _, f := range structDesc.Fields { + d.Exp.Equal(true, types.IsPrimitiveKind(f.T.Desc.Kind()), + "Non-primitive CSV export not supported:", f.T.Desc.Describe()) + fieldNames = append(fieldNames, f.Name) + } + return +}