diff --git a/seq/csvseq/iterate.go b/seq/csvseq/iterate.go new file mode 100644 index 0000000..4f040fe --- /dev/null +++ b/seq/csvseq/iterate.go @@ -0,0 +1,24 @@ +package csvseq + +import ( + "encoding/csv" + "io" + "iter" +) + +// Iterate creates an iterator over the records of the CSV reader. Errors occuring might be csv.ErrFieldCount or +// parse errors. As Iterate is supposed to consume all the records, the error is never io.EOF. +func Iterate(reader *csv.Reader) iter.Seq2[[]string, error] { + return func(yield func([]string, error) bool) { + for { + record, err := reader.Read() + if err == io.EOF { + return + } + + if !yield(record, err) { + return + } + } + } +} diff --git a/seq/csvseq/iterate_example_test.go b/seq/csvseq/iterate_example_test.go new file mode 100644 index 0000000..9594032 --- /dev/null +++ b/seq/csvseq/iterate_example_test.go @@ -0,0 +1,63 @@ +package csvseq_test + +import ( + "encoding/csv" + "errors" + "fmt" + "strings" + + "github.com/GodsBoss/g/seq/csvseq" +) + +func ExampleIterate_tooFewFields() { + raw := strings.Join( + []string{ + "Foo,Bar,Baz", + "a,b", + "1,2,3", + }, + "\n", + ) + + reader := csv.NewReader(strings.NewReader(raw)) + reader.FieldsPerRecord = 3 + + for record, err := range csvseq.Iterate(reader) { + if err != nil { + fmt.Println("Invalid record " + strings.Join(record, ",") + " - " + err.Error()) + break + } + } + + // Output: + // Invalid record a,b - record on line 2: wrong number of fields +} + +func ExampleIterate_exhaustion() { + raw := strings.Join( + []string{ + "1,2,3", + "a,b,c", + "x,y,z", + }, + "\n", + ) + + reader := csv.NewReader(strings.NewReader(raw)) + + var errs error + + for record, err := range csvseq.Iterate(reader) { + fmt.Println(record[0]) + errs = errors.Join(errs, err) + } + + if errs != nil { + fmt.Println(errs) + } + + // Output: + // 1 + // a + // x +} diff --git a/seq/csvseq/iterate_test.go b/seq/csvseq/iterate_test.go new file mode 100644 index 0000000..4b85a56 --- /dev/null +++ b/seq/csvseq/iterate_test.go @@ -0,0 +1,17 @@ +package csvseq_test + +import ( + "encoding/csv" + "strings" + "testing" + + "github.com/GodsBoss/g/seq/csvseq" +) + +func TestEmpty(t *testing.T) { + iterator := csvseq.Iterate(csv.NewReader(strings.NewReader(""))) + + for record, err := range iterator { + t.Errorf("expected no iteration, got %v; %v", record, err) + } +}