Skip to content

Commit 0898372

Browse files
authored
Merge pull request #1 from dennigogo/added-filter-list-with-query-parser
added possibility to use unique filter in several places
2 parents 21e38bf + 586157a commit 0898372

File tree

6 files changed

+238
-94
lines changed

6 files changed

+238
-94
lines changed

filter_test.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,52 @@
11
package rqp
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func Test_Where(t *testing.T) {
10+
t.Run("ErrUnknownMethod", func(t *testing.T) {
11+
filter := Filter{
12+
Key: "id[not]",
13+
Name: "id",
14+
Method: NOT,
15+
Or: true,
16+
}
17+
_, err := filter.Where()
18+
assert.Equal(t, err, ErrUnknownMethod)
19+
20+
filter = Filter{
21+
Key: "id[fake]",
22+
Name: "id",
23+
Method: "fake",
24+
Or: true,
25+
}
26+
_, err = filter.Where()
27+
assert.Equal(t, err, ErrUnknownMethod)
28+
})
29+
}
30+
31+
func Test_Args(t *testing.T) {
32+
t.Run("ErrUnknownMethod", func(t *testing.T) {
33+
filter := Filter{
34+
Key: "id[not]",
35+
Name: "id",
36+
Method: NOT,
37+
Or: true,
38+
Value: "id",
39+
}
40+
_, err := filter.Args()
41+
assert.Equal(t, err, ErrUnknownMethod)
42+
43+
filter = Filter{
44+
Key: "id[fake]",
45+
Name: "id",
46+
Method: "fake",
47+
Or: true,
48+
}
49+
_, err = filter.Args()
50+
assert.Equal(t, err, ErrUnknownMethod)
51+
})
52+
}

go.mod

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@ module github.com/timsolov/rest-query-parser
33
go 1.13
44

55
require (
6-
github.com/josharian/impl v0.0.0-20191119165012-6b9658ad00c7 // indirect
76
github.com/pkg/errors v0.9.1
87
github.com/stretchr/testify v1.5.1
9-
golang.org/x/mod v0.3.0 // indirect
10-
golang.org/x/tools v0.0.0-20200515220128-d3bf790afa53 // indirect
118
)

go.sum

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,12 @@
11
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
22
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3-
github.com/josharian/impl v0.0.0-20191119165012-6b9658ad00c7 h1:dhk1N6iuFDo1Lcew31sAQxrh8GVWaw0xu0MWNnMc6ao=
4-
github.com/josharian/impl v0.0.0-20191119165012-6b9658ad00c7/go.mod h1:t4Tr0tn92eq5ISef4cS5plFAMYAqZlAXtgUcKE6y8nw=
53
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
64
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
75
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
86
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
97
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
10-
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
11-
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
128
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
139
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
14-
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
15-
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
16-
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
17-
golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
18-
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
19-
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
20-
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
21-
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
22-
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
23-
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
24-
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
25-
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
26-
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
27-
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
28-
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
29-
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
30-
golang.org/x/tools v0.0.0-20200515220128-d3bf790afa53 h1:vmsb6v0zUdmUlXfwKaYrHPPRCV0lHq/IwNIf0ASGjyQ=
31-
golang.org/x/tools v0.0.0-20200515220128-d3bf790afa53/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
32-
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
33-
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
34-
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
35-
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
3610
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
3711
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
3812
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=

main.go

Lines changed: 110 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ type Query struct {
1818
Offset int
1919
Limit int
2020
Sorts []Sort
21-
Filters []*Filter
21+
Filters [][]*Filter
2222

2323
delimiterIN string
2424
delimiterOR string
@@ -219,9 +219,11 @@ func (q *Query) AddSortBy(by string, desc bool) *Query {
219219
// HaveFilter returns true if request contains some filter
220220
func (q *Query) HaveFilter(name string) bool {
221221

222-
for _, v := range q.Filters {
223-
if v.Name == name {
224-
return true
222+
for _, filters := range q.Filters {
223+
for _, v := range filters {
224+
if v.Name == name {
225+
return true
226+
}
225227
}
226228
}
227229

@@ -230,27 +232,31 @@ func (q *Query) HaveFilter(name string) bool {
230232

231233
// AddFilter adds a filter to Query
232234
func (q *Query) AddFilter(name string, m Method, value interface{}) *Query {
233-
q.Filters = append(q.Filters, &Filter{
234-
Name: name,
235-
Method: m,
236-
Value: value,
235+
q.Filters = append(q.Filters, []*Filter{
236+
{
237+
Name: name,
238+
Method: m,
239+
Value: value,
240+
},
237241
})
238242
return q
239243
}
240244

241245
// RemoveFilter removes the filter by name
242246
func (q *Query) RemoveFilter(name string) error {
243247

244-
for i, v := range q.Filters {
245-
if v.Name == name {
246-
// safe remove element from slice
247-
if i < len(q.Filters)-1 {
248-
copy(q.Filters[i:], q.Filters[i+1:])
249-
}
250-
q.Filters[len(q.Filters)-1] = nil
251-
q.Filters = q.Filters[:len(q.Filters)-1]
248+
for key, filters := range q.Filters {
249+
for i, v := range filters {
250+
if v.Name == name {
251+
// safe remove element from slice
252+
if i < len(q.Filters[key])-1 {
253+
copy(q.Filters[key][i:], q.Filters[key][i+1:])
254+
}
255+
q.Filters[key][len(q.Filters[key])-1] = nil
256+
q.Filters[key] = q.Filters[key][:len(q.Filters[key])-1]
252257

253-
return nil
258+
return nil
259+
}
254260
}
255261
}
256262

@@ -289,9 +295,11 @@ func (q *Query) RemoveValidation(NameAndOrTags string) error {
289295
// GetFilter returns filter by name
290296
func (q *Query) GetFilter(name string) (*Filter, error) {
291297

292-
for _, v := range q.Filters {
293-
if v.Name == name {
294-
return v, nil
298+
for _, filters := range q.Filters {
299+
for _, v := range filters {
300+
if v.Name == name {
301+
return v, nil
302+
}
295303
}
296304
}
297305

@@ -313,9 +321,11 @@ type Replacer map[string]string
313321
func (q *Query) ReplaceNames(r Replacer) {
314322

315323
for name, newname := range r {
316-
for i, v := range q.Filters {
317-
if v.Name == name {
318-
q.Filters[i].Name = newname
324+
for key, filters := range q.Filters {
325+
for i, v := range filters {
326+
if v.Name == name {
327+
q.Filters[key][i].Name = newname
328+
}
319329
}
320330
}
321331
for i, v := range q.Fields {
@@ -340,55 +350,74 @@ func (q *Query) Where() string {
340350
return ""
341351
}
342352

353+
var whereList []string
354+
343355
var where string
344-
var OR bool = false
356+
var OR bool
345357

346-
for i := 0; i < len(q.Filters); i++ {
347-
filter := q.Filters[i]
358+
for key := range q.Filters {
359+
where = ""
360+
OR = false
361+
if len(q.Filters[key]) == 0 {
362+
continue
363+
}
364+
for i := 0; i < len(q.Filters[key]); i++ {
365+
filter := q.Filters[key][i]
348366

349-
prefix := ""
350-
suffix := ""
367+
prefix := ""
368+
suffix := ""
351369

352-
if filter.Or && !OR {
353-
if i == 0 {
354-
prefix = "("
370+
if filter.Or && !OR {
371+
if i == 0 {
372+
prefix = "("
373+
} else {
374+
prefix = " AND ("
375+
}
376+
OR = true
377+
} else if filter.Or && OR {
378+
prefix = " OR "
379+
// if last element of next element not OR method
380+
if i+1 == len(q.Filters[key]) || (i+1 < len(q.Filters[key]) && !q.Filters[key][i+1].Or) {
381+
suffix = ")"
382+
OR = false
383+
}
355384
} else {
356-
prefix = " AND ("
357-
}
358-
OR = true
359-
} else if filter.Or && OR {
360-
prefix = " OR "
361-
// if last element of next element not OR method
362-
if i+1 == len(q.Filters) || (i+1 < len(q.Filters) && !q.Filters[i+1].Or) {
363-
suffix = ")"
364-
OR = false
385+
if i > 0 {
386+
prefix = " AND "
387+
}
365388
}
366-
} else {
367-
if i > 0 {
368-
prefix = " AND "
389+
390+
if a, err := filter.Where(); err == nil {
391+
where += fmt.Sprintf("%s%s%s", prefix, a, suffix)
392+
} else {
393+
continue
369394
}
370395
}
371-
372-
if a, err := filter.Where(); err == nil {
373-
where += fmt.Sprintf("%s%s%s", prefix, a, suffix)
374-
} else {
375-
continue
396+
if where != "" {
397+
whereList = append(whereList, where)
376398
}
399+
}
377400

401+
if len(whereList) == 0 {
402+
return ""
378403
}
379404

380-
return where
405+
return strings.Join(whereList, " AND ")
381406
}
382407

383408
// WHERE returns list of filters for WHERE SQL statement with `WHERE` word
384409
// return example: `WHERE id > 0 AND email LIKE 'some@email.com'`
385410
func (q *Query) WHERE() string {
386-
387411
if len(q.Filters) == 0 {
388412
return ""
389413
}
390414

391-
return " WHERE " + q.Where()
415+
where := q.Where()
416+
if where == "" {
417+
return ""
418+
}
419+
420+
return " WHERE " + where
392421
}
393422

394423
// Args returns slice of arguments for WHERE statement
@@ -400,14 +429,20 @@ func (q *Query) Args() []interface{} {
400429
return args
401430
}
402431

403-
for i := 0; i < len(q.Filters); i++ {
404-
filter := q.Filters[i]
405-
406-
if a, err := filter.Args(); err == nil {
407-
args = append(args, a...)
408-
} else {
432+
for key := range q.Filters {
433+
if len(q.Filters[key]) == 0 {
409434
continue
410435
}
436+
437+
for i := 0; i < len(q.Filters[key]); i++ {
438+
filter := q.Filters[key][i]
439+
440+
if a, err := filter.Args(); err == nil {
441+
args = append(args, a...)
442+
} else {
443+
continue
444+
}
445+
}
411446
}
412447

413448
return args
@@ -503,11 +538,14 @@ func (q *Query) Parse() (err error) {
503538
err = q.parseSort(values, q.validations[low])
504539
delete(requiredNames, low)
505540
default:
506-
if len(values) != 1 {
541+
if len(values) == 0 {
507542
return errors.Wrap(ErrBadFormat, key)
508543
}
509-
if err = q.parseFilter(key, values[0]); err != nil {
510-
return err
544+
545+
for i := 0; i < len(values); i++ {
546+
if err = q.parseFilter(key, values[i]); err != nil {
547+
return err
548+
}
511549
}
512550
}
513551

@@ -576,6 +614,8 @@ func (q *Query) parseFilter(key, value string) error {
576614
return errors.Wrap(ErrEmptyValue, key)
577615
}
578616

617+
filters := make([]*Filter, 0)
618+
579619
if strings.Contains(value, q.delimiterOR) { // OR multiple filter
580620
parts := strings.Split(value, q.delimiterOR)
581621
for i, v := range parts {
@@ -609,7 +649,7 @@ func (q *Query) parseFilter(key, value string) error {
609649
// set OR
610650
filter.Or = true
611651

612-
q.Filters = append(q.Filters, filter)
652+
filters = append(filters, filter)
613653
}
614654
} else { // Single filter
615655
filter, err := newFilter(key, value, q.delimiterIN, q.validations)
@@ -623,20 +663,26 @@ func (q *Query) parseFilter(key, value string) error {
623663
return errors.Wrap(err, key)
624664
}
625665

626-
q.Filters = append(q.Filters, filter)
666+
filters = append(filters, filter)
627667
}
628668

669+
q.Filters = append(q.Filters, filters)
670+
629671
return nil
630672
}
631673

632674
// clean the filters slice
633675
func (q *Query) cleanFilters() {
634676
if len(q.Filters) > 0 {
635-
for i := range q.Filters {
636-
q.Filters[i] = nil
677+
for key := range q.Filters {
678+
for i := range q.Filters[key] {
679+
q.Filters[key][i] = nil
680+
}
681+
q.Filters[key] = nil
637682
}
638683
q.Filters = nil
639684
}
685+
q.Filters = make([][]*Filter, 0)
640686
}
641687

642688
func (q *Query) parseSort(value []string, validate ValidationFunc) error {

0 commit comments

Comments
 (0)