diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..e7e9d11
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,2 @@
+# Default ignored files
+/workspace.xml
diff --git a/.idea/gokendoparser.iml b/.idea/gokendoparser.iml
new file mode 100644
index 0000000..5e764c4
--- /dev/null
+++ b/.idea/gokendoparser.iml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..28a804d
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..08c8ab2
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index df38532..ee65010 100644
--- a/README.md
+++ b/README.md
@@ -1,47 +1,70 @@
-![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/raditzlawliet/gokendoparser.svg?label=release)
-![Codecov](https://img.shields.io/codecov/c/github/raditzlawliet/gokendoparser.svg)
-[![](https://godoc.org/github.com/raditzlawliet/gokendoparser?status.svg)](http://godoc.org/github.com/raditzlawliet/gokendoparser)
-[![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/raditzlawliet/gokendoparser/issues)
-
-
-# Go Kendo Parser
-Your Golang Kendo parser, parsing Kendo data source request to golang struct immediately. Available parser to
+![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/raditzlawliet/kendoparser.svg?label=release)
+![Codecov](https://img.shields.io/codecov/c/github/raditzlawliet/kendoparser.svg)
+[![](https://godoc.org/github.com/raditzlawliet/kendoparser?status.svg)](http://godoc.org/github.com/raditzlawliet/kendoparser)
+[![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/raditzlawliet/kendoparser/issues)
+
+
+# Golang Kendo Parser (v 1.*)
+Parsing Kendo DataSource filter & sort request to any kind of data in go that can immediately serve to mongo query or aggregate and other ORMs. Already used in EACIIT's environment and can be scale-able for generic purpose. Currently there are few parser available:
+- [mongo-go-driver Filter](https://github.com/mongodb/mongo-go-driver/) (mainly used for primary test)
- [eaciit/dbox Filter](https://github.com/eaciit/dbox)
- [eaciit/dbox Pipe or Aggregation type](https://github.com/eaciit/dbox)
- sebar/dbflex Filter
-- [mongo-go-driver Filter](https://github.com/mongodb/mongo-go-driver/)
- [xorm/builder Filter](https://gitea.com/xorm/builder/) This builder have nice ToSQL function, so you can transform into SQL
## Features
-- Convert kendo datasource request into go struct
-- Basic Operator
-- Transform filter + Chaining
-- Plugable operator handler
-- Parser Sort
-- Custom pre-filter / before parse handler
-- Extendable to any result
+- Parse Kendo DataSource request into go struct
+- Parse Kendo DataSource request into filter & sort database / orm-ish
+- Transforming filter + Chaining
+- Customizable filter operator
+- Additional Pre-parse filter
+- Adaptor based, customizable parse into other generic purpose
+- Kendo Request Wrapper
+- Go mod support
## Getting Started
-Go get, import, use
+- Install
+```sh
+go get -v raditzlawliet/kendoparser
+```
+
+- Import
+```go
+import (
+ kp "github.com/raditzlawliet/kendoparser"
+ kpmongo "github.com/raditzlawliet/kendoparser/parser/kpmongo"
+)
+```
+- Use
+```go
+request := struct {
+ Filter kp.Filter,
+ Sort kp.Sort,
+}{}
-### Parse Filter
-#### JSON Sample
+filter := request.Filter.Parse(kpmongo.FilterParser)
+sort := request.Sort.Parse(kpmongo.SortParser)
+```
+#### How to use Parse Filter
+- JSON Sample
```json
{
"data": {
"filter": {
"field": "id",
"operator": "eq",
- "value": "val",
+ "value": "val"
}
}
}
```
-#### GO Implementation
+- GO Implementation
```go
-import kpmgo "github.com/raditzlawliet/gokendoparser/adapter/mgo"
+import kpmongo "github.com/raditzlawliet/kendoparser/parser/kpmongo"
+```
+```go
// just for information
// you can use gorilla mux or knot
var k = k *knot.WebContext
@@ -59,11 +82,11 @@ payload := KendoRequest {
},
}
-filter := payload.Data.Filter.Parse(kpmongo.ParseFilter)
-sort := payload.Data.Sort.Parse(kpmongo.ParseSort)
+filter := payload.Data.Filter.Parse(kpmongo.FilterParser)
+sort := payload.Data.Sort.Parse(kpmongo.SortParser)
```
-#### More JSON
+- More Example
```json
{
"data": {
@@ -72,14 +95,14 @@ sort := payload.Data.Sort.Parse(kpmongo.ParseSort)
"filter": {
"field": "id",
"operator": "eq",
- "value": "val",
+ "value": "val"
}
},
{
"filter": {
"field": "abc",
"operator": "in",
- "values": ["a", "b"],
+ "values": ["a", "b"]
}
}
],
@@ -88,7 +111,7 @@ sort := payload.Data.Sort.Parse(kpmongo.ParseSort)
}
```
```go
-import kpmgo "github.com/raditzlawliet/gokendoparser/adapter/mgo"
+import kpmongo "github.com/raditzlawliet/kendoparser/parser/kpmongo"
// just for information
// you can use gorilla mux or knot
var k = k *knot.WebContext
@@ -97,7 +120,7 @@ var k = k *knot.WebContext
payload := &KendoRequest{}
k.GetPayload(payload)
-// Usually payload the struct will be this
+// Usually payload the struct will be like this
payload := KendoRequest {
Data: KendoData{
Filter: KendoFilter{
@@ -113,48 +136,95 @@ payload := KendoRequest {
},
}
-filter := payload.Data.Filter.Parse(kpmongo.ParseFilter)
-sort := payload.Data.Sort.Parse(kpmongo.ParseSort)
+filter := payload.Data.Filter.Parse(kpmongo.FilterParser)
+sort := payload.Data.Sort.Parse(kpmongo.SortParser)
```
+#### Available Parser & Operator Manager - Filters
+- [kpmongo - mongo-go-driver](./parser/mongo)
+ - equal, notequal, equaldate, notequaldate, contain, notcontain, in, notin, gt, lt, gte, lte, gtdate, ltdate, gtedate, ltedate, exists, dateexists, between
+- [kpdbox - eaciit/dbox](./parser/dbox)
+ - equal, notequal, contain, notcontain, in, gt, lt, gte, lte, gtedate, ltedate, exists, between
+- [kpdboxpipe - eaciit/dbox](./parser/dboxpipe)
+ - equal, notequal, contain, notcontain, in, gt, lt, gte, lte, gtedate, ltedate, exists, between
+- [kpdbflex - sebar/dbflex](./parser/dbflex)
+ - equal, notequal, contain, notcontain, in, gt, lt, gte, lte, gtedate, ltedate, exists, between
+- [kpxorm - xorm/builder](./parser/xorm)
+ - equal, notequal, contain, notcontain, in, gt, lt, gte, lte, gtedate, ltedate, exists, between
+
+#### Operator Manager
+_Operator Manager_ mainly used for filter parser to parsing the data based on operator. In available parser they also have each _Operator Manager_.
+You also can create your own _Operator Manager_ and you can also set scoped _Operator Manager_ for spesific payload
+
+- Extending Existing Operator Manager
-### Extend & Hook custom operator handler
-By default, package already registerd with basic operator such as
-- Equal
-- Not Equal
-- Contain
-- Not Contain
-- In
-- Gte
-- Lte
-- Gte Date
-- Lte Date
-- Exists
-
-But if you want to add custom operator that didn't exists yet, you can register in manually (for sample you can see [operator.go](adapter/mongo/operator.go)). Please ensure the return must be same with other operator each adapter. Each adapter have operatorManager that helping you to register into each adapter parser
```go
-type Operator interface {
- Filter(KendoFilter) interface{}
+import kpmongo "github.com/raditzlawliet/kendoparser/parser/kpmongo"
+
+// Create the func
+func IsOne(kf kendoparser.Filter) interface{} {
+ return bson.M{kf.Field: bson.M{"$eq": 1}}
}
-type EqualOp struct{}
+// Assign into Exisiting Operator Manager
+kpmongo.OperatorManager.RegisterOperator(IsOne, "isone")
-// Filter Filter
-func (EqualOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- if kf.IgnoreCase {
- return EqCi{kf.Field: kf.Value}
- }
- return builder.Eq{kf.Field: kf.Value}
+// Example kendo json request
+"filter": {
+ "field": "id",
+ "operator": "isone"
}
-func register() {
- operatorManager.RegisterOperator(equalOp, "eq", "equal")
+// Parse
+request := struct {
+ Filter kp.Filter,
+}{}
+filter := request.Filter.Parse(kpmongo.FilterParser)
+
+// Result
+{"id" : {"$eq": 1}}
+```
+
+- Creating Your own Operator Manager
+
+ Usually when you try to create your own Operator Manager, you should create your own Parser. if the parser already existed, i recommended you use the existing Operator Manager.
+
+```go
+// creating global package variable
+var (
+ // OperatorManager of Mongo Parser
+ OperatorManager = new(kendoparser.OperatorManager)
+ // Operator bundle of Mongo Parser
+ Operator = OperatorBundle{}
+)
+
+// Wrapper Bundle, so you can put all the func filter into this struct
+type OperatorBundle struct{}
+
+// Register when import
+func init() {
+ RegisterOperator()
+}
+
+// Registration Process
+func RegisterOperator() {
+ OperatorManager.SetDefaultOperator(Operator.Equal)
+ OperatorManager.RegisterOperator(Operator.Equal, "eq", "equal")
+}
+
+// Some Filter
+func (o *OperatorBundle) Equal(kf kendoparser.Filter) interface{} {
+ if value, ok := kf.Value.(string); ok && kf.IgnoreCase {
+ value := regexp.QuoteMeta(value)
+ return bson.M{kf.Field: primitive.Regex{Pattern: "^" + strings.ToLower(value) + "$", Options: "i"}}
+ }
+ return bson.M{kf.Field: bson.M{"$eq": kf.Value}}
}
```
-### Transforming filter
+#### Transforming filter
Need modify your field? lowercase all field before processing? don't worry, you can use Transform to modify and apply to your all field. See [kendo_test.go](kendo_test.go)) for more uses
```go
-import kpmgo "github.com/raditzlawliet/gokendoparser/adapter/mgo"
+import kpmongo "github.com/raditzlawliet/kendoparser/parser/kpmongo"
kendoFilter := KendoFilter{}
@@ -172,16 +242,16 @@ kendoFilter.Transform(transformIDMongo) // only current filter
kendoFilter.TransformAll(transformIDMongo) // include filters
// chaining is possible
-kendoFilter.TransformFieldAll(strings.ToLower).TransformAll(transformIDMongo).Parse(kpmongo.ParseFilter)
+kendoFilter.TransformFieldAll(strings.ToLower).TransformAll(transformIDMongo).Parse(kpmongo.FilterParser)
```
-### Custom pre-filter
-You can also add custom single handler before building filter by registered operator. This approach you can add custom direct filter within loop filter. pre-filter it self act same like parser, so you can chain the filter with other filter. But if your pre-filter already return value, the last parse only act return the value
+#### Additional pre-parse filter
+You can also add additional single handler before building filter by registered operator. This approach you can add custom direct filter within loop filter. pre-filter it self act same like parser, so you can chain the filter with other filter. But if your pre-filter already return value, the last parse only act return the value
```go
-import kpmgo "github.com/raditzlawliet/gokendoparser/adapter/mgo"
+import kpmongo "github.com/raditzlawliet/kendoparser/parser/kpmongo"
-beforeFilter := func (kf *KendoFilter) interface{} {
+beforeParser := func (kf *KendoFilter) interface{} {
return nil
}
@@ -192,11 +262,12 @@ resultFilter := kendoFilter.TransformAllField(strings.ToLower).
kf.Field = "_id"
}
}).
- BeforeParse(beforeFilter).
- Parse(kpmongo.ParseFilter)
+ AddParse(beforeParser).
+ Parse(kpmongo.FilterParser)
// reset if needed another
-kendoFilter.ResetPreFilter()
+kendoFilter.ResetAdditionalParsers()
+kendoFilter.ResetAllAdditionalParsers() // Recursive to all filter childs
// dbox pipe
resultFilterPipe := kendoFilter.TransformAllField(strings.ToLower).
@@ -205,21 +276,23 @@ resultFilterPipe := kendoFilter.TransformAllField(strings.ToLower).
kf.Field = "_id"
}
}).
- BeforeParse(beforeFilter).
- Parse(kpmongo.ParseFilter)
+ AddParse(beforeParser).
+ Parse(kpmongo.FilterParser)
```
-## Sort
+#### Sort
do you need sort? You can do it easly.
```go
-import kpmgo "github.com/raditzlawliet/gokendoparser/adapter/mgo"
+import kpmongo "github.com/raditzlawliet/kendoparser/parser/kpmongo"
-sort := kData.Sort.Parse(kpmongo.ParseSort)
+sort := kData.Sort.Parse(kpmongo.SortParser)
```
## FAQ
-- ### go mod tidy keep error `git.eaciitapp.com/sebar/dbflex: no matching versions for query "latest"`
+- go mod tidy keep error `git.eaciitapp.com/sebar/dbflex: no matching versions for query "latest"`
+ This error appear because I use some private database driver in this parser, but you can exclude this using go.mod.
+
Modify go.mod file, if you dont have the package, just use this dummy in your go.mod, AND If you have the package and using it, replace it into your correct path package:
```replace git.eaciitapp.com/sebar/dbflex => ./pkg/git.eaciitapp.com/sebar/dbflex```
@@ -232,5 +305,4 @@ Feel free to contribute, don't forget to mention if needed
MIT License
## Author and Contributor
-Radityo
-
+Radityo
\ No newline at end of file
diff --git a/adapter/dbflex/operator.go b/adapter/dbflex/operator.go
deleted file mode 100644
index 45eca7d..0000000
--- a/adapter/dbflex/operator.go
+++ /dev/null
@@ -1,171 +0,0 @@
-package kpdbflex
-
-import (
- "time"
-
- "git.eaciitapp.com/sebar/dbflex"
-
- "github.com/raditzlawliet/gokendoparser"
-
- "github.com/spf13/cast"
-)
-
-var (
- operatorManager = new(gokendoparser.OperatorManager)
- equalOp = EqualOp{}
- notEqualOp = NotEqualOp{}
- containOp = ContainOp{}
- inOp = InOp{}
- gtOp = GtOp{}
- gteOp = GteOp{}
- ltOp = LtOp{}
- lteOp = LteOp{}
- gtDateOp = GtDateOp{}
- gteDateOp = GteDateOp{}
- ltDateOp = LtDateOp{}
- lteDateOp = LteDateOp{}
- rangeOp = RangeOp{}
-)
-
-func init() {
- RegisterOperator()
-}
-
-// RegisterOperator RegisterOperator
-func RegisterOperator() {
- operatorManager.SetDefaultOperator(equalOp)
- operatorManager.RegisterOperator(equalOp, "eq", "equal")
- operatorManager.RegisterOperator(notEqualOp, "ne", "neq", "notequal")
- operatorManager.RegisterOperator(containOp, "contain", "contains", "include", "includes")
- // operatorManager.RegisterOperator(notContainOp, "notcontains", "notcontains", "doesnotcontain", "doesnotcontains", "notinclude", "notincludes", "doesnotinclude", "doesnotincludes") // not supported yet
- operatorManager.RegisterOperator(inOp, "in")
- operatorManager.RegisterOperator(gtOp, "gt")
- operatorManager.RegisterOperator(gteOp, "gte")
- operatorManager.RegisterOperator(ltOp, "lt")
- operatorManager.RegisterOperator(lteOp, "lte")
- operatorManager.RegisterOperator(gtDateOp, "gtdate")
- operatorManager.RegisterOperator(gteDateOp, "gtedate")
- operatorManager.RegisterOperator(ltDateOp, "ltdate")
- operatorManager.RegisterOperator(lteDateOp, "ltedate")
- operatorManager.RegisterOperator(rangeOp, "range", "between")
-}
-
-// GetOperatorManager Get Operator Manager
-func GetOperatorManager() *gokendoparser.OperatorManager {
- return operatorManager
-}
-
-// EqualOp EqualOp
-type EqualOp struct{}
-
-// NotEqualOp NotEqualOp
-type NotEqualOp struct{}
-
-// ContainOp ContainOp
-type ContainOp struct{}
-
-// InOp InOp
-type InOp struct{}
-
-// GtOp GtOp
-type GtOp struct{}
-
-// GteOp GteOp
-type GteOp struct{}
-
-// LtOp LtOp
-type LtOp struct{}
-
-// LteOp LteOp
-type LteOp struct{}
-
-// GtDateOp GtDateOp
-type GtDateOp struct{}
-
-// GteDateOp GteDateOp
-type GteDateOp struct{}
-
-// LtDateOp LtDateOp
-type LtDateOp struct{}
-
-// LteDateOp LteDateOp
-type LteDateOp struct{}
-
-// RangeOp RangeOp
-type RangeOp struct{}
-
-// Filter Filter
-func (EqualOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- return dbflex.Eq(kf.Field, kf.Value)
-}
-
-// Filter Filter
-func (NotEqualOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- return dbflex.Ne(kf.Field, kf.Value)
-}
-
-// Filter Filter
-func (ContainOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- return dbflex.Contains(kf.Field, kf.Value)
-}
-
-// Filter Filter
-func (InOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- return dbflex.In(kf.Field, kf.Values...)
-}
-
-// Filter Filter
-func (GtOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- return dbflex.Gt(kf.Field, kf.Value)
-}
-
-// Filter Filter
-func (GteOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- return dbflex.Gte(kf.Field, kf.Value)
-}
-
-// Filter Filter
-func (LtOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- return dbflex.Lt(kf.Field, kf.Value)
-}
-
-// Filter Filter
-func (LteOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- return dbflex.Lte(kf.Field, kf.Value)
-}
-
-// Filter Filter
-func (GtDateOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- dtVariable, _ := time.Parse(time.RFC3339, cast.ToString(kf.Value))
- return dbflex.Gt(kf.Field, dtVariable)
-}
-
-// Filter Filter
-func (GteDateOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- dtVariable, _ := time.Parse(time.RFC3339, cast.ToString(kf.Value))
- return dbflex.Gte(kf.Field, dtVariable)
-}
-
-// Filter Filter
-func (LtDateOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- dtVariable, _ := time.Parse(time.RFC3339, cast.ToString(kf.Value))
- return dbflex.Lt(kf.Field, dtVariable)
-}
-
-// Filter Filter
-func (LteDateOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- dtVariable, _ := time.Parse(time.RFC3339, cast.ToString(kf.Value))
- return dbflex.Lte(kf.Field, dtVariable)
-}
-
-// Filter Filter
-func (RangeOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- var v0, v1 interface{}
- if len(kf.Values) > 0 {
- v0 = kf.Values[0]
- }
- if len(kf.Values) > 1 {
- v1 = kf.Values[1]
- }
- return dbflex.Range(kf.Field, v0, v1)
-}
diff --git a/adapter/dbox/operator.go b/adapter/dbox/operator.go
deleted file mode 100644
index 507b610..0000000
--- a/adapter/dbox/operator.go
+++ /dev/null
@@ -1,164 +0,0 @@
-package kpdbox
-
-import (
- "regexp"
- "time"
-
- "github.com/eaciit/dbox"
- "github.com/eaciit/toolkit"
- "github.com/raditzlawliet/gokendoparser"
- "github.com/raditzlawliet/gokendoparser/helper"
-
- "github.com/spf13/cast"
-)
-
-var (
- operatorManager = new(gokendoparser.OperatorManager)
- equalOp = EqualOp{}
- notEqualOp = NotEqualOp{}
- containOp = ContainOp{}
- notContainOp = NotContainOp{}
- inOp = InOp{}
- gteOp = GteOp{}
- lteOp = LteOp{}
- gteDateOp = GteDateOp{}
- lteDateOp = LteDateOp{}
- existsOp = ExistsOp{}
- betweenOp = BetweenOp{}
-)
-
-func init() {
- RegisterOperator()
-}
-
-// RegisterOperator RegisterOperator
-func RegisterOperator() {
- operatorManager.SetDefaultOperator(equalOp)
- operatorManager.RegisterOperator(equalOp, "eq", "equal")
- operatorManager.RegisterOperator(notEqualOp, "ne", "neq", "notequal")
- operatorManager.RegisterOperator(containOp, "contain", "contains", "include", "includes")
- operatorManager.RegisterOperator(notContainOp, "notcontains", "notcontains", "doesnotcontain", "doesnotcontains", "notinclude", "notincludes", "doesnotinclude", "doesnotincludes")
- operatorManager.RegisterOperator(inOp, "in")
- operatorManager.RegisterOperator(gteOp, "gte")
- operatorManager.RegisterOperator(lteOp, "lte")
- operatorManager.RegisterOperator(gteDateOp, "gtedate")
- operatorManager.RegisterOperator(lteDateOp, "ltedate")
- operatorManager.RegisterOperator(existsOp, "exist", "exists")
- operatorManager.RegisterOperator(betweenOp, "between")
-}
-
-// GetOperatorManager Get Operator Manager
-func GetOperatorManager() *gokendoparser.OperatorManager {
- return operatorManager
-}
-
-// EqualOp EqualOp
-type EqualOp struct{}
-
-// NotEqualOp NotEqualOp
-type NotEqualOp struct{}
-
-// ContainOp ContainOp
-type ContainOp struct{}
-
-// NotContainOp NotContainOp
-type NotContainOp struct{}
-
-// InOp InOp
-type InOp struct{}
-
-// GteOp GteOp
-type GteOp struct{}
-
-// LteOp LteOp
-type LteOp struct{}
-
-// GteDateOp GteDateOp
-type GteDateOp struct{}
-
-// LteDateOp LteDateOp
-type LteDateOp struct{}
-
-// ExistsOp ExistsOp
-type ExistsOp struct{}
-
-// BetweenOp BetweenOp
-type BetweenOp struct{}
-
-// Filter Filter
-func (EqualOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- return dbox.Eq(kf.Field, kf.Value)
-}
-
-// Filter Filter
-func (NotEqualOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- return dbox.Ne(kf.Field, kf.Value)
-}
-
-// Filter Filter
-func (ContainOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- return dbox.Contains(kf.Field, cast.ToString(kf.Value))
-}
-
-// Filter Filter
-func (NotContainOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- value := regexp.QuoteMeta(cast.ToString(kf.Value))
- return &dbox.Filter{
- Field: kf.Field,
- Op: dbox.FilterOpEqual, // equal are field = value and can be manipulate for others
- Value: toolkit.M{"$ne": toolkit.M{
- "$regex": `` + value + ``,
- "$options": "i",
- }},
- }
-}
-
-// Filter Filter
-func (InOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- return dbox.In(kf.Field, kf.Values...)
-}
-
-// Filter Filter
-func (GteOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- return dbox.Gte(kf.Field, kf.Value)
-}
-
-// Filter Filter
-func (LteOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- return dbox.Lte(kf.Field, kf.Value)
-}
-
-// Filter Filter
-func (GteDateOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- dtVariable, _ := time.Parse(time.RFC3339, cast.ToString(kf.Value))
- return dbox.Gte(kf.Field, dtVariable)
-}
-
-// Filter Filter
-func (LteDateOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- dtVariable, _ := time.Parse(time.RFC3339, cast.ToString(kf.Value))
- return dbox.Lte(kf.Field, dtVariable)
-}
-
-// Filter Filter
-func (ExistsOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- return &dbox.Filter{
- Field: kf.Field,
- Op: dbox.FilterOpEqual,
- Value: toolkit.M{
- "$exists": helper.StringToBool(cast.ToString(kf.Value), false),
- },
- }
-}
-
-// Filter Filter
-func (BetweenOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- var v0, v1 interface{}
- if len(kf.Values) > 0 {
- v0 = kf.Values[0]
- }
- if len(kf.Values) > 1 {
- v1 = kf.Values[1]
- }
- return dbox.And(dbox.Gte(kf.Field, v0), dbox.Lte(kf.Field, v1))
-}
diff --git a/adapter/dbox/operator_test.go b/adapter/dbox/operator_test.go
deleted file mode 100644
index e73d706..0000000
--- a/adapter/dbox/operator_test.go
+++ /dev/null
@@ -1,142 +0,0 @@
-package kpdbox
-
-import (
- "testing"
-
- "github.com/eaciit/dbox"
- tk "github.com/eaciit/toolkit"
- "github.com/raditzlawliet/gokendoparser"
- "github.com/stretchr/testify/require"
-)
-
-func Test_OperatorHook(t *testing.T) {
- // Single filter
- betOp := BetweenOp{}
- operatorManager.RegisterOperator(betOp, "between_custom")
-
- // testing eq / global
- {
- kendoFilter := gokendoparser.KendoFilter{
- Field: "_id", Operator: "eq", Value: "val",
- }
-
- resultFilter := kendoFilter.Parse(ParseFilter).(*dbox.Filter)
- expectedFilter := dbox.Eq("_id", "val")
- require.Equal(t, expectedFilter, resultFilter, "Result dbox filter must same")
-
- kendoRequest := gokendoparser.KendoRequest{}
- e := tk.UnjsonFromString(`{
- "data": {
- "filter": {
- "field": "_id",
- "operator": "eq",
- "value": "val"
- }
- }
- }`, &kendoRequest)
- require.Nil(t, e, "Json parse must work")
- require.Equal(t, kendoFilter, kendoRequest.Data.Filter, "Filter must same")
- resultFilterJSON := kendoRequest.Data.Filter.Parse(ParseFilter).(*dbox.Filter)
- require.Equal(t, expectedFilter, resultFilterJSON, "Result dbox filter must same")
- }
-
- // testing custom registered between
- {
- kendoFilter := gokendoparser.KendoFilter{
- Field: "v", Operator: "between_custom", Values: []interface{}{"1", "2"},
- }
-
- resultFilter := kendoFilter.Parse(ParseFilter).(*dbox.Filter)
- expectedFilter := dbox.And(dbox.Gte("v", "1"), dbox.Lte("v", "2"))
- require.Equal(t, expectedFilter, resultFilter, "Result dbox filter must same")
-
- kendoRequest := gokendoparser.KendoRequest{}
- e := tk.UnjsonFromString(`{
- "data": {
- "filter": {
- "field": "v",
- "operator": "between_custom",
- "values": ["1", "2"]
- }
- }
- }`, &kendoRequest)
- require.Nil(t, e, "Json parse must work")
- require.Equal(t, kendoFilter, kendoRequest.Data.Filter, "Filter must same")
- resultFilterJSON := kendoRequest.Data.Filter.Parse(ParseFilter).(*dbox.Filter)
- require.Equal(t, expectedFilter, resultFilterJSON, "Result dbox filter must same")
- }
-}
-
-func Test_OperatorHookLocalScope(t *testing.T) {
- operatorManager.Reset()
- operatorManager.SetDefaultOperator(EqualOp{})
- // testing custom registered between but not registered yet
- {
- kendoFilter := gokendoparser.KendoFilter{
- Field: "v", Operator: "between_custom", Values: []interface{}{"1", "2"},
- }
-
- resultFilter := kendoFilter.Parse(ParseFilter).(*dbox.Filter)
- expectedFilter := dbox.Eq("v", "") // because between not registered YET
- require.Equal(t, expectedFilter, resultFilter, "Result dbox filter must same")
-
- }
-
- operatorManager.Reset()
- operatorManager.SetDefaultOperator(EqualOp{})
- {
- // Single filter
- betOp := BetweenOp{}
-
- kendoFilter := gokendoparser.KendoFilter{
- Field: "v", Operator: "between_custom", Values: []interface{}{"1", "2"},
- }
-
- resultFilter := kendoFilter.RegisterOperator(betOp, "between_custom").Parse(ParseFilter).(*dbox.Filter)
- expectedFilter := dbox.And(dbox.Gte("v", "1"), dbox.Lte("v", "2"))
- require.Equal(t, expectedFilter, resultFilter, "Result dbox filter must same")
- }
-
- operatorManager.Reset()
- operatorManager.SetDefaultOperator(EqualOp{})
- {
- // Single filter
- betOp := BetweenOp{}
-
- kendoFilter := gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{
- Field: "v", Operator: "between_custom", Values: []interface{}{"1", "2"},
- },
- gokendoparser.KendoFilter{
- Field: "v", Operator: "between_custom", Values: []interface{}{"1", "2"},
- },
- },
- Logic: "and",
- }
-
- resultFilter := kendoFilter.RegisterOperatorAll(betOp, "between_custom").Parse(ParseFilter).(*dbox.Filter)
- expectedFilter :=
- dbox.And(
- dbox.And(dbox.Gte("v", "1"), dbox.Lte("v", "2")),
- dbox.And(dbox.Gte("v", "1"), dbox.Lte("v", "2")),
- )
- require.Equal(t, expectedFilter, resultFilter, "Result dbox filter must same")
- }
-
- operatorManager.Reset()
- operatorManager.SetDefaultOperator(EqualOp{})
- {
- // Single filter
- betOp := BetweenOp{}
-
- kendoFilter := gokendoparser.KendoFilter{
- Field: "v", Operator: "between_custom", Values: []interface{}{"1", "2"},
- }
-
- resultFilter := kendoFilter.RegisterOperator(betOp, "between_custom").Parse(ParseFilter).(*dbox.Filter)
- expectedFilter := dbox.And(dbox.Gte("v", "1"), dbox.Lte("v", "2"))
- require.Equal(t, expectedFilter, resultFilter, "Result dbox filter must same")
- }
-
-}
diff --git a/adapter/dboxpipe/kendo_test.go b/adapter/dboxpipe/kendo_test.go
deleted file mode 100644
index 193b158..0000000
--- a/adapter/dboxpipe/kendo_test.go
+++ /dev/null
@@ -1,182 +0,0 @@
-package kpdboxpipe
-
-import (
- "strings"
- "testing"
- "time"
-
- tk "github.com/eaciit/toolkit"
- "github.com/raditzlawliet/gokendoparser"
- "github.com/raditzlawliet/gokendoparser/helper"
- "github.com/spf13/cast"
- "github.com/stretchr/testify/require"
- "gopkg.in/mgo.v2/bson"
-)
-
-func Test_ParseFilter(t *testing.T) {
- kendoFilter := gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "_id", Operator: "eq", Value: "val"},
- },
- Logic: "and",
- }
- resultFilter := kendoFilter.Parse(ParseFilter).(tk.M)
- expectedFilter := tk.M{"$and": []tk.M{tk.M{"_id": tk.M{"$eq": "val"}}}}
- require.Equal(t, expectedFilter, resultFilter, "Result filter must same")
-
- kendoFilter = gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "_id", Operator: "eq", Value: "val"},
- gokendoparser.KendoFilter{Field: "_id", Operator: "neq", Value: "val"},
- },
- Logic: "or",
- },
- gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "_id", Operator: "eq", Value: "val2"},
- gokendoparser.KendoFilter{Field: "_id", Operator: "neq", Value: "val2"},
- },
- Logic: "or",
- },
- },
- Logic: "and",
- }
- resultFilter = kendoFilter.Parse(ParseFilter).(tk.M)
- expectedFilter = tk.M{"$and": []tk.M{
- tk.M{"$or": []tk.M{
- tk.M{"_id": tk.M{"$eq": "val"}},
- tk.M{"_id": tk.M{"$ne": "val"}},
- }},
- tk.M{"$or": []tk.M{
- tk.M{"_id": tk.M{"$eq": "val2"}},
- tk.M{"_id": tk.M{"$ne": "val2"}},
- }},
- }}
- require.Equal(t, expectedFilter, resultFilter, "Result filter must same")
-
- // operator check
- kendoFilter = gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "_id", Operator: "eq", Value: "val"},
- gokendoparser.KendoFilter{Field: "_id", Operator: "neq", Value: "val"},
- gokendoparser.KendoFilter{Field: "_id", Operator: "contains", Value: "val"},
- gokendoparser.KendoFilter{Field: "_id", Operator: "in", Values: []interface{}{"val"}},
- gokendoparser.KendoFilter{Field: "_id", Operator: "gte", Value: "val"},
- gokendoparser.KendoFilter{Field: "_id", Operator: "lte", Value: "val"},
- gokendoparser.KendoFilter{Field: "time", Operator: "gtedate", Value: "2006-01-02T15:04:05Z07:00"},
- gokendoparser.KendoFilter{Field: "time", Operator: "ltedate", Value: "2006-01-02T15:04:05Z07:00"},
- gokendoparser.KendoFilter{Field: "_id", Operator: "unknown", Value: "val"},
- },
- Logic: "and",
- }
- resultFilter = kendoFilter.Parse(ParseFilter).(tk.M)
- testTime, _ := time.Parse(time.RFC3339, "2006-01-02T15:04:05Z07:00")
- expectedFilter = tk.M{"$and": []tk.M{
- tk.M{"_id": tk.M{"$eq": "val"}},
- tk.M{"_id": tk.M{"$ne": "val"}},
- tk.M{"_id": helper.RegexContains("val", false)},
- tk.M{"_id": tk.M{"$in": []interface{}{"val"}}},
- tk.M{"_id": tk.M{"$gte": "val"}},
- tk.M{"_id": tk.M{"$lte": "val"}},
- tk.M{"time": tk.M{"$gte": testTime}},
- tk.M{"time": tk.M{"$lte": testTime}},
- tk.M{"_id": tk.M{"$eq": "val"}},
- }}
- require.Equal(t, expectedFilter, resultFilter, "Result filter must same")
-}
-
-func Test_PreFilterHandler(t *testing.T) {
- // transform single filter
- // ID => _id
- {
- kendoFilter := gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "ID", Operator: "eq", Value: "val"},
- gokendoparser.KendoFilter{Field: "STATUS", Operator: "eq", Value: "true"},
- },
- Logic: "or",
- },
- gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "ID", Operator: "eq", Value: "val2"},
- gokendoparser.KendoFilter{Field: "ID", Operator: "neq", Value: "val2"},
- },
- Logic: "or",
- },
- },
- Logic: "and",
- }
-
- // try dbox pipe
- resultFilterPipe := kendoFilter.TransformAllField(strings.ToLower).
- TransformAll(func(kf *gokendoparser.KendoFilter) {
- if kf.Field == "id" {
- kf.Field = "_id"
- }
- }).
- BeforeParseAll(func(kf *gokendoparser.KendoFilter) interface{} {
- if kf.Field == "status" {
- // return your custom handler
- return tk.M{kf.Field: helper.StringToBool(cast.ToString(kf.Value), false)}
- }
- return nil // pas nil to continue original filter
- }).Parse(ParseFilter).(tk.M)
-
- expectedFilterPipe := tk.M{"$and": []tk.M{
- tk.M{"$or": []tk.M{
- tk.M{"_id": tk.M{"$eq": "val"}},
- tk.M{"status": true},
- }},
- tk.M{"$or": []tk.M{
- tk.M{"_id": tk.M{"$eq": "val2"}},
- tk.M{"_id": tk.M{"$ne": "val2"}},
- }},
- }}
- require.Equal(t, expectedFilterPipe, resultFilterPipe, "Result dbox filter must same")
- }
-}
-
-func Test_Sort(t *testing.T) {
- {
- kData := gokendoparser.KendoData{
- Sort: gokendoparser.KendoSortArray{
- gokendoparser.KendoSort{
- Field: "foo",
- Dir: "DESC",
- },
- gokendoparser.KendoSort{
- Field: "bar",
- Dir: "ASC",
- },
- gokendoparser.KendoSort{
- Field: "_id",
- Dir: "desc",
- },
- },
- }
-
- // try dbox filter
- result := kData.Sort.Parse(ParseSort).(bson.D)
-
- expectedPipe := bson.D{
- bson.DocElem{
- Name: "foo",
- Value: -1,
- },
- bson.DocElem{
- Name: "bar",
- Value: 1,
- },
- bson.DocElem{
- Name: "_id",
- Value: -1,
- },
- }
-
- require.Equal(t, expectedPipe, result, "Result must same")
- }
-}
diff --git a/adapter/dboxpipe/operator.go b/adapter/dboxpipe/operator.go
deleted file mode 100644
index c251c61..0000000
--- a/adapter/dboxpipe/operator.go
+++ /dev/null
@@ -1,155 +0,0 @@
-package kpdboxpipe
-
-import (
- "regexp"
- "strings"
- "time"
-
- "github.com/eaciit/toolkit"
- "github.com/raditzlawliet/gokendoparser"
- "github.com/raditzlawliet/gokendoparser/helper"
- "gopkg.in/mgo.v2/bson"
-
- "github.com/spf13/cast"
-)
-
-var (
- operatorManager = new(gokendoparser.OperatorManager)
- equalOp = EqualOp{}
- notEqualOp = NotEqualOp{}
- containOp = ContainOp{}
- notContainOp = NotContainOp{}
- inOp = InOp{}
- gteOp = GteOp{}
- lteOp = LteOp{}
- gteDateOp = GteDateOp{}
- lteDateOp = LteDateOp{}
- existsOp = ExistsOp{}
- betweenOp = BetweenOp{}
-)
-
-func init() {
- RegisterOperator()
-}
-
-// RegisterOperator RegisterOperator
-func RegisterOperator() {
- operatorManager.SetDefaultOperator(equalOp)
- operatorManager.RegisterOperator(equalOp, "eq", "equal")
- operatorManager.RegisterOperator(notEqualOp, "ne", "neq", "notequal")
- operatorManager.RegisterOperator(containOp, "contain", "contains", "include", "includes")
- operatorManager.RegisterOperator(notContainOp, "notcontains", "notcontains", "doesnotcontain", "doesnotcontains", "notinclude", "notincludes", "doesnotinclude", "doesnotincludes")
- operatorManager.RegisterOperator(inOp, "in")
- operatorManager.RegisterOperator(gteOp, "gte")
- operatorManager.RegisterOperator(lteOp, "lte")
- operatorManager.RegisterOperator(gteDateOp, "gtedate")
- operatorManager.RegisterOperator(lteDateOp, "ltedate")
- operatorManager.RegisterOperator(existsOp, "exist", "exists")
- operatorManager.RegisterOperator(betweenOp, "between")
-}
-
-// GetOperatorManager Get Operator Manager
-func GetOperatorManager() *gokendoparser.OperatorManager {
- return operatorManager
-}
-
-//EqualOp EqualOp
-type EqualOp struct{}
-
-// NotEqualOp NotEqualOp
-type NotEqualOp struct{}
-
-// ContainOp ContainOp
-type ContainOp struct{}
-
-// NotContainOp NotContainOp
-type NotContainOp struct{}
-
-// InOp InOp
-type InOp struct{}
-
-// GteOp GteOp
-type GteOp struct{}
-
-// LteOp LteOp
-type LteOp struct{}
-
-// GteDateOp GteDateOp
-type GteDateOp struct{}
-
-// LteDateOp LteDateOp
-type LteDateOp struct{}
-
-// ExistsOp ExistsOp
-type ExistsOp struct{}
-
-// BetweenOp BetweenOp
-type BetweenOp struct{}
-
-// Filter Filter
-func (EqualOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- if kf.IgnoreCase {
- value := regexp.QuoteMeta(cast.ToString(kf.Value))
- return toolkit.M{kf.Field: bson.RegEx{Pattern: "^" + strings.ToLower(value) + "$", Options: "i"}}
- }
- return toolkit.M{kf.Field: toolkit.M{"$eq": kf.Value}}
-}
-
-// Filter Filter
-func (NotEqualOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- return toolkit.M{kf.Field: toolkit.M{"$ne": kf.Value}}
-}
-
-// Filter Filter
-func (ContainOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- return toolkit.M{kf.Field: helper.RegexContains(cast.ToString(kf.Value), kf.IgnoreCase)}
-}
-
-// Filter Filter
-func (NotContainOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- return toolkit.M{kf.Field: toolkit.M{"$ne": helper.RegexContains(cast.ToString(kf.Value), kf.IgnoreCase)}}
-}
-
-// Filter Filter
-func (InOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- return toolkit.M{kf.Field: toolkit.M{"$in": kf.Values}}
-}
-
-// Filter Filter
-func (GteOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- return toolkit.M{kf.Field: toolkit.M{"$gte": kf.Value}}
-}
-
-// Filter Filter
-func (LteOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- return toolkit.M{kf.Field: toolkit.M{"$lte": kf.Value}}
-}
-
-// Filter Filter
-func (GteDateOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- dtVariable, _ := time.Parse(time.RFC3339, cast.ToString(kf.Value))
- return toolkit.M{kf.Field: toolkit.M{"$gte": dtVariable}}
-}
-
-// Filter Filter
-func (LteDateOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- dtVariable, _ := time.Parse(time.RFC3339, cast.ToString(kf.Value))
- return toolkit.M{kf.Field: toolkit.M{"$lte": dtVariable}}
-}
-
-// Filter Filter
-func (ExistsOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- return toolkit.M{kf.Field: toolkit.M{"$exists": helper.StringToBool(cast.ToString(kf.Value), false)}}
-}
-
-// Filter Filter
-func (BetweenOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- var v0, v1 interface{}
- if len(kf.Values) > 0 {
- v0 = kf.Values[0]
- }
- if len(kf.Values) > 1 {
- v1 = kf.Values[1]
- }
- return toolkit.M{kf.Field: toolkit.M{"$gte": v0, "$lte": v1}}
-}
diff --git a/adapter/mongo/kendo_test.go b/adapter/mongo/kendo_test.go
deleted file mode 100644
index b4a7b86..0000000
--- a/adapter/mongo/kendo_test.go
+++ /dev/null
@@ -1,199 +0,0 @@
-package kpmongo
-
-import (
- "strings"
- "testing"
- "time"
-
- "github.com/raditzlawliet/gokendoparser"
- "github.com/raditzlawliet/gokendoparser/helper"
- "github.com/spf13/cast"
- "github.com/stretchr/testify/require"
- "go.mongodb.org/mongo-driver/bson"
-)
-
-func Test_ParseFilter(t *testing.T) {
- kendoFilter := gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "_id", Operator: "eq", Value: "val"},
- },
- Logic: "and",
- }
- resultFilter := kendoFilter.Parse(ParseFilter).(bson.D)
- expectedFilter := bson.D{
- {
- "$and", []bson.D{
- bson.D{{"_id", bson.M{"$eq": "val"}}},
- },
- },
- }
- require.Equal(t, expectedFilter, resultFilter, "Result filter must same")
-
- kendoFilter = gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "_id", Operator: "eq", Value: "val"},
- gokendoparser.KendoFilter{Field: "_id", Operator: "neq", Value: "val"},
- },
- Logic: "or",
- },
- gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "_id", Operator: "eq", Value: "val2"},
- gokendoparser.KendoFilter{Field: "_id", Operator: "neq", Value: "val2"},
- },
- Logic: "or",
- },
- },
- Logic: "and",
- }
- resultFilter = kendoFilter.Parse(ParseFilter).(bson.D)
-
- expectedFilter = bson.D{
- {
- "$and", []bson.D{
- bson.D{{"$or", []bson.D{
- bson.D{{"_id", bson.M{"$eq": "val"}}},
- bson.D{{"_id", bson.M{"$ne": "val"}}},
- }}},
- bson.D{{"$or", []bson.D{
- bson.D{{"_id", bson.M{"$eq": "val2"}}},
- bson.D{{"_id", bson.M{"$ne": "val2"}}},
- }}},
- },
- },
- }
- require.Equal(t, expectedFilter, resultFilter, "Result filter must same")
-
- // operator check
- kendoFilter = gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "_id", Operator: "eq", Value: "val"},
- gokendoparser.KendoFilter{Field: "_id", Operator: "neq", Value: "val"},
- gokendoparser.KendoFilter{Field: "_id", Operator: "contains", Value: "val"},
- gokendoparser.KendoFilter{Field: "_id", Operator: "in", Values: []interface{}{"val"}},
- gokendoparser.KendoFilter{Field: "_id", Operator: "gte", Value: "val"},
- gokendoparser.KendoFilter{Field: "_id", Operator: "lte", Value: "val"},
- gokendoparser.KendoFilter{Field: "time", Operator: "gtedate", Value: "2006-01-02T15:04:05Z07:00"},
- gokendoparser.KendoFilter{Field: "time", Operator: "ltedate", Value: "2006-01-02T15:04:05Z07:00"},
- gokendoparser.KendoFilter{Field: "_id", Operator: "unknown", Value: "val"},
- },
- Logic: "and",
- }
- resultFilter = kendoFilter.Parse(ParseFilter).(bson.D)
- testTime, _ := time.Parse(time.RFC3339, "2006-01-02T15:04:05Z07:00")
-
- expectedFilter = bson.D{
- {
- "$and", []bson.D{
- bson.D{{"_id", bson.M{"$eq": "val"}}},
- bson.D{{"_id", bson.M{"$ne": "val"}}},
- bson.D{{"_id", RegexContains("val", false)}},
- bson.D{{"_id", bson.M{"$in": []interface{}{"val"}}}},
- bson.D{{"_id", bson.M{"$gte": "val"}}},
- bson.D{{"_id", bson.M{"$lte": "val"}}},
- bson.D{{"time", bson.M{"$gte": testTime}}},
- bson.D{{"time", bson.M{"$lte": testTime}}},
- bson.D{{"_id", bson.M{"$eq": "val"}}},
- },
- },
- }
- require.Equal(t, expectedFilter, resultFilter, "Result filter must same")
-}
-
-func Test_PreFilterHandler(t *testing.T) {
- // transform single filter
- // ID => _id
- {
- kendoFilter := gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "ID", Operator: "eq", Value: "val"},
- gokendoparser.KendoFilter{Field: "STATUS", Operator: "eq", Value: "true"},
- },
- Logic: "or",
- },
- gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "ID", Operator: "eq", Value: "val2"},
- gokendoparser.KendoFilter{Field: "ID", Operator: "neq", Value: "val2"},
- },
- Logic: "or",
- },
- },
- Logic: "and",
- }
-
- // try dbox pipe
- resultFilter := kendoFilter.TransformAllField(strings.ToLower).
- TransformAll(func(kf *gokendoparser.KendoFilter) {
- if kf.Field == "id" {
- kf.Field = "_id"
- }
- }).
- BeforeParseAll(func(kf *gokendoparser.KendoFilter) interface{} {
- if kf.Field == "status" {
- // return your custom handler
- return bson.M{kf.Field: helper.StringToBool(cast.ToString(kf.Value), false)}
- }
- return nil // pas nil to continue original filter
- }).Parse(ParseFilter).(bson.D)
-
- expectedFilter := bson.D{
- {
- "$and", []bson.D{
- bson.D{{"$or", []bson.D{
- bson.D{{"_id", bson.M{"$eq": "val"}}},
- bson.D{{"status", true}},
- }}},
- bson.D{{"$or", []bson.D{
- bson.D{{"_id", bson.M{"$eq": "val2"}}},
- bson.D{{"_id", bson.M{"$ne": "val2"}}},
- }}},
- },
- },
- }
-
- require.Equal(t, expectedFilter, resultFilter, "Result dbox filter must same")
- }
-}
-
-func Test_Sort(t *testing.T) {
- {
- kData := gokendoparser.KendoData{
- Sort: gokendoparser.KendoSortArray{
- gokendoparser.KendoSort{
- Field: "foo",
- Dir: "DESC",
- },
- gokendoparser.KendoSort{
- Field: "bar",
- Dir: "ASC",
- },
- gokendoparser.KendoSort{
- Field: "_id",
- Dir: "desc",
- },
- },
- }
-
- // try dbox filter
- result := kData.Sort.Parse(ParseSort).(bson.D)
-
- expectedPipe := bson.D{
- bson.E{"foo", -1},
- bson.E{
- "bar",
- 1,
- },
- bson.E{
- "_id",
- -1,
- },
- }
-
- require.Equal(t, expectedPipe, result, "Result must same")
- }
-}
diff --git a/adapter/mongo/operator.go b/adapter/mongo/operator.go
deleted file mode 100644
index a1cecd7..0000000
--- a/adapter/mongo/operator.go
+++ /dev/null
@@ -1,193 +0,0 @@
-package kpmongo
-
-import (
- "regexp"
- "strings"
- "time"
-
- "github.com/raditzlawliet/gokendoparser"
- "github.com/raditzlawliet/gokendoparser/helper"
- "go.mongodb.org/mongo-driver/bson"
- "go.mongodb.org/mongo-driver/bson/primitive"
-
- "github.com/spf13/cast"
-)
-
-var (
- operatorManager = new(gokendoparser.OperatorManager)
- equalOp = EqualOp{}
- notEqualOp = NotEqualOp{}
- equalDateOp = EqualDateOp{}
- notEqualDateOp = NotEqualDateOp{}
- containOp = ContainOp{}
- notContainOp = NotContainOp{}
- inOp = InOp{}
- gteOp = GteOp{}
- lteOp = LteOp{}
- gteDateOp = GteDateOp{}
- lteDateOp = LteDateOp{}
- existsOp = ExistsOp{}
- betweenOp = BetweenOp{}
-)
-
-func init() {
- RegisterOperator()
-}
-
-// RegisterOperator RegisterOperator
-func RegisterOperator() {
- operatorManager.SetDefaultOperator(equalOp)
- operatorManager.RegisterOperator(equalOp, "eq", "equal")
- operatorManager.RegisterOperator(notEqualOp, "ne", "neq", "notequal")
- operatorManager.RegisterOperator(equalDateOp, "eqdate", "equaldate")
- operatorManager.RegisterOperator(notEqualDateOp, "nedate", "neqdate", "notequaldate")
- operatorManager.RegisterOperator(containOp, "contain", "contains", "include", "includes")
- operatorManager.RegisterOperator(notContainOp, "notcontains", "notcontains", "doesnotcontain", "doesnotcontains", "notinclude", "notincludes", "doesnotinclude", "doesnotincludes")
- operatorManager.RegisterOperator(inOp, "in")
- operatorManager.RegisterOperator(gteOp, "gte")
- operatorManager.RegisterOperator(lteOp, "lte")
- operatorManager.RegisterOperator(gteDateOp, "gtedate")
- operatorManager.RegisterOperator(lteDateOp, "ltedate")
- operatorManager.RegisterOperator(existsOp, "exist", "exists")
- operatorManager.RegisterOperator(betweenOp, "between")
-}
-
-// GetOperatorManager Get Operator Manager
-func GetOperatorManager() *gokendoparser.OperatorManager {
- return operatorManager
-}
-
-//EqualOp EqualOp
-type EqualOp struct{}
-
-// NotEqualOp NotEqualOp
-type NotEqualOp struct{}
-
-//EqualOp EqualOp
-type EqualDateOp struct{}
-
-// NotEqualOp NotEqualOp
-type NotEqualDateOp struct{}
-
-// ContainOp ContainOp
-type ContainOp struct{}
-
-// NotContainOp NotContainOp
-type NotContainOp struct{}
-
-// InOp InOp
-type InOp struct{}
-
-// GteOp GteOp
-type GteOp struct{}
-
-// LteOp LteOp
-type LteOp struct{}
-
-// GteDateOp GteDateOp
-type GteDateOp struct{}
-
-// LteDateOp LteDateOp
-type LteDateOp struct{}
-
-// ExistsOp ExistsOp
-type ExistsOp struct{}
-
-// BetweenOp BetweenOp
-type BetweenOp struct{}
-
-// Filter Filter
-func (EqualOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- if kf.IgnoreCase {
- value := regexp.QuoteMeta(cast.ToString(kf.Value))
- return bson.M{kf.Field: primitive.Regex{Pattern: "^" + strings.ToLower(value) + "$", Options: "i"}}
- }
- return bson.M{kf.Field: bson.M{"$eq": kf.Value}}
-}
-
-// Filter Filter
-func (NotEqualOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- return bson.M{kf.Field: bson.M{"$ne": kf.Value}}
-}
-
-// Filter Filter
-func (EqualDateOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- dtVariable, _ := time.Parse(time.RFC3339, cast.ToString(kf.Value))
- return bson.M{kf.Field: bson.M{"$eq": dtVariable}}
-}
-
-// Filter Filter
-func (NotEqualDateOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- dtVariable, _ := time.Parse(time.RFC3339, cast.ToString(kf.Value))
- return bson.M{kf.Field: bson.M{"$ne": dtVariable}}
-}
-
-// Filter Filter
-func (ContainOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- return bson.M{kf.Field: RegexContains(cast.ToString(kf.Value), kf.IgnoreCase)}
-}
-
-// Filter Filter
-func (NotContainOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- return bson.M{kf.Field: bson.M{"$ne": RegexContains(cast.ToString(kf.Value), kf.IgnoreCase)}}
-}
-
-// Filter Filter
-func (InOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- return bson.M{kf.Field: bson.M{"$in": kf.Values}}
-}
-
-// Filter Filter
-func (GteOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- return bson.M{kf.Field: bson.M{"$gte": kf.Value}}
-}
-
-// Filter Filter
-func (LteOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- return bson.M{kf.Field: bson.M{"$lte": kf.Value}}
-}
-
-// Filter Filter
-func (GteDateOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- dtVariable, _ := time.Parse(time.RFC3339, cast.ToString(kf.Value))
- return bson.M{kf.Field: bson.M{"$gte": dtVariable}}
-}
-
-// Filter Filter
-func (LteDateOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- dtVariable, _ := time.Parse(time.RFC3339, cast.ToString(kf.Value))
- return bson.M{kf.Field: bson.M{"$lte": dtVariable}}
-}
-
-// Filter Filter
-func (ExistsOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- return bson.M{kf.Field: bson.M{"$exists": helper.StringToBool(cast.ToString(kf.Value), false)}}
-}
-
-// Filter Filter
-func (BetweenOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- var v0, v1 interface{}
- if len(kf.Values) > 0 {
- v0 = kf.Values[0]
- }
- if len(kf.Values) > 1 {
- v1 = kf.Values[1]
- }
- return bson.M{kf.Field: bson.M{"$gte": v0, "$lte": v1}}
-}
-
-// RegexCaseInsensitive Generate bson.RegEx for case insensitive
-func RegexCaseInsensitive(value string) primitive.Regex {
- value = regexp.QuoteMeta(value)
- return primitive.Regex{Pattern: "^" + strings.ToLower(value) + "$", Options: "i"}
-}
-
-// RegexContains Generate bson.RegEx for contains
-func RegexContains(value string, ignoreCase bool) primitive.Regex {
- value = regexp.QuoteMeta(value)
- if ignoreCase {
- return primitive.Regex{Pattern: "" + strings.ToLower(value) + "", Options: "i"}
- } else {
- return primitive.Regex{Pattern: "" + value + "", Options: ""}
- }
-}
diff --git a/adapter/xorm/operator.go b/adapter/xorm/operator.go
deleted file mode 100644
index 1a0226f..0000000
--- a/adapter/xorm/operator.go
+++ /dev/null
@@ -1,178 +0,0 @@
-package kpxorm
-
-import (
- "time"
-
- "github.com/raditzlawliet/gokendoparser"
- "github.com/raditzlawliet/gokendoparser/helper"
- "github.com/spf13/cast"
- "xorm.io/builder"
-)
-
-var (
- operatorManager = gokendoparser.OperatorManager{}
- equalOp = EqualOp{}
- notEqualOp = NotEqualOp{}
- containOp = ContainOp{}
- notContainOp = NotContainOp{}
- inOp = InOp{}
- gtOp = GtOp{}
- ltOp = LtOp{}
- gteOp = GteOp{}
- lteOp = LteOp{}
- gteDateOp = GteDateOp{}
- lteDateOp = LteDateOp{}
- existsOp = ExistsOp{}
- betweenOp = BetweenOp{}
-)
-
-func init() {
- RegisterOperator()
-}
-
-// RegisterOperator RegisterOperator
-func RegisterOperator() {
- operatorManager.SetDefaultOperator(equalOp)
- operatorManager.RegisterOperator(equalOp, "eq", "equal")
- operatorManager.RegisterOperator(notEqualOp, "ne", "neq", "notequal")
- operatorManager.RegisterOperator(containOp, "contain", "contains", "include", "includes")
- operatorManager.RegisterOperator(notContainOp, "notcontains", "notcontains", "doesnotcontain", "doesnotcontains", "notinclude", "notincludes", "doesnotinclude", "doesnotincludes")
- operatorManager.RegisterOperator(inOp, "in")
- operatorManager.RegisterOperator(gtOp, "gt")
- operatorManager.RegisterOperator(ltOp, "lt")
- operatorManager.RegisterOperator(gteOp, "gte")
- operatorManager.RegisterOperator(lteOp, "lte")
- operatorManager.RegisterOperator(gteDateOp, "gtedate")
- operatorManager.RegisterOperator(lteDateOp, "ltedate")
- operatorManager.RegisterOperator(existsOp, "exist", "exists")
- operatorManager.RegisterOperator(betweenOp, "between")
-}
-
-//EqualOp EqualOp
-type EqualOp struct{}
-
-// NotEqualOp NotEqualOp
-type NotEqualOp struct{}
-
-// ContainOp ContainOp
-type ContainOp struct{}
-
-// NotContainOp NotContainOp
-type NotContainOp struct{}
-
-// InOp InOp
-type InOp struct{}
-
-// GtOp GtOp
-type GtOp struct{}
-
-// LtOp LtOp
-type LtOp struct{}
-
-// GteOp GteOp
-type GteOp struct{}
-
-// LteOp LteOp
-type LteOp struct{}
-
-// GteDateOp GteDateOp
-type GteDateOp struct{}
-
-// LteDateOp LteDateOp
-type LteDateOp struct{}
-
-// ExistsOp ExistsOp
-type ExistsOp struct{}
-
-// BetweenOp BetweenOp
-type BetweenOp struct{}
-
-// Filter Filter
-func (EqualOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- if kf.IgnoreCase {
- return EqCi{kf.Field: kf.Value}
- }
- return builder.Eq{kf.Field: kf.Value}
-}
-
-// Filter Filter
-func (NotEqualOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- return builder.Neq{kf.Field: kf.Value}
-}
-
-// Filter Filter
-func (ContainOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- if kf.IgnoreCase {
- return LikeCi{kf.Field, cast.ToString(kf.Value)}
- }
- return builder.Like{cast.ToString(kf.Value), cast.ToString(kf.Value)}
-}
-
-// Filter Filter
-func (NotContainOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- if kf.IgnoreCase {
- return builder.Not{
- LikeCi{kf.Field, cast.ToString(kf.Value)},
- }
- }
- return builder.Not{
- builder.Like{cast.ToString(kf.Value), cast.ToString(kf.Value)},
- }
-}
-
-// Filter Filter
-func (InOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- return builder.In(kf.Field, kf.Values...)
-}
-
-// Filter Filter
-func (GtOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- return builder.Gt{kf.Field: kf.Value}
-}
-
-// Filter Filter
-func (LtOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- return builder.Lt{kf.Field: kf.Value}
-}
-
-// Filter Filter
-func (GteOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- return builder.Gte{kf.Field: kf.Value}
-}
-
-// Filter Filter
-func (LteOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- return builder.Lte{kf.Field: kf.Value}
-}
-
-// Filter Filter
-func (GteDateOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- dtVariable, _ := time.Parse(time.RFC3339, cast.ToString(kf.Value))
- return builder.Gte{kf.Field: dtVariable}
-}
-
-// Filter Filter
-func (LteDateOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- dtVariable, _ := time.Parse(time.RFC3339, cast.ToString(kf.Value))
- return builder.Lte{kf.Field: dtVariable}
-}
-
-// Filter Filter
-func (ExistsOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- if helper.StringToBool(cast.ToString(kf.Value), false) {
- return builder.NotNull{kf.Field}
- }
- return builder.IsNull{kf.Field}
-}
-
-// Filter Filter
-func (BetweenOp) Filter(kf gokendoparser.KendoFilter) interface{} {
- var v0, v1 interface{}
- if len(kf.Values) > 0 {
- v0 = kf.Values[0]
- }
- if len(kf.Values) > 1 {
- v1 = kf.Values[1]
- }
- return builder.Between{kf.Field, v0, v1}
-}
diff --git a/go.mod b/go.mod
index c4e2687..eb967b9 100644
--- a/go.mod
+++ b/go.mod
@@ -1,10 +1,10 @@
-module github.com/raditzlawliet/gokendoparser
+module github.com/raditzlawliet/kendoparser
go 1.13
require (
git.eaciitapp.com/sebar/dbflex v0.0.0-00010101000000-000000000000
- github.com/eaciit/cast v0.0.0-20160225070732-c06c4b07187e // indirect
+ github.com/eaciit/cast v0.0.0-20160225070732-c06c4b07187e
github.com/eaciit/dbox v0.0.0-20180917055501-9a504bed8cc5
github.com/eaciit/errorlib v0.0.0-20150626203730-179dfd7a1051 // indirect
github.com/eaciit/toolkit v0.0.0-20191214194902-30b3fd1abbf4
diff --git a/helper.go b/helper.go
deleted file mode 100644
index 0b872ba..0000000
--- a/helper.go
+++ /dev/null
@@ -1,60 +0,0 @@
-package gokendoparser
-
-import (
- "regexp"
- "strings"
-
- "gopkg.in/mgo.v2/bson"
-)
-
-// BoolToString cast bool to string with extra format (usefull for inline func)
-// BoolToString(true, "Yes", "No") will return "Yes"
-func BoolToString(b bool, y string, n string) string {
- if y == "" {
- y = "true"
- }
- if n == "" {
- n = "false"
- }
- if b {
- return y
- }
- return n
-}
-
-// StringToBool cast string to bool with extra options default value. empty string will be default
-// normally like js will use
-// StringToBool("ya", false) will return true
-// StringToBool("", false) will return false
-// StringToBool("", true) will return true
-func StringToBool(str string, def bool) bool {
- str = strings.ToLower(strings.TrimSpace(str))
- if !def {
- if str == "y" || str == "yes" || str == "true" || str == "1" || str == "ya" || str == "active" ||
- strings.Contains(str, "true") || strings.HasPrefix(str, "yes") {
- return true
- }
- return false
- }
- if str == "n" || str == "no" || str == "false" || str == "0" || str == "not" || str == "not active" || str == "inactive" ||
- strings.HasPrefix(str, "not") || strings.HasPrefix(str, "false") || strings.HasPrefix(str, "no") {
- return false
- }
- return true
-}
-
-// RegexCaseInsensitive Generate bson.RegEx for case insensitive
-func RegexCaseInsensitive(value string) bson.RegEx {
- value = regexp.QuoteMeta(value)
- return bson.RegEx{Pattern: "^" + strings.ToLower(value) + "$", Options: "i"}
-}
-
-// RegexContains Generate bson.RegEx for contains
-func RegexContains(value string, ignoreCase bool) bson.RegEx {
- value = regexp.QuoteMeta(value)
- if ignoreCase {
- return bson.RegEx{Pattern: "" + strings.ToLower(value) + "", Options: "i"}
- } else {
- return bson.RegEx{Pattern: "" + strings.ToLower(value) + "", Options: ""}
- }
-}
diff --git a/kendo.go b/kendo.go
index e1e6b8d..3a97508 100644
--- a/kendo.go
+++ b/kendo.go
@@ -1,4 +1,4 @@
-package gokendoparser
+package kendoparser
/*
* @Author
@@ -7,28 +7,22 @@ package gokendoparser
// KendoRequest option variable to struct (each apps has different format, defined/extend yourself if needed)
type KendoRequest struct {
- Data KendoData `json:"data"`
+ Data Data `json:"data"`
}
-// RegisterOperatorAll register operator local scope include childs
-func (k *KendoRequest) RegisterOperatorAll(f Operator, ops ...string) *KendoRequest {
- k.Data.Filter.RegisterOperatorAll(f, ops...)
- return k
+// Data Kendo DataSource payload
+type Data struct {
+ Filter Filter `json:"filter"`
+ Page int `json:"page"`
+ PageSize int `json:"pageSize"`
+ Skip int `json:"skip"`
+ Take int `json:"take"`
+ Sort Sort `json:"sort"`
}
-// KendoData datasource payload
-type KendoData struct {
- Filter KendoFilter `json:"filter"`
- Page int `json:"page"`
- PageSize int `json:"pageSize"`
- Skip int `json:"skip"`
- Take int `json:"take"`
- Sort KendoSortArray `json:"sort"`
-}
-
-// KendoFilter struct filters
-type KendoFilter struct {
- Filters []KendoFilter `json:"filters"`
+// Filter struct filters
+type Filter struct {
+ Filters []Filter `json:"filters"`
Logic string `json:"logic"`
Field string `json:"field"`
Operator string `json:"operator"`
@@ -36,135 +30,112 @@ type KendoFilter struct {
Value interface{} `json:"value"`
Values []interface{} `json:"values"`
- // will not change the original value
- registeredOperators map[string]Operator
- // for extension
- preParser []ParseFilter
+ // logic pre-parser
+ additionalParsers []FilterParser
+ operatorManager *OperatorManager
}
-// GetRegisteredOperators GetRegisteredOperators
-func (kf *KendoFilter) GetRegisteredOperators() map[string]Operator {
- return kf.registeredOperators
+// AdditionalParsers AdditionalParsers
+func (f *Filter) AdditionalParsers() []FilterParser {
+ return f.additionalParsers
}
-// AddRegisteredOperator AddRegisteredOperator
-func (kf *KendoFilter) AddRegisteredOperator(k string, op Operator) *KendoFilter {
- if kf.registeredOperators == nil {
- kf.registeredOperators = map[string]Operator{}
- }
- if op != nil {
- kf.registeredOperators[k] = op
+// SetOperatorManager scoped Operator Manager
+func (f *Filter) SetOperatorManager(om *OperatorManager) *Filter {
+ f.operatorManager = om
+ for i := range f.Filters {
+ f.Filters[i].SetOperatorManager(om)
}
- return kf
+ return f
}
-// GetBeforeParse GetBeforeParse
-func (kf *KendoFilter) GetBeforeParse() []ParseFilter {
- return kf.preParser
+// GetOperatorManager scoped Operator Manager
+func (f *Filter) GetOperatorManager() *OperatorManager {
+ return f.operatorManager
}
-// BeforeParse BeforeParse
-func (kf *KendoFilter) BeforeParse(fs ...ParseFilter) *KendoFilter {
- if kf.preParser == nil {
- kf.preParser = []ParseFilter{}
+// AddParser AddParser
+func (f *Filter) AddParser(parsers ...FilterParser) *Filter {
+ if f.additionalParsers == nil {
+ f.additionalParsers = []FilterParser{}
}
- for _, f := range fs {
- if f != nil {
- kf.preParser = append(kf.preParser, f)
+ for _, parser := range parsers {
+ if parser != nil {
+ f.additionalParsers = append(f.additionalParsers, parser)
}
}
- return kf
+ return f
}
-// BeforeParseAll BeforeParseAll
-func (kf *KendoFilter) BeforeParseAll(fs ...ParseFilter) *KendoFilter {
- for i := range kf.Filters {
- kf.Filters[i].BeforeParseAll(fs...)
+// AddAllParser AddAllParser
+func (f *Filter) AddAllParser(parsers ...FilterParser) *Filter {
+ for i := range f.Filters {
+ f.Filters[i].AddAllParser(parsers...)
}
- kf.BeforeParse(fs...)
- return kf
+ f.AddParser(parsers...)
+ return f
}
// Parse Parse will return interface
-func (kf *KendoFilter) Parse(f ParseFilter) interface{} {
- return f(kf)
+func (f *Filter) Parse(parser FilterParser) interface{} {
+ return parser(f)
}
-// ResetBeforeParse reset all pre-filter available
-func (kf *KendoFilter) ResetBeforeParse() *KendoFilter {
- kf.preParser = []ParseFilter{}
- return kf
+// ResetAdditionalParsers reset all pre-filter available
+func (f *Filter) ResetAdditionalParsers() *Filter {
+ f.additionalParsers = []FilterParser{}
+ return f
}
-// ResetBeforeParseAll reset all pre-filter available
-func (kf *KendoFilter) ResetBeforeParseAll() *KendoFilter {
- for i := range kf.Filters {
- kf.Filters[i].ResetBeforeParseAll()
+// ResetAllAdditionalParsers reset all pre-filter available
+func (f *Filter) ResetAllAdditionalParsers() *Filter {
+ for i := range f.Filters {
+ f.Filters[i].ResetAllAdditionalParsers()
}
- kf.preParser = []ParseFilter{}
- return kf
+ f.additionalParsers = []FilterParser{}
+ return f
}
// Transform your filter
-func (kf *KendoFilter) Transform(t func(*KendoFilter)) *KendoFilter {
- t(kf)
- return kf
+func (f *Filter) Transform(transform func(*Filter)) *Filter {
+ transform(f)
+ return f
}
// TransformField only transform field
-func (kf *KendoFilter) TransformField(t func(string) string) *KendoFilter {
- kf.Field = t(kf.Field)
- return kf
+func (f *Filter) TransformField(transform func(string) string) *Filter {
+ f.Field = transform(f.Field)
+ return f
}
// TransformAll your filter include all childs
-func (kf *KendoFilter) TransformAll(t func(*KendoFilter)) *KendoFilter {
- for i := range kf.Filters {
- kf.Filters[i].TransformAll(t)
+func (f *Filter) TransformAll(transform func(*Filter)) *Filter {
+ for i := range f.Filters {
+ f.Filters[i].TransformAll(transform)
}
- kf.Transform(t)
- return kf
+ f.Transform(transform)
+ return f
}
// TransformAllField only transform field include all childs
-func (kf *KendoFilter) TransformAllField(t func(string) string) *KendoFilter {
- for i := range kf.Filters {
- kf.Filters[i].TransformAllField(t)
- }
- kf.TransformField(t)
- return kf
-}
-
-// RegisterOperator register operator local scope
-func (kf *KendoFilter) RegisterOperator(f Operator, ops ...string) *KendoFilter {
- if kf.registeredOperators == nil {
- kf.registeredOperators = map[string]Operator{}
- }
- for _, op := range ops {
- kf.registeredOperators[op] = f
- }
- return kf
-}
-
-// RegisterOperatorAll register operator local scope include childs
-func (kf *KendoFilter) RegisterOperatorAll(f Operator, ops ...string) *KendoFilter {
- for i := range kf.Filters {
- kf.Filters[i].RegisterOperatorAll(f, ops...)
+func (f *Filter) TransformAllField(transform func(string) string) *Filter {
+ for i := range f.Filters {
+ f.Filters[i].TransformAllField(transform)
}
- kf.RegisterOperator(f, ops...)
- return kf
+ f.TransformField(transform)
+ return f
}
-// KendoSort struct sort
-type KendoSort struct {
+// SortDetail struct sort
+type SortDetail struct {
Dir string `json:"dir"`
Field string `json:"field"`
}
-// KendoSortArray alias []KendoSort
-type KendoSortArray []KendoSort
+// Sort alias []SortDetail
+type Sort []SortDetail
// Parse Parse
-func (ksa *KendoSortArray) Parse(f ParseSort) interface{} {
- return f(ksa)
+func (s *Sort) Parse(parser SortParser) interface{} {
+ return parser(s)
}
diff --git a/kendo_test.go b/kendo_test.go
new file mode 100644
index 0000000..4696494
--- /dev/null
+++ b/kendo_test.go
@@ -0,0 +1,59 @@
+package kendoparser
+
+import (
+ "fmt"
+ "github.com/eaciit/cast"
+ "github.com/stretchr/testify/require"
+ "go.mongodb.org/mongo-driver/bson"
+ "go.mongodb.org/mongo-driver/bson/primitive"
+ "regexp"
+ "strings"
+ "testing"
+)
+
+func Test_All(t *testing.T) {
+ // Operator Manager
+ om := OperatorManager{}
+ equal := func(kf Filter) interface{} {
+ if kf.IgnoreCase {
+ value := regexp.QuoteMeta(cast.ToString(kf.Value))
+ return bson.M{kf.Field: primitive.Regex{Pattern: "^" + strings.ToLower(value) + "$", Options: "i"}}
+ }
+ return bson.M{kf.Field: bson.M{"$eq": kf.Value}}
+ }
+ om.SetDefaultOperator(equal)
+ om.RegisterOperator(equal, "eq")
+ require.Equal(t, 1, len(om.OperatorFilters), "Must same")
+ om.Reset()
+ require.Equal(t, 0, len(om.OperatorFilters), "Must same")
+
+ // Sort
+ payloadSort := Sort{
+ SortDetail{
+ Field: "foo",
+ Dir: "DESC",
+ },
+ SortDetail{
+ Field: "bar",
+ Dir: "ASC",
+ },
+ SortDetail{
+ Field: "_id",
+ Dir: "desc",
+ },
+ }
+ // testing kendo sort
+ sortParser := func(s *Sort) interface{} {
+ sorter := []string{}
+ for _, ks := range *s {
+ sort := 1
+ if strings.ToLower(ks.Dir) == "desc" {
+ sort = -1
+ }
+ sorter = append(sorter, fmt.Sprintf("%v=%v", ks.Field, sort))
+ }
+ return sorter
+ }
+
+ require.Equal(t, []string{"foo=-1", "bar=1", "_id=-1"}, payloadSort.Parse(sortParser), "Must same")
+}
diff --git a/operator.go b/operator.go
index 6fbb65a..d887d35 100644
--- a/operator.go
+++ b/operator.go
@@ -1,30 +1,27 @@
-package gokendoparser
+package kendoparser
import (
"sync"
)
-// Operator basic interface of OperatorHander will have 2 of this func
-type Operator interface {
- Filter(KendoFilter) interface{}
-}
+type OperatorFilter func(Filter) interface{}
// OperatorManager OperatorManager
type OperatorManager struct {
- DefaultOperator Operator
- RegisteredOperators map[string]Operator
- mutex sync.Mutex
+ DefaultOperatorFilter OperatorFilter
+ OperatorFilters map[string]OperatorFilter
+ mutex sync.Mutex
}
// RegisterOperator register operator with safe
-func (om *OperatorManager) RegisterOperator(f Operator, ops ...string) {
+func (om *OperatorManager) RegisterOperator(f OperatorFilter, ops ...string) {
om.mutex.Lock()
for _, op := range ops {
if op != "" {
- if om.RegisteredOperators == nil {
- om.RegisteredOperators = map[string]Operator{}
+ if om.OperatorFilters == nil {
+ om.OperatorFilters = map[string]OperatorFilter{}
}
- om.RegisteredOperators[op] = f
+ om.OperatorFilters[op] = f
}
}
om.mutex.Unlock()
@@ -33,20 +30,13 @@ func (om *OperatorManager) RegisterOperator(f Operator, ops ...string) {
// Reset resetting global register (if needed)
func (om *OperatorManager) Reset() {
om.mutex.Lock()
- om.RegisteredOperators = map[string]Operator{}
+ om.OperatorFilters = map[string]OperatorFilter{}
om.mutex.Unlock()
}
//SetDefaultOperator by default, if no operator found, will use this instead
-func (om *OperatorManager) SetDefaultOperator(f Operator) {
+func (om *OperatorManager) SetDefaultOperator(f OperatorFilter) {
om.mutex.Lock()
- om.DefaultOperator = f
+ om.DefaultOperatorFilter = f
om.mutex.Unlock()
}
-
-// RegisterTo RegisterTo
-func (om *OperatorManager) RegisterTo(k *KendoRequest) {
- for op, fop := range om.RegisteredOperators {
- k.RegisterOperatorAll(fop, op)
- }
-}
diff --git a/parser.go b/parser.go
index ff2f546..88db192 100644
--- a/parser.go
+++ b/parser.go
@@ -1,14 +1,7 @@
-package gokendoparser
+package kendoparser
-// [Deprecated], use directly instead
-// // Parser Parser
-// type Parser interface {
-// ParseFilter(kf *KendoFilter) interface{}
-// ParserSort(ksa *KendoSortArray) interface{}
-// }
+// FilterParser FilterParser
+type FilterParser func(f *Filter) interface{}
-// ParseFilter ParseFilter
-type ParseFilter func(kf *KendoFilter) interface{}
-
-// ParseSort ParseSort
-type ParseSort func(ksa *KendoSortArray) interface{}
+// SortParser SortParser
+type SortParser func(s *Sort) interface{}
diff --git a/adapter/dbflex/kendo.go b/parser/dbflex/kendo.go
similarity index 54%
rename from adapter/dbflex/kendo.go
rename to parser/dbflex/kendo.go
index 7d8ac6b..446bd8f 100644
--- a/adapter/dbflex/kendo.go
+++ b/parser/dbflex/kendo.go
@@ -6,49 +6,47 @@ import (
"git.eaciitapp.com/sebar/dbflex"
- "github.com/raditzlawliet/gokendoparser"
+ "github.com/raditzlawliet/kendoparser"
)
-// Parser Parser
-// type Parser struct{}
-
-// ParseFilter convert KendoFilter into *dbox.Filter combination automaticly
+// FilterParser convert Filter into *dbox.Filter combination automaticly
// return can @Nullable if filter and filters empty
-func ParseFilter(kf *gokendoparser.KendoFilter) interface{} {
+func FilterParser(kf *kendoparser.Filter) interface{} {
// single filter
if len(kf.Filters) == 0 {
// processing will use copy instead to avoid change original value
ckFilter := *kf
// very customable handler
- if kf.GetBeforeParse() != nil {
- for _, handler := range kf.GetBeforeParse() {
+ if kf.AdditionalParsers() != nil {
+ for _, handler := range kf.AdditionalParsers() {
if r := handler(&ckFilter); r != nil {
return r
}
}
}
- // local scope operator
- if kf.GetRegisteredOperators() != nil {
- if opHandler, ok := kf.GetRegisteredOperators()[kf.Operator]; ok && opHandler != nil {
- return opHandler.Filter(ckFilter)
+ // (scoped)
+ if om := kf.GetOperatorManager(); om != nil {
+ // parser scope registered
+ if opHandler, ok := OperatorManager.OperatorFilters[kf.Operator]; ok {
+ return opHandler(ckFilter)
}
}
- // parser scope registered
- if opHandler, ok := operatorManager.RegisteredOperators[kf.Operator]; ok {
- return opHandler.Filter(ckFilter)
+ // (global)
+ if opHandler, ok := OperatorManager.OperatorFilters[kf.Operator]; ok {
+ return opHandler(ckFilter)
}
- // global defult
- return operatorManager.DefaultOperator.Filter(ckFilter)
+ // default (global)
+ return OperatorManager.DefaultOperatorFilter(ckFilter)
}
// so filters has some values
filters := []*dbflex.Filter{}
for _, kFilterChild := range kf.Filters {
- filter := ParseFilter(&kFilterChild)
+ filter := FilterParser(&kFilterChild)
if filter != nil {
filters = append(filters, filter.(*dbflex.Filter))
}
@@ -64,7 +62,7 @@ func ParseFilter(kf *gokendoparser.KendoFilter) interface{} {
}
// ParserSort return []string
-func ParserSort(ksa *gokendoparser.KendoSortArray) interface{} {
+func ParserSort(ksa *kendoparser.Sort) interface{} {
sorter := []string{}
for _, ks := range *ksa {
if strings.ToLower(ks.Dir) == "desc" {
diff --git a/adapter/dbflex/kendo_test.go b/parser/dbflex/kendo_test.go
similarity index 50%
rename from adapter/dbflex/kendo_test.go
rename to parser/dbflex/kendo_test.go
index b1e150c..ab983d2 100644
--- a/adapter/dbflex/kendo_test.go
+++ b/parser/dbflex/kendo_test.go
@@ -8,22 +8,22 @@ import (
"git.eaciitapp.com/sebar/dbflex"
tk "github.com/eaciit/toolkit"
- "github.com/raditzlawliet/gokendoparser"
+ "github.com/raditzlawliet/kendoparser"
"github.com/stretchr/testify/require"
)
-func Test_ParseFilter(t *testing.T) {
+func Test_FilterParser(t *testing.T) {
// Single filter
{
- kendoFilter := gokendoparser.KendoFilter{
+ kendoFilter := kendoparser.Filter{
Field: "_id", Operator: "eq", Value: "val",
}
- resultFilter := kendoFilter.Parse(Parser{}).(*dbflex.Filter)
+ resultFilter := kendoFilter.Parse(FilterParser).(*dbflex.Filter)
expectedFilter := dbflex.Eq("_id", "val")
require.Equal(t, expectedFilter, resultFilter, "Result dbox filter must same")
- kendoRequest := gokendoparser.KendoRequest{}
+ kendoRequest := kendoparser.KendoRequest{}
e := tk.UnjsonFromString(`{
"data": {
"filter": {
@@ -35,43 +35,43 @@ func Test_ParseFilter(t *testing.T) {
}`, &kendoRequest)
require.Nil(t, e, "Json parse must work")
require.Equal(t, kendoFilter, kendoRequest.Data.Filter, "Filter must same")
- resultFilterJSON := kendoRequest.Data.Filter.Parse(Parser{}).(*dbflex.Filter)
+ resultFilterJSON := kendoRequest.Data.Filter.Parse(FilterParser).(*dbflex.Filter)
require.Equal(t, expectedFilter, resultFilterJSON, "Result dbox filter must same")
}
{
- kendoFilter := gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "_id", Operator: "eq", Value: "val"},
+ kendoFilter := kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "_id", Operator: "eq", Value: "val"},
},
Logic: "and",
}
- resultFilter := kendoFilter.Parse(Parser{}).(*dbflex.Filter)
+ resultFilter := kendoFilter.Parse(FilterParser).(*dbflex.Filter)
expectedFilter := dbflex.And(dbflex.Eq("_id", "val"))
require.Equal(t, expectedFilter, resultFilter, "Result dbox filter must same")
}
{
- kendoFilter := gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "_id", Operator: "eq", Value: "val"},
- gokendoparser.KendoFilter{Field: "_id", Operator: "neq", Value: "val"},
+ kendoFilter := kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "_id", Operator: "eq", Value: "val"},
+ kendoparser.Filter{Field: "_id", Operator: "neq", Value: "val"},
},
Logic: "or",
},
- gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "_id", Operator: "eq", Value: "val2"},
- gokendoparser.KendoFilter{Field: "_id", Operator: "neq", Value: "val2"},
+ kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "_id", Operator: "eq", Value: "val2"},
+ kendoparser.Filter{Field: "_id", Operator: "neq", Value: "val2"},
},
Logic: "or",
},
},
Logic: "and",
}
- resultFilter := kendoFilter.Parse(Parser{})
+ resultFilter := kendoFilter.Parse(FilterParser)
expectedFilter := dbflex.And(
dbflex.Or(
dbflex.Eq("_id", "val"),
@@ -87,22 +87,22 @@ func Test_ParseFilter(t *testing.T) {
// operator check
{
- kendoFilter := gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "_id", Operator: "eq", Value: "val"},
- gokendoparser.KendoFilter{Field: "_id", Operator: "neq", Value: "val"},
- // gokendoparser.KendoFilter{Field: "_id", Operator: "doesnotcontain", Value: "val"},
- gokendoparser.KendoFilter{Field: "_id", Operator: "contain", Value: "val"},
- gokendoparser.KendoFilter{Field: "_id", Operator: "in", Values: []interface{}{"val"}},
- gokendoparser.KendoFilter{Field: "_id", Operator: "gte", Value: "val"},
- gokendoparser.KendoFilter{Field: "_id", Operator: "lte", Value: "val"},
- gokendoparser.KendoFilter{Field: "time", Operator: "gtedate", Value: "2006-01-02T15:04:05Z07:00"},
- gokendoparser.KendoFilter{Field: "time", Operator: "ltedate", Value: "2006-01-02T15:04:05Z07:00"},
- gokendoparser.KendoFilter{Field: "_id", Operator: "unknown", Value: "val"},
+ kendoFilter := kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "_id", Operator: "eq", Value: "val"},
+ kendoparser.Filter{Field: "_id", Operator: "neq", Value: "val"},
+ // kendoparser.Filter{Field: "_id", Operator: "doesnotcontain", Value: "val"},
+ kendoparser.Filter{Field: "_id", Operator: "contain", Value: "val"},
+ kendoparser.Filter{Field: "_id", Operator: "in", Values: []interface{}{"val"}},
+ kendoparser.Filter{Field: "_id", Operator: "gte", Value: "val"},
+ kendoparser.Filter{Field: "_id", Operator: "lte", Value: "val"},
+ kendoparser.Filter{Field: "time", Operator: "gtedate", Value: "2006-01-02T15:04:05Z07:00"},
+ kendoparser.Filter{Field: "time", Operator: "ltedate", Value: "2006-01-02T15:04:05Z07:00"},
+ kendoparser.Filter{Field: "_id", Operator: "unknown", Value: "val"},
},
Logic: "and",
}
- resultFilter := kendoFilter.Parse(Parser{}).(*dbflex.Filter)
+ resultFilter := kendoFilter.Parse(FilterParser).(*dbflex.Filter)
testTime, _ := time.Parse(time.RFC3339, "2006-01-02T15:04:05Z07:00")
expectedFilter := dbflex.And(
dbflex.Eq("_id", "val"),
@@ -123,16 +123,16 @@ func Test_TransformField(t *testing.T) {
// transform single filter field
// _ID => _id
{
- kendoFilter := gokendoparser.KendoFilter{
+ kendoFilter := kendoparser.Filter{
Field: "_ID", Operator: "eq", Value: "val",
}
kendoFilter.TransformField(strings.ToLower)
- resultFilter := kendoFilter.Parse(Parser{}).(*dbflex.Filter)
+ resultFilter := kendoFilter.Parse(FilterParser).(*dbflex.Filter)
expectedFilter := dbflex.Eq("_id", "val")
require.Equal(t, expectedFilter, resultFilter, "Result dbox filter must same")
- kendoRequest := gokendoparser.KendoRequest{}
+ kendoRequest := kendoparser.KendoRequest{}
e := tk.UnjsonFromString(`{
"data": {
"filter": {
@@ -146,26 +146,26 @@ func Test_TransformField(t *testing.T) {
require.Nil(t, e, "Json parse must work")
require.Equal(t, kendoFilter, kendoRequest.Data.Filter, "Filter must same")
- resultFilterJSON := kendoRequest.Data.Filter.Parse(Parser{}).(*dbflex.Filter)
+ resultFilterJSON := kendoRequest.Data.Filter.Parse(FilterParser).(*dbflex.Filter)
require.Equal(t, expectedFilter, resultFilterJSON, "Result dbox filter must same")
}
// test Transform single field, should not affect the child filter
// _ID => _id
{
- kendoFilter := gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "_ID", Operator: "eq", Value: "val"},
- gokendoparser.KendoFilter{Field: "_ID", Operator: "neq", Value: "val"},
+ kendoFilter := kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "_ID", Operator: "eq", Value: "val"},
+ kendoparser.Filter{Field: "_ID", Operator: "neq", Value: "val"},
},
Logic: "or",
},
- gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "_ID", Operator: "eq", Value: "val2"},
- gokendoparser.KendoFilter{Field: "_ID", Operator: "neq", Value: "val2"},
+ kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "_ID", Operator: "eq", Value: "val2"},
+ kendoparser.Filter{Field: "_ID", Operator: "neq", Value: "val2"},
},
Logic: "or",
},
@@ -173,7 +173,7 @@ func Test_TransformField(t *testing.T) {
Logic: "and",
}
kendoFilter.TransformField(strings.ToLower)
- resultFilter := kendoFilter.Parse(Parser{}).(*dbflex.Filter)
+ resultFilter := kendoFilter.Parse(FilterParser).(*dbflex.Filter)
expectedFilter := dbflex.And(
dbflex.Or(
dbflex.Eq("_ID", "val"),
@@ -190,19 +190,19 @@ func Test_TransformField(t *testing.T) {
// test transform all field
// _ID => _id
{
- kendoFilter := gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "_ID", Operator: "eq", Value: "val"},
- gokendoparser.KendoFilter{Field: "_ID", Operator: "neq", Value: "val"},
+ kendoFilter := kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "_ID", Operator: "eq", Value: "val"},
+ kendoparser.Filter{Field: "_ID", Operator: "neq", Value: "val"},
},
Logic: "or",
},
- gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "_ID", Operator: "eq", Value: "val2"},
- gokendoparser.KendoFilter{Field: "_ID", Operator: "neq", Value: "val2"},
+ kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "_ID", Operator: "eq", Value: "val2"},
+ kendoparser.Filter{Field: "_ID", Operator: "neq", Value: "val2"},
},
Logic: "or",
},
@@ -210,7 +210,7 @@ func Test_TransformField(t *testing.T) {
Logic: "and",
}
kendoFilter.TransformAllField(strings.ToLower)
- resultFilter := kendoFilter.Parse(Parser{}).(*dbflex.Filter)
+ resultFilter := kendoFilter.Parse(FilterParser).(*dbflex.Filter)
expectedFilter := dbflex.And(
dbflex.Or(
dbflex.Eq("_id", "val"),
@@ -227,17 +227,17 @@ func Test_TransformField(t *testing.T) {
func Test_Sort(t *testing.T) {
{
- kData := gokendoparser.KendoData{
- Sort: gokendoparser.KendoSortArray{
- gokendoparser.KendoSort{
+ kData := kendoparser.Data{
+ Sort: kendoparser.Sort{
+ kendoparser.SortDetail{
Field: "foo",
Dir: "DESC",
},
- gokendoparser.KendoSort{
+ kendoparser.SortDetail{
Field: "bar",
Dir: "ASC",
},
- gokendoparser.KendoSort{
+ kendoparser.SortDetail{
Field: "_id",
Dir: "desc",
},
@@ -245,7 +245,7 @@ func Test_Sort(t *testing.T) {
}
// try dbox filter
- result := kData.Sort.Parse(Parser{}).([]string)
+ result := kData.Sort.Parse(ParserSort).([]string)
expected := []string{"-foo", "bar", "-_id"}
require.Equal(t, expected, result, "Result must same")
}
diff --git a/parser/dbflex/operator.go b/parser/dbflex/operator.go
new file mode 100644
index 0000000..a7485a3
--- /dev/null
+++ b/parser/dbflex/operator.go
@@ -0,0 +1,105 @@
+package kpdbflex
+
+import (
+ "time"
+
+ "git.eaciitapp.com/sebar/dbflex"
+
+ "github.com/raditzlawliet/kendoparser"
+
+ "github.com/spf13/cast"
+)
+
+var (
+ // OperatorManager of Mongo Parser
+ OperatorManager = new(kendoparser.OperatorManager)
+ // Operator bundle of Mongo Parser
+ Operator = OperatorBundle{}
+)
+
+type OperatorBundle struct{}
+
+func init() {
+ RegisterOperator()
+}
+
+// RegisterOperator RegisterOperator
+func RegisterOperator() {
+ OperatorManager.SetDefaultOperator(Operator.Equal)
+ OperatorManager.RegisterOperator(Operator.Equal, "eq", "equal")
+ OperatorManager.RegisterOperator(Operator.NotEqual, "ne", "neq", "notequal")
+ OperatorManager.RegisterOperator(Operator.Contain, "contain", "contains", "include", "includes")
+ OperatorManager.RegisterOperator(Operator.In, "in")
+ OperatorManager.RegisterOperator(Operator.Gt, "gt")
+ OperatorManager.RegisterOperator(Operator.Gte, "gte")
+ OperatorManager.RegisterOperator(Operator.Lt, "lt")
+ OperatorManager.RegisterOperator(Operator.Lte, "lte")
+ OperatorManager.RegisterOperator(Operator.GtDate, "gtdate")
+ OperatorManager.RegisterOperator(Operator.GteDate, "gtedate")
+ OperatorManager.RegisterOperator(Operator.LtDate, "ltdate")
+ OperatorManager.RegisterOperator(Operator.LteDate, "ltedate")
+ OperatorManager.RegisterOperator(Operator.Range, "range", "between")
+}
+
+func (o *OperatorBundle) Equal(kf kendoparser.Filter) interface{} {
+ return dbflex.Eq(kf.Field, kf.Value)
+}
+
+func (o *OperatorBundle) NotEqual(kf kendoparser.Filter) interface{} {
+ return dbflex.Ne(kf.Field, kf.Value)
+}
+
+func (o *OperatorBundle) Contain(kf kendoparser.Filter) interface{} {
+ return dbflex.Contains(kf.Field, cast.ToString(kf.Value))
+}
+
+func (o *OperatorBundle) In(kf kendoparser.Filter) interface{} {
+ return dbflex.In(kf.Field, kf.Values...)
+}
+
+func (o *OperatorBundle) Gt(kf kendoparser.Filter) interface{} {
+ return dbflex.Gt(kf.Field, kf.Value)
+}
+
+func (o *OperatorBundle) Gte(kf kendoparser.Filter) interface{} {
+ return dbflex.Gte(kf.Field, kf.Value)
+}
+
+func (o *OperatorBundle) Lt(kf kendoparser.Filter) interface{} {
+ return dbflex.Lt(kf.Field, kf.Value)
+}
+
+func (o *OperatorBundle) Lte(kf kendoparser.Filter) interface{} {
+ return dbflex.Lte(kf.Field, kf.Value)
+}
+
+func (o *OperatorBundle) GtDate(kf kendoparser.Filter) interface{} {
+ dtVariable, _ := time.Parse(time.RFC3339, cast.ToString(kf.Value))
+ return dbflex.Gt(kf.Field, dtVariable)
+}
+
+func (o *OperatorBundle) GteDate(kf kendoparser.Filter) interface{} {
+ dtVariable, _ := time.Parse(time.RFC3339, cast.ToString(kf.Value))
+ return dbflex.Gte(kf.Field, dtVariable)
+}
+
+func (o *OperatorBundle) LtDate(kf kendoparser.Filter) interface{} {
+ dtVariable, _ := time.Parse(time.RFC3339, cast.ToString(kf.Value))
+ return dbflex.Lt(kf.Field, dtVariable)
+}
+
+func (o *OperatorBundle) LteDate(kf kendoparser.Filter) interface{} {
+ dtVariable, _ := time.Parse(time.RFC3339, cast.ToString(kf.Value))
+ return dbflex.Lte(kf.Field, dtVariable)
+}
+
+func (o *OperatorBundle) Range(kf kendoparser.Filter) interface{} {
+ var v0, v1 interface{}
+ if len(kf.Values) > 0 {
+ v0 = kf.Values[0]
+ }
+ if len(kf.Values) > 1 {
+ v1 = kf.Values[1]
+ }
+ return dbflex.Range(kf.Field, v0, v1)
+}
diff --git a/adapter/dbox/kendo.go b/parser/dbox/kendo.go
similarity index 60%
rename from adapter/dbox/kendo.go
rename to parser/dbox/kendo.go
index 516b0c9..c2834e6 100644
--- a/adapter/dbox/kendo.go
+++ b/parser/dbox/kendo.go
@@ -5,33 +5,33 @@ import (
"strings"
"github.com/eaciit/dbox"
- "github.com/raditzlawliet/gokendoparser"
+ "github.com/raditzlawliet/kendoparser"
)
// Parser Parser
// type Parser struct{}
-// ParseFilter convert KendoFilter into *dbox.Filter combination automaticly
+// FilterParser convert Filter into *dbox.Filter combination automaticly
// return can @Nullable if filter and filters empty
-func ParseFilter(kf *gokendoparser.KendoFilter) interface{} {
+func FilterParser(kf *kendoparser.Filter) interface{} {
// single filter
if len(kf.Filters) == 0 {
// processing will use copy instead to avoid change original value
ckFilter := *kf
// very customable handler
- if kf.GetBeforeParse() != nil {
- for _, handler := range kf.GetBeforeParse() {
+ if kf.AdditionalParsers() != nil {
+ for _, handler := range kf.AdditionalParsers() {
if r := handler(&ckFilter); r != nil {
return r
}
}
}
- // local scope operator
- if kf.GetRegisteredOperators() != nil {
- if opHandler, ok := kf.GetRegisteredOperators()[kf.Operator]; ok && opHandler != nil {
- f := opHandler.Filter(ckFilter)
+ // (scoped)
+ if om := kf.GetOperatorManager(); om != nil {
+ if opHandler, ok := om.OperatorFilters[kf.Operator]; ok {
+ f := opHandler(ckFilter)
if f != nil {
return f.(*dbox.Filter)
}
@@ -39,17 +39,17 @@ func ParseFilter(kf *gokendoparser.KendoFilter) interface{} {
}
}
- // parser scope registered
- if opHandler, ok := operatorManager.RegisteredOperators[kf.Operator]; ok {
- f := opHandler.Filter(ckFilter)
+ // (global)
+ if opHandler, ok := OperatorManager.OperatorFilters[kf.Operator]; ok {
+ f := opHandler(ckFilter)
if f != nil {
return f.(*dbox.Filter)
}
return nil
}
- // // global defult
- f := operatorManager.DefaultOperator.Filter(ckFilter)
+ // default (global)
+ f := OperatorManager.DefaultOperatorFilter(ckFilter)
if f != nil {
return f.(*dbox.Filter)
}
@@ -59,7 +59,7 @@ func ParseFilter(kf *gokendoparser.KendoFilter) interface{} {
// so filters has some values
dboxFilters := []*dbox.Filter{}
for _, kFilterChild := range kf.Filters {
- dboxFilter := ParseFilter(&kFilterChild)
+ dboxFilter := FilterParser(&kFilterChild)
if dboxFilter != nil {
dboxFilters = append(dboxFilters, dboxFilter.(*dbox.Filter))
}
@@ -74,8 +74,8 @@ func ParseFilter(kf *gokendoparser.KendoFilter) interface{} {
return nil // can return nil if filter & filters are meh ...
}
-// ParseSort return []string
-func ParseSort(ksa *gokendoparser.KendoSortArray) interface{} {
+// SortParser return []string
+func SortParser(ksa *kendoparser.Sort) interface{} {
sorter := []string{}
for _, ks := range *ksa {
if strings.ToLower(ks.Dir) == "desc" {
diff --git a/adapter/dbox/kendo_test.go b/parser/dbox/kendo_test.go
similarity index 51%
rename from adapter/dbox/kendo_test.go
rename to parser/dbox/kendo_test.go
index c1ee1e0..a4dfaa9 100644
--- a/adapter/dbox/kendo_test.go
+++ b/parser/dbox/kendo_test.go
@@ -7,24 +7,24 @@ import (
"github.com/eaciit/dbox"
tk "github.com/eaciit/toolkit"
- "github.com/raditzlawliet/gokendoparser"
- "github.com/raditzlawliet/gokendoparser/helper"
+ "github.com/raditzlawliet/kendoparser"
+ "github.com/raditzlawliet/kendoparser/helper"
"github.com/spf13/cast"
"github.com/stretchr/testify/require"
)
-func Test_ParseFilter(t *testing.T) {
+func Test_FilterParser(t *testing.T) {
// Single filter
{
- kendoFilter := gokendoparser.KendoFilter{
+ kendoFilter := kendoparser.Filter{
Field: "_id", Operator: "eq", Value: "val",
}
- resultFilter := kendoFilter.Parse(ParseFilter).(*dbox.Filter)
+ resultFilter := kendoFilter.Parse(FilterParser).(*dbox.Filter)
expectedFilter := dbox.Eq("_id", "val")
require.Equal(t, expectedFilter, resultFilter, "Result dbox filter must same")
- kendoRequest := gokendoparser.KendoRequest{}
+ kendoRequest := kendoparser.KendoRequest{}
e := tk.UnjsonFromString(`{
"data": {
"filter": {
@@ -36,43 +36,43 @@ func Test_ParseFilter(t *testing.T) {
}`, &kendoRequest)
require.Nil(t, e, "Json parse must work")
require.Equal(t, kendoFilter, kendoRequest.Data.Filter, "Filter must same")
- resultFilterJSON := kendoRequest.Data.Filter.Parse(ParseFilter).(*dbox.Filter)
+ resultFilterJSON := kendoRequest.Data.Filter.Parse(FilterParser).(*dbox.Filter)
require.Equal(t, expectedFilter, resultFilterJSON, "Result dbox filter must same")
}
{
- kendoFilter := gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "_id", Operator: "eq", Value: "val"},
+ kendoFilter := kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "_id", Operator: "eq", Value: "val"},
},
Logic: "and",
}
- resultFilter := kendoFilter.Parse(ParseFilter).(*dbox.Filter)
+ resultFilter := kendoFilter.Parse(FilterParser).(*dbox.Filter)
expectedFilter := dbox.And(dbox.Eq("_id", "val"))
require.Equal(t, expectedFilter, resultFilter, "Result dbox filter must same")
}
{
- kendoFilter := gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "_id", Operator: "eq", Value: "val"},
- gokendoparser.KendoFilter{Field: "_id", Operator: "neq", Value: "val"},
+ kendoFilter := kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "_id", Operator: "eq", Value: "val"},
+ kendoparser.Filter{Field: "_id", Operator: "neq", Value: "val"},
},
Logic: "or",
},
- gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "_id", Operator: "eq", Value: "val2"},
- gokendoparser.KendoFilter{Field: "_id", Operator: "neq", Value: "val2"},
+ kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "_id", Operator: "eq", Value: "val2"},
+ kendoparser.Filter{Field: "_id", Operator: "neq", Value: "val2"},
},
Logic: "or",
},
},
Logic: "and",
}
- resultFilter := kendoFilter.Parse(ParseFilter)
+ resultFilter := kendoFilter.Parse(FilterParser)
expectedFilter := dbox.And(
dbox.Or(
dbox.Eq("_id", "val"),
@@ -88,23 +88,23 @@ func Test_ParseFilter(t *testing.T) {
// operator check
{
- kendoFilter := gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "_id", Operator: "eq", Value: "val"},
- gokendoparser.KendoFilter{Field: "_id", Operator: "neq", Value: "val"},
- gokendoparser.KendoFilter{Field: "_id", Operator: "doesnotcontain", Value: "val"},
- gokendoparser.KendoFilter{Field: "_id", Operator: "contain", Value: "val"},
- gokendoparser.KendoFilter{Field: "_id", Operator: "in", Values: []interface{}{"val"}},
- gokendoparser.KendoFilter{Field: "_id", Operator: "gte", Value: "val"},
- gokendoparser.KendoFilter{Field: "_id", Operator: "lte", Value: "val"},
- gokendoparser.KendoFilter{Field: "time", Operator: "gtedate", Value: "2006-01-02T15:04:05Z07:00"},
- gokendoparser.KendoFilter{Field: "time", Operator: "ltedate", Value: "2006-01-02T15:04:05Z07:00"},
- gokendoparser.KendoFilter{Field: "_id", Operator: "unknown", Value: "val"},
- gokendoparser.KendoFilter{Field: "_id", Operator: "exists", Value: "val"},
+ kendoFilter := kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "_id", Operator: "eq", Value: "val"},
+ kendoparser.Filter{Field: "_id", Operator: "neq", Value: "val"},
+ kendoparser.Filter{Field: "_id", Operator: "doesnotcontain", Value: "val"},
+ kendoparser.Filter{Field: "_id", Operator: "contain", Value: "val"},
+ kendoparser.Filter{Field: "_id", Operator: "in", Values: []interface{}{"val"}},
+ kendoparser.Filter{Field: "_id", Operator: "gte", Value: "val"},
+ kendoparser.Filter{Field: "_id", Operator: "lte", Value: "val"},
+ kendoparser.Filter{Field: "time", Operator: "gtedate", Value: "2006-01-02T15:04:05Z07:00"},
+ kendoparser.Filter{Field: "time", Operator: "ltedate", Value: "2006-01-02T15:04:05Z07:00"},
+ kendoparser.Filter{Field: "_id", Operator: "unknown", Value: "val"},
+ kendoparser.Filter{Field: "_id", Operator: "exists", Value: "val"},
},
Logic: "and",
}
- resultFilter := kendoFilter.Parse(ParseFilter).(*dbox.Filter)
+ resultFilter := kendoFilter.Parse(FilterParser).(*dbox.Filter)
testTime, _ := time.Parse(time.RFC3339, "2006-01-02T15:04:05Z07:00")
expectedFilter := dbox.And(
dbox.Eq("_id", "val"),
@@ -132,16 +132,16 @@ func Test_TransformField(t *testing.T) {
// transform single filter field
// _ID => _id
{
- kendoFilter := gokendoparser.KendoFilter{
+ kendoFilter := kendoparser.Filter{
Field: "_ID", Operator: "eq", Value: "val",
}
kendoFilter.TransformField(strings.ToLower)
- resultFilter := kendoFilter.Parse(ParseFilter).(*dbox.Filter)
+ resultFilter := kendoFilter.Parse(FilterParser).(*dbox.Filter)
expectedFilter := dbox.Eq("_id", "val")
require.Equal(t, expectedFilter, resultFilter, "Result dbox filter must same")
- kendoRequest := gokendoparser.KendoRequest{}
+ kendoRequest := kendoparser.KendoRequest{}
e := tk.UnjsonFromString(`{
"data": {
"filter": {
@@ -155,26 +155,26 @@ func Test_TransformField(t *testing.T) {
require.Nil(t, e, "Json parse must work")
require.Equal(t, kendoFilter, kendoRequest.Data.Filter, "Filter must same")
- resultFilterJSON := kendoRequest.Data.Filter.Parse(ParseFilter).(*dbox.Filter)
+ resultFilterJSON := kendoRequest.Data.Filter.Parse(FilterParser).(*dbox.Filter)
require.Equal(t, expectedFilter, resultFilterJSON, "Result dbox filter must same")
}
// test Transform single field, should not affect the child filter
// _ID => _id
{
- kendoFilter := gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "_ID", Operator: "eq", Value: "val"},
- gokendoparser.KendoFilter{Field: "_ID", Operator: "neq", Value: "val"},
+ kendoFilter := kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "_ID", Operator: "eq", Value: "val"},
+ kendoparser.Filter{Field: "_ID", Operator: "neq", Value: "val"},
},
Logic: "or",
},
- gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "_ID", Operator: "eq", Value: "val2"},
- gokendoparser.KendoFilter{Field: "_ID", Operator: "neq", Value: "val2"},
+ kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "_ID", Operator: "eq", Value: "val2"},
+ kendoparser.Filter{Field: "_ID", Operator: "neq", Value: "val2"},
},
Logic: "or",
},
@@ -182,7 +182,7 @@ func Test_TransformField(t *testing.T) {
Logic: "and",
}
kendoFilter.TransformField(strings.ToLower)
- resultFilter := kendoFilter.Parse(ParseFilter).(*dbox.Filter)
+ resultFilter := kendoFilter.Parse(FilterParser).(*dbox.Filter)
expectedFilter := dbox.And(
dbox.Or(
dbox.Eq("_ID", "val"),
@@ -199,19 +199,19 @@ func Test_TransformField(t *testing.T) {
// test transform all field
// _ID => _id
{
- kendoFilter := gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "_ID", Operator: "eq", Value: "val"},
- gokendoparser.KendoFilter{Field: "_ID", Operator: "neq", Value: "val"},
+ kendoFilter := kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "_ID", Operator: "eq", Value: "val"},
+ kendoparser.Filter{Field: "_ID", Operator: "neq", Value: "val"},
},
Logic: "or",
},
- gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "_ID", Operator: "eq", Value: "val2"},
- gokendoparser.KendoFilter{Field: "_ID", Operator: "neq", Value: "val2"},
+ kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "_ID", Operator: "eq", Value: "val2"},
+ kendoparser.Filter{Field: "_ID", Operator: "neq", Value: "val2"},
},
Logic: "or",
},
@@ -219,7 +219,7 @@ func Test_TransformField(t *testing.T) {
Logic: "and",
}
kendoFilter.TransformAllField(strings.ToLower)
- resultFilter := kendoFilter.Parse(ParseFilter).(*dbox.Filter)
+ resultFilter := kendoFilter.Parse(FilterParser).(*dbox.Filter)
expectedFilter := dbox.And(
dbox.Or(
dbox.Eq("_id", "val"),
@@ -237,21 +237,21 @@ func Test_Transform(t *testing.T) {
// transform single filter
// ID => _id
{
- kendoFilter := gokendoparser.KendoFilter{
+ kendoFilter := kendoparser.Filter{
Field: "ID", Operator: "eq", Value: "val",
}
kendoFilter.TransformField(strings.ToLower)
- kendoFilter.Transform(func(kf *gokendoparser.KendoFilter) {
+ kendoFilter.Transform(func(kf *kendoparser.Filter) {
if kf.Field == "id" {
kf.Field = "_id"
}
})
- resultFilter := kendoFilter.Parse(ParseFilter).(*dbox.Filter)
+ resultFilter := kendoFilter.Parse(FilterParser).(*dbox.Filter)
expectedFilter := dbox.Eq("_id", "val")
require.Equal(t, expectedFilter, resultFilter, "Result dbox filter must same")
- kendoRequest := gokendoparser.KendoRequest{}
+ kendoRequest := kendoparser.KendoRequest{}
e := tk.UnjsonFromString(`{
"data": {
"filter": {
@@ -262,7 +262,7 @@ func Test_Transform(t *testing.T) {
}
}`, &kendoRequest)
kendoRequest.Data.Filter.TransformField(strings.ToLower)
- kendoRequest.Data.Filter.Transform(func(kf *gokendoparser.KendoFilter) {
+ kendoRequest.Data.Filter.Transform(func(kf *kendoparser.Filter) {
if kf.Field == "id" {
kf.Field = "_id"
}
@@ -270,25 +270,25 @@ func Test_Transform(t *testing.T) {
require.Nil(t, e, "Json parse must work")
require.Equal(t, kendoFilter, kendoRequest.Data.Filter, "Filter must same")
- resultFilterJSON := kendoRequest.Data.Filter.Parse(ParseFilter).(*dbox.Filter)
+ resultFilterJSON := kendoRequest.Data.Filter.Parse(FilterParser).(*dbox.Filter)
require.Equal(t, expectedFilter, resultFilterJSON, "Result dbox filter must same")
}
// test Transform single, should not affect the child filter
{
- kendoFilter := gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "ID", Operator: "eq", Value: "val"},
- gokendoparser.KendoFilter{Field: "ID", Operator: "neq", Value: "val"},
+ kendoFilter := kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "ID", Operator: "eq", Value: "val"},
+ kendoparser.Filter{Field: "ID", Operator: "neq", Value: "val"},
},
Logic: "or",
},
- gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "ID", Operator: "eq", Value: "val2"},
- gokendoparser.KendoFilter{Field: "ID", Operator: "neq", Value: "val2"},
+ kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "ID", Operator: "eq", Value: "val2"},
+ kendoparser.Filter{Field: "ID", Operator: "neq", Value: "val2"},
},
Logic: "or",
},
@@ -296,12 +296,12 @@ func Test_Transform(t *testing.T) {
Logic: "and",
}
kendoFilter.TransformField(strings.ToLower)
- kendoFilter.Transform(func(kf *gokendoparser.KendoFilter) {
+ kendoFilter.Transform(func(kf *kendoparser.Filter) {
if kf.Field == "id" {
kf.Field = "_id"
}
})
- resultFilter := kendoFilter.Parse(ParseFilter).(*dbox.Filter)
+ resultFilter := kendoFilter.Parse(FilterParser).(*dbox.Filter)
expectedFilter := dbox.And(
dbox.Or(
dbox.Eq("ID", "val"),
@@ -318,19 +318,19 @@ func Test_Transform(t *testing.T) {
// test transform all
// ID => _id
{
- kendoFilter := gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "ID", Operator: "eq", Value: "val"},
- gokendoparser.KendoFilter{Field: "ID", Operator: "neq", Value: "val"},
+ kendoFilter := kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "ID", Operator: "eq", Value: "val"},
+ kendoparser.Filter{Field: "ID", Operator: "neq", Value: "val"},
},
Logic: "or",
},
- gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "ID", Operator: "eq", Value: "val2"},
- gokendoparser.KendoFilter{Field: "ID", Operator: "neq", Value: "val2"},
+ kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "ID", Operator: "eq", Value: "val2"},
+ kendoparser.Filter{Field: "ID", Operator: "neq", Value: "val2"},
},
Logic: "or",
},
@@ -338,12 +338,12 @@ func Test_Transform(t *testing.T) {
Logic: "and",
}
kendoFilter.TransformAllField(strings.ToLower)
- kendoFilter.TransformAll(func(kf *gokendoparser.KendoFilter) {
+ kendoFilter.TransformAll(func(kf *kendoparser.Filter) {
if kf.Field == "id" {
kf.Field = "_id"
}
})
- resultFilter := kendoFilter.Parse(ParseFilter).(*dbox.Filter)
+ resultFilter := kendoFilter.Parse(FilterParser).(*dbox.Filter)
expectedFilter := dbox.And(
dbox.Or(
dbox.Eq("_id", "val"),
@@ -361,19 +361,19 @@ func Test_PreFilterHandler(t *testing.T) {
// transform single filter
// ID => _id
{
- kendoFilter := gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "ID", Operator: "eq", Value: "val"},
- gokendoparser.KendoFilter{Field: "STATUS", Operator: "eq", Value: "true"},
+ kendoFilter := kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "ID", Operator: "eq", Value: "val"},
+ kendoparser.Filter{Field: "STATUS", Operator: "eq", Value: "true"},
},
Logic: "or",
},
- gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "ID", Operator: "eq", Value: "val2"},
- gokendoparser.KendoFilter{Field: "ID", Operator: "neq", Value: "val2"},
+ kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "ID", Operator: "eq", Value: "val2"},
+ kendoparser.Filter{Field: "ID", Operator: "neq", Value: "val2"},
},
Logic: "or",
},
@@ -382,22 +382,22 @@ func Test_PreFilterHandler(t *testing.T) {
}
// try dbox filter
resultFilter := kendoFilter.TransformAllField(strings.ToLower).
- TransformAll(func(kf *gokendoparser.KendoFilter) {
+ TransformAll(func(kf *kendoparser.Filter) {
if kf.Field == "id" {
kf.Field = "_id"
}
}).
- BeforeParseAll(func(kf *gokendoparser.KendoFilter) interface{} {
+ AddAllParser(func(kf *kendoparser.Filter) interface{} {
if kf.Field == "status" {
// return your custom handler
return dbox.Eq(kf.Field, helper.StringToBool(cast.ToString(kf.Value), false))
}
return nil // pas nil to continue original filter
}).
- Parse(ParseFilter).(*dbox.Filter)
+ Parse(FilterParser).(*dbox.Filter)
// reset if needed another
- kendoFilter.ResetBeforeParseAll()
+ kendoFilter.ResetAllAdditionalParsers()
expectedFilter := dbox.And(
dbox.Or(
@@ -414,17 +414,17 @@ func Test_PreFilterHandler(t *testing.T) {
}
func Test_Sort(t *testing.T) {
{
- kData := gokendoparser.KendoData{
- Sort: gokendoparser.KendoSortArray{
- gokendoparser.KendoSort{
+ kData := kendoparser.Data{
+ Sort: kendoparser.Sort{
+ kendoparser.SortDetail{
Field: "foo",
Dir: "DESC",
},
- gokendoparser.KendoSort{
+ kendoparser.SortDetail{
Field: "bar",
Dir: "ASC",
},
- gokendoparser.KendoSort{
+ kendoparser.SortDetail{
Field: "_id",
Dir: "desc",
},
@@ -432,7 +432,7 @@ func Test_Sort(t *testing.T) {
}
// try dbox filter
- result := kData.Sort.Parse(ParseSort).([]string)
+ result := kData.Sort.Parse(SortParser).([]string)
expected := []string{"-foo", "bar", "-_id"}
require.Equal(t, expected, result, "Result must same")
}
diff --git a/parser/dbox/operator.go b/parser/dbox/operator.go
new file mode 100644
index 0000000..2e2e8ff
--- /dev/null
+++ b/parser/dbox/operator.go
@@ -0,0 +1,109 @@
+package kpdbox
+
+import (
+ "regexp"
+ "time"
+
+ "github.com/eaciit/dbox"
+ "github.com/eaciit/toolkit"
+ "github.com/raditzlawliet/kendoparser"
+ "github.com/raditzlawliet/kendoparser/helper"
+
+ "github.com/spf13/cast"
+)
+
+var (
+ // OperatorManager of Mongo Parser
+ OperatorManager = new(kendoparser.OperatorManager)
+ // Operator bundle of Mongo Parser
+ Operator = OperatorBundle{}
+)
+
+type OperatorBundle struct{}
+
+func init() {
+ RegisterOperator()
+}
+
+// RegisterOperator RegisterOperator
+func RegisterOperator() {
+ OperatorManager.SetDefaultOperator(Operator.Equal)
+ OperatorManager.RegisterOperator(Operator.Equal, "eq", "equal")
+ OperatorManager.RegisterOperator(Operator.NotEqual, "ne", "neq", "notequal")
+ OperatorManager.RegisterOperator(Operator.Contain, "contain", "contains", "include", "includes")
+ OperatorManager.RegisterOperator(Operator.NotContain, "notcontains", "notcontains", "doesnotcontain", "doesnotcontains", "notinclude", "notincludes", "doesnotinclude", "doesnotincludes")
+ OperatorManager.RegisterOperator(Operator.In, "in")
+ OperatorManager.RegisterOperator(Operator.Gte, "gte")
+ OperatorManager.RegisterOperator(Operator.Lte, "lte")
+ OperatorManager.RegisterOperator(Operator.GteDate, "gtedate")
+ OperatorManager.RegisterOperator(Operator.LteDate, "ltedate")
+ OperatorManager.RegisterOperator(Operator.Exists, "exist", "exists")
+ OperatorManager.RegisterOperator(Operator.Between, "between")
+}
+
+func (o *OperatorBundle) Equal(kf kendoparser.Filter) interface{} {
+ return dbox.Eq(kf.Field, kf.Value)
+}
+
+func (o *OperatorBundle) NotEqual(kf kendoparser.Filter) interface{} {
+ return dbox.Ne(kf.Field, kf.Value)
+}
+
+func (o *OperatorBundle) Contain(kf kendoparser.Filter) interface{} {
+ return dbox.Contains(kf.Field, cast.ToString(kf.Value))
+}
+
+func (o *OperatorBundle) NotContain(kf kendoparser.Filter) interface{} {
+ value := regexp.QuoteMeta(cast.ToString(kf.Value))
+ return &dbox.Filter{
+ Field: kf.Field,
+ Op: dbox.FilterOpEqual, // equal are field = value and can be manipulate for others
+ Value: toolkit.M{"$ne": toolkit.M{
+ "$regex": `` + value + ``,
+ "$options": "i",
+ }},
+ }
+}
+
+func (o *OperatorBundle) In(kf kendoparser.Filter) interface{} {
+ return dbox.In(kf.Field, kf.Values...)
+}
+
+func (o *OperatorBundle) Gte(kf kendoparser.Filter) interface{} {
+ return dbox.Gte(kf.Field, kf.Value)
+}
+
+func (o *OperatorBundle) Lte(kf kendoparser.Filter) interface{} {
+ return dbox.Lte(kf.Field, kf.Value)
+}
+
+func (o *OperatorBundle) GteDate(kf kendoparser.Filter) interface{} {
+ dtVariable, _ := time.Parse(time.RFC3339, cast.ToString(kf.Value))
+ return dbox.Gte(kf.Field, dtVariable)
+}
+
+func (o *OperatorBundle) LteDate(kf kendoparser.Filter) interface{} {
+ dtVariable, _ := time.Parse(time.RFC3339, cast.ToString(kf.Value))
+ return dbox.Lte(kf.Field, dtVariable)
+}
+
+func (o *OperatorBundle) Exists(kf kendoparser.Filter) interface{} {
+ return &dbox.Filter{
+ Field: kf.Field,
+ Op: dbox.FilterOpEqual,
+ Value: toolkit.M{
+ "$exists": helper.StringToBool(cast.ToString(kf.Value), false),
+ },
+ }
+}
+
+func (o *OperatorBundle) Between(kf kendoparser.Filter) interface{} {
+ var v0, v1 interface{}
+ if len(kf.Values) > 0 {
+ v0 = kf.Values[0]
+ }
+ if len(kf.Values) > 1 {
+ v1 = kf.Values[1]
+ }
+ return dbox.And(dbox.Gte(kf.Field, v0), dbox.Lte(kf.Field, v1))
+}
diff --git a/adapter/dboxpipe/kendo.go b/parser/dboxpipe/kendo.go
similarity index 61%
rename from adapter/dboxpipe/kendo.go
rename to parser/dboxpipe/kendo.go
index 822ef63..044a105 100644
--- a/adapter/dboxpipe/kendo.go
+++ b/parser/dboxpipe/kendo.go
@@ -5,34 +5,34 @@ import (
"strings"
"github.com/eaciit/toolkit"
- "github.com/raditzlawliet/gokendoparser"
+ "github.com/raditzlawliet/kendoparser"
"gopkg.in/mgo.v2/bson"
)
// Parser Parser
// type Parser struct{}
-// ParseFilter convert KendoFilter into M for pipe combination automaticly
+// FilterParser convert Filter into M for pipe combination automaticly
// return can @Nullable if filter and filters empty
-func ParseFilter(kf *gokendoparser.KendoFilter) interface{} {
+func FilterParser(kf *kendoparser.Filter) interface{} {
// defaultFilter := toolkit.M{"_id": toolkit.M{"$exists": true}}
if len(kf.Filters) == 0 {
// processing will use copy instead to avoid change original value
ckFilter := *kf
// very customable handler
- if kf.GetBeforeParse() != nil {
- for _, handler := range kf.GetBeforeParse() {
+ if kf.AdditionalParsers() != nil {
+ for _, handler := range kf.AdditionalParsers() {
if r := handler(&ckFilter); r != nil {
return r
}
}
}
- // local scope operator
- if kf.GetRegisteredOperators() != nil {
- if opHandler, ok := kf.GetRegisteredOperators()[kf.Operator]; ok && opHandler != nil {
- f := opHandler.Filter(ckFilter)
+ // (scoped)
+ if om := kf.GetOperatorManager(); om != nil {
+ if opHandler, ok := om.OperatorFilters[kf.Operator]; ok {
+ f := opHandler(ckFilter)
if f != nil {
return f.(toolkit.M)
}
@@ -40,17 +40,17 @@ func ParseFilter(kf *gokendoparser.KendoFilter) interface{} {
}
}
- // global operator
- if opHandler, ok := operatorManager.RegisteredOperators[kf.Operator]; ok {
- f := opHandler.Filter(ckFilter)
+ // (global)
+ if opHandler, ok := OperatorManager.OperatorFilters[kf.Operator]; ok {
+ f := opHandler(ckFilter)
if f != nil {
return f.(toolkit.M)
}
return nil
}
- // defaultx
- f := operatorManager.DefaultOperator.Filter(ckFilter)
+ // default (global)
+ f := OperatorManager.DefaultOperatorFilter(ckFilter)
if f != nil {
return f.(toolkit.M)
}
@@ -60,7 +60,7 @@ func ParseFilter(kf *gokendoparser.KendoFilter) interface{} {
// so filters has some values
filters := []toolkit.M{}
for _, kFilterChild := range kf.Filters {
- filter := ParseFilter(&kFilterChild)
+ filter := FilterParser(&kFilterChild)
if filter != nil {
filters = append(filters, filter.(toolkit.M))
}
@@ -76,8 +76,8 @@ func ParseFilter(kf *gokendoparser.KendoFilter) interface{} {
return nil
}
-// ParseSort ParseSort
-func ParseSort(ksa *gokendoparser.KendoSortArray) interface{} {
+// SortParser SortParser
+func SortParser(ksa *kendoparser.Sort) interface{} {
sorter := bson.D{}
for _, ks := range *ksa {
sort := 1
diff --git a/parser/dboxpipe/kendo_test.go b/parser/dboxpipe/kendo_test.go
new file mode 100644
index 0000000..bd4fae2
--- /dev/null
+++ b/parser/dboxpipe/kendo_test.go
@@ -0,0 +1,182 @@
+package kpdboxpipe
+
+import (
+ "strings"
+ "testing"
+ "time"
+
+ tk "github.com/eaciit/toolkit"
+ "github.com/raditzlawliet/kendoparser"
+ "github.com/raditzlawliet/kendoparser/helper"
+ "github.com/spf13/cast"
+ "github.com/stretchr/testify/require"
+ "gopkg.in/mgo.v2/bson"
+)
+
+func Test_FilterParser(t *testing.T) {
+ kendoFilter := kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "_id", Operator: "eq", Value: "val"},
+ },
+ Logic: "and",
+ }
+ resultFilter := kendoFilter.Parse(FilterParser).(tk.M)
+ expectedFilter := tk.M{"$and": []tk.M{tk.M{"_id": tk.M{"$eq": "val"}}}}
+ require.Equal(t, expectedFilter, resultFilter, "Result filter must same")
+
+ kendoFilter = kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "_id", Operator: "eq", Value: "val"},
+ kendoparser.Filter{Field: "_id", Operator: "neq", Value: "val"},
+ },
+ Logic: "or",
+ },
+ kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "_id", Operator: "eq", Value: "val2"},
+ kendoparser.Filter{Field: "_id", Operator: "neq", Value: "val2"},
+ },
+ Logic: "or",
+ },
+ },
+ Logic: "and",
+ }
+ resultFilter = kendoFilter.Parse(FilterParser).(tk.M)
+ expectedFilter = tk.M{"$and": []tk.M{
+ tk.M{"$or": []tk.M{
+ tk.M{"_id": tk.M{"$eq": "val"}},
+ tk.M{"_id": tk.M{"$ne": "val"}},
+ }},
+ tk.M{"$or": []tk.M{
+ tk.M{"_id": tk.M{"$eq": "val2"}},
+ tk.M{"_id": tk.M{"$ne": "val2"}},
+ }},
+ }}
+ require.Equal(t, expectedFilter, resultFilter, "Result filter must same")
+
+ // operator check
+ kendoFilter = kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "_id", Operator: "eq", Value: "val"},
+ kendoparser.Filter{Field: "_id", Operator: "neq", Value: "val"},
+ kendoparser.Filter{Field: "_id", Operator: "contains", Value: "val"},
+ kendoparser.Filter{Field: "_id", Operator: "in", Values: []interface{}{"val"}},
+ kendoparser.Filter{Field: "_id", Operator: "gte", Value: "val"},
+ kendoparser.Filter{Field: "_id", Operator: "lte", Value: "val"},
+ kendoparser.Filter{Field: "time", Operator: "gtedate", Value: "2006-01-02T15:04:05Z07:00"},
+ kendoparser.Filter{Field: "time", Operator: "ltedate", Value: "2006-01-02T15:04:05Z07:00"},
+ kendoparser.Filter{Field: "_id", Operator: "unknown", Value: "val"},
+ },
+ Logic: "and",
+ }
+ resultFilter = kendoFilter.Parse(FilterParser).(tk.M)
+ testTime, _ := time.Parse(time.RFC3339, "2006-01-02T15:04:05Z07:00")
+ expectedFilter = tk.M{"$and": []tk.M{
+ tk.M{"_id": tk.M{"$eq": "val"}},
+ tk.M{"_id": tk.M{"$ne": "val"}},
+ tk.M{"_id": helper.RegexContains("val", false)},
+ tk.M{"_id": tk.M{"$in": []interface{}{"val"}}},
+ tk.M{"_id": tk.M{"$gte": "val"}},
+ tk.M{"_id": tk.M{"$lte": "val"}},
+ tk.M{"time": tk.M{"$gte": testTime}},
+ tk.M{"time": tk.M{"$lte": testTime}},
+ tk.M{"_id": tk.M{"$eq": "val"}},
+ }}
+ require.Equal(t, expectedFilter, resultFilter, "Result filter must same")
+}
+
+func Test_PreFilterHandler(t *testing.T) {
+ // transform single filter
+ // ID => _id
+ {
+ kendoFilter := kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "ID", Operator: "eq", Value: "val"},
+ kendoparser.Filter{Field: "STATUS", Operator: "eq", Value: "true"},
+ },
+ Logic: "or",
+ },
+ kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "ID", Operator: "eq", Value: "val2"},
+ kendoparser.Filter{Field: "ID", Operator: "neq", Value: "val2"},
+ },
+ Logic: "or",
+ },
+ },
+ Logic: "and",
+ }
+
+ // try dbox pipe
+ resultFilterPipe := kendoFilter.TransformAllField(strings.ToLower).
+ TransformAll(func(kf *kendoparser.Filter) {
+ if kf.Field == "id" {
+ kf.Field = "_id"
+ }
+ }).
+ AddAllParser(func(kf *kendoparser.Filter) interface{} {
+ if kf.Field == "status" {
+ // return your custom handler
+ return tk.M{kf.Field: helper.StringToBool(cast.ToString(kf.Value), false)}
+ }
+ return nil // pas nil to continue original filter
+ }).Parse(FilterParser).(tk.M)
+
+ expectedFilterPipe := tk.M{"$and": []tk.M{
+ tk.M{"$or": []tk.M{
+ tk.M{"_id": tk.M{"$eq": "val"}},
+ tk.M{"status": true},
+ }},
+ tk.M{"$or": []tk.M{
+ tk.M{"_id": tk.M{"$eq": "val2"}},
+ tk.M{"_id": tk.M{"$ne": "val2"}},
+ }},
+ }}
+ require.Equal(t, expectedFilterPipe, resultFilterPipe, "Result dbox filter must same")
+ }
+}
+
+func Test_Sort(t *testing.T) {
+ {
+ kData := kendoparser.Data{
+ Sort: kendoparser.Sort{
+ kendoparser.SortDetail{
+ Field: "foo",
+ Dir: "DESC",
+ },
+ kendoparser.SortDetail{
+ Field: "bar",
+ Dir: "ASC",
+ },
+ kendoparser.SortDetail{
+ Field: "_id",
+ Dir: "desc",
+ },
+ },
+ }
+
+ // try dbox filter
+ result := kData.Sort.Parse(SortParser).(bson.D)
+
+ expectedPipe := bson.D{
+ bson.DocElem{
+ Name: "foo",
+ Value: -1,
+ },
+ bson.DocElem{
+ Name: "bar",
+ Value: 1,
+ },
+ bson.DocElem{
+ Name: "_id",
+ Value: -1,
+ },
+ }
+
+ require.Equal(t, expectedPipe, result, "Result must same")
+ }
+}
diff --git a/parser/dboxpipe/operator.go b/parser/dboxpipe/operator.go
new file mode 100644
index 0000000..d592c19
--- /dev/null
+++ b/parser/dboxpipe/operator.go
@@ -0,0 +1,100 @@
+package kpdboxpipe
+
+import (
+ "regexp"
+ "strings"
+ "time"
+
+ "github.com/eaciit/toolkit"
+ "github.com/raditzlawliet/kendoparser"
+ "github.com/raditzlawliet/kendoparser/helper"
+ "gopkg.in/mgo.v2/bson"
+
+ "github.com/spf13/cast"
+)
+
+var (
+ // OperatorManager of Mongo Parser
+ OperatorManager = new(kendoparser.OperatorManager)
+ // Operator bundle of Mongo Parser
+ Operator = OperatorBundle{}
+)
+
+type OperatorBundle struct{}
+
+func init() {
+ RegisterOperator()
+}
+
+// RegisterOperator RegisterOperator
+func RegisterOperator() {
+ OperatorManager.SetDefaultOperator(Operator.Equal)
+ OperatorManager.RegisterOperator(Operator.Equal, "eq", "equal")
+ OperatorManager.RegisterOperator(Operator.NotEqual, "ne", "neq", "notequal")
+ OperatorManager.RegisterOperator(Operator.Contain, "contain", "contains", "include", "includes")
+ OperatorManager.RegisterOperator(Operator.NotContain, "notcontains", "notcontains", "doesnotcontain", "doesnotcontains", "notinclude", "notincludes", "doesnotinclude", "doesnotincludes")
+ OperatorManager.RegisterOperator(Operator.In, "in")
+ OperatorManager.RegisterOperator(Operator.Gte, "gte")
+ OperatorManager.RegisterOperator(Operator.Lte, "lte")
+ OperatorManager.RegisterOperator(Operator.GteDate, "gtedate")
+ OperatorManager.RegisterOperator(Operator.LteDate, "ltedate")
+ OperatorManager.RegisterOperator(Operator.Exists, "exist", "exists")
+ OperatorManager.RegisterOperator(Operator.Between, "between")
+}
+
+func (o *OperatorBundle) Equal(kf kendoparser.Filter) interface{} {
+ if kf.IgnoreCase {
+ value := regexp.QuoteMeta(cast.ToString(kf.Value))
+ return toolkit.M{kf.Field: bson.RegEx{Pattern: "^" + strings.ToLower(value) + "$", Options: "i"}}
+ }
+ return toolkit.M{kf.Field: toolkit.M{"$eq": kf.Value}}
+}
+
+func (o *OperatorBundle) NotEqual(kf kendoparser.Filter) interface{} {
+ return toolkit.M{kf.Field: toolkit.M{"$ne": kf.Value}}
+}
+
+func (o *OperatorBundle) Contain(kf kendoparser.Filter) interface{} {
+ return toolkit.M{kf.Field: helper.RegexContains(cast.ToString(kf.Value), kf.IgnoreCase)}
+}
+
+func (o *OperatorBundle) NotContain(kf kendoparser.Filter) interface{} {
+ return toolkit.M{kf.Field: toolkit.M{"$ne": helper.RegexContains(cast.ToString(kf.Value), kf.IgnoreCase)}}
+}
+
+func (o *OperatorBundle) In(kf kendoparser.Filter) interface{} {
+ return toolkit.M{kf.Field: toolkit.M{"$in": kf.Values}}
+}
+
+func (o *OperatorBundle) Gte(kf kendoparser.Filter) interface{} {
+ return toolkit.M{kf.Field: toolkit.M{"$gte": kf.Value}}
+}
+
+func (o *OperatorBundle) Lte(kf kendoparser.Filter) interface{} {
+ return toolkit.M{kf.Field: toolkit.M{"$lte": kf.Value}}
+}
+
+func (o *OperatorBundle) GteDate(kf kendoparser.Filter) interface{} {
+ dtVariable, _ := time.Parse(time.RFC3339, cast.ToString(kf.Value))
+ return toolkit.M{kf.Field: toolkit.M{"$gte": dtVariable}}
+}
+
+func (o *OperatorBundle) LteDate(kf kendoparser.Filter) interface{} {
+ dtVariable, _ := time.Parse(time.RFC3339, cast.ToString(kf.Value))
+ return toolkit.M{kf.Field: toolkit.M{"$lte": dtVariable}}
+}
+
+func (o *OperatorBundle) Exists(kf kendoparser.Filter) interface{} {
+ return toolkit.M{kf.Field: toolkit.M{"$exists": helper.StringToBool(cast.ToString(kf.Value), false)}}
+}
+
+func (o *OperatorBundle) Between(kf kendoparser.Filter) interface{} {
+ var v0, v1 interface{}
+ if len(kf.Values) > 0 {
+ v0 = kf.Values[0]
+ }
+ if len(kf.Values) > 1 {
+ v1 = kf.Values[1]
+ }
+ return toolkit.M{kf.Field: toolkit.M{"$gte": v0, "$lte": v1}}
+}
diff --git a/adapter/mongo/kendo.go b/parser/mongo/kendo.go
similarity index 62%
rename from adapter/mongo/kendo.go
rename to parser/mongo/kendo.go
index d3bf421..7a88783 100644
--- a/adapter/mongo/kendo.go
+++ b/parser/mongo/kendo.go
@@ -4,16 +4,13 @@ package kpmongo
import (
"strings"
- "github.com/raditzlawliet/gokendoparser"
+ "github.com/raditzlawliet/kendoparser"
"go.mongodb.org/mongo-driver/bson"
)
-// Parser Parser
-// type Parser struct{}
-
-// ParseFilter convert KendoFilter into bson.M/D/A for pipe combination automaticly
+// FilterParser convert Filter into bson.M/D/A for pipe combination automaticly
// return can @Nullable if filter and filters empty
-func ParseFilter(kf *gokendoparser.KendoFilter) interface{} {
+func FilterParser(kf *kendoparser.Filter) interface{} {
// defaultFilter := toolkit.M{"_id": toolkit.M{"$exists": true}}
if len(kf.Filters) == 0 {
if kf.Operator == "" {
@@ -24,18 +21,18 @@ func ParseFilter(kf *gokendoparser.KendoFilter) interface{} {
ckFilter := *kf
// very customable handler
- if kf.GetBeforeParse() != nil {
- for _, handler := range kf.GetBeforeParse() {
+ if kf.AdditionalParsers() != nil {
+ for _, handler := range kf.AdditionalParsers() {
if r := handler(&ckFilter); r != nil {
return r
}
}
}
- // local scope operator
- if kf.GetRegisteredOperators() != nil {
- if opHandler, ok := kf.GetRegisteredOperators()[kf.Operator]; ok && opHandler != nil {
- f := opHandler.Filter(ckFilter)
+ // (scoped)
+ if om := kf.GetOperatorManager(); om != nil {
+ if opHandler, ok := om.OperatorFilters[kf.Operator]; ok {
+ f := opHandler(ckFilter)
if f != nil {
return f
}
@@ -43,17 +40,17 @@ func ParseFilter(kf *gokendoparser.KendoFilter) interface{} {
}
}
- // global operator
- if opHandler, ok := operatorManager.RegisteredOperators[kf.Operator]; ok {
- f := opHandler.Filter(ckFilter)
+ // (global)
+ if opHandler, ok := OperatorManager.OperatorFilters[kf.Operator]; ok {
+ f := opHandler(ckFilter)
if f != nil {
return f
}
return bson.D{{}}
}
- // defaultx
- f := operatorManager.DefaultOperator.Filter(ckFilter)
+ // default (global)
+ f := OperatorManager.DefaultOperatorFilter(ckFilter)
if f != nil {
return f
}
@@ -63,7 +60,7 @@ func ParseFilter(kf *gokendoparser.KendoFilter) interface{} {
// so filters has some values
filters := []bson.D{}
for _, kFilterChild := range kf.Filters {
- filter := ParseFilter(&kFilterChild)
+ filter := FilterParser(&kFilterChild)
if filter != nil {
switch filterAssertion := filter.(type) {
case bson.D:
@@ -88,8 +85,8 @@ func ParseFilter(kf *gokendoparser.KendoFilter) interface{} {
return bson.D{{}}
}
-// ParseSort ParseSort
-func ParseSort(ksa *gokendoparser.KendoSortArray) interface{} {
+// SortParser SortParser
+func SortParser(ksa *kendoparser.Sort) interface{} {
sorter := bson.D{}
for _, ks := range *ksa {
sort := 1
diff --git a/parser/mongo/kendo_test.go b/parser/mongo/kendo_test.go
new file mode 100644
index 0000000..f8765c0
--- /dev/null
+++ b/parser/mongo/kendo_test.go
@@ -0,0 +1,335 @@
+package kpmongo
+
+import (
+ "github.com/raditzlawliet/kendoparser"
+ "github.com/raditzlawliet/kendoparser/helper"
+ "github.com/spf13/cast"
+ "github.com/stretchr/testify/require"
+ "go.mongodb.org/mongo-driver/bson"
+ "strings"
+ "testing"
+ "time"
+)
+
+func Test_Parser(t *testing.T) {
+ kendoFilter := kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "_id", Operator: "eq", Value: "val"},
+ },
+ Logic: "and",
+ }
+ resultFilter := kendoFilter.Parse(FilterParser).(bson.D)
+ expectedFilter := bson.D{
+ {
+ "$and", []bson.D{
+ bson.D{{"_id", bson.M{"$eq": "val"}}},
+ },
+ },
+ }
+ require.Equal(t, expectedFilter, resultFilter, "Result filter must same")
+
+ kendoFilter = kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "_id", Operator: "eq", Value: "val"},
+ kendoparser.Filter{Field: "_id", Operator: "neq", Value: "val"},
+ },
+ Logic: "or",
+ },
+ kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "_id", Operator: "eq", Value: "val2"},
+ kendoparser.Filter{Field: "_id", Operator: "neq", Value: "val2"},
+ },
+ Logic: "or",
+ },
+ },
+ Logic: "and",
+ }
+ resultFilter = kendoFilter.Parse(FilterParser).(bson.D)
+
+ expectedFilter = bson.D{
+ {
+ "$and", []bson.D{
+ bson.D{{"$or", []bson.D{
+ bson.D{{"_id", bson.M{"$eq": "val"}}},
+ bson.D{{"_id", bson.M{"$ne": "val"}}},
+ }}},
+ bson.D{{"$or", []bson.D{
+ bson.D{{"_id", bson.M{"$eq": "val2"}}},
+ bson.D{{"_id", bson.M{"$ne": "val2"}}},
+ }}},
+ },
+ },
+ }
+ require.Equal(t, expectedFilter, resultFilter, "Result filter must same")
+
+ // operator check
+ kendoFilter = kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "_id", Operator: "eq", Value: "val"},
+ kendoparser.Filter{Field: "_id", Operator: "neq", Value: "val"},
+ kendoparser.Filter{Field: "_id", Operator: "contains", Value: "val"},
+ kendoparser.Filter{Field: "_id", Operator: "in", Values: []interface{}{"val"}},
+ kendoparser.Filter{Field: "_id", Operator: "gte", Value: "val"},
+ kendoparser.Filter{Field: "_id", Operator: "lte", Value: "val"},
+ kendoparser.Filter{Field: "time", Operator: "gtedate", Value: "2006-01-02T15:04:05Z07:00"},
+ kendoparser.Filter{Field: "time", Operator: "ltedate", Value: "2006-01-02T15:04:05Z07:00"},
+ kendoparser.Filter{Field: "_id", Operator: "unknown", Value: "val"},
+ },
+ Logic: "and",
+ }
+ resultFilter = kendoFilter.Parse(FilterParser).(bson.D)
+ testTime, _ := time.Parse(time.RFC3339, "2006-01-02T15:04:05Z07:00")
+
+ expectedFilter = bson.D{
+ {
+ "$and", []bson.D{
+ bson.D{{"_id", bson.M{"$eq": "val"}}},
+ bson.D{{"_id", bson.M{"$ne": "val"}}},
+ bson.D{{"_id", RegexContains("val", false)}},
+ bson.D{{"_id", bson.M{"$in": []interface{}{"val"}}}},
+ bson.D{{"_id", bson.M{"$gte": "val"}}},
+ bson.D{{"_id", bson.M{"$lte": "val"}}},
+ bson.D{{"time", bson.M{"$gte": testTime}}},
+ bson.D{{"time", bson.M{"$lte": testTime}}},
+ bson.D{{"_id", bson.M{"$eq": "val"}}},
+ },
+ },
+ }
+ require.Equal(t, expectedFilter, resultFilter, "Result filter must same")
+}
+
+func Test_AdditionalParser(t *testing.T) {
+ // transform single filter
+ // ID => _id
+ {
+ kendoFilter := kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "ID", Operator: "eq", Value: "val"},
+ kendoparser.Filter{Field: "STATUS", Operator: "eq", Value: "true"},
+ },
+ Logic: "or",
+ },
+ kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "ID", Operator: "eq", Value: "val2"},
+ kendoparser.Filter{Field: "ID", Operator: "neq", Value: "val2"},
+ },
+ Logic: "or",
+ },
+ },
+ Logic: "and",
+ }
+
+ // try
+ resultFilter := kendoFilter.TransformAllField(strings.ToLower).
+ TransformAll(func(kf *kendoparser.Filter) {
+ if kf.Field == "id" {
+ kf.Field = "_id"
+ }
+ }).
+ AddAllParser(func(kf *kendoparser.Filter) interface{} {
+ if kf.Field == "status" {
+ // return your custom handler
+ return bson.M{kf.Field: helper.StringToBool(cast.ToString(kf.Value), false)}
+ }
+ return nil // pas nil to continue original filter
+ }).Parse(FilterParser).(bson.D)
+ expectedFilter := bson.D{
+ {
+ "$and", []bson.D{
+ bson.D{{"$or", []bson.D{
+ bson.D{{"_id", bson.M{"$eq": "val"}}},
+ bson.D{{"status", true}},
+ }}},
+ bson.D{{"$or", []bson.D{
+ bson.D{{"_id", bson.M{"$eq": "val2"}}},
+ bson.D{{"_id", bson.M{"$ne": "val2"}}},
+ }}},
+ },
+ },
+ }
+ require.Equal(t, expectedFilter, resultFilter, "Result filter must same")
+
+ // reset again, so additional parser will gone
+ resultFilter = kendoFilter.TransformAllField(strings.ToLower).
+ TransformAll(func(kf *kendoparser.Filter) {
+ if kf.Field == "id" {
+ kf.Field = "_id"
+ }
+ }).
+ AddAllParser(func(kf *kendoparser.Filter) interface{} {
+ if kf.Field == "status" {
+ // return your custom handler
+ return bson.M{kf.Field: helper.StringToBool(cast.ToString(kf.Value), false)}
+ }
+ return nil // pas nil to continue original filter
+ }).ResetAllAdditionalParsers().Parse(FilterParser).(bson.D)
+ expectedFilter = bson.D{
+ {
+ "$and", []bson.D{
+ bson.D{{"$or", []bson.D{
+ bson.D{{"_id", bson.M{"$eq": "val"}}},
+ bson.D{{"status", bson.M{"$eq": "true"}}},
+ }}},
+ bson.D{{"$or", []bson.D{
+ bson.D{{"_id", bson.M{"$eq": "val2"}}},
+ bson.D{{"_id", bson.M{"$ne": "val2"}}},
+ }}},
+ },
+ },
+ }
+ require.Equal(t, expectedFilter, resultFilter, "Result filter must same")
+
+ // Reset only the wrapper (but not the childs), so reset will not work
+ resultFilter = kendoFilter.TransformAllField(strings.ToLower).
+ TransformAll(func(kf *kendoparser.Filter) {
+ if kf.Field == "id" {
+ kf.Field = "_id"
+ }
+ }).
+ AddAllParser(func(kf *kendoparser.Filter) interface{} {
+ if kf.Field == "status" {
+ // return your custom handler
+ return bson.M{kf.Field: helper.StringToBool(cast.ToString(kf.Value), false)}
+ }
+ return nil // pas nil to continue original filter
+ }).ResetAdditionalParsers().Parse(FilterParser).(bson.D)
+ expectedFilter = bson.D{
+ {
+ "$and", []bson.D{
+ bson.D{{"$or", []bson.D{
+ bson.D{{"_id", bson.M{"$eq": "val"}}},
+ bson.D{{"status", true}},
+ }}},
+ bson.D{{"$or", []bson.D{
+ bson.D{{"_id", bson.M{"$eq": "val2"}}},
+ bson.D{{"_id", bson.M{"$ne": "val2"}}},
+ }}},
+ },
+ },
+ }
+ require.Equal(t, expectedFilter, resultFilter, "Result filter must same")
+ }
+}
+
+func Test_Sort(t *testing.T) {
+ {
+ kData := kendoparser.Data{
+ Sort: kendoparser.Sort{
+ kendoparser.SortDetail{
+ Field: "foo",
+ Dir: "DESC",
+ },
+ kendoparser.SortDetail{
+ Field: "bar",
+ Dir: "ASC",
+ },
+ kendoparser.SortDetail{
+ Field: "_id",
+ Dir: "desc",
+ },
+ },
+ }
+
+ // try filter
+ result := kData.Sort.Parse(SortParser).(bson.D)
+
+ expectedPipe := bson.D{
+ bson.E{"foo", -1},
+ bson.E{
+ "bar",
+ 1,
+ },
+ bson.E{
+ "_id",
+ -1,
+ },
+ }
+
+ require.Equal(t, expectedPipe, result, "Result must same")
+ }
+}
+
+func Test_OperatorManager(t *testing.T) {
+ om := kendoparser.OperatorManager{}
+ om.RegisterOperator(func(kf kendoparser.Filter) interface{} {
+ return bson.M{kf.Field: bson.M{"$eq": 1}}
+ }, "eq")
+
+ {
+ kendoFilter := kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "_id", Operator: "eq", Value: "val"},
+ },
+ Logic: "and",
+ }
+ resultFilter := kendoFilter.Parse(FilterParser).(bson.D)
+ expectedFilter := bson.D{
+ {
+ "$and", []bson.D{
+ bson.D{{"_id", bson.M{"$eq": "val"}}},
+ },
+ },
+ }
+ require.Equal(t, expectedFilter, resultFilter, "Result filter must same")
+ }
+
+ {
+ kendoFilter := kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "_id", Operator: "eq", Value: "val"},
+ },
+ Logic: "and",
+ }
+ resultFilter := kendoFilter.SetOperatorManager(&om).Parse(FilterParser).(bson.D)
+ expectedFilter := bson.D{
+ {
+ "$and", []bson.D{
+ bson.D{{"_id", bson.M{"$eq": 1}}},
+ },
+ },
+ }
+ require.Equal(t, expectedFilter, resultFilter, "Result filter must same")
+ }
+ om.Reset()
+
+ {
+ kendoFilter := kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "_id", Operator: "eq", Value: "val"},
+ },
+ Logic: "and",
+ }
+ resultFilter := kendoFilter.Parse(FilterParser).(bson.D)
+ expectedFilter := bson.D{
+ {
+ "$and", []bson.D{
+ bson.D{{"_id", bson.M{"$eq": "val"}}},
+ },
+ },
+ }
+ require.Equal(t, expectedFilter, resultFilter, "Result filter must same")
+ }
+ {
+ kendoFilter := kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "_id", Operator: "eq", Value: "val"},
+ },
+ Logic: "and",
+ }
+ resultFilter := kendoFilter.SetOperatorManager(nil).Parse(FilterParser).(bson.D)
+ expectedFilter := bson.D{
+ {
+ "$and", []bson.D{
+ bson.D{{"_id", bson.M{"$eq": "val"}}},
+ },
+ },
+ }
+ require.Equal(t, expectedFilter, resultFilter, "Result filter must same")
+ }
+}
diff --git a/parser/mongo/operator.go b/parser/mongo/operator.go
new file mode 100644
index 0000000..01e4068
--- /dev/null
+++ b/parser/mongo/operator.go
@@ -0,0 +1,197 @@
+package kpmongo
+
+import (
+ "regexp"
+ "strings"
+ "time"
+
+ "github.com/raditzlawliet/kendoparser"
+ "github.com/raditzlawliet/kendoparser/helper"
+ "go.mongodb.org/mongo-driver/bson"
+ "go.mongodb.org/mongo-driver/bson/primitive"
+
+ "github.com/spf13/cast"
+)
+
+var (
+ // OperatorManager of Mongo Parser
+ OperatorManager = new(kendoparser.OperatorManager)
+ // Operator bundle of Mongo Parser
+ Operator = OperatorBundle{}
+)
+
+type OperatorBundle struct{}
+
+func init() {
+ RegisterOperator()
+}
+
+// RegisterOperator RegisterOperator
+func RegisterOperator() {
+ OperatorManager.SetDefaultOperator(Operator.Equal)
+ OperatorManager.RegisterOperator(Operator.Equal, "eq", "equal", "=", "==")
+ OperatorManager.RegisterOperator(Operator.NotEqual, "ne", "neq", "notequal", "<>", "!=")
+ OperatorManager.RegisterOperator(Operator.EqualDate, "eqdate", "equaldate", "=date", "==date")
+ OperatorManager.RegisterOperator(Operator.NotEqualDate, "nedate", "neqdate", "notequaldate", "<>date", "!=date")
+ OperatorManager.RegisterOperator(Operator.Contain, "contain", "contains", "include", "includes")
+ OperatorManager.RegisterOperator(Operator.NotContain, "notcontains", "notcontains", "doesnotcontain", "doesnotcontains", "notinclude", "notincludes", "doesnotinclude", "doesnotincludes")
+ OperatorManager.RegisterOperator(Operator.In, "in")
+ OperatorManager.RegisterOperator(Operator.NotIn, "notin", "nin")
+ OperatorManager.RegisterOperator(Operator.Gt, "gt", ">")
+ OperatorManager.RegisterOperator(Operator.Lt, "lt", "<")
+ OperatorManager.RegisterOperator(Operator.Gte, "gte", ">=")
+ OperatorManager.RegisterOperator(Operator.Lte, "lte", "<=")
+ OperatorManager.RegisterOperator(Operator.GtDate, "gtdate", ">date")
+ OperatorManager.RegisterOperator(Operator.LtDate, "ltdate", "=date")
+ OperatorManager.RegisterOperator(Operator.LteDate, "ltedate", "<=date")
+ OperatorManager.RegisterOperator(Operator.Exists, "exist", "exists")
+ OperatorManager.RegisterOperator(Operator.DateExists, "dateexist", "dateexists")
+ OperatorManager.RegisterOperator(Operator.Between, "between")
+}
+
+func (o *OperatorBundle) Equal(kf kendoparser.Filter) interface{} {
+ // Ignore-case only for string :D
+ if value, ok := kf.Value.(string); ok && kf.IgnoreCase {
+ value := regexp.QuoteMeta(value)
+ return bson.M{kf.Field: primitive.Regex{Pattern: "^" + strings.ToLower(value) + "$", Options: "i"}}
+ }
+ // other string, it will directly :|
+ return bson.M{kf.Field: bson.M{"$eq": kf.Value}}
+}
+
+func (o *OperatorBundle) NotEqual(kf kendoparser.Filter) interface{} {
+ return bson.M{kf.Field: bson.M{"$ne": kf.Value}}
+}
+
+func (o *OperatorBundle) EqualDate(kf kendoparser.Filter) interface{} {
+ dtVariable, _ := time.Parse(time.RFC3339, cast.ToString(kf.Value))
+ return bson.M{kf.Field: bson.M{"$eq": dtVariable}}
+}
+
+func (o *OperatorBundle) NotEqualDate(kf kendoparser.Filter) interface{} {
+ dtVariable, _ := time.Parse(time.RFC3339, cast.ToString(kf.Value))
+ return bson.M{kf.Field: bson.M{"$ne": dtVariable}}
+}
+
+func (o *OperatorBundle) Contain(kf kendoparser.Filter) interface{} {
+ return bson.M{kf.Field: RegexContains(cast.ToString(kf.Value), kf.IgnoreCase)}
+}
+
+func (o *OperatorBundle) ContainNumber(kf kendoparser.Filter) interface{} {
+ field := kf.Field
+ if !strings.HasPrefix(field, "$") {
+ field = "$" + field
+ }
+ return bson.M{
+ "$expr": bson.M{
+ "$regexMatch": bson.M{
+ "input": bson.M{"$toString": field},
+ "regex": RegexContains(cast.ToString(kf.Value), kf.IgnoreCase),
+ },
+ },
+ }
+}
+
+func (o *OperatorBundle) NotContain(kf kendoparser.Filter) interface{} {
+ return bson.M{kf.Field: bson.M{"$ne": RegexContains(cast.ToString(kf.Value), kf.IgnoreCase)}}
+}
+
+func (o *OperatorBundle) In(kf kendoparser.Filter) interface{} {
+ return bson.M{kf.Field: bson.M{"$in": kf.Values}}
+}
+
+func (o *OperatorBundle) NotIn(kf kendoparser.Filter) interface{} {
+ return bson.M{kf.Field: bson.M{"$nin": kf.Values}}
+}
+
+func (o *OperatorBundle) Gt(kf kendoparser.Filter) interface{} {
+ return bson.M{kf.Field: bson.M{"$gt": kf.Value}}
+}
+
+func (o *OperatorBundle) Lt(kf kendoparser.Filter) interface{} {
+ return bson.M{kf.Field: bson.M{"$lt": kf.Value}}
+}
+
+func (o *OperatorBundle) Gte(kf kendoparser.Filter) interface{} {
+ return bson.M{kf.Field: bson.M{"$gte": kf.Value}}
+}
+
+func (o *OperatorBundle) Lte(kf kendoparser.Filter) interface{} {
+ return bson.M{kf.Field: bson.M{"$lte": kf.Value}}
+}
+
+func (o *OperatorBundle) GtDate(kf kendoparser.Filter) interface{} {
+ str := cast.ToString(kf.Value)
+ if t, ok := kf.Value.(time.Time); ok { // fixing time.Time value not valid converted :|
+ str = t.Format(time.RFC3339)
+ }
+ dtVariable, _ := time.Parse(time.RFC3339, str)
+ return bson.M{kf.Field: bson.M{"$gt": dtVariable}}
+}
+
+func (o *OperatorBundle) LtDate(kf kendoparser.Filter) interface{} {
+ str := cast.ToString(kf.Value)
+ if t, ok := kf.Value.(time.Time); ok { // fixing time.Time value not valid converted :|
+ str = t.Format(time.RFC3339)
+ }
+ dtVariable, _ := time.Parse(time.RFC3339, str)
+ return bson.M{kf.Field: bson.M{"$lt": dtVariable}}
+}
+
+func (o *OperatorBundle) GteDate(kf kendoparser.Filter) interface{} {
+ str := cast.ToString(kf.Value)
+ if t, ok := kf.Value.(time.Time); ok { // fixing time.Time value not valid converted :|
+ str = t.Format(time.RFC3339)
+ }
+ dtVariable, _ := time.Parse(time.RFC3339, str)
+ return bson.M{kf.Field: bson.M{"$gte": dtVariable}}
+}
+
+func (o *OperatorBundle) LteDate(kf kendoparser.Filter) interface{} {
+ str := cast.ToString(kf.Value)
+ if t, ok := kf.Value.(time.Time); ok { // fixing time.Time value not valid converted :|
+ str = t.Format(time.RFC3339)
+ }
+ dtVariable, _ := time.Parse(time.RFC3339, str)
+ return bson.M{kf.Field: bson.M{"$lte": dtVariable}}
+}
+
+func (o *OperatorBundle) Exists(kf kendoparser.Filter) interface{} {
+ return bson.M{kf.Field: bson.M{"$exists": helper.StringToBool(cast.ToString(kf.Value), false)}}
+}
+
+// filter for time.Time / DateTime in Mongo exists or not (usefull for safe-delete flag)
+func (o *OperatorBundle) DateExists(kf kendoparser.Filter) interface{} {
+ if strings.ToLower(cast.ToString(kf.Value)) == "true" {
+ return bson.M{"$and": bson.A{
+ bson.M{kf.Field: bson.M{"$exists": true}},
+ bson.M{kf.Field: bson.M{"$ne": time.Time{}}},
+ }}
+ }
+ return bson.M{"$or": bson.A{
+ bson.M{kf.Field: bson.M{"$exists": false}},
+ bson.M{kf.Field: bson.M{"$eq": time.Time{}}},
+ }}
+}
+
+func (o *OperatorBundle) Between(kf kendoparser.Filter) interface{} {
+ var v0, v1 interface{}
+ if len(kf.Values) > 0 {
+ v0 = kf.Values[0]
+ }
+ if len(kf.Values) > 1 {
+ v1 = kf.Values[1]
+ }
+ return bson.M{kf.Field: bson.M{"$gte": v0, "$lte": v1}}
+}
+
+// RegexContains Generate bson.RegEx for contains
+func RegexContains(value string, ignoreCase bool) primitive.Regex {
+ value = regexp.QuoteMeta(value)
+ if ignoreCase {
+ return primitive.Regex{Pattern: "" + strings.ToLower(value) + "", Options: "i"}
+ } else {
+ return primitive.Regex{Pattern: "" + value + "", Options: ""}
+ }
+}
diff --git a/adapter/xorm/cond_eqci.go b/parser/xorm/cond_eqci.go
similarity index 100%
rename from adapter/xorm/cond_eqci.go
rename to parser/xorm/cond_eqci.go
diff --git a/adapter/xorm/cond_likeci.go b/parser/xorm/cond_likeci.go
similarity index 100%
rename from adapter/xorm/cond_likeci.go
rename to parser/xorm/cond_likeci.go
diff --git a/adapter/xorm/kendo.go b/parser/xorm/kendo.go
similarity index 62%
rename from adapter/xorm/kendo.go
rename to parser/xorm/kendo.go
index 6f8bc47..c72349e 100644
--- a/adapter/xorm/kendo.go
+++ b/parser/xorm/kendo.go
@@ -5,7 +5,7 @@ import (
"fmt"
"strings"
- "github.com/raditzlawliet/gokendoparser"
+ "github.com/raditzlawliet/kendoparser"
"xorm.io/builder"
)
@@ -13,9 +13,9 @@ import (
// Parser Parser
// type Parser struct{}
-// ParseFilter convert KendoFilter into bson.M/D/A for pipe combination automaticly
+// FilterParser convert Filter into bson.M/D/A for pipe combination automaticly
// return can @Nullable if filter and filters empty
-func ParseFilter(kf *gokendoparser.KendoFilter) interface{} {
+func FilterParser(kf *kendoparser.Filter) interface{} {
// defaultFilter := toolkit.M{"_id": toolkit.M{"$exists": true}}
if len(kf.Filters) == 0 {
if kf.Operator == "" {
@@ -26,18 +26,18 @@ func ParseFilter(kf *gokendoparser.KendoFilter) interface{} {
ckFilter := *kf
// very customable handler
- if kf.GetBeforeParse() != nil {
- for _, handler := range kf.GetBeforeParse() {
+ if kf.AdditionalParsers() != nil {
+ for _, handler := range kf.AdditionalParsers() {
if r := handler(&ckFilter); r != nil {
return r
}
}
}
- // local scope operator
- if kf.GetRegisteredOperators() != nil {
- if opHandler, ok := kf.GetRegisteredOperators()[kf.Operator]; ok && opHandler != nil {
- f := opHandler.Filter(ckFilter)
+ // (scoped)
+ if om := kf.GetOperatorManager(); om != nil {
+ if opHandler, ok := om.OperatorFilters[kf.Operator]; ok {
+ f := opHandler(ckFilter)
if f != nil {
return f
}
@@ -45,17 +45,17 @@ func ParseFilter(kf *gokendoparser.KendoFilter) interface{} {
}
}
- // global operator
- if opHandler, ok := operatorManager.RegisteredOperators[kf.Operator]; ok {
- f := opHandler.Filter(ckFilter)
+ // (global)
+ if opHandler, ok := OperatorManager.OperatorFilters[kf.Operator]; ok {
+ f := opHandler(ckFilter)
if f != nil {
return f
}
return builder.NewCond()
}
- // defaultx
- f := operatorManager.DefaultOperator.Filter(ckFilter)
+ // default (global)
+ f := OperatorManager.DefaultOperatorFilter(ckFilter)
if f != nil {
return f
}
@@ -65,7 +65,7 @@ func ParseFilter(kf *gokendoparser.KendoFilter) interface{} {
// so filters has some values
filters := []builder.Cond{}
for _, kFilterChild := range kf.Filters {
- filter := ParseFilter(&kFilterChild)
+ filter := FilterParser(&kFilterChild)
if filter != nil {
filters = append(filters, filter.(builder.Cond))
}
@@ -80,8 +80,8 @@ func ParseFilter(kf *gokendoparser.KendoFilter) interface{} {
return builder.NewCond()
}
-// ParseSort ParseSort
-func ParseSort(ksa *gokendoparser.KendoSortArray) interface{} {
+// SortParser SortParser
+func SortParser(ksa *kendoparser.Sort) interface{} {
sorter := []string{}
for _, ks := range *ksa {
sort := "ASC"
diff --git a/adapter/xorm/kendo_test.go b/parser/xorm/kendo_test.go
similarity index 52%
rename from adapter/xorm/kendo_test.go
rename to parser/xorm/kendo_test.go
index cc0b65a..d7516af 100644
--- a/adapter/xorm/kendo_test.go
+++ b/parser/xorm/kendo_test.go
@@ -4,20 +4,20 @@ import (
"strings"
"testing"
- "github.com/raditzlawliet/gokendoparser"
+ "github.com/raditzlawliet/kendoparser"
"github.com/stretchr/testify/require"
"xorm.io/builder"
)
-func Test_ParseFilter(t *testing.T) {
- kendoFilter := gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "_id", Operator: "eq", Value: "val"},
+func Test_FilterParser(t *testing.T) {
+ kendoFilter := kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "_id", Operator: "eq", Value: "val"},
},
Logic: "and",
}
- resultFilter := kendoFilter.Parse(ParseFilter)
+ resultFilter := kendoFilter.Parse(FilterParser)
expectedFilter := builder.And(
builder.Eq{"_id": "val"},
)
@@ -26,26 +26,26 @@ func Test_ParseFilter(t *testing.T) {
require.Nil(t, err)
t.Log(sql, params)
- kendoFilter = gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "_id", Operator: "eq", Value: "val"},
- gokendoparser.KendoFilter{Field: "_id", Operator: "neq", Value: "val"},
+ kendoFilter = kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "_id", Operator: "eq", Value: "val"},
+ kendoparser.Filter{Field: "_id", Operator: "neq", Value: "val"},
},
Logic: "or",
},
- gokendoparser.KendoFilter{
- Filters: []gokendoparser.KendoFilter{
- gokendoparser.KendoFilter{Field: "_id", Operator: "eq", Value: "val2"},
- gokendoparser.KendoFilter{Field: "_id", Operator: "neq", Value: "val2"},
+ kendoparser.Filter{
+ Filters: []kendoparser.Filter{
+ kendoparser.Filter{Field: "_id", Operator: "eq", Value: "val2"},
+ kendoparser.Filter{Field: "_id", Operator: "neq", Value: "val2"},
},
Logic: "or",
},
},
Logic: "and",
}
- resultFilter = kendoFilter.Parse(ParseFilter)
+ resultFilter = kendoFilter.Parse(FilterParser)
expectedFilter = builder.And(
builder.Or(
@@ -63,21 +63,21 @@ func Test_ParseFilter(t *testing.T) {
t.Log(sql, params)
// // operator check
- // kendoFilter = gokendoparser.KendoFilter{
- // Filters: []gokendoparser.KendoFilter{
- // gokendoparser.KendoFilter{Field: "_id", Operator: "eq", Value: "val"},
- // gokendoparser.KendoFilter{Field: "_id", Operator: "neq", Value: "val"},
- // gokendoparser.KendoFilter{Field: "_id", Operator: "contains", Value: "val"},
- // gokendoparser.KendoFilter{Field: "_id", Operator: "in", Values: []interface{}{"val"}},
- // gokendoparser.KendoFilter{Field: "_id", Operator: "gte", Value: "val"},
- // gokendoparser.KendoFilter{Field: "_id", Operator: "lte", Value: "val"},
- // gokendoparser.KendoFilter{Field: "time", Operator: "gtedate", Value: "2006-01-02T15:04:05Z07:00"},
- // gokendoparser.KendoFilter{Field: "time", Operator: "ltedate", Value: "2006-01-02T15:04:05Z07:00"},
- // gokendoparser.KendoFilter{Field: "_id", Operator: "unknown", Value: "val"},
+ // kendoFilter = kendoparser.Filter{
+ // Filters: []kendoparser.Filter{
+ // kendoparser.Filter{Field: "_id", Operator: "eq", Value: "val"},
+ // kendoparser.Filter{Field: "_id", Operator: "neq", Value: "val"},
+ // kendoparser.Filter{Field: "_id", Operator: "contains", Value: "val"},
+ // kendoparser.Filter{Field: "_id", Operator: "in", Values: []interface{}{"val"}},
+ // kendoparser.Filter{Field: "_id", Operator: "gte", Value: "val"},
+ // kendoparser.Filter{Field: "_id", Operator: "lte", Value: "val"},
+ // kendoparser.Filter{Field: "time", Operator: "gtedate", Value: "2006-01-02T15:04:05Z07:00"},
+ // kendoparser.Filter{Field: "time", Operator: "ltedate", Value: "2006-01-02T15:04:05Z07:00"},
+ // kendoparser.Filter{Field: "_id", Operator: "unknown", Value: "val"},
// },
// Logic: "and",
// }
- // resultFilter = kendoFilter.Parse(ParseFilter).(bson.D)
+ // resultFilter = kendoFilter.Parse(FilterParser).(bson.D)
// testTime, _ := time.Parse(time.RFC3339, "2006-01-02T15:04:05Z07:00")
// expectedFilter = bson.D{
@@ -102,19 +102,19 @@ func Test_ParseFilter(t *testing.T) {
// // transform single filter
// // ID => _id
// {
-// kendoFilter := gokendoparser.KendoFilter{
-// Filters: []gokendoparser.KendoFilter{
-// gokendoparser.KendoFilter{
-// Filters: []gokendoparser.KendoFilter{
-// gokendoparser.KendoFilter{Field: "ID", Operator: "eq", Value: "val"},
-// gokendoparser.KendoFilter{Field: "STATUS", Operator: "eq", Value: "true"},
+// kendoFilter := kendoparser.Filter{
+// Filters: []kendoparser.Filter{
+// kendoparser.Filter{
+// Filters: []kendoparser.Filter{
+// kendoparser.Filter{Field: "ID", Operator: "eq", Value: "val"},
+// kendoparser.Filter{Field: "STATUS", Operator: "eq", Value: "true"},
// },
// Logic: "or",
// },
-// gokendoparser.KendoFilter{
-// Filters: []gokendoparser.KendoFilter{
-// gokendoparser.KendoFilter{Field: "ID", Operator: "eq", Value: "val2"},
-// gokendoparser.KendoFilter{Field: "ID", Operator: "neq", Value: "val2"},
+// kendoparser.Filter{
+// Filters: []kendoparser.Filter{
+// kendoparser.Filter{Field: "ID", Operator: "eq", Value: "val2"},
+// kendoparser.Filter{Field: "ID", Operator: "neq", Value: "val2"},
// },
// Logic: "or",
// },
@@ -124,18 +124,18 @@ func Test_ParseFilter(t *testing.T) {
// // try dbox pipe
// resultFilter := kendoFilter.TransformAllField(strings.ToLower).
-// TransformAll(func(kf *gokendoparser.KendoFilter) {
+// TransformAll(func(kf *kendoparser.Filter) {
// if kf.Field == "id" {
// kf.Field = "_id"
// }
// }).
-// BeforeParseAll(func(kf *gokendoparser.KendoFilter) interface{} {
+// AddAllParser(func(kf *kendoparser.Filter) interface{} {
// if kf.Field == "status" {
// // return your custom handler
// return bson.M{kf.Field: helper.StringToBool(kf.Value, false)}
// }
// return nil // pas nil to continue original filter
-// }).Parse(ParseFilter).(bson.D)
+// }).Parse(FilterParser).(bson.D)
// expectedFilter := bson.D{
// {
@@ -158,17 +158,17 @@ func Test_ParseFilter(t *testing.T) {
func Test_Sort(t *testing.T) {
{
- kData := gokendoparser.KendoData{
- Sort: gokendoparser.KendoSortArray{
- gokendoparser.KendoSort{
+ kData := kendoparser.Data{
+ Sort: kendoparser.Sort{
+ kendoparser.SortDetail{
Field: "foo",
Dir: "DESC",
},
- gokendoparser.KendoSort{
+ kendoparser.SortDetail{
Field: "bar",
Dir: "ASC",
},
- gokendoparser.KendoSort{
+ kendoparser.SortDetail{
Field: "_id",
Dir: "desc",
},
@@ -176,7 +176,7 @@ func Test_Sort(t *testing.T) {
}
// try dbox filter
- result := kData.Sort.Parse(ParseSort)
+ result := kData.Sort.Parse(SortParser)
expectedPipe := strings.Join([]string{
"foo DESC", "bar ASC", "_id DESC",
}, ", ")
diff --git a/parser/xorm/operator.go b/parser/xorm/operator.go
new file mode 100644
index 0000000..edd662b
--- /dev/null
+++ b/parser/xorm/operator.go
@@ -0,0 +1,118 @@
+package kpxorm
+
+import (
+ "time"
+
+ "github.com/raditzlawliet/kendoparser"
+ "github.com/raditzlawliet/kendoparser/helper"
+ "github.com/spf13/cast"
+ "xorm.io/builder"
+)
+
+var (
+ // OperatorManager of Mongo Parser
+ OperatorManager = new(kendoparser.OperatorManager)
+ // Operator bundle of Mongo Parser
+ Operator = OperatorBundle{}
+)
+
+type OperatorBundle struct{}
+
+func init() {
+ RegisterOperator()
+}
+
+// RegisterOperator RegisterOperator
+func RegisterOperator() {
+ OperatorManager.SetDefaultOperator(Operator.Equal)
+ OperatorManager.RegisterOperator(Operator.Equal, "eq", "equal")
+ OperatorManager.RegisterOperator(Operator.NotEqual, "ne", "neq", "notequal")
+ OperatorManager.RegisterOperator(Operator.Contain, "contain", "contains", "include", "includes")
+ OperatorManager.RegisterOperator(Operator.NotContain, "notcontains", "notcontains", "doesnotcontain", "doesnotcontains", "notinclude", "notincludes", "doesnotinclude", "doesnotincludes")
+ OperatorManager.RegisterOperator(Operator.In, "in")
+ OperatorManager.RegisterOperator(Operator.Gt, "gt")
+ OperatorManager.RegisterOperator(Operator.Lt, "lt")
+ OperatorManager.RegisterOperator(Operator.Gte, "gte")
+ OperatorManager.RegisterOperator(Operator.Lte, "lte")
+ OperatorManager.RegisterOperator(Operator.GteDate, "gtedate")
+ OperatorManager.RegisterOperator(Operator.LteDate, "ltedate")
+ OperatorManager.RegisterOperator(Operator.Exists, "exist", "exists")
+ OperatorManager.RegisterOperator(Operator.Between, "between")
+}
+
+func (o *OperatorBundle) Equal(kf kendoparser.Filter) interface{} {
+ if kf.IgnoreCase {
+ return EqCi{kf.Field: kf.Value}
+ }
+ return builder.Eq{kf.Field: kf.Value}
+}
+
+func (o *OperatorBundle) NotEqual(kf kendoparser.Filter) interface{} {
+ return builder.Neq{kf.Field: kf.Value}
+}
+
+func (o *OperatorBundle) Contain(kf kendoparser.Filter) interface{} {
+ if kf.IgnoreCase {
+ return LikeCi{kf.Field, cast.ToString(kf.Value)}
+ }
+ return builder.Like{cast.ToString(kf.Value), cast.ToString(kf.Value)}
+}
+
+func (o *OperatorBundle) NotContain(kf kendoparser.Filter) interface{} {
+ if kf.IgnoreCase {
+ return builder.Not{
+ LikeCi{kf.Field, cast.ToString(kf.Value)},
+ }
+ }
+ return builder.Not{
+ builder.Like{cast.ToString(kf.Value), cast.ToString(kf.Value)},
+ }
+}
+
+func (o *OperatorBundle) In(kf kendoparser.Filter) interface{} {
+ return builder.In(kf.Field, kf.Values...)
+}
+
+func (o *OperatorBundle) Gt(kf kendoparser.Filter) interface{} {
+ return builder.Gt{kf.Field: kf.Value}
+}
+
+func (o *OperatorBundle) Lt(kf kendoparser.Filter) interface{} {
+ return builder.Lt{kf.Field: kf.Value}
+}
+
+func (o *OperatorBundle) Gte(kf kendoparser.Filter) interface{} {
+ return builder.Gte{kf.Field: kf.Value}
+}
+
+func (o *OperatorBundle) Lte(kf kendoparser.Filter) interface{} {
+ return builder.Lte{kf.Field: kf.Value}
+}
+
+func (o *OperatorBundle) GteDate(kf kendoparser.Filter) interface{} {
+ dtVariable, _ := time.Parse(time.RFC3339, cast.ToString(kf.Value))
+ return builder.Gte{kf.Field: dtVariable}
+}
+
+func (o *OperatorBundle) LteDate(kf kendoparser.Filter) interface{} {
+ dtVariable, _ := time.Parse(time.RFC3339, cast.ToString(kf.Value))
+ return builder.Lte{kf.Field: dtVariable}
+}
+
+func (o *OperatorBundle) Exists(kf kendoparser.Filter) interface{} {
+ if helper.StringToBool(cast.ToString(kf.Value), false) {
+ return builder.NotNull{kf.Field}
+ }
+ return builder.IsNull{kf.Field}
+}
+
+func (o *OperatorBundle) Between(kf kendoparser.Filter) interface{} {
+ var v0, v1 interface{}
+ if len(kf.Values) > 0 {
+ v0 = kf.Values[0]
+ }
+ if len(kf.Values) > 1 {
+ v1 = kf.Values[1]
+ }
+ return builder.Between{kf.Field, v0, v1}
+}
diff --git a/v0.4.0/operator.go b/v0.4.0/operator.go
index 7ef10d6..30046ef 100644
--- a/v0.4.0/operator.go
+++ b/v0.4.0/operator.go
@@ -11,10 +11,10 @@ import (
"gopkg.in/mgo.v2/bson"
)
-// RegisteredOperators a global list registered operator, will use in all kendo, you can overwrite in struct scope if needed
+// OperatorFilters a global list registered operator, will use in all kendo, you can overwrite in struct scope if needed
var RegisteredOperators = map[string]Operator{}
-// DefaultOperator will call if registerd not found, default operator is equa
+// DefaultOperatorFilter will call if registerd not found, default operator is equa
var DefaultOperator Operator = EqualOp{}
var mutex = &sync.Mutex{}