-
Notifications
You must be signed in to change notification settings - Fork 26
/
model_gen.go
131 lines (115 loc) · 2.97 KB
/
model_gen.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package main
import (
"encoding/csv"
"fmt"
"html/template"
"os"
"path/filepath"
"sort"
"strings"
"golang.org/x/text/cases"
"golang.org/x/text/language"
)
type columnIndex int
const (
Name columnIndex = iota
InternalName
FieldType
Description
GroupName
FormField
Options
ReadOnlyValue
ReadOnlyDefinition
Calculated
ExternalOptions
Deleted
HubspotDefined
CreatedUser
Usages
)
func main() {
fmt.Printf("Running with arges: %s\n", os.Args[1:]) // Without command name.
if len(os.Args) != 3 {
fmt.Println("Missing required parameters: <objectName> <csvFilePath>")
os.Exit(1)
}
objectName, csvFilePath := os.Args[1], os.Args[2]
file, err := os.Open(csvFilePath)
if err != nil {
fmt.Printf("Failed to open CSV file: %s", err)
os.Exit(1)
}
defer file.Close()
rows, err := csv.NewReader(file).ReadAll()
if err != nil {
fmt.Printf("Failed to read CSV file: %s", err)
os.Exit(1)
}
sort.Slice(rows, func(i, j int) bool {
// Order by InternalName ascending.
return rows[i][InternalName] < rows[j][InternalName]
})
modelFields, internalNames := makeModelAndInternalNames(rows)
out, err := filepath.Abs(fmt.Sprintf("../../%s_model.go", strings.ToLower(objectName)))
if err != nil {
fmt.Printf("Failed to get absolute path: %s", err)
os.Exit(1)
}
if err := createFileFromTmpl(out, objectName, modelFields, internalNames); err != nil {
fmt.Printf("Failed to create file from template: %s", err)
os.Exit(1)
}
fmt.Printf("Generated code in: %s\n", out)
}
func createFileFromTmpl(outPath, objectName string, modelFields, internalNames []string) error {
f, err := os.OpenFile(outPath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0o644)
if err != nil {
return fmt.Errorf("file open error: %w", err)
}
defer f.Close()
t, err := template.ParseFiles("./model.tmpl")
if err != nil {
return fmt.Errorf("file parse error: %w", err)
}
data := map[string]interface{}{
"ObjectName": objectName,
"ModelFields": modelFields,
"InternalNames": internalNames,
}
if err := t.Execute(f, data); err != nil {
return fmt.Errorf("template execute error: %w", err)
}
return nil
}
func makeModelAndInternalNames(rows [][]string) (model []string, names []string) {
modelFields, internalNames := make([]string, 0, len(rows)), make([]string, 0, len(rows))
for i, row := range rows {
if i != 0 { // Skip header row.
modelFields = append(modelFields, fmt.Sprintf("%s %s", snakeToCamel(row[InternalName]), switchHsType(row[FieldType])))
internalNames = append(internalNames, row[InternalName])
}
}
return modelFields, internalNames
}
func snakeToCamel(snakeStr string) string {
var camelStr string
for _, part := range strings.Split(snakeStr, "_") {
camelStr += cases.Title(language.Und).String(part)
}
return camelStr
}
func switchHsType(fieldType string) string {
switch fieldType {
case "string", "enumeration":
return "*HsStr"
case "number":
return "*HsInt"
case "bool":
return "*HsBool"
case "datetime":
return "*HsTime"
default:
return fieldType
}
}