Skip to content

Commit 2ff342c

Browse files
authored
Merge pull request #10 from hatch-is/update-filter
Update filter
2 parents aa8317d + 1da1de1 commit 2ff342c

File tree

28 files changed

+7617
-12
lines changed

28 files changed

+7617
-12
lines changed

Godeps/Godeps.json

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

filter/filter.go

Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,281 @@
1+
package filter
2+
3+
import (
4+
"reflect"
5+
"strconv"
6+
"strings"
7+
"time"
8+
"unicode"
9+
10+
"github.com/pquerna/ffjson/ffjson"
11+
"gopkg.in/mgo.v2/bson"
12+
)
13+
14+
const (
15+
id = "id"
16+
_id = "_id"
17+
desc = "desc"
18+
//ID ...
19+
ID = "ID"
20+
)
21+
22+
//Filter describe fiter query
23+
type Filter struct {
24+
skip int
25+
limit int
26+
query bson.M
27+
sort []string
28+
search string
29+
}
30+
31+
//BeforeFilter ...
32+
type BeforeFilter struct {
33+
Skip interface{}
34+
Limit interface{}
35+
Where map[string]interface{}
36+
Sort map[string]string
37+
Search string
38+
}
39+
40+
func (bf *BeforeFilter) getSort() []string {
41+
var sort []string
42+
sort = make([]string, 0)
43+
for key, value := range bf.Sort {
44+
if desc == strings.ToLower(value) {
45+
key = "-" + key
46+
}
47+
sort = append(sort, key)
48+
}
49+
return sort
50+
}
51+
52+
func (bf *BeforeFilter) getLimit() int {
53+
return convertParam(bf.Limit)
54+
}
55+
56+
func (bf *BeforeFilter) getSkip() int {
57+
return convertParam(bf.Skip)
58+
}
59+
60+
//convertParam to convert skip/limit to int
61+
//by default return 0
62+
func convertParam(param interface{}) int {
63+
var result int
64+
switch param.(type) {
65+
default:
66+
return int(0)
67+
case float64:
68+
result = int(param.(float64))
69+
case string:
70+
t, err := strconv.Atoi(param.(string))
71+
if err != nil {
72+
result = int(0)
73+
}
74+
result = t
75+
}
76+
if result < 0 {
77+
return int(0)
78+
}
79+
return result
80+
}
81+
82+
//GetSkip ...
83+
func (f *Filter) GetSkip() int {
84+
return f.skip
85+
}
86+
87+
//GetLimit ...
88+
func (f *Filter) GetLimit() int {
89+
return f.limit
90+
}
91+
92+
//GetSearch ...
93+
func (f *Filter) GetSearch() string {
94+
return f.search
95+
}
96+
97+
//GetSort ...
98+
func (f *Filter) GetSort() []string {
99+
return f.sort
100+
}
101+
102+
//GetQuery ...
103+
func (f *Filter) GetQuery() bson.M {
104+
return f.query
105+
}
106+
107+
//AddQuery ...
108+
func (f *Filter) AddQuery(q bson.M) {
109+
if f.query == nil {
110+
f.query = q
111+
} else {
112+
f.query["$and"] = append(f.query["$and"].([]bson.M), q)
113+
}
114+
}
115+
116+
//GetFilterData ...
117+
func GetFilterData(filter string, t interface{}) Filter {
118+
var f Filter
119+
if filter != "" {
120+
var tmp BeforeFilter
121+
ffjson.Unmarshal([]byte(filter), &tmp)
122+
f.limit = tmp.getLimit()
123+
f.skip = tmp.getSkip()
124+
f.sort = tmp.getSort()
125+
f.query = tmp.parseWhere(t)
126+
}
127+
return f
128+
}
129+
130+
func (bf *BeforeFilter) parseWhere(t interface{}) bson.M {
131+
var q bson.M
132+
for key, values := range bf.Where {
133+
if key == "and" || key == "or" {
134+
key = "$" + key
135+
q = parseAnd(key, values.([]interface{}), q, t)
136+
} else {
137+
q = parse(key, values, q, t)
138+
}
139+
}
140+
return q
141+
}
142+
143+
func parse(key string, values interface{}, q bson.M, t interface{}) bson.M {
144+
if key == id {
145+
key = _id
146+
}
147+
val := reflect.ValueOf(t)
148+
var fieldType string
149+
if val.FieldByName(convertName(key)).IsValid() == true {
150+
fieldType = val.FieldByName(convertName(key)).Type().String()
151+
if fieldType == "*time.Time" || fieldType == "time.Time" {
152+
if q == nil {
153+
q = bson.M{"$and": []bson.M{}}
154+
} else {
155+
if q["$and"] == nil {
156+
q["$and"] = []bson.M{}
157+
}
158+
}
159+
q = parseFilterDate("$and", key, values, q)
160+
}
161+
if fieldType == "bson.ObjectId" {
162+
q = parseID(key, values, q)
163+
}
164+
}
165+
return q
166+
}
167+
168+
func addKeyToQuery(key string, q bson.M) bson.M {
169+
if q == nil {
170+
q = bson.M{key: []bson.M{}}
171+
} else {
172+
q[key] = []bson.M{}
173+
}
174+
return q
175+
}
176+
177+
func parseID(key string, values interface{}, q bson.M) bson.M {
178+
q = addKeyToQuery(key, q)
179+
for field, data := range values.(map[string]interface{}) {
180+
ids := convertStringIDtoObjectID(data)
181+
if len(ids) > 0 {
182+
if field == "in" || field == "nin" || field == "all" {
183+
q[key] = bson.M{"$" + field: ids}
184+
}
185+
}
186+
}
187+
return q
188+
}
189+
190+
func parseAndIDData(key string, field string, data interface{}, q bson.M) bson.M {
191+
if field == id {
192+
field = _id
193+
}
194+
slice := data.(map[string]interface{})
195+
for k, value := range slice {
196+
IDS := convertStringIDtoObjectID(value)
197+
if len(IDS) > 0 {
198+
if k == "in" || k == "nin" || k == "all" {
199+
q[key] = append(q[key].([]bson.M), bson.M{field: bson.M{"$" + k: IDS}})
200+
}
201+
}
202+
}
203+
return q
204+
}
205+
206+
func convertStringIDtoObjectID(data interface{}) []bson.ObjectId {
207+
var ids []bson.ObjectId
208+
ids = make([]bson.ObjectId, 0)
209+
switch data.(type) {
210+
case []interface{}:
211+
ids = prepareIDSArray(data.([]interface{}))
212+
case string:
213+
ids = prepareInIds(data.(string))
214+
}
215+
return ids
216+
}
217+
218+
func prepareIDSArray(values []interface{}) []bson.ObjectId {
219+
var ids []bson.ObjectId
220+
ids = make([]bson.ObjectId, 0)
221+
for _, id := range values {
222+
ids = append(ids, bson.ObjectIdHex(id.(string)))
223+
}
224+
return ids
225+
}
226+
227+
func parseAnd(key string, values []interface{}, q bson.M, t interface{}) bson.M {
228+
val := reflect.ValueOf(t)
229+
if q == nil {
230+
q = bson.M{key: []bson.M{}}
231+
} else {
232+
q[key] = []bson.M{}
233+
}
234+
for _, value := range values {
235+
for field, data := range value.(map[string]interface{}) {
236+
fieldName := convertName(field)
237+
var fieldType string
238+
if val.FieldByName(fieldName).IsValid() == true {
239+
fieldType = val.FieldByName(fieldName).Type().String()
240+
if fieldType == "*time.Time" || fieldType == "time.Time" {
241+
q = parseFilterDate(key, field, data, q)
242+
}
243+
if fieldType == "bson.ObjectId" {
244+
q = parseAndIDData(key, field, data, q)
245+
}
246+
}
247+
}
248+
}
249+
return q
250+
}
251+
252+
func convertName(name string) string {
253+
if name == id || name == _id {
254+
return ID
255+
}
256+
newName := []rune(name)
257+
newName[0] = unicode.ToUpper(newName[0])
258+
return string(newName)
259+
}
260+
261+
func parseFilterDate(key string, field string, data interface{}, q bson.M) bson.M {
262+
for k, v := range data.(map[string]interface{}) {
263+
if k == "lte" || k == "lt" || k == "gte" || k == "gt" {
264+
t, err := time.Parse(time.RFC3339, v.(string))
265+
if err == nil {
266+
q[key] = append(q[key].([]bson.M), bson.M{field: bson.M{"$" + k: t}})
267+
}
268+
}
269+
}
270+
return q
271+
}
272+
273+
func prepareInIds(sID string) []bson.ObjectId {
274+
var ids []bson.ObjectId
275+
ids = make([]bson.ObjectId, 0)
276+
IDs := strings.Split(sID, ",")
277+
for _, id := range IDs {
278+
ids = append(ids, bson.ObjectIdHex(id))
279+
}
280+
return ids
281+
}

model/articles.go

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package model
33
import (
44
"encoding/json"
55
"io"
6+
"knowledge-base/filter"
67
"knowledge-base/store"
78
"strconv"
89

@@ -17,18 +18,15 @@ type ArticlesModel struct{}
1718
//Read get articles
1819
func (artModel *ArticlesModel) Read(qFilter string) (result []store.Article, total int, left int, err error) {
1920
artDb := store.ArticlesCollectionConnect()
21+
result = make([]store.Article, 0)
2022

21-
query, isSort, err := artModel.convertFilter(qFilter)
22-
if err != nil {
23-
return
24-
}
25-
skip, limit := getSkipLimit(qFilter)
26-
query["deleted"] = false
27-
if isSort == false {
23+
f := filter.GetFilterData(qFilter, store.Article{})
24+
25+
if f.GetSearch() == "" {
2826
fields := bson.M{}
29-
result, total, left, err = artDb.Read(query, fields, skip, limit)
27+
result, total, left, err = artDb.Read(f.GetQuery(), fields, f.GetSkip(), f.GetLimit(), f.GetSort())
3028
} else {
31-
result, total, left, err = artDb.Search(query, skip, limit)
29+
result, total, left, err = artDb.Search(f.GetQuery(), f.GetSkip(), f.GetLimit())
3230
}
3331

3432
if err != nil {

store/articles.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,15 @@ func ArticlesCollectionConnect() *ArticlesCollection {
5151
}
5252

5353
//Read return entries of Articles collections
54-
func (art *ArticlesCollection) Read(query bson.M, fields bson.M, skip int, limit int) (result []Article, total int, left int, err error) {
54+
func (art *ArticlesCollection) Read(query bson.M, fields bson.M, skip int, limit int, sort []string) (result []Article, total int, left int, err error) {
5555
session, artCollection, err := art.conn.getSessionAndCollection(art.collection)
5656
if err != nil {
5757
return
5858
}
5959
defer session.Close()
60+
query = checkUpdated(query)
6061
result = make([]Article, 0)
61-
err = artCollection.Find(query).Select(fields).Skip(skip).Limit(limit).All(&result)
62+
err = artCollection.Find(query).Select(fields).Skip(skip).Limit(limit).Sort(sort...).All(&result)
6263
if err != nil {
6364
return
6465
}
@@ -174,7 +175,7 @@ func (art *ArticlesCollection) Search(q bson.M, skip int, limit int) (result []A
174175
return
175176
}
176177
defer session.Close()
177-
178+
q = checkUpdated(q)
178179
fields := bson.M{
179180
"score": bson.M{
180181
"$meta": "textScore",

store/db.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66

77
"gopkg.in/mgo.v2"
8+
"gopkg.in/mgo.v2/bson"
89
//"gopkg.in/mgo.v2/bson"
910
"knowledge-base/conf"
1011
)
@@ -59,3 +60,12 @@ func (c *MongoConnection) getSessionAndCollection(collectionName string) (sessio
5960
}
6061
return
6162
}
63+
64+
func checkUpdated(q bson.M) bson.M {
65+
if q == nil {
66+
q = bson.M{"deleted": false}
67+
} else if q["deleted"] == nil {
68+
q["deleted"] = false
69+
}
70+
return q
71+
}

0 commit comments

Comments
 (0)