Skip to content

Commit f42761a

Browse files
committed
Add a generator for golang
1 parent fbfc5b3 commit f42761a

File tree

9 files changed

+292
-2
lines changed

9 files changed

+292
-2
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ js/node_modules
44
js/yarn-error.log
55
**/*.jar
66
**/gen/
7+
**/generated.go

go/cmd/declarations/declarations.go

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
// generate.go
2+
package main
3+
4+
import (
5+
"encoding/json"
6+
"fmt"
7+
"go/format"
8+
"io/ioutil"
9+
"os"
10+
"path/filepath"
11+
"strings"
12+
"text/template"
13+
14+
"github.com/goccy/go-yaml"
15+
)
16+
17+
// Field represents a field in the YAML file
18+
type Field struct {
19+
Name string `yaml:"name"`
20+
Type string `yaml:"type"`
21+
}
22+
23+
// Config represents the structure of the YAML file
24+
type Config struct {
25+
Fields []Field `yaml:"fields"`
26+
Name string `yaml:"name"`
27+
Identifier map[string]any `yaml:"identifier"`
28+
}
29+
30+
// MethodData represents data needed to generate a method
31+
type MethodData struct {
32+
ClassName string
33+
MethodName string
34+
Name string
35+
}
36+
37+
// ClassData represents data needed to generate a class
38+
type ClassData struct {
39+
ClassName string
40+
Name string
41+
Identifier string
42+
}
43+
44+
const structTemplate = `
45+
type {{.ClassName}} struct {
46+
Builder
47+
name string
48+
identifier map[string]any
49+
values map[string]any
50+
}
51+
52+
func New{{.ClassName}}() *{{.ClassName}} {
53+
x := {{.ClassName}}{}
54+
x.init()
55+
return &x
56+
}
57+
58+
func (c *{{.ClassName}}) init() {
59+
c.name = "{{.Name}}"
60+
c.identifier= make(map[string]any)
61+
json.Unmarshal([]byte("{{.Identifier}}"), &c.identifier)
62+
c.values = make(map[string]any)
63+
}
64+
65+
func (c *{{.ClassName}}) Format() (string, error) {
66+
return format(c.name, c.identifier, c.values)
67+
}
68+
69+
func (c *{{.ClassName}}) UnknownValue(name string, value any) {
70+
c.values[name] = value
71+
}
72+
`
73+
74+
// Template for generating methods
75+
const methodTemplate = `
76+
77+
func (c *{{.ClassName}}) {{.MethodName}}(value any) {
78+
c.values["{{.Name}}"] = value
79+
}
80+
`
81+
82+
func CreateFile(path string) (*strings.Builder, error) {
83+
yamlFile, err := os.ReadFile(path)
84+
if err != nil {
85+
return nil, err
86+
}
87+
var config Config
88+
err = yaml.Unmarshal(yamlFile, &config)
89+
if err != nil {
90+
return nil, err
91+
}
92+
b, _ := json.Marshal(config.Identifier)
93+
94+
tmplM, err := template.New("method").Parse(methodTemplate)
95+
if err != nil {
96+
return nil, err
97+
}
98+
tmplC, err := template.New("class").Parse(structTemplate)
99+
if err != nil {
100+
return nil, err
101+
}
102+
103+
c := strings.Builder{}
104+
escapedIdentifier := strings.ReplaceAll(string(b), `"`, `\"`)
105+
cData := ClassData{
106+
ClassName: capitalize(config.Name),
107+
Name: config.Name,
108+
Identifier: escapedIdentifier,
109+
}
110+
err = tmplC.Execute(&c, cData)
111+
if err != nil {
112+
return nil, err
113+
}
114+
115+
// Iterate through fields and generate methods
116+
for _, field := range config.Fields {
117+
data := MethodData{
118+
ClassName: capitalize(config.Name),
119+
MethodName: "Add" + capitalize(removeDash(field.Name)),
120+
Name: removeDash(field.Name),
121+
}
122+
err = tmplM.Execute(&c, data)
123+
if err != nil {
124+
return nil, err
125+
}
126+
}
127+
return &c, nil
128+
}
129+
130+
func main() {
131+
// Read and parse the YAML file
132+
yamlDir := "pkg/qtag/declarations"
133+
files, err := ioutil.ReadDir(yamlDir)
134+
if err != nil {
135+
panic(err)
136+
}
137+
138+
c := strings.Builder{}
139+
c.WriteString("package qtag\nimport (\n\t\"encoding/json\"\n)\n\n")
140+
for _, f := range files {
141+
var s *strings.Builder
142+
s, err = CreateFile(filepath.Join(yamlDir, f.Name()))
143+
if err != nil {
144+
panic(err)
145+
}
146+
c.WriteString(s.String())
147+
}
148+
149+
// Create the generated file
150+
f, err := os.Create("pkg/qtag/generated.go")
151+
if err != nil {
152+
panic(err)
153+
}
154+
defer f.Close()
155+
156+
formattedCode, err := format.Source([]byte(c.String()))
157+
if err != nil {
158+
panic(err)
159+
}
160+
f.Write(formattedCode)
161+
fmt.Println("example/generated.go has been generated")
162+
}
163+
164+
// capitalize capitalizes the first letter of a string
165+
func capitalize(s string) string {
166+
if len(s) == 0 {
167+
return ""
168+
}
169+
return string(s[0]-32) + s[1:]
170+
}
171+
172+
func removeDash(s string) string {
173+
if len(s) == 0 {
174+
return ""
175+
}
176+
if strings.Contains(s, "-") {
177+
return strings.Replace(s, "-", "__", -1)
178+
}
179+
return s
180+
}

go/generate.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package main
2+
3+
//go:generate go run cmd/declarations/declarations.go

go/go.mod

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,16 @@ require (
1010
)
1111

1212
require (
13+
github.com/davecgh/go-spew v1.1.1 // indirect
1314
github.com/fatih/color v1.10.0 // indirect
1415
github.com/google/go-cmp v0.5.8 // indirect
1516
github.com/mattn/go-colorable v0.1.8 // indirect
1617
github.com/mattn/go-isatty v0.0.12 // indirect
18+
github.com/pmezard/go-difflib v1.0.0 // indirect
19+
github.com/stretchr/testify v1.9.0 // indirect
1720
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect
1821
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
1922
golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12 // indirect
2023
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
24+
gopkg.in/yaml.v3 v3.0.1 // indirect
2125
)

go/go.sum

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12 h1:npHgfD4Tl2WJS3AJaMUi5ynGDPUBfkg3U3fCzDyXZ+4=
22
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM=
33
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
5+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
46
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
57
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
68
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
@@ -21,11 +23,14 @@ github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ
2123
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
2224
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
2325
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
26+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
2427
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
2528
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
2629
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
2730
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
2831
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
32+
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
33+
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
2934
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
3035
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
3136
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@@ -61,5 +66,7 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1N
6166
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
6267
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
6368
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
69+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
70+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
6471
gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o=
6572
gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g=

go/pkg/qtag/builder.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package qtag
2+
3+
import (
4+
"encoding/json"
5+
"errors"
6+
"fmt"
7+
"strings"
8+
)
9+
10+
type Builder interface {
11+
init(name string)
12+
}
13+
14+
func format(name string, identifier map[string]any, values map[string]any) (string, error) {
15+
modifiedValues := make(map[string]any)
16+
for k, v := range values {
17+
if strings.Contains(k, "__") {
18+
modifiedValues[strings.ReplaceAll(k, "__", "-")] = v
19+
} else {
20+
modifiedValues[k] = v
21+
}
22+
}
23+
if f, ok := identifier["fields"]; ok {
24+
if m, ok := f.(map[string]any); ok {
25+
for k, v := range m {
26+
modifiedValues[k] = v
27+
}
28+
b, err := json.Marshal(modifiedValues)
29+
if err != nil {
30+
return "", err
31+
}
32+
return string(b), nil
33+
}
34+
return "", errors.New("field 'fields' should be a map")
35+
}
36+
if f, ok := identifier["prefix"]; ok {
37+
b, err := json.Marshal(modifiedValues)
38+
if err != nil {
39+
return "", err
40+
}
41+
return fmt.Sprintf("%s %s", f, string(b)), nil
42+
}
43+
return "", fmt.Errorf("unknown qtag format")
44+
}
45+
46+
type UnknownQtag struct {
47+
Builder
48+
name string
49+
identifier map[string]any
50+
values map[string]any
51+
}
52+
53+
func NewUnknownQtag(name string) *UnknownQtag {
54+
x := UnknownQtag{}
55+
x.init()
56+
x.name = name
57+
return &x
58+
}
59+
60+
func (c *UnknownQtag) init() {
61+
c.identifier = make(map[string]any)
62+
json.Unmarshal([]byte("{\"fields\":{\"app\":\""+c.name+"\"}}"), &c.identifier)
63+
c.values = make(map[string]any)
64+
}
65+
66+
func (c *UnknownQtag) Format() (string, error) {
67+
return format(c.name, c.identifier, c.values)
68+
}
69+
70+
func (c *UnknownQtag) UnknownValue(name string, value any) {
71+
c.values[name] = value
72+
}

go/pkg/qtag/builder_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package qtag
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func TestInit(t *testing.T) {
10+
var x = NewDbt()
11+
x.AddConnection_name("x")
12+
s, err := x.Format()
13+
assert.NoError(t, err)
14+
assert.Equal(t, `{"app":"dbt","connection_name":"x"}`, s)
15+
}

go/pkg/qtag/declarations/dbt.yaml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ fields:
2020
type: DIMENSION
2121
- name: project_name
2222
type: DIMENSION
23-
- name: target_name
24-
type: DIMENSION
2523
- name: target_database
2624
type: DIMENSION
2725
- name: target_schema

go/pkg/qtag/declarations/sundeck.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,13 @@ fields:
3434
type: DIMENSION
3535
- name: kind
3636
type: DIMENSION
37+
- name: auto_routing_matched
38+
type: DIMENSION
39+
- name: auto_routing_matched_warehouse
40+
type: DIMENSION
41+
- name: auto_routing_matched_warehouse_size
42+
type: DIMENSION
43+
- name: auto_routing_num_computed_signatures
44+
type: TRACE
45+
- name: auto_routing_warehouse_pool
46+
type: DIMENSION

0 commit comments

Comments
 (0)