From b743fffb234f1b55d75ab4f057954f37b2775ea4 Mon Sep 17 00:00:00 2001 From: Alexandre Tuleu Date: Sun, 17 Jan 2016 12:58:59 +0100 Subject: [PATCH] Implements csv parsing --- album_csv_reader.go | 116 +++++++++++++++++++++++++++++++++++++-- album_csv_reader_test.go | 31 ++++++----- 2 files changed, 128 insertions(+), 19 deletions(-) diff --git a/album_csv_reader.go b/album_csv_reader.go index 2f3c548..af85d29 100644 --- a/album_csv_reader.go +++ b/album_csv_reader.go @@ -1,21 +1,129 @@ package main import ( + "encoding/csv" "fmt" "io" + "strconv" + "time" ) // AlbumCsvReader can read Album definition from a csv file type AlbumCsvReader struct { + r *csv.Reader + columns map[string]int } +const ( + cID string = "IdAlbum" + cISBN = "ISBN" + cSeries = "Serie" + cNum = "Num" + cNumA = "NumA" + cTitle = "Titre" + cEditor = "Editeur" + cCollection = "Collection" + cLegalDeposit = "DL" + cPrintDate = "AI" + cState = "Etat" + cPurchaseDate = "DateAchat" + cPerso1 = "Perso1" + cPerso2 = "Perso2" +) + +var requiredFields = []string{cID, cISBN, cSeries, cNum, cNumA, cTitle, cEditor, cCollection, cLegalDeposit, cPrintDate, cState, cPurchaseDate, cPerso1, cPerso2} + // NewAlbumCsvReader creates a new AlbumCsvReader from a reader -func NewAlbumCsvReader(r io.Reader) *AlbumCsvReader { - return nil +func NewAlbumCsvReader(r io.Reader) (*AlbumCsvReader, error) { + res := &AlbumCsvReader{ + r: csv.NewReader(r), + columns: make(map[string]int), + } + res.r.Comma = ';' + //reads the first line + colNames, err := res.r.Read() + if err != nil { + return nil, fmt.Errorf("album_csv: could not read first line: %s", err) + } + + for i, n := range colNames { + res.columns[n] = i + } + + missing := []string{} + for _, f := range requiredFields { + if _, ok := res.columns[f]; ok == false { + missing = append(missing, f) + } + } + + if len(missing) != 0 { + return nil, fmt.Errorf("Invalid CSV file, missing required fields: %v", missing) + } + + return res, nil } // Read get the next line in the CSV and return an Album or an error, // or io.EOF if stream is closed -func (a *AlbumCsvReader) Read() (*Album, error) { - return nil, fmt.Errorf("Niot uyet implemented") +func (r *AlbumCsvReader) Read() (*Album, error) { + data, err := r.r.Read() + if err != nil { + return nil, err + } + + res := &Album{ + ISBN: data[r.columns[cISBN]], + Series: data[r.columns[cSeries]], + NumA: data[r.columns[cNumA]], + Title: data[r.columns[cTitle]], + Editor: data[r.columns[cEditor]], + Collection: data[r.columns[cCollection]], + } + + ID, err := strconv.ParseInt(data[r.columns[cID]], 0, 64) + if err != nil { + return nil, fmt.Errorf("AlbumCsvReader: %s: %s", cID, err) + } + res.ID = uint64(ID) + + if len(data[r.columns[cNum]]) == 0 { + res.Num = -1 + } else { + n, err := strconv.ParseInt(data[r.columns[cNum]], 0, 32) + if err != nil { + return nil, fmt.Errorf("AlbumCsvReader: %s: %s", cNum, err) + } + res.Num = int(n) + } + if len(data[r.columns[cLegalDeposit]]) != 0 { + res.LegalDeposit, err = time.ParseInLocation("01/2006", data[r.columns[cLegalDeposit]], time.UTC) + if err != nil { + return nil, fmt.Errorf("AlbumCsvReader: %s: %s", cLegalDeposit, err) + } + } + + if len(data[r.columns[cPrintDate]]) != 0 { + res.PrintDate, err = time.ParseInLocation("01/2006", data[r.columns[cPrintDate]], time.UTC) + if err != nil { + return nil, fmt.Errorf("AlbumCsvReader: %s: %s", cPrintDate, err) + } + } + + state, err := strconv.ParseInt(data[r.columns[cState]], 0, 32) + if err != nil { + return nil, fmt.Errorf("AlbumCsvReader: %s: %s", cState, err) + } + res.State = AlbumState(state) + + if len(data[r.columns[cPurchaseDate]]) != 0 { + res.PurchaseDate, err = time.ParseInLocation("02/01/2006", data[r.columns[cPurchaseDate]], time.UTC) + if err != nil { + return nil, fmt.Errorf("AlbumCsvReader: %s: %s", cPurchaseDate, err) + } + } + + res.SatID = fmt.Sprintf("%s-%s", data[r.columns[cPerso1]], data[r.columns[cPerso2]]) + + return res, nil } diff --git a/album_csv_reader_test.go b/album_csv_reader_test.go index 2e057d3..0e57f88 100644 --- a/album_csv_reader_test.go +++ b/album_csv_reader_test.go @@ -38,7 +38,7 @@ func (s *AlbumCsvReaderSuite) TestCanReadCsv(c *C) { Editor: "Sarbacane", Collection: "", State: 1, - LegalDeposit: time.Date(2009, 10, 0, 0, 0, 0, 0, time.UTC), + LegalDeposit: time.Date(2009, 10, 1, 0, 0, 0, 0, time.UTC), PurchaseDate: time.Date(2013, 9, 3, 0, 0, 0, 0, time.UTC), SatID: "RACO-1", }, @@ -50,7 +50,7 @@ func (s *AlbumCsvReaderSuite) TestCanReadCsv(c *C) { Title: "Le roi Oscar et autres racontars", Editor: "Sarbacane", Collection: "", - LegalDeposit: time.Date(2011, 01, 0, 0, 0, 0, 0, time.UTC), + LegalDeposit: time.Date(2011, 01, 1, 0, 0, 0, 0, time.UTC), State: 2, PurchaseDate: time.Date(2013, 9, 3, 0, 0, 0, 0, time.UTC), SatID: "RACO-2", @@ -64,7 +64,7 @@ func (s *AlbumCsvReaderSuite) TestCanReadCsv(c *C) { Title: "''Atar Gull'' ou le destin d'un esclave modèle", Editor: "Dargaud", Collection: "Long Courrier", - LegalDeposit: time.Date(2011, 10, 0, 0, 0, 0, 0, time.UTC), + LegalDeposit: time.Date(2011, 10, 1, 0, 0, 0, 0, time.UTC), State: 3, PurchaseDate: time.Date(2013, 9, 4, 0, 0, 0, 0, time.UTC), SatID: "LONG-11", @@ -78,7 +78,7 @@ func (s *AlbumCsvReaderSuite) TestCanReadCsv(c *C) { Title: "Tanino Liberatore", Editor: "Kesselring", Collection: "", - LegalDeposit: time.Date(1985, 12, 0, 0, 0, 0, 0, time.UTC), + LegalDeposit: time.Date(1985, 12, 1, 0, 0, 0, 0, time.UTC), State: 4, PurchaseDate: time.Date(2013, 12, 7, 0, 0, 0, 0, time.UTC), SatID: "LIB-00", @@ -105,7 +105,7 @@ func (s *AlbumCsvReaderSuite) TestCanReadCsv(c *C) { Title: "Humour noir et hommes en blanc", Editor: "Éditions du Grésivaudan", Collection: "", - LegalDeposit: time.Date(1972, 11, 0, 0, 0, 0, 0, time.UTC), + LegalDeposit: time.Date(1972, 11, 1, 0, 0, 0, 0, time.UTC), State: 0, PurchaseDate: time.Date(2013, 9, 3, 0, 0, 0, 0, time.UTC), SatID: "SERR-1", @@ -119,8 +119,8 @@ func (s *AlbumCsvReaderSuite) TestCanReadCsv(c *C) { Title: "Le Sport", Editor: "Glénat", Collection: "", - LegalDeposit: time.Date(1977, 10, 0, 0, 0, 0, 0, time.UTC), - PrintDate: time.Date(1977, 11, 0, 0, 0, 0, 0, time.UTC), + LegalDeposit: time.Date(1977, 10, 1, 0, 0, 0, 0, time.UTC), + PrintDate: time.Date(1977, 11, 1, 0, 0, 0, 0, time.UTC), State: 0, PurchaseDate: time.Date(2013, 9, 3, 0, 0, 0, 0, time.UTC), SatID: "SERR-2", @@ -134,8 +134,8 @@ func (s *AlbumCsvReaderSuite) TestCanReadCsv(c *C) { Title: "L'automobile", Editor: "Glénat", Collection: "", - LegalDeposit: time.Date(1978, 12, 0, 0, 0, 0, 0, time.UTC), - PrintDate: time.Date(1978, 12, 0, 0, 0, 0, 0, time.UTC), + LegalDeposit: time.Date(1978, 12, 1, 0, 0, 0, 0, time.UTC), + PrintDate: time.Date(1978, 12, 1, 0, 0, 0, 0, time.UTC), State: 0, PurchaseDate: time.Date(2013, 9, 3, 0, 0, 0, 0, time.UTC), SatID: "SERR-3", @@ -149,7 +149,7 @@ func (s *AlbumCsvReaderSuite) TestCanReadCsv(c *C) { Title: "...vice compris", Editor: "Glénat", Collection: "", - LegalDeposit: time.Date(1979, 10, 0, 0, 0, 0, 0, time.UTC), + LegalDeposit: time.Date(1979, 10, 1, 0, 0, 0, 0, time.UTC), State: 0, PurchaseDate: time.Date(2013, 9, 3, 0, 0, 0, 0, time.UTC), SatID: "SERR-7", @@ -163,7 +163,7 @@ func (s *AlbumCsvReaderSuite) TestCanReadCsv(c *C) { Title: "Savoir vivre", Editor: "Glénat", Collection: "", - LegalDeposit: time.Date(1981, 10, 0, 0, 0, 0, 0, time.UTC), + LegalDeposit: time.Date(1981, 10, 1, 0, 0, 0, 0, time.UTC), State: 0, PurchaseDate: time.Date(2013, 9, 3, 0, 0, 0, 0, time.UTC), SatID: "SERR-5", @@ -177,7 +177,7 @@ func (s *AlbumCsvReaderSuite) TestCanReadCsv(c *C) { Title: "La Bouffe", Editor: "Glénat", Collection: "", - LegalDeposit: time.Date(1982, 10, 0, 0, 0, 0, 0, time.UTC), + LegalDeposit: time.Date(1982, 10, 1, 0, 0, 0, 0, time.UTC), State: 0, PurchaseDate: time.Date(2013, 9, 3, 0, 0, 0, 0, time.UTC), SatID: "SERR-4", @@ -191,18 +191,19 @@ func (s *AlbumCsvReaderSuite) TestCanReadCsv(c *C) { Title: "Le bricolage", Editor: "Glénat", Collection: "", - LegalDeposit: time.Date(1983, 12, 0, 0, 0, 0, 0, time.UTC), + LegalDeposit: time.Date(1983, 12, 1, 0, 0, 0, 0, time.UTC), State: 0, PurchaseDate: time.Date(2013, 9, 3, 0, 0, 0, 0, time.UTC), SatID: "SERR-6", }, } - r := NewAlbumCsvReader(strings.NewReader(csvData)) + r, err := NewAlbumCsvReader(strings.NewReader(csvData)) + c.Assert(err, IsNil) for _, e := range expected { res, err := r.Read() if c.Check(err, IsNil) == true { - c.Check(res, Equals, e) + c.Check(*res, Equals, e, Commentf("expected: %+v actual: %+v", e, res)) } }