Skip to content

Commit

Permalink
Add a generator for golang
Browse files Browse the repository at this point in the history
  • Loading branch information
rymurr committed Jul 30, 2024
1 parent fbfc5b3 commit f42761a
Show file tree
Hide file tree
Showing 9 changed files with 292 additions and 2 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ js/node_modules
js/yarn-error.log
**/*.jar
**/gen/
**/generated.go
180 changes: 180 additions & 0 deletions go/cmd/declarations/declarations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
// generate.go
package main

import (
"encoding/json"
"fmt"
"go/format"
"io/ioutil"
"os"
"path/filepath"
"strings"
"text/template"

"github.com/goccy/go-yaml"
)

// Field represents a field in the YAML file
type Field struct {
Name string `yaml:"name"`
Type string `yaml:"type"`
}

// Config represents the structure of the YAML file
type Config struct {
Fields []Field `yaml:"fields"`
Name string `yaml:"name"`
Identifier map[string]any `yaml:"identifier"`
}

// MethodData represents data needed to generate a method
type MethodData struct {
ClassName string
MethodName string
Name string
}

// ClassData represents data needed to generate a class
type ClassData struct {
ClassName string
Name string
Identifier string
}

const structTemplate = `
type {{.ClassName}} struct {
Builder
name string
identifier map[string]any
values map[string]any
}
func New{{.ClassName}}() *{{.ClassName}} {
x := {{.ClassName}}{}
x.init()
return &x
}
func (c *{{.ClassName}}) init() {
c.name = "{{.Name}}"
c.identifier= make(map[string]any)
json.Unmarshal([]byte("{{.Identifier}}"), &c.identifier)
c.values = make(map[string]any)
}
func (c *{{.ClassName}}) Format() (string, error) {
return format(c.name, c.identifier, c.values)
}
func (c *{{.ClassName}}) UnknownValue(name string, value any) {
c.values[name] = value
}
`

// Template for generating methods
const methodTemplate = `
func (c *{{.ClassName}}) {{.MethodName}}(value any) {
c.values["{{.Name}}"] = value
}
`

func CreateFile(path string) (*strings.Builder, error) {
yamlFile, err := os.ReadFile(path)
if err != nil {
return nil, err
}
var config Config
err = yaml.Unmarshal(yamlFile, &config)
if err != nil {
return nil, err
}
b, _ := json.Marshal(config.Identifier)

tmplM, err := template.New("method").Parse(methodTemplate)
if err != nil {
return nil, err
}
tmplC, err := template.New("class").Parse(structTemplate)
if err != nil {
return nil, err
}

c := strings.Builder{}
escapedIdentifier := strings.ReplaceAll(string(b), `"`, `\"`)
cData := ClassData{
ClassName: capitalize(config.Name),
Name: config.Name,
Identifier: escapedIdentifier,
}
err = tmplC.Execute(&c, cData)
if err != nil {
return nil, err
}

// Iterate through fields and generate methods
for _, field := range config.Fields {
data := MethodData{
ClassName: capitalize(config.Name),
MethodName: "Add" + capitalize(removeDash(field.Name)),
Name: removeDash(field.Name),
}
err = tmplM.Execute(&c, data)
if err != nil {
return nil, err
}
}
return &c, nil
}

func main() {
// Read and parse the YAML file
yamlDir := "pkg/qtag/declarations"
files, err := ioutil.ReadDir(yamlDir)
if err != nil {
panic(err)
}

c := strings.Builder{}
c.WriteString("package qtag\nimport (\n\t\"encoding/json\"\n)\n\n")
for _, f := range files {
var s *strings.Builder
s, err = CreateFile(filepath.Join(yamlDir, f.Name()))
if err != nil {
panic(err)
}
c.WriteString(s.String())
}

// Create the generated file
f, err := os.Create("pkg/qtag/generated.go")
if err != nil {
panic(err)
}
defer f.Close()

formattedCode, err := format.Source([]byte(c.String()))
if err != nil {
panic(err)
}
f.Write(formattedCode)
fmt.Println("example/generated.go has been generated")
}

// capitalize capitalizes the first letter of a string
func capitalize(s string) string {
if len(s) == 0 {
return ""
}
return string(s[0]-32) + s[1:]
}

func removeDash(s string) string {
if len(s) == 0 {
return ""
}
if strings.Contains(s, "-") {
return strings.Replace(s, "-", "__", -1)
}
return s
}
3 changes: 3 additions & 0 deletions go/generate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package main

//go:generate go run cmd/declarations/declarations.go
4 changes: 4 additions & 0 deletions go/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,16 @@ require (
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fatih/color v1.10.0 // indirect
github.com/google/go-cmp v0.5.8 // indirect
github.com/mattn/go-colorable v0.1.8 // indirect
github.com/mattn/go-isatty v0.0.12 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/testify v1.9.0 // indirect
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
7 changes: 7 additions & 0 deletions go/go.sum
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12 h1:npHgfD4Tl2WJS3AJaMUi5ynGDPUBfkg3U3fCzDyXZ+4=
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
Expand All @@ -21,11 +23,14 @@ github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
Expand Down Expand Up @@ -61,5 +66,7 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1N
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o=
gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g=
72 changes: 72 additions & 0 deletions go/pkg/qtag/builder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package qtag

import (
"encoding/json"
"errors"
"fmt"
"strings"
)

type Builder interface {
init(name string)
}

func format(name string, identifier map[string]any, values map[string]any) (string, error) {
modifiedValues := make(map[string]any)
for k, v := range values {
if strings.Contains(k, "__") {
modifiedValues[strings.ReplaceAll(k, "__", "-")] = v
} else {
modifiedValues[k] = v
}
}
if f, ok := identifier["fields"]; ok {
if m, ok := f.(map[string]any); ok {
for k, v := range m {
modifiedValues[k] = v
}
b, err := json.Marshal(modifiedValues)
if err != nil {
return "", err
}
return string(b), nil
}
return "", errors.New("field 'fields' should be a map")
}
if f, ok := identifier["prefix"]; ok {
b, err := json.Marshal(modifiedValues)
if err != nil {
return "", err
}
return fmt.Sprintf("%s %s", f, string(b)), nil
}
return "", fmt.Errorf("unknown qtag format")
}

type UnknownQtag struct {
Builder
name string
identifier map[string]any
values map[string]any
}

func NewUnknownQtag(name string) *UnknownQtag {
x := UnknownQtag{}
x.init()
x.name = name
return &x
}

func (c *UnknownQtag) init() {
c.identifier = make(map[string]any)
json.Unmarshal([]byte("{\"fields\":{\"app\":\""+c.name+"\"}}"), &c.identifier)
c.values = make(map[string]any)
}

func (c *UnknownQtag) Format() (string, error) {
return format(c.name, c.identifier, c.values)
}

func (c *UnknownQtag) UnknownValue(name string, value any) {
c.values[name] = value
}
15 changes: 15 additions & 0 deletions go/pkg/qtag/builder_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package qtag

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestInit(t *testing.T) {
var x = NewDbt()
x.AddConnection_name("x")
s, err := x.Format()
assert.NoError(t, err)
assert.Equal(t, `{"app":"dbt","connection_name":"x"}`, s)
}
2 changes: 0 additions & 2 deletions go/pkg/qtag/declarations/dbt.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ fields:
type: DIMENSION
- name: project_name
type: DIMENSION
- name: target_name
type: DIMENSION
- name: target_database
type: DIMENSION
- name: target_schema
Expand Down
10 changes: 10 additions & 0 deletions go/pkg/qtag/declarations/sundeck.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,13 @@ fields:
type: DIMENSION
- name: kind
type: DIMENSION
- name: auto_routing_matched
type: DIMENSION
- name: auto_routing_matched_warehouse
type: DIMENSION
- name: auto_routing_matched_warehouse_size
type: DIMENSION
- name: auto_routing_num_computed_signatures
type: TRACE
- name: auto_routing_warehouse_pool
type: DIMENSION

0 comments on commit f42761a

Please sign in to comment.