Skip to content
This repository has been archived by the owner on May 1, 2023. It is now read-only.
/ kendoparser Public archive

Parsing Kendo DataSource filter & sort request 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 general purpose

Notifications You must be signed in to change notification settings

raditzlawliet/kendoparser

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

24 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GitHub tag (latest SemVer) Codecov contributions welcome

Go Kendo Parser

Your Golang Kendo parser, parsing Kendo data source request to golang struct immediately. Available parser to

Features

  • Convert kendo datasource request into go struct
  • Basic Operator
  • Transform filter + Chaining
  • Plugable operator handler
  • local scope operator
  • Parser Sort
  • Custom pre-filter handler

Incoming Feature

  • Convert kendo datasource request into go struct
  • Basic Operator
  • Transform filter + Chaining
  • Plugable operator handler
  • local scope operator
  • Parser Sort
  • Custom pre-filter handler
  • Extendable to any driver

Getting Started

Easy to use like title said

To eaciit/dbox filter

JSON Sample

{
    "data": {
        "filter": {
            "field": "id",
            "operator": "eq",
            "value": "val",
        }
    }
}

GO Implementation

// just for information
// you can use gorilla mux or knot
var k = k *knot.WebContext

// retrieve payload
payload := &KendoRequest{}
k.GetPayload(payload)

// Usually payload the struct will be this
payload := KendoRequest {
    Data: KendoData{
        Filter: KendoFilter{
            Field: "_id", Operator: "eq", Value: "val"
        },
    },
}

resultFilter := payload.Data.ToDboxFilter() 
// dbox.Eq("_id", "val")

More JSON

{
    "data": {
        "filters": [
            {
                "filter": {
                    "field": "id",
                    "operator": "eq",
                    "value": "val",
                }
            },
            {
                "filter": {
                    "field": "abc",
                    "operator": "in",
                    "values": ["a", "b"],
                }
            }
        ],
        "logic": "and"
    }
}
// just for information
// you can use gorilla mux or knot
var k = k *knot.WebContext

// retrieve payload
payload := &KendoRequest{}
k.GetPayload(payload)

// Usually payload the struct will be this
payload := KendoRequest {
    Data: KendoData{
        Filter: KendoFilter{
            Filters: []KendoFilter{
                Filter: KendoFilter{
                    Field: "_id", Operator: "eq", Value: "val"
                },
                Filter: KendoFilter{
                    Field: "abc", Operator: "in", Values: []interface{}{"a", "b"}
                },
            }
        },
    },
}

resultFilter := payload.Data.ToDboxFilter() 
// dbox.And(
//     dbox.Eq("_id", "val"),
//     dbox.In("abc", []interface{}{"a", "b"}...),
// )

To eaciit/dbox aggregation filter (return eaciit/toolkit/M)

Same like previously one

resultFilter := payload.Data.ToDboxPipe() 
// tk.M{"$and": []tk.M{tk.M{"_id": tk.M{"$eq": "val"}}}}

To eaciit/dbflux filter (Coming soon)

Same like previously one

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 global handler (for sample you can see operator_between.go). You must implement all function in Operator interface (or just return nil if you dont want implement other hook)

type Operator interface {
	ToDboxFilter(KendoFilter) *dbox.Filter
	ToDboxPipe(KendoFilter) toolkit.M
}
// extend struct from interface Operator, all interface func must appear
type BetweenOperator struct {}

func (BetweenOperator) ToDboxFilter(kf KendoFilter) *dbox.Filter {
	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))
}
func (BetweenOperator) ToDboxPipe(kf KendoFilter) toolkit.M {
    return nil // pass whatever if you dont want to implement
    // return DefaultOperator // or pass default
}
// register it 
betOp := BetweenOperator{}
RegisterOperator("between", betOp)

// reset 
ResetRegisterOperator()

// overwrite Default Operator
SetDefaultOperator(betOp)

Local scope Operator

You also can defined local scope only operator, just use the struct and register like global scope. It support nested or not

betOp := BetweenOperator{}
kendoFilter := KendoFilter{}

// register operator in it struct only
kendoFilter.RegisterOperator("between", betOp)

// register operator in it struct and all child filters
kendoFilter.RegisterOperatorAll("between", betOp)

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) for more uses

kendoFilter := KendoFilter{}

// transform filter field or all field in filters into lower case
kendoFilter.TransformField(strings.ToLower) // only current filter
kendoFilter.TransformFieldAll(strings.ToLower) // include filters

// custom transform include value (if needed), it use pointer KendoFilter, so you can direct modify. No need to return
transformIDMongo := func(kf *KendoFilter) {
    if kf.Field == "id" {
        kf.Field = "_id"
    }
}
kendoFilter.Transform(transformIDMongo) // only current filter
kendoFilter.TransformAll(transformIDMongo) // include filters

// chaining is possible
kendoFilter.TransformFieldAll(strings.ToLower).TransformAll(transformIDMongo).ToDboxFilter()

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. For example you can direct create your custom filter when the field is "status" like below

// dbox filter
resultFilter := kendoFilter.TransformAllField(strings.ToLower).
    TransformAll(func(kf *KendoFilter) {
        if kf.Field == "id" {
            kf.Field = "_id"
        }
    }).
    PreDboxFilterAll(func(kf *KendoFilter) *dbox.Filter {
        if kf.Field == "status" {
            // return your custom handler
            return dbox.Eq(kf.Field, StringToBool(kf.Value, false))
        }
        return nil // pas nil to continue original filter
    }).
    ToDboxFilter()

// reset if needed another
kendoFilter.ResetPreFilter()

// dbox pipe
resultFilterPipe := kendoFilter.TransformAllField(strings.ToLower).
    TransformAll(func(kf *KendoFilter) {
        if kf.Field == "id" {
            kf.Field = "_id"
        }
    }).
    PreDboxPipeAll(func(kf *KendoFilter) tk.M {
        if kf.Field == "status" {
            // return your custom handler
            return tk.M{kf.Field: StringToBool(kf.Value, false)}
        }
        return nil // pas nil to continue original filter
    }).
    ToDboxPipe()

currently we have 2 pre-filter handler, later we will have custom handler more dynamic if needed.

Sort

do you need sort? You can do it easly.

result := kData.Sort.ToDbox()
resultPipe := kData.Sort.ToDboxPipe()

Contribute

Feel free to contribute, don't forget to mention if needed

License

MIT License

Author and Contributor

Radityo

About

Parsing Kendo DataSource filter & sort request 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 general purpose

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages