Skip to content

Commit ea9c62f

Browse files
authored
Validate query name (#126)
* tests: Fix failing tests for wrapped errors * gen: fix import error * parser: Validate query names Query names must be valid Go identifiers
1 parent 1af2caa commit ea9c62f

4 files changed

Lines changed: 64 additions & 22 deletions

File tree

internal/dinosql/gen.go

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -174,18 +174,22 @@ func (r Result) UsesArrays() bool {
174174
return false
175175
}
176176

177-
func (r Result) Imports(filename string) [][]string {
178-
if filename == "db.go" {
179-
return [][]string{
180-
[]string{"context", "database/sql", "fmt"},
177+
func (r Result) Imports(settings PackageSettings) func(string) [][]string {
178+
return func(filename string) [][]string {
179+
if filename == "db.go" {
180+
imps := []string{"context", "database/sql"}
181+
if settings.EmitPreparedQueries {
182+
imps = append(imps, "fmt")
183+
}
184+
return [][]string{imps}
181185
}
182-
}
183186

184-
if filename == "models.go" {
185-
return r.ModelImports()
186-
}
187+
if filename == "models.go" {
188+
return r.ModelImports()
189+
}
187190

188-
return r.QueryImports(filename)
191+
return r.QueryImports(filename)
192+
}
189193
}
190194

191195
func (r Result) ModelImports() [][]string {
@@ -950,7 +954,7 @@ func lowerTitle(s string) string {
950954
func Generate(r *Result, global GenerateSettings, settings PackageSettings) (map[string]string, error) {
951955
funcMap := template.FuncMap{
952956
"lowerTitle": lowerTitle,
953-
"imports": r.Imports,
957+
"imports": r.Imports(settings),
954958
}
955959

956960
pkg := settings.Name

internal/dinosql/parser.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,25 @@ func rangeVars(root nodes.Node) []nodes.RangeVar {
288288
return vars
289289
}
290290

291-
// TODO: Validate metadata
291+
// A query name must be a valid Go identifier
292+
//
293+
// https://golang.org/ref/spec#Identifiers
294+
func validateQueryName(name string) error {
295+
if len(name) == 0 {
296+
return fmt.Errorf("invalid query name: %q", name)
297+
}
298+
for i, c := range name {
299+
isLetter := unicode.IsLetter(c) || c == '_'
300+
isDigit := unicode.IsDigit(c)
301+
if i == 0 && !isLetter {
302+
return fmt.Errorf("invalid query name: %q", name)
303+
} else if !(isLetter || isDigit) {
304+
return fmt.Errorf("invalid query name: %q", name)
305+
}
306+
}
307+
return nil
308+
}
309+
292310
func parseMetadata(t string) (string, string, error) {
293311
for _, line := range strings.Split(t, "\n") {
294312
if !strings.HasPrefix(line, "-- name:") {
@@ -301,13 +319,17 @@ func parseMetadata(t string) (string, string, error) {
301319
if len(part) != 4 {
302320
return "", "", fmt.Errorf("invalid query comment: %s", line)
303321
}
322+
queryName := part[2]
304323
queryType := strings.TrimSpace(part[3])
305324
switch queryType {
306325
case ":one", ":many", ":exec", ":execrows":
307326
default:
308327
return "", "", fmt.Errorf("invalid query type: %s", queryType)
309328
}
310-
return part[2], strings.TrimSpace(part[3]), nil
329+
if err := validateQueryName(queryName); err != nil {
330+
return "", "", err
331+
}
332+
return queryName, queryType, nil
311333
}
312334
return "", "", nil
313335
}

internal/dinosql/parser_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,3 +205,18 @@ func TestCompile(t *testing.T) {
205205
t.Errorf("%s: %s", err, string(output))
206206
}
207207
}
208+
209+
func TestParseMetadata(t *testing.T) {
210+
for _, query := range []string{
211+
`-- name: CreateFoo, :one`,
212+
`-- name: 9Foo_, :one`,
213+
`-- name: CreateFoo :two`,
214+
`-- name: CreateFoo`,
215+
`-- name: CreateFoo :one something`,
216+
`-- name: `,
217+
} {
218+
if _, _, err := parseMetadata(query); err == nil {
219+
t.Errorf("expected invalid metadata: %q", query)
220+
}
221+
}
222+
}

internal/dinosql/testdata/ondeck/prepared/db.go

Lines changed: 11 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)