156 lines
3.8 KiB
Go
156 lines
3.8 KiB
Go
package csv
|
|
|
|
import (
|
|
"encoding/csv"
|
|
"fmt"
|
|
"io"
|
|
|
|
"github.com/mayswind/ezbookkeeping/pkg/converters/datatable"
|
|
"github.com/mayswind/ezbookkeeping/pkg/core"
|
|
"github.com/mayswind/ezbookkeeping/pkg/errs"
|
|
"github.com/mayswind/ezbookkeeping/pkg/log"
|
|
)
|
|
|
|
// CsvFileBasicDataTable defines the structure of csv data table
|
|
type CsvFileBasicDataTable struct {
|
|
allLines [][]string
|
|
hasTitleLine bool
|
|
}
|
|
|
|
// CsvFileBasicDataTableRow defines the structure of csv data table row
|
|
type CsvFileBasicDataTableRow struct {
|
|
dataTable *CsvFileBasicDataTable
|
|
allItems []string
|
|
}
|
|
|
|
// CsvFileBasicDataTableRowIterator defines the structure of csv data table row iterator
|
|
type CsvFileBasicDataTableRowIterator struct {
|
|
dataTable *CsvFileBasicDataTable
|
|
currentIndex int
|
|
}
|
|
|
|
// DataRowCount returns the total count of data row
|
|
func (t *CsvFileBasicDataTable) DataRowCount() int {
|
|
if len(t.allLines) < 1 {
|
|
return 0
|
|
}
|
|
|
|
if t.hasTitleLine {
|
|
return len(t.allLines) - 1
|
|
} else {
|
|
return len(t.allLines)
|
|
}
|
|
}
|
|
|
|
// HeaderColumnNames returns the header column name list
|
|
func (t *CsvFileBasicDataTable) HeaderColumnNames() []string {
|
|
if len(t.allLines) < 1 {
|
|
return nil
|
|
}
|
|
|
|
if t.hasTitleLine {
|
|
return t.allLines[0]
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// DataRowIterator returns the iterator of data row
|
|
func (t *CsvFileBasicDataTable) DataRowIterator() datatable.BasicDataTableRowIterator {
|
|
startIndex := -1
|
|
|
|
if t.hasTitleLine {
|
|
startIndex = 0
|
|
}
|
|
|
|
return &CsvFileBasicDataTableRowIterator{
|
|
dataTable: t,
|
|
currentIndex: startIndex,
|
|
}
|
|
}
|
|
|
|
// ColumnCount returns the total count of column in this data row
|
|
func (r *CsvFileBasicDataTableRow) ColumnCount() int {
|
|
return len(r.allItems)
|
|
}
|
|
|
|
// GetData returns the data in the specified column index
|
|
func (r *CsvFileBasicDataTableRow) GetData(columnIndex int) string {
|
|
if columnIndex >= len(r.allItems) {
|
|
return ""
|
|
}
|
|
|
|
return r.allItems[columnIndex]
|
|
}
|
|
|
|
// HasNext returns whether the iterator does not reach the end
|
|
func (t *CsvFileBasicDataTableRowIterator) HasNext() bool {
|
|
return t.currentIndex+1 < len(t.dataTable.allLines)
|
|
}
|
|
|
|
// CurrentRowId returns current index
|
|
func (t *CsvFileBasicDataTableRowIterator) CurrentRowId() string {
|
|
return fmt.Sprintf("line#%d", t.currentIndex)
|
|
}
|
|
|
|
// Next returns the next basic data row
|
|
func (t *CsvFileBasicDataTableRowIterator) Next() datatable.BasicDataTableRow {
|
|
if t.currentIndex+1 >= len(t.dataTable.allLines) {
|
|
return nil
|
|
}
|
|
|
|
t.currentIndex++
|
|
|
|
rowItems := t.dataTable.allLines[t.currentIndex]
|
|
|
|
return &CsvFileBasicDataTableRow{
|
|
dataTable: t.dataTable,
|
|
allItems: rowItems,
|
|
}
|
|
}
|
|
|
|
// CreateNewCsvBasicDataTable returns comma separated values data table by io readers
|
|
func CreateNewCsvBasicDataTable(ctx core.Context, reader io.Reader, hasTitleLine bool) (datatable.BasicDataTable, error) {
|
|
return createNewCsvFileBasicDataTable(ctx, reader, ',', hasTitleLine)
|
|
}
|
|
|
|
// CreateNewCustomCsvBasicDataTable returns character separated values data table by io readers
|
|
func CreateNewCustomCsvBasicDataTable(allLines [][]string, hasTitleLine bool) datatable.BasicDataTable {
|
|
return &CsvFileBasicDataTable{
|
|
allLines: allLines,
|
|
hasTitleLine: hasTitleLine,
|
|
}
|
|
}
|
|
|
|
func createNewCsvFileBasicDataTable(ctx core.Context, reader io.Reader, separator rune, hasTitleLine bool) (*CsvFileBasicDataTable, error) {
|
|
csvReader := csv.NewReader(reader)
|
|
csvReader.Comma = separator
|
|
csvReader.FieldsPerRecord = -1
|
|
|
|
allLines := make([][]string, 0)
|
|
|
|
for {
|
|
items, err := csvReader.Read()
|
|
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
|
|
if err != nil {
|
|
log.Errorf(ctx, "[csv_file_basic_data_table.createNewCsvFileDataTable] cannot parse csv data, because %s", err.Error())
|
|
return nil, errs.ErrInvalidCSVFile
|
|
}
|
|
|
|
if len(items) == 1 && items[0] == "" {
|
|
continue
|
|
}
|
|
|
|
allLines = append(allLines, items)
|
|
}
|
|
|
|
return &CsvFileBasicDataTable{
|
|
allLines: allLines,
|
|
hasTitleLine: hasTitleLine,
|
|
}, nil
|
|
}
|