func (this *FunctionCallLower) Evaluate(item *dparval.Value) (*dparval.Value, error) { // first evaluate the argument av, err := this.Operands[0].Expr.Evaluate(item) // the spec defines this functin to ONLY operate on strings // all other types result in NULL if err != nil { switch err := err.(type) { case *dparval.Undefined: // undefined returns null return dparval.NewValue(nil), nil default: // any other error return to caller return nil, err } } if av.Type() == dparval.STRING { avalue := av.Value() switch avalue := avalue.(type) { case string: return dparval.NewValue(strings.ToLower(avalue)), nil } } return dparval.NewValue(nil), nil }
func TestCount(t *testing.T) { dataset := dparval.ValueCollection{ dparval.NewValue(map[string]interface{}{ "name": "marty", "status": "alive", }), dparval.NewValue(map[string]interface{}{ "name": "gerald", "status": nil, }), dparval.NewValue(map[string]interface{}{ "name": "steve", }), } tests := AggregateTestSet{ // test * (counts all rows) { NewFunctionCall("COUNT", FunctionArgExpressionList{NewStarFunctionArgExpression()}), dparval.NewValue(3.0), }, // test expression (eliminiates null and missing) { NewFunctionCall("COUNT", FunctionArgExpressionList{NewFunctionArgExpression(NewProperty("status"))}), dparval.NewValue(1.0), }, } tests.Run(t, dataset) }
func (this *FunctionCallCeil) Evaluate(item *dparval.Value) (*dparval.Value, error) { // first evaluate the argument av, err := this.Operands[0].Expr.Evaluate(item) // the spec defines this functin to ONLY operate on numeric values // all other types result in NULL if err != nil { switch err := err.(type) { case *dparval.Undefined: // undefined returns null return dparval.NewValue(nil), nil default: // any other error return to caller return nil, err } } if av.Type() == dparval.NUMBER { avalue := av.Value() switch avalue := avalue.(type) { case float64: return dparval.NewValue(math.Ceil(avalue)), nil } } return dparval.NewValue(nil), nil }
func (this *OrOperator) Evaluate(item *dparval.Value) (*dparval.Value, error) { var rv interface{} var re error rv = false re = nil for _, operand := range this.Operands { operandVal, err := operand.Evaluate(item) if err != nil { switch err := err.(type) { case *dparval.Undefined: rv = nil re = err continue default: // any other error should be returned to caller return nil, err } } // now interpret the evaluated value in a boolean context operandValVal := operandVal.Value() operandBoolVal := ValueInBooleanContext(operandValVal) if operandBoolVal == true { return dparval.NewValue(true), nil } else if operandBoolVal == nil && rv == false { rv = operandBoolVal re = nil } // if operandBoolVal is true, do nothing // rv starts as true, and should never change back to true } if re != nil { return nil, re } return dparval.NewValue(rv), re }
func init() { doc := dparval.NewValue(map[string]interface{}{ "name": "mike", "children": []interface{}{ map[string]interface{}{ "name": "bob", }, map[string]interface{}{ "name": "dan", }, }, }) doc.SetAttachment("meta", map[string]interface{}{"id": "1"}) joinerTestData = append(joinerTestData, doc) doc = dparval.NewValue(map[string]interface{}{ "name": "dustin", "children": []interface{}{ map[string]interface{}{ "name": "mary", }, map[string]interface{}{ "name": "jane", }, }, }) doc.SetAttachment("meta", map[string]interface{}{"id": "2"}) joinerTestData = append(joinerTestData, doc) }
func (vi *viewIndex) ValueCount() (int64, query.Error) { indexItemChannel := make(catalog.EntryChannel) indexWarnChannel := make(query.ErrorChannel) indexErrorChannel := make(query.ErrorChannel) go vi.ScanRange(catalog.LookupValue{dparval.NewValue(nil)}, catalog.LookupValue{dparval.NewValue(nil)}, catalog.Both, 0, indexItemChannel, indexWarnChannel, indexErrorChannel) var err query.Error nullCount := int64(0) ok := true for ok { select { case _, ok = <-indexItemChannel: if ok { nullCount += 1 } case _, ok = <-indexWarnChannel: // ignore warnings here case err, ok = <-indexErrorChannel: if err != nil { return 0, err } } } totalCount, err := ViewTotalRows(vi.bucket.cbbucket, vi.DDocName(), vi.ViewName(), map[string]interface{}{}) if err != nil { return 0, err } return totalCount - nullCount, nil }
func (this *FunctionCallLength) Evaluate(item *dparval.Value) (*dparval.Value, error) { // first evaluate the argument av, err := this.Operands[0].Expr.Evaluate(item) // the spec does not define it to operate on missing, so return null if err != nil { switch err := err.(type) { case *dparval.Undefined: // undefined returns null return dparval.NewValue(nil), nil default: // any other error return to caller return nil, err } } // return the length only if the operand is a string if av.Type() == dparval.STRING { avalue := av.Value() switch avalue := avalue.(type) { case string: return dparval.NewValue(float64(len(avalue))), nil } } return dparval.NewValue(nil), nil }
func (this *FunctionCallStrToMillis) Evaluate(item *dparval.Value) (*dparval.Value, error) { av, err := this.Operands[0].Expr.Evaluate(item) if err != nil { switch err := err.(type) { case *dparval.Undefined: // undefined returns null return dparval.NewValue(nil), nil default: // any other error return to caller return nil, err } } val := av.Value() switch val := val.(type) { case string: t, err := strToTime(val) if err != nil { return nil, fmt.Errorf("Date not in a recognized format.") } return dparval.NewValue(timeToMillis(t)), nil default: return dparval.NewValue(nil), nil } }
func (this *FunctionCallMin) UpdateAggregate(group *dparval.Value, item *dparval.Value) error { aggregate_key := this.Key() currentVal, err := aggregateValue(group, aggregate_key) if err != nil { return fmt.Errorf("group defaults not set correctly") } if this.Operands[0].Expr != nil { val, err := this.Operands[0].Expr.Evaluate(item) val, err = eliminateNullMissing(val, err) if err != nil { return err } if val != nil { nextVal := val.Value() currVal := currentVal.Value() if currVal == nil { // any value is greater than nil (we eliminated null/mising already) setAggregateValue(group, aggregate_key, dparval.NewValue(nextVal)) } else { // check to see comp := CollateJSON(nextVal, currVal) if comp < 0 { setAggregateValue(group, aggregate_key, dparval.NewValue(nextVal)) } } } } return nil }
func (this *CollectionAnyOperator) Evaluate(item *dparval.Value) (*dparval.Value, error) { // first evaluate the over ov, err := this.Over.Evaluate(item) if err != nil { switch err := err.(type) { case *dparval.Undefined: // spec says return false return dparval.NewValue(false), nil default: // any other error should be returned to caller return nil, err } } // see if we're dealing with an array if ov.Type() == dparval.ARRAY { // by accessing the array contents this way // we avoid parsing it ok := true index := 0 for ok { inner, err := ov.Index(index) index = index + 1 if err != nil { switch err := err.(type) { case *dparval.Undefined: ok = false default: return nil, err } } else { // duplicate the existing context innerContext := item.Duplicate() // add this object named as the alias innerContext.SetPath(this.As, inner) // now evaluate the condition in this new context innerResult, err := this.Condition.Evaluate(innerContext) if err != nil { switch err := err.(type) { case *dparval.Undefined: // this is not true, keep trying continue default: // any other error should be returned to caller return nil, err } } innerResultVal := innerResult.Value() // check to see if this value is true innerBoolResult := ValueInBooleanContext(innerResultVal) if innerBoolResult == true { return dparval.NewValue(true), nil } } } return dparval.NewValue(false), nil } return dparval.NewValue(false), nil }
func (this *FunctionCallAvg) UpdateAggregate(group *dparval.Value, item *dparval.Value) error { aggregate_key := this.Key() // avg needs to track sum and count to produce its value count_key := aggregate_key + "_count" sum_key := aggregate_key + "_sum" _, err := aggregateValue(group, aggregate_key) if err != nil { return fmt.Errorf("group defaults not set correctly") } currentCount, err := aggregateValue(group, count_key) if err != nil { return fmt.Errorf("group defaults not set correctly") } currentSum, err := aggregateValue(group, sum_key) if err != nil { return fmt.Errorf("group defaults not set correctly") } if this.Operands[0].Expr != nil { val, err := this.Operands[0].Expr.Evaluate(item) val, err = eliminateNonNumber(val, err) if err != nil { return err } if val != nil { nextVal := val.Value() nextValFloat := nextVal.(float64) if currentCount.Type() == dparval.NUMBER { currentCountVal := currentCount.Value() currentCountFloat, ok := currentCountVal.(float64) if !ok { return fmt.Errorf("count value not a number") } if currentSum.Type() == dparval.NUMBER { currentSumVal := currentSum.Value() currentSumFloat, ok := currentSumVal.(float64) if !ok { return fmt.Errorf("sum value not a number") } nextCountFloat := currentCountFloat + 1 nextSumFloat := currentSumFloat + nextValFloat nextVal := nextSumFloat / nextCountFloat setAggregateValue(group, count_key, dparval.NewValue(nextCountFloat)) setAggregateValue(group, sum_key, dparval.NewValue(nextSumFloat)) setAggregateValue(group, aggregate_key, dparval.NewValue(nextVal)) } } } } return nil }
func (this *FunctionCallMax) DefaultAggregate(group *dparval.Value) error { aggregate_key := this.Key() currentVal, err := aggregateValue(group, aggregate_key) if err != nil { currentVal = dparval.NewValue(nil) // store this, so that even if all values are eliminated we return null setAggregateValue(group, aggregate_key, dparval.NewValue(currentVal)) } return nil }
func (this *FunctionCallTrunc) Evaluate(item *dparval.Value) (*dparval.Value, error) { // first evaluate the argument av, err := this.Operands[0].Expr.Evaluate(item) if err != nil { switch err := err.(type) { case *dparval.Undefined: // undefined returns null return dparval.NewValue(nil), nil default: // any other error return to caller return nil, err } } precision := 0 if len(this.Operands) > 1 { // evaluate the second argument pv, err := this.Operands[1].Expr.Evaluate(item) // we need precision to be an integer if err != nil { switch err := err.(type) { case *dparval.Undefined: // undefined returns null return dparval.NewValue(nil), nil default: // any other error return to caller return nil, err } } if pv.Type() == dparval.NUMBER { pvalue := pv.Value() switch pvalue := pvalue.(type) { case float64: precision = int(pvalue) } } else { // FIXME log warning here? return dparval.NewValue(nil), nil } } // the spec defines this functin to ONLY operate on numeric values // all other types result in NULL if av.Type() == dparval.NUMBER { avalue := av.Value() switch avalue := avalue.(type) { case float64: return dparval.NewValue(TruncateFloat(avalue, precision)), nil } } return dparval.NewValue(nil), nil }
func (this *FunctionCallSplit) Evaluate(item *dparval.Value) (*dparval.Value, error) { // first evaluate the arguments av, err := this.Operands[0].Expr.Evaluate(item) if err != nil { switch err := err.(type) { case *dparval.Undefined: // undefined returns null return dparval.NewValue(nil), nil default: // any other error return to caller return nil, err } // FIXME warn if arguments were wrong type? if av.Type() != dparval.STRING { return dparval.NewValue(nil), nil } } var sep *dparval.Value = nil if len(this.Operands) > 1 { sep, err = this.Operands[1].Expr.Evaluate(item) if err != nil { switch err := err.(type) { case *dparval.Undefined: // undefined returns null return dparval.NewValue(nil), nil default: // any other error return to caller return nil, err } } // FIXME warn if arguments were wrong type? if sep.Type() != dparval.STRING { return dparval.NewValue(nil), nil } } var sa []string if sep != nil { sa = strings.Split(av.Value().(string), sep.Value().(string)) } else { sa = strings.Fields(av.Value().(string)) } rv := make([]interface{}, len(sa)) for i, s := range sa { rv[i] = s } return dparval.NewValue(rv), nil }
func (this *FunctionCallNowMillis) Evaluate(item *dparval.Value) (*dparval.Value, error) { // first retrieve the query object q := item.GetAttachment("query") query, ok := q.(network.Query) if !ok { return dparval.NewValue(nil), nil } return dparval.NewValue(timeToMillis(query.StartTime())), nil }
func (this *InOperator) Evaluate(context *dparval.Value) (*dparval.Value, error) { false_result := dparval.NewValue(false) true_result := dparval.NewValue(true) lv, err := this.Left.Evaluate(context) if err != nil { return nil, err } rv, err := this.Right.Evaluate(context) if err != nil { return nil, err } lvalue := lv.Value() if rv.Type() == dparval.ARRAY { ok := true index := 0 for ok { inner, err := rv.Index(index) index = index + 1 if err != nil { switch err := err.(type) { case *dparval.Undefined: ok = false default: return nil, err } } else { if lv.Type() != inner.Type() { continue } else { iv := inner.Value() switch lvalue := lvalue.(type) { case string: if lvalue == iv { return true_result, nil } default: if reflect.DeepEqual(lvalue, iv) == true { return true_result, nil } } } } } } return false_result, nil }
// sum and avg have same elimination rules, test them together func TestSumAndAvg(t *testing.T) { dataset := dparval.ValueCollection{ dparval.NewValue(map[string]interface{}{ "name": "marty", "score": 20.0, }), dparval.NewValue(map[string]interface{}{ "name": "gerald", "score": nil, }), dparval.NewValue(map[string]interface{}{ "name": "steve", }), dparval.NewValue(map[string]interface{}{ "name": "siri", "score": "thirty", }), dparval.NewValue(map[string]interface{}{ "name": "deep", "score": 10.0, }), dparval.NewValue(map[string]interface{}{ "name": "ketaki", "score": "false", }), dparval.NewValue(map[string]interface{}{ "name": "pratap", "score": []interface{}{5.5}, }), dparval.NewValue(map[string]interface{}{ "name": "karen", "score": map[string]interface{}{"score": 5.5}, }), } tests := AggregateTestSet{ // test expression (eliminiates null and missing) { NewFunctionCall("SUM", FunctionArgExpressionList{NewFunctionArgExpression(NewProperty("score"))}), dparval.NewValue(30.0), }, { NewFunctionCall("AVG", FunctionArgExpressionList{NewFunctionArgExpression(NewProperty("score"))}), dparval.NewValue(15.0), }, } tests.Run(t, dataset) }
func init() { doc := dparval.NewValue(map[string]interface{}{"name": "mike", "age": 100.0}) doc.SetAttachment("meta", map[string]interface{}{"id": "1"}) testData = append(testData, doc) doc = dparval.NewValue(map[string]interface{}{"name": "dustin"}) doc.SetAttachment("meta", map[string]interface{}{"id": "1"}) testData = append(testData, doc) doc = dparval.NewValue(map[string]interface{}{"name": "bob", "age": nil}) doc.SetAttachment("meta", map[string]interface{}{"id": "1"}) testData = append(testData, doc) doc = dparval.NewValue(map[string]interface{}{"name": "marty", "age": 99.0}) doc.SetAttachment("meta", map[string]interface{}{"id": "1"}) testData = append(testData, doc) doc = dparval.NewValue(map[string]interface{}{"name": "steve", "age": 200.0}) doc.SetAttachment("meta", map[string]interface{}{"id": "2"}) testData = append(testData, doc) doc = dparval.NewValue(map[string]interface{}{"name": "gerald", "age": 175.0}) doc.SetAttachment("meta", map[string]interface{}{"id": "3"}) testData = append(testData, doc) doc = dparval.NewValue(map[string]interface{}{"name": "siri", "age": 74.0}) doc.SetAttachment("meta", map[string]interface{}{"id": "4"}) testData = append(testData, doc) doc = dparval.NewValue(map[string]interface{}{"name": "ali", "age": 100.0}) doc.SetAttachment("meta", map[string]interface{}{"id": "1"}) testData = append(testData, doc) }
func (this *FunctionCallTypeName) Evaluate(item *dparval.Value) (*dparval.Value, error) { // first evaluate the argument av, err := this.Operands[0].Expr.Evaluate(item) if err != nil { switch err := err.(type) { case *dparval.Undefined: // undefined returns "missing" return dparval.NewValue("missing"), nil default: // any other error return to caller return nil, err } } switch av.Type() { case dparval.NUMBER: return dparval.NewValue("number"), nil case dparval.STRING: return dparval.NewValue("string"), nil case dparval.BOOLEAN: return dparval.NewValue("boolean"), nil case dparval.ARRAY: return dparval.NewValue("array"), nil case dparval.OBJECT: return dparval.NewValue("object"), nil case dparval.NULL: return dparval.NewValue("null"), nil default: return dparval.NewValue(nil), nil } }
func (this *FunctionCallDatePartMillis) Evaluate(item *dparval.Value) (*dparval.Value, error) { // first evaluate the argument (part) av, err := this.Operands[0].Expr.Evaluate(item) // the part must be a string, undefined results in ull if err != nil { switch err := err.(type) { case *dparval.Undefined: // undefined returns null return dparval.NewValue(nil), nil default: // any other error return to caller return nil, err } } if av.Type() == dparval.STRING { part := av.Value() switch part := part.(type) { case string: // now look at the second argument dv, err := this.Operands[1].Expr.Evaluate(item) // the part must be a string, undefined results in null if err != nil { switch err := err.(type) { case *dparval.Undefined: // undefined returns null return dparval.NewValue(nil), nil default: // any other error return to caller return nil, err } } if dv.Type() == dparval.NUMBER { millis := dv.Value() switch millis := millis.(type) { case float64: t := time.Unix(0, int64(millis)*1000000) return datePart(part, t) } } } } return dparval.NewValue(nil), nil }
func (this *FunctionCallArrayAgg) DefaultAggregate(group *dparval.Value) error { aggregate_key := this.Key() if this.Distinct { aggregate_unique_key := aggregate_key + "_unique" uniqueness_map := dparval.NewValue(map[string]interface{}{}) setAggregateValue(group, aggregate_unique_key, uniqueness_map) } currentVal, err := aggregateValue(group, aggregate_key) if err != nil { currentVal = dparval.NewValue([]interface{}{}) // store this, so that even if all values are eliminated we return null setAggregateValue(group, aggregate_key, dparval.NewValue(currentVal)) } return nil }
func (this *FunctionCallLTrim) Evaluate(item *dparval.Value) (*dparval.Value, error) { // first evaluate the argument av, err := this.Operands[0].Expr.Evaluate(item) // the spec defines this functin to ONLY operate on strings // all other types result in NULL if err != nil { switch err := err.(type) { case *dparval.Undefined: // undefined returns null return dparval.NewValue(nil), nil default: // any other error return to caller return nil, err } } // evaluate the second argument cutlist, err := this.Operands[1].Expr.Evaluate(item) // the cut list MUST be a string, otherwise return null if err != nil { switch err := err.(type) { case *dparval.Undefined: // undefined returns null return dparval.NewValue(nil), nil default: // any other error return to caller return nil, err } } if av.Type() == dparval.STRING { if cutlist.Type() == dparval.STRING { avalue := av.Value() switch avalue := avalue.(type) { case string: cutvlal := cutlist.Value() switch cutvlal := cutvlal.(type) { case string: return dparval.NewValue(strings.TrimLeft(avalue, cutvlal)), nil } } } } // FIXME warn if cutlist wasnt string? return dparval.NewValue(nil), nil }
func (this *FunctionCallGreatest) Evaluate(item *dparval.Value) (*dparval.Value, error) { var rv interface{} = nil for _, arg := range this.Operands { av, err := arg.Expr.Evaluate(item) if err != nil { switch err := err.(type) { case *dparval.Undefined: // undefined doesn't change the result default: // any other error return to caller return nil, err } } avalue := av.Value() // now compare this value with rv compres := CollateJSON(avalue, rv) if compres > 0 { rv = avalue } } return dparval.NewValue(rv), nil }
func (this *FunctionCallSum) UpdateAggregate(group *dparval.Value, item *dparval.Value) error { aggregate_key := this.Key() currentVal, err := aggregateValue(group, aggregate_key) if err != nil { return fmt.Errorf("group defaults not set correctly") } if this.Operands[0].Expr != nil { val, err := this.Operands[0].Expr.Evaluate(item) val, err = eliminateNonNumber(val, err) if err != nil { return err } if val != nil { nextVal := val.Value() if currentVal.Type() == dparval.NUMBER { currentValVal := currentVal.Value() currentFloat, ok := currentValVal.(float64) if !ok { return fmt.Errorf("count value not a number") } nextVal = nextVal.(float64) + currentFloat } setAggregateValue(group, aggregate_key, dparval.NewValue(nextVal)) } } return nil }
func (this *FunctionCallFirstNum) Evaluate(item *dparval.Value) (*dparval.Value, error) { for _, arg := range this.Operands { av, err := arg.Expr.Evaluate(item) if err != nil { switch err := err.(type) { case *dparval.Undefined: // do NOT return missing continue default: // any other error return to caller return nil, err } } if av.Type() == dparval.NUMBER { num := av.Value().(float64) if !math.IsNaN(num) && !math.IsInf(num, 1) && !math.IsInf(num, -1) { return av, nil } else { continue } } else { continue } } // if all values were +/-Infinity or NaN return NULL return dparval.NewValue(nil), nil }
func (this *BinaryOperator) compare(context *dparval.Value) (*dparval.Value, error) { lv, rv, err := this.EvaluateBoth(context) if err != nil { return nil, err } // if either side is NULL, the result is NULL if lv.Type() == dparval.NULL || rv.Type() == dparval.NULL { return nil, nil } lvalue := lv.Value() rvalue := rv.Value() // if we got this far, we evaluated both sides // there were no errors, and neither side was NULL or MISSING // now check types (types must be the same) ltype := collationType(lvalue) rtype := collationType(rvalue) // ugly fixups for boolean (returns different values for true/false) if ltype == 2 { // fixup for boolean type ltype = 1 } if rtype == 2 { rtype = 1 } if ltype != rtype { return nil, &TypeMismatch{ltype, rtype} } return dparval.NewValue(float64(CollateJSON(lvalue, rvalue))), nil }
func (this *Grouper) processItem(item *dparval.Value) bool { groupkey := dparval.NewValue(make([]interface{}, len(this.GroupBy))) for i, groupElement := range this.GroupBy { groupkeyval, err := this.Base.Evaluate(groupElement, item) if err == nil { groupkey.SetIndex(i, groupkeyval) } else { switch err := err.(type) { case *dparval.Undefined: // FIXME better way? groupkey.SetIndex(i, "__tuqtng__MISSING__") default: return this.Base.SendError(query.NewError(err, "error evaluating group by")) } } } // FIXME slow, but lets me use map to match same groups groupkeybytes := groupkey.Bytes() groupkeystring := string(groupkeybytes) group, ok := this.groups[groupkeystring] if !ok { // new group this.groups[groupkeystring] = item group = item this.setGroupDefaults(group) } this.updateGroup(group, item) return true }
// CompositeKeysToArray convert list of composite keys to JSON array of // values. func CompositeKeysToArray(keys []*dparval.Value) []byte { secKey := dparval.NewValue(make([]interface{}, len(keys))) for i, key := range keys { secKey.SetIndex(i, key) } return secKey.Bytes() }
// N1QLTransform will use compile list of expression from N1QL's DDL // statement and evaluate a document using them to return a secondary // key as JSON object. func N1QLTransform(document []byte, cExprs []interface{}) ([]byte, error) { arrValue := make([]*dparval.Value, 0, len(cExprs)) for _, cExpr := range cExprs { expr := cExpr.(ast.Expression) // TODO: CBIDXT-133: needs to send nil secondary keys to indexer key, err := expr.Evaluate(dparval.NewValueFromBytes(document)) if err != nil { return nil, nil } arrValue = append(arrValue, key) } if len(arrValue) > 1 { secKey := dparval.NewValue(make([]interface{}, len(cExprs))) for i, key := range arrValue { secKey.SetIndex(i, key) } return secKey.Bytes(), nil // [ seckey1, seckey2, ... ] } else if len(arrValue) == 1 { return arrValue[0].Bytes(), nil // seckey1 } return nil, ErrorEmptyN1QLExpression }
func TestDotMember(t *testing.T) { sampleContext := map[string]interface{}{ "address": map[string]interface{}{ "street": "1 recursive function", }, "contact": map[string]interface{}{ "name": map[string]interface{}{ "first": "n1ql", "last": "couchbase", "all": []interface{}{ "n1ql", "couchbase", }, }, }, "friends": []interface{}{ "a", "b", "c", }, "name": "bob", } sampleMeta := map[string]interface{}{ "id": "first", } tests := ExpressionTestSet{ {NewDotMemberOperator(NewProperty("address"), NewProperty("street")), "1 recursive function", nil}, {NewDotMemberOperator(NewDotMemberOperator(NewProperty("contact"), NewProperty("name")), NewProperty("first")), "n1ql", nil}, {NewDotMemberOperator(NewDotMemberOperator(NewProperty("contact"), NewProperty("name")), NewProperty("last")), "couchbase", nil}, {NewDotMemberOperator(NewProperty("address"), NewProperty("city")), nil, &dparval.Undefined{"city"}}, {NewDotMemberOperator(NewDotMemberOperator(NewProperty("contact"), NewProperty("name")), NewProperty("middle")), nil, &dparval.Undefined{"middle"}}, {NewDotMemberOperator(NewDotMemberOperator(NewProperty("contact"), NewProperty("namez")), NewProperty("first")), nil, &dparval.Undefined{"namez"}}, {NewDotMemberOperator(NewProperty("name"), NewProperty("city")), nil, &dparval.Undefined{"city"}}, {NewBracketMemberOperator(NewProperty("friends"), NewLiteralNumber(0.0)), "a", nil}, {NewBracketMemberOperator(NewProperty("friends"), NewLiteralNumber(1.0)), "b", nil}, {NewBracketMemberOperator(NewProperty("friends"), NewLiteralNumber(2.0)), "c", nil}, {NewBracketMemberOperator(NewProperty("friends"), NewLiteralNumber(-1.0)), nil, &dparval.Undefined{}}, {NewBracketMemberOperator(NewProperty("friends"), NewLiteralNumber(10.0)), nil, &dparval.Undefined{}}, {NewBracketMemberOperator(NewProperty("foo"), NewLiteralNumber(10.0)), nil, &dparval.Undefined{"foo"}}, {NewBracketMemberOperator(NewProperty("friends"), NewProperty("bar")), nil, &dparval.Undefined{"bar"}}, //compound test {NewBracketMemberOperator(NewDotMemberOperator(NewDotMemberOperator(NewProperty("contact"), NewProperty("name")), NewProperty("all")), NewLiteralNumber(0.0)), "n1ql", nil}, // test using bracket member on object instead of array {NewBracketMemberOperator(NewProperty("address"), NewLiteralString("street")), "1 recursive function", nil}, } context := dparval.NewValue(sampleContext) context.SetAttachment("meta", sampleMeta) tests.RunWithItem(t, context) }