• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

stephenafamo / bob / 12288008769

12 Dec 2024 01:21AM UTC coverage: 48.932% (-0.2%) from 49.164%
12288008769

Pull #325

github

stephenafamo
Modify expected structure of template FS
Pull Request #325: Refactor template parsing and organisation

113 of 139 new or added lines in 3 files covered. (81.29%)

6 existing lines in 3 files now uncovered.

6323 of 12922 relevant lines covered (48.93%)

223.26 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

69.86
/gen/templates.go
1
package gen
2

3
import (
4
        "embed"
5
        "fmt"
6
        "io/fs"
7
        "strings"
8
        "text/template"
9
        "unicode"
10

11
        "github.com/Masterminds/sprig/v3"
12
        "github.com/stephenafamo/bob/gen/drivers"
13
        "github.com/stephenafamo/bob/gen/importers"
14
        "github.com/volatiletech/strmangle"
15
)
16

17
//go:embed templates
18
var templates embed.FS
19

20
//go:embed bobgen-mysql/templates
21
var mysqlTemplates embed.FS
22

23
//go:embed bobgen-psql/templates
24
var psqlTemplates embed.FS
25

26
//go:embed bobgen-sqlite/templates
27
var sqliteTemplates embed.FS
28

29
//nolint:gochecknoglobals
30
var (
31
        ModelTemplates, _       = fs.Sub(templates, "templates/models")
32
        FactoryTemplates, _     = fs.Sub(templates, "templates/factory")
33
        MySQLModelTemplates, _  = fs.Sub(mysqlTemplates, "bobgen-mysql/templates/models")
34
        PSQLModelTemplates, _   = fs.Sub(psqlTemplates, "bobgen-psql/templates/models")
35
        SQLiteModelTemplates, _ = fs.Sub(sqliteTemplates, "bobgen-sqlite/templates/models")
36
        typesReplacer           = strings.NewReplacer(
37
                " ", "_",
38
                ".", "_",
39
                ",", "_",
40
                "*", "_",
41
                "[", "_",
42
                "]", "_",
43
        )
44
)
45

46
type Importer map[string]struct{}
47

48
// To be used inside templates to record an import.
49
// Always returns an empty string
50
func (i Importer) Import(pkgs ...string) string {
28,220✔
51
        if len(pkgs) < 1 {
28,220✔
52
                return ""
×
53
        }
×
54
        pkg := fmt.Sprintf("%q", pkgs[0])
28,220✔
55
        if len(pkgs) > 1 {
29,600✔
56
                pkg = fmt.Sprintf("%s %q", pkgs[0], pkgs[1])
1,380✔
57
        }
1,380✔
58

59
        i[pkg] = struct{}{}
28,220✔
60
        return ""
28,220✔
61
}
62

63
func (i Importer) ImportList(list importers.List) string {
10,776✔
64
        for _, p := range list {
14,816✔
65
                i[p] = struct{}{}
4,040✔
66
        }
4,040✔
67
        return ""
10,776✔
68
}
69

70
func (i Importer) ToList() importers.List {
1,028✔
71
        var list importers.List
1,028✔
72
        for pkg := range i {
9,840✔
73
                list = append(list, pkg)
8,812✔
74
        }
8,812✔
75

76
        return list
1,028✔
77
}
78

79
type TemplateData[T, C, I any] struct {
80
        Dialect  string
81
        Importer Importer
82

83
        Table         drivers.Table[C, I]
84
        Tables        drivers.Tables[C, I]
85
        Enums         []drivers.Enum
86
        Aliases       drivers.Aliases
87
        Types         drivers.Types
88
        Relationships Relationships
89

90
        // Controls what names are output
91
        PkgName string
92

93
        // Control various generation features
94
        AddSoftDeletes    bool
95
        AddEnumTypes      bool
96
        EnumNullPrefix    string
97
        NoFactory         bool
98
        NoTests           bool
99
        NoBackReferencing bool
100

101
        // Tags control which tags are added to the struct
102
        Tags []string
103
        // RelationTag controls the value of the tags for the Relationship struct
104
        RelationTag string
105
        // Generate struct tags as camelCase or snake_case
106
        StructTagCasing string
107
        // Contains field names that should have tags values set to '-'
108
        TagIgnore map[string]struct{}
109

110
        // Supplied by the driver
111
        ExtraInfo     T
112
        ModelsPackage string
113

114
        // DriverName is the module name of the underlying `database/sql` driver
115
        DriverName string
116
}
117

118
func (t *TemplateData[T, C, I]) ResetImports() {
1,832✔
119
        t.Importer = make(Importer)
1,832✔
120
}
1,832✔
121

122
func loadTemplate(tpl *template.Template, customFuncs template.FuncMap, name, content string) error {
476✔
123
        _, err := tpl.New(name).
476✔
124
                Funcs(sprig.GenericFuncMap()).
476✔
125
                Funcs(templateFunctions).
476✔
126
                Funcs(customFuncs).
476✔
127
                Parse(content)
476✔
128
        if err != nil {
476✔
NEW
129
                return fmt.Errorf("failed to parse template: %s: %w", name, err)
×
UNCOV
130
        }
×
131

132
        return nil
476✔
133
}
134

135
// templateFunctions is a map of some helper functions that get passed into the
136
// templates. If you wish to pass a new function into your own template,
137
// you can add that with Config.CustomTemplateFuncs
138
//
139
//nolint:gochecknoglobals
140
var templateFunctions = template.FuncMap{
141
        "titleCase":          strmangle.TitleCase,
142
        "ignore":             strmangle.Ignore,
143
        "generateTags":       strmangle.GenerateTags,
144
        "generateIgnoreTags": strmangle.GenerateIgnoreTags,
145
        "normalizeType":      NormalizeType,
146
        "enumVal": func(val string) string {
80✔
147
                var newval strings.Builder
80✔
148
                for _, r := range val {
704✔
149
                        if r == '_' || unicode.IsLetter(r) || unicode.IsDigit(r) {
1,248✔
150
                                newval.WriteRune(r)
624✔
151
                                continue
624✔
152
                        }
153
                        newval.WriteString(fmt.Sprintf("U%x", r))
×
154
                }
155

156
                // Title case after doing unicode replacements or they will be stripped
157
                return strmangle.TitleCase(newval.String())
80✔
158
        },
159
        "columnTagName": func(casing, name, alias string) string {
8,184✔
160
                switch casing {
8,184✔
161
                case "camel":
×
162
                        return strmangle.CamelCase(name)
×
163
                case "title":
×
164
                        return strmangle.TitleCase(name)
×
165
                case "alias":
×
166
                        return alias
×
167
                default:
8,184✔
168
                        return name
8,184✔
169
                }
170
        },
171
        "quoteAndJoin": func(s1, s2 string) string {
×
172
                if s1 == "" && s2 == "" {
×
173
                        return ""
×
174
                }
×
175

176
                if s1 == "" {
×
177
                        return fmt.Sprintf("%q", s2)
×
178
                }
×
179

180
                if s2 == "" {
×
181
                        return fmt.Sprintf("%q", s1)
×
182
                }
×
183

184
                return fmt.Sprintf("%q, %q", s1, s2)
×
185
        },
186
        "isPrimitiveType":    isPrimitiveType,
187
        "relQueryMethodName": relQueryMethodName,
188
}
189

190
func relQueryMethodName(tAlias drivers.TableAlias, relAlias string) string {
1,248✔
191
        for _, colAlias := range tAlias.Columns {
6,725✔
192
                // clash with field name
5,477✔
193
                if colAlias == relAlias {
5,493✔
194
                        return "Related" + relAlias
16✔
195
                }
16✔
196
        }
197

198
        return relAlias
1,232✔
199
}
200

201
func NormalizeType(val string) string {
7,676✔
202
        return typesReplacer.Replace(val)
7,676✔
203
}
7,676✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc