Esempio n. 1
0
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
			}
		}
	})
}
Esempio n. 2
0
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
}
Esempio n. 3
0
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
			}
		}
	})
}
Esempio n. 4
0
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)
}
Esempio n. 5
0
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
}
Esempio n. 6
0
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
}
Esempio n. 7
0
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
	}
}
Esempio n. 8
0
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
}
Esempio n. 9
0
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
}
Esempio n. 10
0
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)
}
Esempio n. 11
0
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)
	}
}
Esempio n. 12
0
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
}
Esempio n. 13
0
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
}
Esempio n. 14
0
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)
}
Esempio n. 15
0
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
	}
}
Esempio n. 16
0
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)
}
Esempio n. 17
0
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
}
Esempio n. 18
0
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
}
Esempio n. 19
0
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)
}
Esempio n. 20
0
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
}
Esempio n. 21
0
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
}
Esempio n. 22
0
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
}
Esempio n. 23
0
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
}
Esempio n. 24
0
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
}