func (this *ValueScan) RunOnce(context *Context, parent value.Value) { this.once.Do(func() { defer context.Recover() // Recover from any panic defer close(this.itemChannel) // Broadcast that I have stopped defer this.notify() // Notify that I have stopped pairs := this.plan.Values() for _, pair := range pairs { key, err := pair.Key.Evaluate(parent, context) if err != nil { context.Error(errors.NewEvaluationError(err, "VALUES")) return } val, err := pair.Value.Evaluate(parent, context) if err != nil { context.Error(errors.NewEvaluationError(err, "VALUES")) return } av := value.NewAnnotatedValue(nil) av.SetAttachment("key", key) av.SetAttachment("value", val) if !this.sendItem(av) { return } } }) }
func (this *Order) Less(i, j int) bool { v1 := this.values[i] v2 := this.values[j] var ev1, ev2 value.Value var c int var e error for i, term := range this.plan.Terms() { s := this.terms[i] sv1 := v1.GetAttachment(s) switch sv1 := sv1.(type) { case value.Value: ev1 = sv1 default: ev1, e = term.Expression().Evaluate(v1, this.context) if e != nil { this.context.Error(errors.NewEvaluationError(e, "ORDER BY")) return false } v1.SetAttachment(s, ev1) } sv2 := v2.GetAttachment(s) switch sv2 := sv2.(type) { case value.Value: ev2 = sv2 default: ev2, e = term.Expression().Evaluate(v2, this.context) if e != nil { this.context.Error(errors.NewEvaluationError(e, "ORDER BY")) return false } v2.SetAttachment(s, ev2) } c = ev1.Collate(ev2) if c == 0 { continue } else if term.Descending() { return c > 0 } else { return c < 0 } } return false }
func (this *KeyScan) RunOnce(context *Context, parent value.Value) { this.once.Do(func() { defer context.Recover() // Recover from any panic defer close(this.itemChannel) // Broadcast that I have stopped defer this.notify() // Notify that I have stopped keys, e := this.plan.Keys().Evaluate(parent, context) if e != nil { context.Error(errors.NewEvaluationError(e, "KEYS")) return } actuals := keys.Actual() switch actuals.(type) { case []interface{}: case nil: actuals = []interface{}(nil) default: actuals = []interface{}{actuals} } acts := actuals.([]interface{}) for _, key := range acts { cv := value.NewScopeValue(make(map[string]interface{}), parent) av := value.NewAnnotatedValue(cv) av.SetAttachment("meta", map[string]interface{}{"id": key}) if !this.sendItem(av) { return } } }) }
func (this *InitialProject) processTerms(item value.AnnotatedValue, context *Context) bool { n := len(this.plan.Terms()) sv := value.NewScopeValue(make(map[string]interface{}, n), item) pv := value.NewAnnotatedValue(sv) pv.SetAnnotations(item) p := value.NewValue(make(map[string]interface{}, n+32)) pv.SetAttachment("projection", p) for _, term := range this.plan.Terms() { if term.Result().Alias() != "" { v, err := term.Result().Expression().Evaluate(item, context) if err != nil { context.Error(errors.NewEvaluationError(err, "projection")) return false } p.SetField(term.Result().Alias(), v) // Explicit aliases override data if term.Result().As() != "" { pv.SetField(term.Result().As(), v) } } else { // Star starval := item.GetValue() if term.Result().Expression() != nil { var err error starval, err = term.Result().Expression().Evaluate(item, context) if err != nil { context.Error(errors.NewEvaluationError(err, "projection")) return false } } // Latest star overwrites previous star switch sa := starval.Actual().(type) { case map[string]interface{}: for k, v := range sa { p.SetField(k, v) } } } } return this.sendItem(pv) }
func (this *IndexNest) fetch(entries []*datastore.IndexEntry, context *Context) ( []interface{}, bool) { // Build list of keys var keys []string if len(entries) <= 16 { keys = _NEST_INDEX_STRING_POOL.Get() defer _NEST_INDEX_STRING_POOL.Put(keys) } else { keys = make([]string, 0, len(entries)) } for _, e := range entries { keys = append(keys, e.PrimaryKey) } // Fetch pairs, errs := this.plan.Keyspace().Fetch(keys) fetchOk := true for _, err := range errs { context.Error(err) if err.IsFatal() { fetchOk = false } } if len(pairs) == 0 { return nil, fetchOk } projection := this.plan.Term().Projection() nvs := make([]interface{}, 0, len(pairs)) for _, pair := range pairs { nestItem := pair.Value var nv value.AnnotatedValue // Apply projection, if any if projection != nil { projectedItem, e := projection.Evaluate(nestItem, context) if e != nil { context.Error(errors.NewEvaluationError(e, "nest path")) return nil, false } if projectedItem.Type() == value.MISSING { continue } nv = value.NewAnnotatedValue(projectedItem) nv.SetAnnotations(nestItem) } else { nv = nestItem } nvs = append(nvs, nv) } return nvs, fetchOk }
func (this *Cover) Evaluate(item value.Value, context Context) (value.Value, error) { var rv value.Value switch item := item.(type) { case value.AnnotatedValue: rv = item.GetCover(this.text) } if rv == nil { return value.MISSING_VALUE, errors.NewEvaluationError(nil, "cover("+this.text+")") } return rv, nil }
func (this *Filter) processItem(item value.AnnotatedValue, context *Context) bool { val, e := this.plan.Condition().Evaluate(item, context) if e != nil { context.Error(errors.NewEvaluationError(e, "filter")) return false } if val.Truth() { return this.sendItem(item) } else { return true } }
func (this *Merge) processMatch(item value.AnnotatedValue, context *Context, update, delete, insert Operator) bool { kv, e := this.plan.Key().Evaluate(item, context) if e != nil { context.Error(errors.NewEvaluationError(e, "MERGE key")) return false } ka := kv.Actual() k, ok := ka.(string) if !ok { context.Error(errors.NewInvalidValueError( fmt.Sprintf("Invalid MERGE key %v of type %T.", ka, ka))) return false } timer := time.Now() fetchOk := true bvs, errs := this.plan.Keyspace().Fetch([]string{k}) this.duration += time.Since(timer) for _, err := range errs { context.Error(err) if err.IsFatal() { fetchOk = false } } if len(bvs) > 0 { bv := bvs[0] item.SetField(this.plan.KeyspaceRef().Alias(), bv.Value) // Perform UPDATE and/or DELETE if update != nil { update.Input().ItemChannel() <- item } if delete != nil { delete.Input().ItemChannel() <- item } } else { // Not matched; INSERT if insert != nil { insert.Input().ItemChannel() <- item } } return fetchOk }
func (this *IntermediateGroup) processItem(item value.AnnotatedValue, context *Context) bool { // Generate the group key var gk string if len(this.plan.Keys()) > 0 { var e error gk, e = groupKey(item, this.plan.Keys(), context) if e != nil { context.Fatal(errors.NewEvaluationError(e, "GROUP key")) return false } } // Get or seed the group value gv := this.groups[gk] if gv == nil { gv = item this.groups[gk] = gv return true } // Cumulate aggregates part, ok := item.GetAttachment("aggregates").(map[string]value.Value) if !ok { context.Fatal(errors.NewInvalidValueError( fmt.Sprintf("Invalid partial aggregates %v of type %T", part, part))) return false } cumulative := gv.GetAttachment("aggregates").(map[string]value.Value) if !ok { context.Fatal(errors.NewInvalidValueError( fmt.Sprintf("Invalid cumulative aggregates %v of type %T", cumulative, cumulative))) return false } for _, agg := range this.plan.Aggregates() { a := agg.String() v, e := agg.CumulateIntermediate(part[a], cumulative[a], context) if e != nil { context.Fatal(errors.NewGroupUpdateError( e, "Error updating intermediate GROUP value.")) return false } cumulative[a] = v } return true }
func (this *IndexJoin) processItem(item value.AnnotatedValue, context *Context) bool { idv, e := this.plan.IdExpr().Evaluate(item, context) if e != nil { context.Error(errors.NewEvaluationError(e, fmt.Sprintf("JOIN FOR %s", this.plan.For()))) return false } found, foundOne := false, false if idv.Type() == value.STRING { var wg sync.WaitGroup defer wg.Wait() id := idv.Actual().(string) conn := datastore.NewIndexConnection(context) defer notifyConn(conn.StopChannel()) // Notify index that I have stopped wg.Add(1) go this.scan(id, context, conn, &wg) var entry *datastore.IndexEntry ok := true for ok { select { case <-this.stopChannel: return false default: } select { case entry, ok = <-conn.EntryChannel(): t := time.Now() if ok { foundOne, ok = this.joinEntry(item, entry, context) found = found || foundOne } this.duration += time.Since(t) case <-this.stopChannel: return false } } } return found || !this.plan.Outer() || this.sendItem(item) }
func (this *InitialProject) processItem(item value.AnnotatedValue, context *Context) bool { terms := this.plan.Terms() n := len(terms) if n > 1 { return this.processTerms(item, context) } if n == 0 { return this.sendItem(item) } // n == 1 result := terms[0].Result() expr := result.Expression() if result.Star() && (expr == expression.SELF || expr == nil) { // Unprefixed star if item.Type() == value.OBJECT { return this.sendItem(item) } else { return this.sendItem(_EMPTY_ANNOTATED_VALUE) } } else if this.plan.Projection().Raw() { // Raw projection of an expression v, err := expr.Evaluate(item, context) if err != nil { context.Error(errors.NewEvaluationError(err, "projection")) return false } if result.As() == "" { return this.sendItem(value.NewAnnotatedValue(v)) } sv := value.NewScopeValue(make(map[string]interface{}, 1), item) sv.SetField(result.As(), v) av := value.NewAnnotatedValue(sv) av.SetAttachment("projection", v) return this.sendItem(av) } else { // Any other projection return this.processTerms(item, context) } }
func eval(cx expression.Expressions, context *Context, parent value.Value) (value.Values, bool) { if cx == nil { return nil, true } cv := make(value.Values, len(cx)) var e error for i, expr := range cx { cv[i], e = expr.Evaluate(parent, context) if e != nil { context.Error(errors.NewEvaluationError(e, "filter term")) return nil, false } } return cv, true }
func (this *InitialGroup) processItem(item value.AnnotatedValue, context *Context) bool { // Generate the group key var gk string if len(this.plan.Keys()) > 0 { var e error gk, e = groupKey(item, this.plan.Keys(), context) if e != nil { context.Fatal(errors.NewEvaluationError(e, "GROUP key")) return false } } // Get or seed the group value gv := this.groups[gk] if gv == nil { gv = item this.groups[gk] = gv aggregates := make(map[string]value.Value, len(this.plan.Aggregates())) gv.SetAttachment("aggregates", aggregates) for _, agg := range this.plan.Aggregates() { aggregates[agg.String()] = agg.Default() } } // Cumulate aggregates aggregates, ok := gv.GetAttachment("aggregates").(map[string]value.Value) if !ok { context.Fatal(errors.NewInvalidValueError( fmt.Sprintf("Invalid aggregates %v of type %T", aggregates, aggregates))) return false } for _, agg := range this.plan.Aggregates() { v, e := agg.CumulateInitial(item, aggregates[agg.String()], context) if e != nil { context.Fatal(errors.NewGroupUpdateError(e, "Error updating initial GROUP value.")) return false } aggregates[agg.String()] = v } return true }
func (this *Let) processItem(item value.AnnotatedValue, context *Context) bool { n := len(this.plan.Bindings()) cv := value.NewScopeValue(make(map[string]interface{}, n), item) lv := value.NewAnnotatedValue(cv) lv.SetAnnotations(item) for _, b := range this.plan.Bindings() { v, e := b.Expression().Evaluate(item, context) if e != nil { context.Error(errors.NewEvaluationError(e, "LET")) return false } lv.SetField(b.Variable(), v) } return this.sendItem(lv) }
func (this *FinalGroup) processItem(item value.AnnotatedValue, context *Context) bool { // Generate the group key var gk string if len(this.plan.Keys()) > 0 { var e error gk, e = groupKey(item, this.plan.Keys(), context) if e != nil { context.Fatal(errors.NewEvaluationError(e, "GROUP key")) return false } } // Get or seed the group value gv := this.groups[gk] if gv != nil { context.Fatal(errors.NewDuplicateFinalGroupError()) return false } gv = item this.groups[gk] = gv // Compute final aggregates aggregates := gv.GetAttachment("aggregates") switch aggregates := aggregates.(type) { case map[string]value.Value: for _, agg := range this.plan.Aggregates() { v, e := agg.ComputeFinal(aggregates[agg.String()], context) if e != nil { context.Fatal(errors.NewGroupUpdateError( e, "Error updating final GROUP value.")) return false } aggregates[agg.String()] = v } return true default: context.Fatal(errors.NewInvalidValueError(fmt.Sprintf( "Invalid or missing aggregates of type %T.", aggregates))) return false } }
func (this *IndexNest) processItem(item value.AnnotatedValue, context *Context) bool { idv, e := this.plan.IdExpr().Evaluate(item, context) if e != nil { context.Error(errors.NewEvaluationError(e, fmt.Sprintf("NEST FOR %s", this.plan.For()))) return false } var entry *datastore.IndexEntry entries := _INDEX_ENTRY_POOL.Get() defer _INDEX_ENTRY_POOL.Put(entries) if idv.Type() == value.STRING { var wg sync.WaitGroup defer wg.Wait() id := idv.Actual().(string) conn := datastore.NewIndexConnection(context) defer notifyConn(conn) // Notify index that I have stopped wg.Add(1) go this.scan(id, context, conn, &wg) ok := true for ok { select { case <-this.stopChannel: return false default: } select { case entry, ok = <-conn.EntryChannel(): if ok { entries = append(entries, entry) } case <-this.stopChannel: return false } } } return this.nestEntries(item, entries, context) }
func (this *Unnest) processItem(item value.AnnotatedValue, context *Context) bool { ev, err := this.plan.Term().Expression().Evaluate(item, context) if err != nil { context.Error(errors.NewEvaluationError(err, "UNNEST path")) return false } actuals := ev.Actual() switch actuals.(type) { case []interface{}: case nil: actuals = []interface{}(nil) default: actuals = []interface{}{actuals} } acts := actuals.([]interface{}) if len(acts) == 0 { // Outer unnest return !this.plan.Term().Outer() || this.sendItem(item) } // Attach and send for i, act := range acts { var av value.AnnotatedValue if i < len(acts)-1 { av = value.NewAnnotatedValue(item.Copy()) } else { av = item } actv := value.NewAnnotatedValue(act) actv.SetAttachment("unnest_position", i) av.SetField(this.plan.Alias(), actv) if !this.sendItem(av) { return false } } return true }
func (this *Limit) beforeItems(context *Context, parent value.Value) bool { val, e := this.plan.Expression().Evaluate(parent, context) if e != nil { context.Error(errors.NewEvaluationError(e, "LIMIT")) return false } actual := val.Actual() switch actual := actual.(type) { case float64: if math.Trunc(actual) == actual { this.limit = int64(actual) return true } } context.Error(errors.NewInvalidValueError( fmt.Sprintf("Invalid LIMIT value %v.", actual))) return false }
func (this *spanScan) scan(context *Context, conn *datastore.IndexConnection) { defer context.Recover() // Recover from any panic dspan, err := evalSpan(this.span, context) if err != nil { context.Error(errors.NewEvaluationError(err, "span")) close(conn.EntryChannel()) return } limit := int64(math.MaxInt64) if this.plan.Limit() != nil { lv, err := this.plan.Limit().Evaluate(nil, context) if err == nil && lv.Type() == value.NUMBER { limit = int64(lv.Actual().(float64)) } } this.plan.Index().Scan(context.RequestId(), dspan, this.plan.Distinct(), limit, context.ScanConsistency(), context.ScanVector(), conn) }
func (this *IndexJoin) fetch(entry *datastore.IndexEntry, context *Context) ( value.AnnotatedValue, bool) { // Build list of keys keys := []string{entry.PrimaryKey} // Fetch pairs, errs := this.plan.Keyspace().Fetch(keys) fetchOk := true for _, err := range errs { context.Error(err) if err.IsFatal() { fetchOk = false } } if len(pairs) == 0 { return nil, fetchOk } pair := pairs[0] av := pair.Value // Apply projection, if any projection := this.plan.Term().Projection() if projection != nil { projectedItem, e := projection.Evaluate(av, context) if e != nil { context.Error(errors.NewEvaluationError(e, "join path")) return nil, false } pv := value.NewAnnotatedValue(projectedItem) pv.SetAnnotations(av) av = pv } return av, fetchOk }
func (this *Join) processItem(item value.AnnotatedValue, context *Context) bool { kv, e := this.plan.Term().Keys().Evaluate(item, context) if e != nil { context.Error(errors.NewEvaluationError(e, "JOIN keys")) return false } actuals := kv.Actual() switch actuals.(type) { case []interface{}: case nil: actuals = []interface{}(nil) default: actuals = []interface{}{actuals} } acts := actuals.([]interface{}) if len(acts) == 0 { // Outer join return !this.plan.Outer() || this.sendItem(item) } // Build list of keys keys := make([]string, 0, len(acts)) for _, key := range acts { k := value.NewValue(key).Actual() switch k := k.(type) { case string: keys = append(keys, k) } } timer := time.Now() // Fetch pairs, errs := this.plan.Keyspace().Fetch(keys) this.duration += time.Since(timer) fetchOk := true for _, err := range errs { context.Error(err) if err.IsFatal() { fetchOk = false } } found := len(pairs) > 0 // Attach and send for i, pair := range pairs { joinItem := pair.Value var jv value.AnnotatedValue // Apply projection, if any projection := this.plan.Term().Projection() if projection != nil { projectedItem, e := projection.Evaluate(joinItem, context) if e != nil { context.Error(errors.NewEvaluationError(e, "join path")) return false } jv = value.NewAnnotatedValue(projectedItem) jv.SetAnnotations(joinItem) } else { jv = joinItem } var av value.AnnotatedValue if i < len(pairs)-1 { av = value.NewAnnotatedValue(item.Copy()) } else { av = item } av.SetField(this.plan.Term().Alias(), jv) if !this.sendItem(av) { return false } } return (found || !this.plan.Outer() || this.sendItem(item)) && fetchOk }
func (this *Fetch) flushBatch(context *Context) bool { defer this.releaseBatch() if len(this.batch) == 0 { return true } keys := _STRING_POOL.Get() defer _STRING_POOL.Put(keys) batchMap := _STRING_ANNOTATED_POOL.Get() defer _STRING_ANNOTATED_POOL.Put(batchMap) for _, av := range this.batch { meta := av.GetAttachment("meta") switch meta := meta.(type) { case map[string]interface{}: key := meta["id"] act := value.NewValue(key).Actual() switch act := act.(type) { case string: keys = append(keys, act) batchMap[act] = av default: context.Error(errors.NewInvalidValueError(fmt.Sprintf( "Missing or invalid primary key %v of type %T.", act, act))) return false } default: context.Error(errors.NewInvalidValueError( "Missing or invalid meta for primary key.")) return false } } timer := time.Now() // Fetch pairs, errs := this.plan.Keyspace().Fetch(keys) context.AddPhaseTime("fetch", time.Since(timer)) fetchOk := true for _, err := range errs { context.Error(err) if err.IsFatal() { fetchOk = false } } fetchMap := _STRING_ANNOTATED_POOL.Get() defer _STRING_ANNOTATED_POOL.Put(fetchMap) // Attach meta for _, pair := range pairs { pv, ok := pair.Value.(value.AnnotatedValue) if !ok { context.Fatal(errors.NewInvalidValueError(fmt.Sprintf( "Invalid fetch value %v of type %T", pair.Value))) return false } var fv value.AnnotatedValue // Apply projection, if any projection := this.plan.Term().Projection() if projection != nil { projectedItem, e := projection.Evaluate(pv, context) if e != nil { context.Error(errors.NewEvaluationError(e, "fetch path")) return false } if projectedItem.Type() == value.MISSING { continue } fv = value.NewAnnotatedValue(projectedItem) fv.SetAnnotations(pv) } else { fv = pv } fetchMap[pair.Key] = fv } // Preserve order of keys for _, key := range keys { fv := fetchMap[key] if fv == nil { continue } item := batchMap[key] item.SetField(this.plan.Term().Alias(), fv) if !this.sendItem(item) { return false } } return fetchOk }
func (this *SendUpsert) flushBatch(context *Context) bool { defer this.releaseBatch() if len(this.batch) == 0 { return true } dpairs := _UPSERT_POOL.Get() defer _UPSERT_POOL.Put(dpairs) keyExpr := this.plan.Key() valExpr := this.plan.Value() var key, val value.Value var err error var ok bool i := 0 for _, av := range this.batch { dpairs = dpairs[0 : i+1] dpair := &dpairs[i] if keyExpr != nil { // UPSERT ... SELECT key, err = keyExpr.Evaluate(av, context) if err != nil { context.Error(errors.NewEvaluationError(err, fmt.Sprintf("UPSERT key for %v", av.GetValue()))) continue } if valExpr != nil { val, err = valExpr.Evaluate(av, context) if err != nil { context.Error(errors.NewEvaluationError(err, fmt.Sprintf("UPSERT value for %v", av.GetValue()))) continue } } else { val = av } } else { // UPSERT ... VALUES key, ok = av.GetAttachment("key").(value.Value) if !ok { context.Error(errors.NewUpsertKeyError(av.GetValue())) continue } val, ok = av.GetAttachment("value").(value.Value) if !ok { context.Error(errors.NewUpsertValueError(av.GetValue())) continue } } dpair.Key, ok = key.Actual().(string) if !ok { context.Error(errors.NewUpsertKeyTypeError(key)) continue } dpair.Value = val i++ } dpairs = dpairs[0:i] timer := time.Now() // Perform the actual UPSERT keys, e := this.plan.Keyspace().Upsert(dpairs) context.AddPhaseTime("upsert", time.Since(timer)) // Update mutation count with number of upserted docs context.AddMutationCount(uint64(len(keys))) if e != nil { context.Error(e) } // Capture the upserted keys in case there is a RETURNING clause for i, k := range keys { av := value.NewAnnotatedValue(make(map[string]interface{})) av.SetAttachment("meta", map[string]interface{}{"id": k}) av.SetField(this.plan.Alias(), dpairs[i].Value) if !this.sendItem(av) { return false } } return true }
func (this *Nest) processItem(item value.AnnotatedValue, context *Context) bool { kv, e := this.plan.Term().Keys().Evaluate(item, context) if e != nil { context.Error(errors.NewEvaluationError(e, "NEST keys")) return false } actuals := kv.Actual() switch actuals.(type) { case []interface{}: case nil: actuals = []interface{}(nil) default: actuals = []interface{}{actuals} } acts := actuals.([]interface{}) if len(acts) == 0 { // Outer nest return !this.plan.Outer() || this.sendItem(item) } // Build list of keys keys := make([]string, 0, len(acts)) for _, key := range acts { k := value.NewValue(key).Actual() switch k := k.(type) { case string: keys = append(keys, k) } } timer := time.Now() // Fetch pairs, errs := this.plan.Keyspace().Fetch(keys) this.duration += time.Since(timer) fetchOk := true for _, err := range errs { context.Error(err) if err.IsFatal() { fetchOk = false } } found := len(pairs) > 0 if !found && !this.plan.Outer() { return true } nvs := make([]interface{}, 0, len(pairs)) for _, pair := range pairs { nestItem := pair.Value var nv value.AnnotatedValue // Apply projection, if any projection := this.plan.Term().Projection() if projection != nil { projectedItem, e := projection.Evaluate(nestItem, context) if e != nil { context.Error(errors.NewEvaluationError(e, "nest path")) return false } if projectedItem.Type() == value.MISSING { continue } nv = value.NewAnnotatedValue(projectedItem) nv.SetAnnotations(nestItem) } else { nv = nestItem } nvs = append(nvs, nv) } // Attach and send item.SetField(this.plan.Term().Alias(), nvs) return this.sendItem(item) && fetchOk }