Skip to content

Commit ddca20d

Browse files
committed
main: copy enum and template generation in from upstream
1 parent fb7ddd6 commit ddca20d

File tree

5 files changed

+246
-1
lines changed

5 files changed

+246
-1
lines changed

enum.go

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package main
2+
3+
import (
4+
"regexp"
5+
"strings"
6+
)
7+
8+
var IdentPattern = regexp.MustCompile("[^a-zA-Z0-9_]+")
9+
10+
type Constant struct {
11+
Name string
12+
Type string
13+
Value string
14+
}
15+
16+
type Enum struct {
17+
Name string
18+
Comment string
19+
Constants []Constant
20+
}
21+
22+
func EnumReplace(value string) string {
23+
id := strings.Replace(value, "-", "_", -1)
24+
id = strings.Replace(id, ":", "_", -1)
25+
id = strings.Replace(id, "/", "_", -1)
26+
return IdentPattern.ReplaceAllString(id, "")
27+
}
28+
29+
func EnumValueName(value string) string {
30+
name := ""
31+
id := strings.Replace(value, "-", "_", -1)
32+
id = strings.Replace(id, ":", "_", -1)
33+
id = strings.Replace(id, "/", "_", -1)
34+
id = IdentPattern.ReplaceAllString(id, "")
35+
for _, part := range strings.Split(id, "_") {
36+
name += strings.Title(part)
37+
}
38+
return name
39+
}

main.go

+169-1
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,25 @@
11
package main
22

33
import (
4+
"bufio"
5+
"bytes"
6+
"errors"
7+
"fmt"
8+
"go/format"
9+
"html/template"
410
"log"
11+
"strings"
512

613
"github.com/stephen/sqlc-sql.js/internal/plugin"
14+
"github.com/stephen/sqlc-sql.js/internal/sdk"
715
)
816

917
func main() {
1018
req := &plugin.CodeGenRequest{}
1119
// XXX: fail on req.Settings.Engine
1220
// XXX: fail on type overrides
21+
// XXX: fail on non-default schema
22+
enums := buildEnums(req)
1323
structs, err := buildStructs(req)
1424
if err != nil {
1525
panic(err)
@@ -20,5 +30,163 @@ func main() {
2030
panic(err)
2131
}
2232

23-
log.Println(queries)
33+
log.Println(queries, enums)
34+
}
35+
36+
type tmplCtx struct {
37+
Q string
38+
Package string
39+
Enums []Enum
40+
Structs []Struct
41+
GoQueries []Query
42+
43+
// TODO: Race conditions
44+
SourceName string
45+
46+
EmitJSONTags bool
47+
EmitDBTags bool
48+
EmitPreparedQueries bool
49+
EmitInterface bool
50+
EmitEmptySlices bool
51+
EmitMethodsWithDBArgument bool
52+
UsesCopyFrom bool
53+
UsesBatch bool
54+
}
55+
56+
func generate(req *plugin.CodeGenRequest, enums []Enum, structs []Struct, queries []Query) (*plugin.CodeGenResponse, error) {
57+
// i := &importer{
58+
// Settings: req.Settings,
59+
// Queries: queries,
60+
// Enums: enums,
61+
// Structs: structs,
62+
// }
63+
64+
funcMap := template.FuncMap{
65+
"lowerTitle": sdk.LowerTitle,
66+
"comment": sdk.DoubleSlashComment,
67+
"escape": sdk.EscapeBacktick,
68+
// "imports": i.Imports,
69+
"hasPrefix": strings.HasPrefix,
70+
}
71+
72+
tmpl := template.Must(
73+
template.New("table").
74+
Funcs(funcMap).
75+
ParseFS(
76+
templates,
77+
"templates/*.tmpl",
78+
"templates/*/*.tmpl",
79+
),
80+
)
81+
82+
golang := req.Settings.Go
83+
tctx := tmplCtx{
84+
EmitInterface: golang.EmitInterface,
85+
EmitJSONTags: golang.EmitJsonTags,
86+
EmitDBTags: golang.EmitDbTags,
87+
EmitPreparedQueries: golang.EmitPreparedQueries,
88+
EmitEmptySlices: golang.EmitEmptySlices,
89+
EmitMethodsWithDBArgument: golang.EmitMethodsWithDbArgument,
90+
Q: "`",
91+
Package: golang.Package,
92+
GoQueries: queries,
93+
Enums: enums,
94+
Structs: structs,
95+
}
96+
97+
if tctx.UsesCopyFrom {
98+
return nil, errors.New(":copyfrom not supported")
99+
}
100+
101+
if tctx.UsesBatch {
102+
return nil, errors.New(":batch* commands not supported")
103+
}
104+
105+
output := map[string]string{}
106+
107+
execute := func(name, templateName string) error {
108+
var b bytes.Buffer
109+
w := bufio.NewWriter(&b)
110+
tctx.SourceName = name
111+
err := tmpl.ExecuteTemplate(w, templateName, &tctx)
112+
w.Flush()
113+
if err != nil {
114+
return err
115+
}
116+
code, err := format.Source(b.Bytes())
117+
if err != nil {
118+
fmt.Println(b.String())
119+
return fmt.Errorf("source error: %w", err)
120+
}
121+
122+
if templateName == "queryFile" && golang.OutputFilesSuffix != "" {
123+
name += golang.OutputFilesSuffix
124+
}
125+
126+
if !strings.HasSuffix(name, ".go") {
127+
name += ".go"
128+
}
129+
output[name] = string(code)
130+
return nil
131+
}
132+
133+
dbFileName := "db.go"
134+
if golang.OutputDbFileName != "" {
135+
dbFileName = golang.OutputDbFileName
136+
}
137+
modelsFileName := "models.go"
138+
if golang.OutputModelsFileName != "" {
139+
modelsFileName = golang.OutputModelsFileName
140+
}
141+
querierFileName := "querier.go"
142+
if golang.OutputQuerierFileName != "" {
143+
querierFileName = golang.OutputQuerierFileName
144+
}
145+
copyfromFileName := "copyfrom.go"
146+
// TODO(Jille): Make this configurable.
147+
148+
batchFileName := "batch.go"
149+
150+
if err := execute(dbFileName, "dbFile"); err != nil {
151+
return nil, err
152+
}
153+
if err := execute(modelsFileName, "modelsFile"); err != nil {
154+
return nil, err
155+
}
156+
if golang.EmitInterface {
157+
if err := execute(querierFileName, "interfaceFile"); err != nil {
158+
return nil, err
159+
}
160+
}
161+
if tctx.UsesCopyFrom {
162+
if err := execute(copyfromFileName, "copyfromFile"); err != nil {
163+
return nil, err
164+
}
165+
}
166+
if tctx.UsesBatch {
167+
if err := execute(batchFileName, "batchFile"); err != nil {
168+
return nil, err
169+
}
170+
}
171+
172+
files := map[string]struct{}{}
173+
for _, gq := range queries {
174+
files[gq.SourceName] = struct{}{}
175+
}
176+
177+
for source := range files {
178+
if err := execute(source, "queryFile"); err != nil {
179+
return nil, err
180+
}
181+
}
182+
resp := plugin.CodeGenResponse{}
183+
184+
for filename, code := range output {
185+
resp.Files = append(resp.Files, &plugin.File{
186+
Name: filename,
187+
Contents: []byte(code),
188+
})
189+
}
190+
191+
return &resp, nil
24192
}

result.go

+32
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,38 @@ import (
1010
"github.com/stephen/sqlc-sql.js/internal/sdk"
1111
)
1212

13+
func buildEnums(req *plugin.CodeGenRequest) []Enum {
14+
var enums []Enum
15+
for _, schema := range req.Catalog.Schemas {
16+
for _, enum := range schema.Enums {
17+
var enumName string
18+
enumName = enum.Name
19+
e := Enum{
20+
Name: StructName(enumName, req.Settings),
21+
Comment: enum.Comment,
22+
}
23+
seen := make(map[string]struct{}, len(enum.Vals))
24+
for i, v := range enum.Vals {
25+
value := EnumReplace(v)
26+
if _, found := seen[value]; found || value == "" {
27+
value = fmt.Sprintf("value_%d", i)
28+
}
29+
e.Constants = append(e.Constants, Constant{
30+
Name: StructName(enumName+"_"+value, req.Settings),
31+
Value: v,
32+
Type: e.Name,
33+
})
34+
seen[value] = struct{}{}
35+
}
36+
enums = append(enums, e)
37+
}
38+
}
39+
if len(enums) > 0 {
40+
sort.Slice(enums, func(i, j int) bool { return enums[i].Name < enums[j].Name })
41+
}
42+
return enums
43+
}
44+
1345
func buildStructs(req *plugin.CodeGenRequest) ([]Struct, error) {
1446
var structs []Struct
1547
for _, schema := range req.Catalog.Schemas {

template.go

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package main
2+
3+
import "embed"
4+
5+
//go:embed templates/*
6+
var templates embed.FS

templates/template.tmpl

Whitespace-only changes.

0 commit comments

Comments
 (0)