Skip to content

Commit

Permalink
Merge pull request #74 from decibelcooper/feat/query_processor
Browse files Browse the repository at this point in the history
User Query Processor
  • Loading branch information
jsccast committed Mar 2, 2021
2 parents 8813042 + 7eea95c commit 542f5cd
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 6 deletions.
5 changes: 5 additions & 0 deletions core/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ type App interface {
// UpdateJavascriptRuntime can be used to modify the
// Javascript environment for actions and condition code.
UpdateJavascriptRuntime(ctx *Context, runtime *otto.Otto) error

// ProcessQuery can be used to replace or wrap queries when unmarshaling a
// rule condition. The method gets the raw generic query data along with
// the query created by Rulio.
ProcessQuery(ctx *Context, raw map[string]interface{}, query Query) Query
}

// Tracer can be used to perform application tracing.
Expand Down
4 changes: 4 additions & 0 deletions core/events_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,10 @@ func (ba *BindingApp) UpdateJavascriptRuntime(ctx *Context, runtime *otto.Otto)
return nil
}

func (ba *BindingApp) ProcessQuery(_ *Context, _ map[string]interface{}, q Query) Query {
return q
}

func TestEventConditionBindings(t *testing.T) {
ctx, loc := TestingLocation(t)
c := make(chan interface{})
Expand Down
4 changes: 4 additions & 0 deletions core/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,7 @@ func (ha *HeaderApp) ProcessBindings(ctx *Context, bs Bindings) Bindings {
func (ha *HeaderApp) UpdateJavascriptRuntime(ctx *Context, runtime *otto.Otto) error {
return nil
}

func (ha *HeaderApp) ProcessQuery(_ *Context, _ map[string]interface{}, q Query) Query {
return q
}
19 changes: 13 additions & 6 deletions core/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -750,17 +750,24 @@ func NotQueryFromMap(ctx *Context, m map[string]interface{}) (Query, bool, error
return q, true, nil
}

func ParseQuery(ctx *Context, m map[string]interface{}) (Query, error) {
func ParseQuery(ctx *Context, m map[string]interface{}) (q Query, err error) {
Log(DEBUG, ctx, "core.ParseQuery", "map", fmt.Sprintf("%#v", m))
if len(m) == 0 {
return EmptyQuery{}, nil
}

defer func() {
if ctx != nil && ctx.App != nil {
q = ctx.App.ProcessQuery(ctx, m, q)
}
}()

q, applicable, err := CodeQueryFromMap(ctx, m)
if applicable {
if err != nil {
return nil, err
} else {
return q, nil
return
}
}

Expand All @@ -769,7 +776,7 @@ func ParseQuery(ctx *Context, m map[string]interface{}) (Query, error) {
if err != nil {
return nil, err
} else {
return q, nil
return
}
}

Expand All @@ -778,7 +785,7 @@ func ParseQuery(ctx *Context, m map[string]interface{}) (Query, error) {
if err != nil {
return nil, err
} else {
return q, nil
return
}
}

Expand All @@ -787,7 +794,7 @@ func ParseQuery(ctx *Context, m map[string]interface{}) (Query, error) {
if err != nil {
return nil, err
} else {
return q, nil
return
}
}

Expand All @@ -796,7 +803,7 @@ func ParseQuery(ctx *Context, m map[string]interface{}) (Query, error) {
if err != nil {
return nil, err
} else {
return q, nil
return
}
}

Expand Down
85 changes: 85 additions & 0 deletions core/query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"net/http/httptest"
"testing"

"github.com/robertkrimen/otto"
"github.com/stretchr/testify/assert"
)

Expand Down Expand Up @@ -512,3 +513,87 @@ func TestOrQueryFromMapGood2(t *testing.T) {
t.Fatal("shouldn't have reported an error")
}
}

type QueryWrapperApp struct {
Query Query
PreExec func(ctx *Context, loc *Location, qc QueryContext, qr QueryResult) (*QueryResult, error)
PostExec func(ctx *Context, loc *Location, qc QueryContext, qr QueryResult) (*QueryResult, error)
}

func (app QueryWrapperApp) Exec(ctx *Context, loc *Location, qc QueryContext, qr QueryResult) (*QueryResult, error) {
r := &qr
var err error
if app.PreExec != nil {
r, err = app.PreExec(ctx, loc, qc, *r)
if err != nil {
return nil, err
}
}

r, err = app.Query.Exec(ctx, loc, qc, *r)
if err != nil {
return nil, err
}

if app.PostExec != nil {
r, err = app.PostExec(ctx, loc, qc, *r)
if err != nil {
return nil, err
}
}

return r, nil
}

func (app QueryWrapperApp) ProcessQuery(ctx *Context, m map[string]interface{}, q Query) Query {
app.Query = q
return app
}

func (app QueryWrapperApp) GenerateHeaders(ctx *Context) map[string]string {
return nil
}

func (app QueryWrapperApp) ProcessBindings(ctx *Context, bs Bindings) Bindings {
return bs
}

func (app QueryWrapperApp) UpdateJavascriptRuntime(ctx *Context, runtime *otto.Otto) error {
return nil
}

func TestAppProcessQuery(t *testing.T) {
var hitCount int

ctx := NewContext("test")
ctx.App = QueryWrapperApp{
PreExec: func(ctx *Context, loc *Location, qc QueryContext, qr QueryResult) (*QueryResult, error) {
hitCount++
return &qr, nil
},
}

loc, err := NewLocation(ctx, "test", nil, nil)
if err != nil {
t.Fatal(err)
}

if err = loc.Clear(ctx); err != nil {
t.Fatal(err)
}

q, err := ParseQueryFromJSON(ctx, `{"or":[{"code": "true"}, {"code": "false"}]}`)
if nil != err {
t.Fatal(err)
}

qc := QueryContext{}
qrInit := QueryResult{[]Bindings{}, 0, 0}
if len(qrInit.Bss) == 0 {
qrInit = InitialQueryResult(ctx)
}
_, err = q.Exec(ctx, loc, qc, qrInit)
assert.NoError(t, err)

assert.Equal(t, 3, hitCount, fmt.Sprintf("expected 3 executions of the query wrapper %T", q))
}

0 comments on commit 542f5cd

Please sign in to comment.