-
Notifications
You must be signed in to change notification settings - Fork 0
/
query.go
96 lines (81 loc) · 1.98 KB
/
query.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
package structquery
import (
"errors"
"fmt"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
)
type QueryType string
type QueryerFunc func(f Field) clause.Expression
type Queryer struct {
Namer schema.Namer
queryFns map[QueryType]QueryerFunc
}
func NewQueryer() *Queryer {
q := &Queryer{
queryFns: make(map[QueryType]QueryerFunc),
Namer: schema.NamingStrategy{}, // default gorm namer
}
registerBuiltin(q)
return q
}
func (q *Queryer) Register(t QueryType, fn QueryerFunc) {
q.queryFns[t] = fn
}
var (
ErrBadQueryValue = errors.New("structquery: query must be struct or a pointer to struct")
ErrBadQueryType = errors.New("structquery: query type not registered")
)
func (q *Queryer) Where(db *gorm.DB, value interface{}) (*gorm.DB, error) {
expr, err := q.And(value)
if err != nil {
return db, err
}
return db.Where(expr), nil
}
func (q *Queryer) And(value interface{}) (clause.Expression, error) {
exprs, err := q.toExprs(value)
if err != nil {
return nil, err
}
return clause.And(exprs...), nil
}
func (q *Queryer) Or(value interface{}) (clause.Expression, error) {
exprs, err := q.toExprs(value)
if err != nil {
return nil, err
}
return clause.Or(exprs...), nil
}
func (q *Queryer) toExprs(value interface{}) ([]clause.Expression, error) {
fields, err := ParseStruct(value)
if err != nil {
return nil, err
}
return q.translate(fields)
}
func (q *Queryer) translate(fields []*Field) ([]clause.Expression, error) {
var exprs []clause.Expression
for _, field := range fields {
if field.QueryType == "" {
continue
}
queryType := field.QueryType
fn, ok := q.queryFns[queryType]
if !ok {
return nil, fmt.Errorf("%w:%s ", ErrBadQueryType, queryType)
}
f := *field
// get column name from options
f.ColumnName = f.Options[OptionColumn]
if f.ColumnName == "" {
f.ColumnName = q.Namer.ColumnName(f.Options[OptionTable], field.Name)
}
expr := fn(f)
if expr != nil {
exprs = append(exprs, expr)
}
}
return exprs, nil
}