Files
satbd-explorer/album_csv_reader.go

145 lines
3.7 KiB
Go

package main
import (
"encoding/csv"
"fmt"
"io"
"regexp"
"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, 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
}
var nullTimeRx = regexp.MustCompile(`(00/)+0000`)
func safeParseTime(format, value string, result *time.Time) error {
if len(value) == 0 || nullTimeRx.MatchString(value) == true {
*result = time.Time{}
return nil
}
var err error
*result, err = time.ParseInLocation(format, value, time.UTC)
if err != nil {
return fmt.Errorf("AlbumCsvReader: %s: %s", cLegalDeposit, err)
}
return nil
}
// Read get the next line in the CSV and return an Album or an error,
// or io.EOF if stream is closed
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]],
}
// simply skip new columns Name
if data[0] == "IdRevue" || data[0] == "IdParaBD" {
return r.Read()
}
ID, err := strconv.ParseInt(data[r.columns[cID]], 0, 64)
if err != nil {
return nil, fmt.Errorf("AlbumCsvReader: %s: %s", cID, err)
}
res.ID = AlbumID(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)
}
err = safeParseTime("01/2006", data[r.columns[cLegalDeposit]], &(res.LegalDeposit))
if err != nil {
return nil, fmt.Errorf("AlbumCsvReader: %s: %s", cLegalDeposit, err)
}
err = safeParseTime("01/2006", data[r.columns[cPrintDate]], &(res.PrintDate))
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)
err = safeParseTime("02/01/2006", data[r.columns[cPurchaseDate]], &(res.PurchaseDate))
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
}