/
query.go
114 lines (97 loc) · 2.26 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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package goquery
import (
"math"
"reflect"
"strings"
"github.com/jinzhu/gorm"
)
type DBSupplier = func() *gorm.DB
func BuildPagedQuery(entity interface{}) PagedQueryFunc {
return BuildPagedQueryWithDBSupplier(DB, entity)
}
func BuildPagedQueryWithDB(db *gorm.DB, entity interface{}) PagedQueryFunc {
supplier := func() *gorm.DB { return db }
return BuildPagedQueryWithDBSupplier(supplier, entity)
}
// BuildPagedQueryWithDBSupplier
// eg:
// entity: &Person{}
// PagedQueryFunc returns []*Person
func BuildPagedQueryWithDBSupplier(supplier DBSupplier, entity interface{}) PagedQueryFunc {
cols := parseDBCols(entity)
colsFilter := ContainStringFilter(cols...)
return func(qReq *QReq) (*PageWrap, error) {
db := supplier()
pw := &PageWrap{}
out := reflect.New(reflect.SliceOf(reflect.TypeOf(entity))).Interface()
preds := parseQueryMap(qReq.Q)
limit := qReq.Size
if limit <= 0 {
limit = 20
} else if limit > 200 {
limit = 200
}
page := qReq.Page
if page <= 0 {
page = 1
}
var count int64
q := db.Model(out)
for _, p := range preds {
if colsFilter(p.Col) {
q = p.Apply(q)
}
}
err := q.Count(&count).Error
if err != nil {
return nil, err
}
pages := int64(math.Ceil(float64(count) / float64(limit)))
pw.Total = count
pw.Size = limit
pw.Page = qReq.Page
pw.Pages = pages
// sort
for _, srt := range qReq.Sort {
if col := strings.TrimLeft(srt, "+-"); colsFilter(col) {
if strings.HasPrefix(srt, "-") {
q = q.Order(col + " desc")
} else {
q = q.Order(col)
}
}
}
offset := (qReq.Page - 1) * limit
q = q.Offset(offset).Limit(limit)
err = q.Find(out).Error
if err != nil {
return nil, err
}
sliceOut := reflect.ValueOf(out).Elem().Interface()
pw.Data = sliceOut
return pw, nil
}
}
func parseQueryMap(qm map[string]string) []*Predicate {
var res []*Predicate
for k, v := range qm {
col, op := parseOp(k)
cond := &Cond{Col: col, Op: op, Val: v}
pred := cond.ToPredicate()
if pred != nil {
res = append(res, pred)
}
}
return res
}
func parseDBCols(entity interface{}) []string {
var res []string
sc := gorm.Scope{Value: entity}
ms := sc.GetModelStruct()
for _, f := range ms.StructFields {
if !f.IsIgnored {
res = append(res, f.DBName)
}
}
return res
}