func TestSqlDelete(t *testing.T) { db := datasource.NewContextSimple() user1 := map[string]value.Value{ "user_id": value.NewIntValue(5), "item_count": value.NewStringValue("5"), "bval": value.NewBoolValue(true), "bvalf": value.NewBoolValue(false), "reg_date": value.NewStringValue("2014/11/01"), "name": value.NewStringValue("bob")} db.Insert(user1) user2 := map[string]value.Value{ "user_id": value.NewIntValue(6), "item_count": value.NewStringValue("5"), "reg_date": value.NewStringValue("2012/11/01"), "name": value.NewStringValue("allison")} db.Insert(user2) assert.Tf(t, len(db.Rows) == 2, "has 2 users") verifySqlDelete(t, ` DELETE FROM mytable WHERE yy(reg_date) == 14 `, db) assert.Tf(t, len(db.Rows) == 1, "must have 1 rows: %v %v", len(db.Rows), db.Rows) assert.Tf(t, db.Rows[0]["name"].ToString() == "allison", "%v", db.Rows) }
func TestBuiltins(t *testing.T) { for _, biTest := range builtinTests { writeContext := datasource.NewContextSimple() //u.Debugf("expr: %v", biTest.expr) exprVm, err := vm.NewVm(biTest.expr) assert.Tf(t, err == nil, "parse err: %v on %s", err, biTest.expr) err = exprVm.Execute(writeContext, readContext) if biTest.val.Err() { assert.Tf(t, err != nil, "%v expected err: %v", biTest.expr, err) } else { tval := biTest.val assert.Tf(t, err == nil, "not nil err: %s %v", biTest.expr, err) val, ok := writeContext.Get("") assert.Tf(t, ok, "Not ok Get? %#v", writeContext) //u.Debugf("Type: %T %T", val, tval.Value) switch testVal := biTest.val.(type) { case value.StringsValue: //u.Infof("Sweet, is StringsValue:") sa := tval.(value.StringsValue).Value().([]string) sb := val.Value().([]string) sort.Strings(sa) sort.Strings(sb) assert.Tf(t, strings.Join(sa, ",") == strings.Join(sb, ","), "should be == expect %v but was %v %v", tval.Value(), val.Value(), biTest.expr) case value.MapValue: if len(testVal.Val()) == 0 { // we didn't expect it to work? _, ok := val.(value.MapValue) assert.Tf(t, !ok, "Was able to convert to mapvalue but should have failed %#v", val) } else { mv, ok := val.(value.MapValue) assert.Tf(t, ok, "Was able to convert to mapvalue: %#v", val) //u.Debugf("mv: %T %v", mv, val) assert.Tf(t, len(testVal.Val()) == len(mv.Val()), "Should have same size maps") mivals := mv.Val() for k, v := range testVal.Val() { valVal := mivals[k] //u.Infof("k:%v v:%v valval:%v", k, v.Value(), valVal.Value()) assert.Equalf(t, valVal.Value(), v.Value(), "Must have found k/v: %v \n\t%#v \n\t%#v", k, v, valVal) } } default: assert.Tf(t, val.Value() == tval.Value(), "should be == expect %v but was %v %v", tval.Value(), val.Value(), biTest.expr) } } } }
func TestRunExpr(t *testing.T) { for _, test := range vmTests { if *NameMatch != "" && !strings.Contains(test.name, *NameMatch) { continue } //u.Debugf("about to parse: %v", test.qlText) exprVm, err := NewVm(test.qlText) //u.Infof("After Parse: %v err=%v", test.qlText, err) switch { case err == nil && !test.parseok: t.Errorf("%q: 1 expected error; got none", test.name) continue case err != nil && test.parseok: t.Errorf("%q: 2 unexpected error: %v", test.name, err) continue case err != nil && !test.parseok: // expected error, got one if testing.Verbose() { u.Infof("%s: %s\n\t%s", test.name, test.qlText, err) } continue } writeContext := datasource.NewContextSimple() err = exprVm.Execute(writeContext, test.context) if exprVm.Tree != nil && exprVm.Tree.Root != nil { //Eval(writeContext, exprVm.Tree.Root) } results, _ := writeContext.Get("") //u.Infof("results: %T %v err=%v", results, results, err) if err != nil && test.evalok { t.Errorf("\n%s -- %v: \n\t%v\nexpected\n\t'%v'", test.name, test.qlText, results, test.result) } if test.result == nil && results != nil { t.Errorf("%s - should have nil result, but got: %v", test.name, results) continue } if test.result != nil && results == nil { t.Errorf("%s - should have non-nil result but was nil", test.name) continue } //u.Infof("results=%T %#v", results, results) if test.result != nil && results.Value() != test.result { t.Fatalf("\n%s -- %v: \n\t%v--%T\nexpected\n\t%v--%T", test.name, test.qlText, results.Value(), results.Value(), test.result, test.result) } else if test.result == nil { // we expected nil } } }
func verifySqlWrite(t *testing.T, sql string) *datasource.ContextSimple { sqlVm, err := NewSqlVm(sql) assert.Tf(t, err == nil, "Should not err %v", err) assert.Tf(t, sqlVm != nil, "Should create vm & parse sql %v", sqlVm) writeContext := datasource.NewContextSimple() err = sqlVm.ExecuteInsert(writeContext) assert.Tf(t, err == nil, "non nil err: %v", err) return writeContext }
func runParse(repeat int, sql string, readContext expr.ContextReader) { for i := 0; i < repeat; i++ { sqlVm, err := expr.ParseSqlVm(sql) if err != nil { panic(err.Error()) } sel := sqlVm.(*expr.SqlSelect) writeContext := datasource.NewContextSimple() _, err = vm.EvalSql(sel, writeContext, readContext) if err != nil { panic(err.Error()) } } }
func verifyBenchmarkSql(t *testing.B, sql string, readContext datasource.ContextReader) *datasource.ContextSimple { sqlVm, err := NewSqlVm(sql) if err != nil { t.Fail() } writeContext := datasource.NewContextSimple() err = sqlVm.Execute(writeContext, readContext) if err != nil { t.Fail() } return writeContext }
func verifySql(t *testing.T, sql string, readrows []datasource.ContextReader) *datasource.ContextSimple { sqlVm, err := NewSqlVm(sql) assert.Tf(t, err == nil, "Should not err %v", err) assert.Tf(t, sqlVm != nil, "Should create vm & parse sql %v", sqlVm) writeContext := datasource.NewContextSimple() for _, row := range readrows { err = sqlVm.Execute(writeContext, row) assert.Tf(t, err == nil, "non nil err: %v", err) } return writeContext }
func BenchmarkVmExecuteNoParse(b *testing.B) { readContext := datasource.NewContextSimpleData( map[string]value.Value{ "int5": value.NewIntValue(5), "item_count": value.NewStringValue("5"), "reg_date": value.NewStringValue("2014/11/01"), "user_id": value.NewStringValue("abc")}, ) sqlVm, err := NewSqlVm(bmSql[0]) if err != nil { b.Fail() } writeContext := datasource.NewContextSimple() b.ReportAllocs() b.StartTimer() for i := 0; i < b.N; i++ { err = sqlVm.Execute(writeContext, readContext) if err != nil { b.Fail() } } }
func TestFilterQlVm(t *testing.T) { t.Parallel() t1, _ := dateparse.ParseAny("12/18/2015") //u.Infof("t1 %v", t1) nminus1 := time.Now().Add(time.Hour * -1) tr := true user := &User{ Name: "Yoda", Created: t1, Updated: &nminus1, Authenticated: true, HasSession: &tr, Address: Address{"Detroit", 55}, Roles: []string{"admin", "api"}, BankAmount: 55.5, } readers := []expr.ContextReader{ datasource.NewContextWrapper(user), datasource.NewContextSimpleNative(map[string]interface{}{ "city": "Peoria, IL", "zip": 5, }), } nc := datasource.NewNestedContextReader(readers, time.Now()) hits := []string{ `FILTER name == "Yoda"`, // upper case sensitive name `FILTER name != "yoda"`, // we should be case-sensitive by default `FILTER name = "Yoda"`, // is equivalent to == `FILTER "Yoda" == name`, // reverse order of identity/value `FILTER name != "Anakin"`, // negation on missing fields == true `FILTER first_name != "Anakin"`, // key doesn't exist `FILTER tolower(name) == "yoda"`, // use functions in evaluation `FILTER FullName == "Yoda, Jedi"`, // use functions on structs in evaluation `FILTER Address.City == "Detroit"`, // traverse struct with path.field `FILTER name LIKE "*da"`, // LIKE `FILTER name NOT LIKE "*kin"`, // LIKE Negation `FILTER name CONTAINS "od"`, // Contains `FILTER name NOT CONTAINS "kin"`, // Contains `FILTER roles INTERSECTS ("user", "api")`, // Intersects `FILTER roles NOT INTERSECTS ("user", "guest")`, // Intersects `FILTER Created < "now-1d"`, // Date Math `FILTER Updated > "now-2h"`, // Date Math `FILTER *`, // match all `FILTER OR ( EXISTS name, -- inline comments EXISTS not_a_key, -- more inline comments )`, // show that line-breaks serve as expression separators `FILTER OR ( EXISTS name EXISTS not_a_key -- even if they have inline comments )`, //`FILTER a == "Yoda" AND b == "Peoria, IL" AND c == 5`, `FILTER AND (name == "Yoda", city == "Peoria, IL", zip == 5, BankAmount > 50)`, `FILTER AND (zip == 5, "Yoda" == name, OR ( city IN ( "Portland, OR", "New York, NY", "Peoria, IL" ) ) )`, `FILTER OR ( EXISTS q, AND ( zip > 0, OR ( zip > 10000, zip < 100 ) ), NOT ( name == "Yoda" ) )`, } for _, q := range hits { fs, err := rel.ParseFilterQL(q) assert.Equal(t, nil, err) match, err := NewFilterVm(nil).Matches(nc, fs) assert.Equalf(t, nil, err, "error matching on query %q: %v", q, err) assert.T(t, match, q) } misses := []string{ `FILTER name == "yoda"`, // casing "FILTER OR (false, false, AND (true, false))", `FILTER AND (name == "Yoda", city == "xxx", zip == 5)`, } for _, q := range misses { fs, err := rel.ParseFilterQL(q) assert.Equal(t, nil, err) match, err := NewFilterVm(nil).Matches(nc, fs) assert.Equal(t, nil, err) assert.T(t, !match) } // Filter Select Statements filterSelects := []fsel{ fsel{`select name, zip FROM mycontext FILTER name == "Yoda"`, map[string]interface{}{"name": "Yoda", "zip": 5}}, } for _, test := range filterSelects { //u.Debugf("about to parse: %v", test.qlText) sel, err := rel.ParseFilterSelect(test.query) assert.T(t, err == nil, "expected no error but got ", err, " for ", test.query) writeContext := datasource.NewContextSimple() _, err = EvalFilerSelect(sel, nil, writeContext, nc) assert.T(t, err == nil, "expected no error but got ", err, " for ", test.query) for key, val := range test.expect { v := value.NewValue(val) v2, ok := writeContext.Get(key) assert.Tf(t, ok, "Get(%q)=%v but got: %#v", key, val, writeContext.Row()) assert.Equalf(t, v2.Value(), v.Value(), "?? %s %v!=%v %T %T", key, v.Value(), v2.Value(), v.Value(), v2.Value()) } } }
// Create handler function for evaluation (ie, field selection from tuples) func (m *Projection) projectionEvaluator() MessageHandler { out := m.MessageOut() columns := m.sql.Columns // if len(m.sql.From) > 1 && m.sql.From[0].Source != nil && len(m.sql.From[0].Source.Columns) > 0 { // // we have re-written this query, lets build new list of columns // columns = make(expr.Columns, 0) // for _, from := range m.sql.From { // for _, col := range from.Source.Columns { // columns = append(columns, col) // } // } // } return func(ctx *expr.Context, msg datasource.Message) bool { // defer func() { // if r := recover(); r != nil { // u.Errorf("crap, %v", r) // } // }() //u.Infof("got projection message: %T %#v", msg, msg.Body()) var outMsg datasource.Message switch mt := msg.(type) { case *datasource.SqlDriverMessageMap: // readContext := datasource.NewContextUrlValues(uv) // use our custom write context for example purposes writeContext := datasource.NewContextSimple() outMsg = writeContext //u.Debugf("about to project: %#v", mt) for _, col := range columns { if col.ParentIndex < 0 { continue } //u.Debugf("col: idx:%v pidx:%v key:%v %s", col.Index, col.ParentIndex, col.Key(), col.Expr) if col.Guard != nil { ifColValue, ok := vm.Eval(mt, col.Guard) if !ok { u.Errorf("Could not evaluate if: %v", col.Guard.String()) //return fmt.Errorf("Could not evaluate if clause: %v", col.Guard.String()) } //u.Debugf("if eval val: %T:%v", ifColValue, ifColValue) switch ifColVal := ifColValue.(type) { case value.BoolValue: if ifColVal.Val() == false { //u.Debugf("Filtering out col") continue } } } if col.Star { for k, v := range mt.Row() { writeContext.Put(&expr.Column{As: k}, nil, value.NewValue(v)) } } else { v, ok := vm.Eval(mt, col.Expr) if !ok { u.Warnf("failed eval key=%v val=%#v expr:%s mt:%#v", col.Key(), v, col.Expr, mt) } else if v == nil { u.Debugf("evaled: key=%v val=%v", col.Key(), v) writeContext.Put(col, mt, v) } else { //u.Debugf("evaled: key=%v val=%v", col.Key(), v.Value()) writeContext.Put(col, mt, v) } } } case *datasource.ContextUrlValues: // readContext := datasource.NewContextUrlValues(uv) // use our custom write context for example purposes writeContext := datasource.NewContextSimple() outMsg = writeContext //u.Infof("about to project: colsct%v %#v", len(sql.Columns), outMsg) for _, col := range columns { //u.Debugf("col: %#v", col) if col.Guard != nil { ifColValue, ok := vm.Eval(mt, col.Guard) if !ok { u.Errorf("Could not evaluate if: %v", col.Guard.String()) //return fmt.Errorf("Could not evaluate if clause: %v", col.Guard.String()) } //u.Debugf("if eval val: %T:%v", ifColValue, ifColValue) switch ifColVal := ifColValue.(type) { case value.BoolValue: if ifColVal.Val() == false { //u.Debugf("Filtering out col") continue } } } if col.Star { for k, v := range mt.Row() { writeContext.Put(&expr.Column{As: k}, nil, v) } } else { //u.Debugf("tree.Root: as?%v %#v", col.As, col.Expr) v, ok := vm.Eval(mt, col.Expr) //u.Debugf("evaled: ok?%v key=%v val=%v", ok, col.Key(), v) if ok { writeContext.Put(col, mt, v) } } } default: u.Errorf("could not project msg: %T", msg) } //u.Debugf("completed projection for: %p %#v", out, outMsg) select { case out <- outMsg: return true case <-m.SigChan(): return false } } }
// Create handler function for evaluation (ie, field selection from tuples) func projectionEvaluator(sql *expr.SqlSelect, task TaskRunner) MessageHandler { out := task.MessageOut() //evaluator := vm.Evaluator(where) return func(ctx *Context, msg datasource.Message) bool { defer func() { if r := recover(); r != nil { u.Errorf("crap, %v", r) } }() //u.Infof("got projection message: %#v", msg.Body()) var outMsg datasource.Message switch mt := msg.(type) { case *datasource.SqlDriverMessageMap: // readContext := datasource.NewContextUrlValues(uv) // use our custom write context for example purposes writeContext := datasource.NewContextSimple() outMsg = writeContext //u.Infof("about to project: colsct%v %#v", len(sql.Columns), outMsg) for _, from := range sql.From { for _, col := range from.Columns { //u.Debugf("col: %#v", col) if col.Guard != nil { ifColValue, ok := vm.Eval(mt, col.Guard) if !ok { u.Errorf("Could not evaluate if: %v", col.Guard.StringAST()) //return fmt.Errorf("Could not evaluate if clause: %v", col.Guard.String()) } //u.Debugf("if eval val: %T:%v", ifColValue, ifColValue) switch ifColVal := ifColValue.(type) { case value.BoolValue: if ifColVal.Val() == false { //u.Debugf("Filtering out col") continue } } } if col.Star { for k, v := range mt.Vals { writeContext.Put(&expr.Column{As: k}, nil, value.NewValue(v)) } } else { //u.Debugf("tree.Root: as?%v %v", col.As, col.Expr.String()) v, ok := vm.Eval(mt, col.Expr) //u.Debugf("evaled: ok?%v key=%v val=%v", ok, col.Key(), v) if ok { writeContext.Put(col, mt, v) } } } } case *datasource.ContextUrlValues: // readContext := datasource.NewContextUrlValues(uv) // use our custom write context for example purposes writeContext := datasource.NewContextSimple() outMsg = writeContext //u.Infof("about to project: colsct%v %#v", len(sql.Columns), outMsg) for _, col := range sql.Columns { //u.Debugf("col: %#v", col) if col.Guard != nil { ifColValue, ok := vm.Eval(mt, col.Guard) if !ok { u.Errorf("Could not evaluate if: %v", col.Guard.StringAST()) //return fmt.Errorf("Could not evaluate if clause: %v", col.Guard.String()) } //u.Debugf("if eval val: %T:%v", ifColValue, ifColValue) switch ifColVal := ifColValue.(type) { case value.BoolValue: if ifColVal.Val() == false { //u.Debugf("Filtering out col") continue } } } if col.Star { for k, v := range mt.Row() { writeContext.Put(&expr.Column{As: k}, nil, v) } } else { //u.Debugf("tree.Root: as?%v %#v", col.As, col.Expr) v, ok := vm.Eval(mt, col.Expr) //u.Debugf("evaled: ok?%v key=%v val=%v", ok, col.Key(), v) if ok { writeContext.Put(col, mt, v) } } } default: u.Errorf("could not project msg: %T", msg) } //u.Debugf("completed projection for: %p %#v", out, outMsg) select { case out <- outMsg: return true case <-task.SigChan(): return false } } }