-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbuild.go
104 lines (97 loc) · 2.48 KB
/
build.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
package sqlf
import (
"fmt"
"strings"
"github.com/qjebbs/go-sqlf/v2/syntax"
)
var _ FragmentBuilder = (*Fragment)(nil)
var _ QueryBuilder = (*Fragment)(nil)
// BuildQuery builds the fragment as full query.
func (f *Fragment) BuildQuery(bindVarStyle syntax.BindVarStyle) (query string, args []any, err error) {
ctx := NewContext(bindVarStyle)
query, err = f.BuildFragment(ctx)
if err != nil {
return "", nil, err
}
args = ctx.Args()
return query, args, nil
}
// BuildFragment builds the fragment with context.
func (f *Fragment) BuildFragment(ctx *Context) (string, error) {
if f == nil {
return "", nil
}
if ctx == nil {
return "", fmt.Errorf("nil context")
}
ctx = contextWithFragment(ctx, f)
body, err := build(ctx, f)
if err != nil {
return "", err
}
fc, err := ctx.mustFragment()
if err != nil {
return "", err
}
if err := fc.checkUsage(); err != nil {
return "", fmt.Errorf("build '%s': %w", f.Raw, err)
}
body = strings.TrimSpace(body)
if body == "" {
return "", nil
}
header, footer := "", ""
if f.Prefix != "" {
header = f.Prefix + " "
}
if f.Suffix != "" {
footer = " " + f.Suffix
}
return header + body + footer, nil
}
// build builds the fragment
func build(ctx *Context, fragment *Fragment) (string, error) {
clause, err := syntax.Parse(fragment.Raw)
if err != nil {
return "", fmt.Errorf("parse '%s': %w", fragment.Raw, err)
}
built, err := buildClause(ctx, clause)
if err != nil {
return "", fmt.Errorf("build '%s': %w", fragment.Raw, err)
}
return built, nil
}
// buildClause builds the parsed clause within current context.
func buildClause(ctx *Context, clause *syntax.Clause) (string, error) {
b := new(strings.Builder)
for _, decl := range clause.ExprList {
switch expr := decl.(type) {
case *syntax.PlainExpr:
b.WriteString(expr.Text)
case *syntax.BindVarExpr:
fc, err := ctx.mustFragment()
if err != nil {
return "", err
}
if expr.Index < 1 || expr.Index > len(fc.Args) {
return "", fmt.Errorf("invalid bind var index %d", expr.Index)
}
s, err := fc.Args[expr.Index-1].BuildFragment(ctx)
if err != nil {
return "", err
}
b.WriteString(s)
case *syntax.FuncCallExpr:
s, err := evalFunction(ctx, expr.Name, expr.Args)
if err != nil {
return "", err
}
b.WriteString(s)
case *syntax.FuncExpr:
return "", fmt.Errorf("unexpected function value at %s, forgot to call it?", expr.Pos())
default:
return "", fmt.Errorf("unknown expression type %T", expr)
}
}
return b.String(), nil
}