jsonl.*jsonlExport.readAndAppendFile   B
last analyzed

Complexity

Conditions 7

Size

Total Lines 31
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 19
nop 0
dl 0
loc 31
rs 8
c 0
b 0
f 0
1
package jsonl
2
3
import (
4
	"adrianolaselva.github.io/csvql/pkg/exportdata"
5
	"bytes"
6
	"database/sql"
7
	"encoding/json"
8
	"fmt"
9
	"github.com/schollz/progressbar/v3"
10
	"os"
11
	"path/filepath"
12
)
13
14
const (
15
	fileModeDefault os.FileMode = 0644
16
)
17
18
type jsonlExport struct {
19
	rows       *sql.Rows
20
	bar        *progressbar.ProgressBar
21
	file       *os.File
22
	exportPath string
23
	columns    []string
24
}
25
26
func NewJsonlExport(rows *sql.Rows, exportPath string, bar *progressbar.ProgressBar) exportdata.Export {
27
	return &jsonlExport{rows: rows, exportPath: exportPath, bar: bar}
28
}
29
30
// Export rows in file
31
func (j *jsonlExport) Export() error {
32
	if err := j.loadColumns(); err != nil {
33
		return fmt.Errorf("failed to load columns: %w", err)
34
	}
35
36
	if err := j.openFile(); err != nil {
37
		return fmt.Errorf("failed to open file: %w", err)
38
	}
39
40
	for j.rows.Next() {
41
		_ = j.bar.Add(1)
42
		if err := j.readAndAppendFile(); err != nil {
43
			return fmt.Errorf("failed to read and append line in file: %w", err)
44
		}
45
	}
46
47
	return nil
48
}
49
50
// Close execute in defer
51
func (j *jsonlExport) Close() error {
52
	defer func(file *os.File) {
53
		_ = file.Close()
54
	}(j.file)
55
56
	return nil
57
}
58
59
// readAndAppendFile read line and append in file
60
func (j *jsonlExport) readAndAppendFile() error {
61
	values := make([]interface{}, len(j.columns))
62
	pointers := make([]interface{}, len(j.columns))
63
	for i := range values {
64
		pointers[i] = &values[i]
65
	}
66
67
	if err := j.rows.Scan(pointers...); err != nil {
68
		return fmt.Errorf("failed to load row: %w", err)
69
	}
70
71
	attr := map[string]interface{}{}
72
	for i, c := range j.columns {
73
		attr[c] = pointers[i]
74
	}
75
76
	payload, err := json.Marshal(attr)
77
	if err != nil {
78
		return fmt.Errorf("failed to serialize row: %w", err)
79
	}
80
81
	buffer := new(bytes.Buffer)
82
	if err := json.Compact(buffer, payload); err != nil {
83
		return fmt.Errorf("failed to compact payload: %w", err)
84
	}
85
86
	if _, err := j.file.WriteString(fmt.Sprintf("%s\n", buffer.String())); err != nil {
87
		return fmt.Errorf("failed to write file %s: %w", j.exportPath, err)
88
	}
89
90
	return nil
91
}
92
93
// openFile open file
94
func (j *jsonlExport) openFile() error {
95
	if _, err := os.Stat(j.exportPath); !os.IsNotExist(err) {
96
		err := os.Remove(j.exportPath)
97
		if err != nil {
98
			return fmt.Errorf("failed to remove file: %w", err)
99
		}
100
	}
101
102
	if err := os.MkdirAll(filepath.Dir(j.exportPath), os.ModePerm); err != nil {
103
		return fmt.Errorf("failed to create path: %w", err)
104
	}
105
106
	file, err := os.OpenFile(j.exportPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, fileModeDefault)
107
	if err != nil {
108
		return fmt.Errorf("failed to open file %s: %w", j.exportPath, err)
109
	}
110
111
	j.file = file
112
113
	return nil
114
}
115
116
// loadColumns load columns
117
func (j *jsonlExport) loadColumns() error {
118
	columns, err := j.rows.Columns()
119
	if err != nil {
120
		return fmt.Errorf("failed to load columns: %w", err)
121
	}
122
123
	j.columns = columns
124
125
	return nil
126
}
127