Skip to content

Commit 4ce9974

Browse files
committed
added concurrent CSV file loader
1 parent c5caf48 commit 4ce9974

File tree

3 files changed

+204
-0
lines changed

3 files changed

+204
-0
lines changed

gencsv/main.go

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
package main
2+
3+
import (
4+
"time"
5+
"fmt"
6+
"flag"
7+
"strings"
8+
"os"
9+
"io"
10+
)
11+
12+
13+
var template = `
14+
package %s
15+
16+
// DO NOT EDIT - this file was generated with
17+
// %s
18+
// On %s
19+
20+
import (
21+
"github.com/tbshill/csv"
22+
"sync"
23+
"os"
24+
"time"
25+
%s
26+
)
27+
28+
type %s struct {
29+
LoadedTimestamp time.Time
30+
Filename string
31+
Rownum int
32+
Errs []error
33+
Data %s
34+
}
35+
36+
func New%s(filename string, row int, data %s) *%s {
37+
return &%s {
38+
Filename: filename,
39+
Rownum: row,
40+
Data: data,
41+
Errs: []error{},
42+
LoadedTimestamp: time.Now(),
43+
}
44+
}
45+
46+
func Load%s(filenames []string, parallelism int, dl, nl string) (chan *%s, chan error){
47+
recordChan, errChan := make(chan *%s), make(chan error)
48+
go func(){
49+
defer close(recordChan)
50+
defer close(errChan)
51+
52+
concurrencyLimit := make(chan struct{}, parallelism)
53+
defer close(concurrencyLimit)
54+
55+
var wg sync.WaitGroup
56+
wg.Add(len(filenames))
57+
58+
for _, filename := range filenames {
59+
concurrencyLimit <- struct{}{}
60+
go func(wg *sync.WaitGroup, filename string) {
61+
62+
defer func(){
63+
<-concurrencyLimit
64+
}()
65+
66+
defer wg.Done()
67+
68+
f, err := os.Open(filename)
69+
if err != nil {
70+
errChan <- err
71+
return
72+
}
73+
74+
defer func(){
75+
if err := f.Close(); err != nil{
76+
errChan <- err
77+
}
78+
}()
79+
80+
rowNum := 0
81+
decoder := csv.NewDecoder(dl, nl, f)
82+
for decoder.Scan() {
83+
rowNum++
84+
var data %s
85+
if err := decoder.Decode(&data); err != nil {
86+
errChan <- err
87+
return // Parser is probably confused so we should exit
88+
}
89+
recordChan <- New%s(filename, rowNum, data)
90+
}
91+
92+
}(&wg, filename)
93+
}
94+
95+
wg.Wait()
96+
}()
97+
return recordChan, errChan
98+
}
99+
`
100+
101+
func generateCsvRecordName(dataType string) string {
102+
normalizedDatatypeName := dataType
103+
if idx := strings.LastIndexByte(dataType,'.'); idx >= 0 {
104+
normalizedDatatypeName = dataType[idx+1:]
105+
}
106+
return fmt.Sprintf("CsvRecord%s", normalizedDatatypeName)
107+
}
108+
109+
func generateImports(imports []string) string {
110+
quoted := make([]string, len(imports))
111+
for i, v := range imports{
112+
quoted[i] = "\""+v+"\""
113+
}
114+
return strings.Join(quoted,"\n\t")
115+
}
116+
117+
func generateTemplate(out io.Writer, genCommand, pkg, dataType string, imports []string) {
118+
csvRecordName := generateCsvRecordName(dataType)
119+
importStr := generateImports(imports)
120+
fmt.Fprintf(out, template,
121+
pkg,
122+
genCommand,
123+
time.Now().String(),
124+
importStr, // 1
125+
csvRecordName, // 2
126+
dataType, // 3
127+
csvRecordName, // 4
128+
dataType, // 5
129+
csvRecordName, // 6
130+
csvRecordName, // 6
131+
csvRecordName, // 6
132+
csvRecordName, // 7
133+
csvRecordName,
134+
dataType,
135+
csvRecordName) // 8
136+
}
137+
138+
var (
139+
outfileName string
140+
pkg string
141+
dataType string
142+
importsRaw string
143+
)
144+
145+
func main() {
146+
flag.StringVar(&outfileName, "out", "", "-out csvloader.go")
147+
flag.StringVar(&pkg, "pkg", "", "-pkg main")
148+
flag.StringVar(&dataType, "data", "", "-data schema.CareCloudLabExtractRecord")
149+
flag.StringVar(&importsRaw, "imports", "", "-imports \"github.com/tbshillcdr/gocdrm/schema,secondImport.com/...\"")
150+
flag.Parse()
151+
152+
var out io.Writer
153+
if outfileName == "" {
154+
out = os.Stdout
155+
} else {
156+
var err error
157+
out, err = os.OpenFile(outfileName,os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0655)
158+
if err != nil {
159+
fmt.Fprintf(os.Stderr, "Failed to create outfile with reason:%v", err)
160+
}
161+
}
162+
163+
if pkg == "" {
164+
fmt.Fprintf(os.Stderr, "-pkg is requried\n")
165+
return
166+
}
167+
168+
if dataType == "" {
169+
fmt.Fprintf(os.Stderr, "-data is requried\n")
170+
return
171+
}
172+
173+
generateTemplate(out, strings.Join(os.Args, " "), pkg, dataType, strings.Split(importsRaw, ","))
174+
}

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
module github.com/tbshill/csv
22

33
go 1.13
4+
5+
require github.com/tbshillcdr/gocdrm v1.0.3

go.sum

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
github.com/agatan/bktree v0.0.0-20170513134333-739c0743f255/go.mod h1:L5xUMDqprPOuD4rCv+HBtHCvDzs4mWOJeVDcOawbFLc=
2+
github.com/creasty/go-levenshtein v0.0.0-20161128082938-38ce641d5030/go.mod h1:lOCZAIOJdOr4nhnfYZxyv6nN4NNG848ubmh4SpwFyI8=
3+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4+
github.com/denisenkom/go-mssqldb v0.10.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
5+
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
6+
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
7+
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
8+
github.com/pkg/sftp v1.13.2/go.mod h1:LzqnAvaD5TWeNBsZpfKxSYn1MbjWwOsCIAFFJbpIsK8=
9+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
10+
github.com/simpleforce/simpleforce v0.0.0-20210518005708-245ee39ac3ec/go.mod h1:abS7k7nPhcNtzsAsfzOedGmI7yU0PDzQVwlHJZwGgOs=
11+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
12+
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
13+
github.com/tbshill/csv v0.0.0-20210811034324-39629ad9b789/go.mod h1:r3GLXBLJKng7p/d03EQDg80TXdDqIMc/MFRfaAxoFFY=
14+
github.com/tbshillcdr/gocdrm v1.0.3 h1:B6T7fnh64Ydmw3XkWLwncEd8mjr6mE2HE6jBtERk3tI=
15+
github.com/tbshillcdr/gocdrm v1.0.3/go.mod h1:NQ6MUPJ1lxu3oY/ZEiu4L5QPmGdt2UqRkI3rzNkI30M=
16+
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
17+
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
18+
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
19+
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
20+
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
21+
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
22+
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
23+
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
24+
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
25+
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
26+
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
27+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
28+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

0 commit comments

Comments
 (0)