forked from sqlc-dev/sqlc
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmeta.go
More file actions
101 lines (95 loc) · 2.29 KB
/
meta.go
File metadata and controls
101 lines (95 loc) · 2.29 KB
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
package metadata
import (
"fmt"
"strings"
"unicode"
)
type CommentSyntax struct {
Dash bool
Hash bool
SlashStar bool
}
const (
CmdExec = ":exec"
CmdExecResult = ":execresult"
CmdExecRows = ":execrows"
CmdMany = ":many"
CmdOne = ":one"
CmdCopyFrom = ":copyfrom"
)
// A query name must be a valid Go identifier
//
// https://golang.org/ref/spec#Identifiers
func validateQueryName(name string) error {
if len(name) == 0 {
return fmt.Errorf("invalid query name: %q", name)
}
for i, c := range name {
isLetter := unicode.IsLetter(c) || c == '_'
isDigit := unicode.IsDigit(c)
if i == 0 && !isLetter {
return fmt.Errorf("invalid query name %q", name)
} else if !(isLetter || isDigit) {
return fmt.Errorf("invalid query name %q", name)
}
}
return nil
}
func Parse(t string, commentStyle CommentSyntax) (string, string, error) {
for _, line := range strings.Split(t, "\n") {
var prefix string
if strings.HasPrefix(line, "--") {
if !commentStyle.Dash {
continue
}
prefix = "--"
}
if strings.HasPrefix(line, "/*") {
if !commentStyle.SlashStar {
continue
}
prefix = "/*"
}
if strings.HasPrefix(line, "#") {
if !commentStyle.Hash {
continue
}
prefix = "#"
}
if prefix == "" {
continue
}
rest := line[len(prefix):]
if !strings.HasPrefix(strings.TrimSpace(rest), "name") {
continue
}
if !strings.Contains(rest, ":") {
continue
}
if !strings.HasPrefix(rest, " name: ") {
return "", "", fmt.Errorf("invalid metadata: %s", line)
}
part := strings.Split(strings.TrimSpace(line), " ")
if prefix == "/*" {
part = part[:len(part)-1] // removes the trailing "*/" element
}
if len(part) == 2 {
return "", "", fmt.Errorf("missing query type [':one', ':many', ':exec', ':execrows', ':execresult', ':copyfrom']: %s", line)
}
if len(part) != 4 {
return "", "", fmt.Errorf("invalid query comment: %s", line)
}
queryName := part[2]
queryType := strings.TrimSpace(part[3])
switch queryType {
case CmdOne, CmdMany, CmdExec, CmdExecResult, CmdExecRows, CmdCopyFrom:
default:
return "", "", fmt.Errorf("invalid query type: %s", queryType)
}
if err := validateQueryName(queryName); err != nil {
return "", "", err
}
return queryName, queryType, nil
}
return "", "", nil
}