forked from infobloxopen/atlas-app-toolkit
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcollection_operators.go
132 lines (116 loc) · 3.5 KB
/
collection_operators.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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package gorm
import (
"context"
"fmt"
"strings"
"github.com/golang/protobuf/proto"
"github.com/jinzhu/gorm"
"github.com/infobloxopen/atlas-app-toolkit/query"
)
// ApplyCollectionOperators applies collection operators to gorm instance db.
func ApplyCollectionOperators(ctx context.Context, db *gorm.DB, obj interface{}, pb proto.Message, f *query.Filtering, s *query.Sorting, p *query.Pagination, fs *query.FieldSelection) (*gorm.DB, error) {
db, fAssocToJoin, err := ApplyFiltering(ctx, db, f, obj, pb)
if err != nil {
return nil, err
}
db, sAssocToJoin, err := ApplySorting(ctx, db, s, obj)
if err != nil {
return nil, err
}
if fAssocToJoin == nil && sAssocToJoin != nil {
fAssocToJoin = make(map[string]struct{})
}
for k := range sAssocToJoin {
fAssocToJoin[k] = struct{}{}
}
db, err = JoinAssociations(ctx, db, fAssocToJoin, obj)
if err != nil {
return nil, err
}
db = ApplyPagination(ctx, db, p)
db, err = ApplyFieldSelection(ctx, db, fs, obj)
if err != nil {
return nil, err
}
return db, nil
}
// ApplyFiltering applies filtering operator f to gorm instance db.
func ApplyFiltering(ctx context.Context, db *gorm.DB, f *query.Filtering, obj interface{}, pb proto.Message) (*gorm.DB, map[string]struct{}, error) {
str, args, assocToJoin, err := FilteringToGorm(ctx, f, obj, pb)
if err != nil {
return nil, nil, err
}
if str != "" {
return db.Where(str, args...), assocToJoin, nil
}
return db, nil, nil
}
// ApplySorting applies sorting operator s to gorm instance db.
func ApplySorting(ctx context.Context, db *gorm.DB, s *query.Sorting, obj interface{}) (*gorm.DB, map[string]struct{}, error) {
var crs []string
var assocToJoin map[string]struct{}
for _, cr := range s.GetCriterias() {
dbName, assoc, err := HandleFieldPath(ctx, strings.Split(cr.GetTag(), "."), obj)
if err != nil {
return nil, nil, err
}
if assoc != "" {
if assocToJoin == nil {
assocToJoin = make(map[string]struct{})
}
assocToJoin[assoc] = struct{}{}
}
if cr.IsDesc() {
crs = append(crs, dbName+" desc")
} else {
crs = append(crs, dbName)
}
}
if len(crs) == 0 {
return db, nil, nil
}
return db.Order(strings.Join(crs, ",")), assocToJoin, nil
}
// JoinAssociations joins obj's associations from assoc to the current gorm query.
func JoinAssociations(ctx context.Context, db *gorm.DB, assoc map[string]struct{}, obj interface{}) (*gorm.DB, error) {
for k := range assoc {
tableName, sourceKeys, targetKeys, err := JoinInfo(ctx, obj, k)
if err != nil {
return nil, err
}
var keyPairs []string
for i, k := range sourceKeys {
keyPairs = append(keyPairs, k+" = "+targetKeys[i])
}
alias := gorm.ToDBName(k)
join := fmt.Sprintf("LEFT JOIN %s %s ON %s", tableName, alias, strings.Join(keyPairs, " AND "))
db = db.Joins(join)
}
return db, nil
}
// ApplyPagination applies pagination operator p to gorm instance db.
func ApplyPagination(ctx context.Context, db *gorm.DB, p *query.Pagination) *gorm.DB {
if p != nil {
if p.GetOffset() > 0 {
db = db.Offset(p.GetOffset())
}
if p.GetLimit() > 0 {
db = db.Limit(p.GetLimit())
}
}
return db
}
// ApplyFieldSelection applies field selection operator fs to gorm instance db.
func ApplyFieldSelection(ctx context.Context, db *gorm.DB, fs *query.FieldSelection, obj interface{}) (*gorm.DB, error) {
toPreload, err := FieldSelectionToGorm(ctx, fs, obj)
if err != nil {
return nil, err
}
for _, assoc := range toPreload {
db, err = preload(db, obj, assoc)
if err != nil {
return nil, err
}
}
return db, nil
}