예제 #1
0
파일: from.go 프로젝트: amarantha-k/query
/*
Qualify all identifiers for the parent expression. Checks for
duplicate aliases.
*/
func (this *SubqueryTerm) Formalize(parent *expression.Formalizer) (f *expression.Formalizer, err error) {
	err = this.subquery.Formalize()
	if err != nil {
		return
	}

	alias := this.Alias()
	if alias == "" {
		err = errors.NewError(nil, "FROM term must have a name or alias.")
		return
	}

	_, ok := parent.Allowed.Field(alias)
	if ok {
		err = errors.NewError(nil, fmt.Sprintf("Duplicate subquery alias %s.", alias))
		return nil, err
	}

	allowed := value.NewScopeValue(make(map[string]interface{}), parent.Allowed)
	allowed.SetField(alias, alias)

	f = expression.NewFormalizer()
	f.Keyspace = alias
	f.Allowed = allowed
	return
}
예제 #2
0
파일: from.go 프로젝트: amarantha-k/query
/*
Qualify all identifiers for the parent expression. Checks for
duplicate aliases.
*/
func (this *KeyspaceTerm) Formalize(parent *expression.Formalizer) (f *expression.Formalizer, err error) {
	keyspace := this.Alias()
	if keyspace == "" {
		err = errors.NewError(nil, "FROM term must have a name or alias.")
		return
	}

	if this.keys != nil {
		_, err = this.keys.Accept(parent)
		if err != nil {
			return
		}
	}

	_, ok := parent.Allowed.Field(keyspace)
	if ok {
		err = errors.NewError(nil, fmt.Sprintf("Duplicate subquery alias %s.", keyspace))
		return nil, err
	}

	allowed := value.NewScopeValue(make(map[string]interface{}), parent.Allowed)
	allowed.SetField(keyspace, keyspace)

	f = expression.NewFormalizer()
	f.Keyspace = keyspace
	f.Allowed = allowed
	return
}
예제 #3
0
func (this *IntersectScan) processKey(item value.AnnotatedValue, context *Context) bool {
	m := item.GetAttachment("meta")
	meta, ok := m.(map[string]interface{})
	if !ok {
		context.Error(errors.NewError(nil,
			fmt.Sprintf("Missing or invalid meta %v of type %T.", m, m)))
		return false
	}

	k := meta["id"]
	key, ok := k.(string)
	if !ok {
		context.Error(errors.NewError(nil,
			fmt.Sprintf("Missing or invalid primary key %v of type %T.", k, k)))
		return false
	}

	count := this.counts[key]
	this.counts[key] = count + 1

	if count+1 == len(this.scans) {
		delete(this.values, key)
		return this.sendItem(item)
	}

	if count == 0 {
		this.values[key] = item
	}

	return true
}
예제 #4
0
파일: from.go 프로젝트: amarantha-k/query
/*
Qualify all identifiers for the parent expression. Checks is
a join alias exists and if it is a duplicate alias.
*/
func (this *Join) Formalize(parent *expression.Formalizer) (f *expression.Formalizer, err error) {
	f, err = this.left.Formalize(parent)
	if err != nil {
		return
	}

	f.Keyspace = ""
	this.right.keys, err = f.Map(this.right.keys)
	if err != nil {
		return
	}

	alias := this.Alias()
	if alias == "" {
		err = errors.NewError(nil, "JOIN term must have a name or alias.")
		return nil, err
	}

	_, ok := f.Allowed.Field(alias)
	if ok {
		err = errors.NewError(nil, fmt.Sprintf("Duplicate JOIN alias %s.", alias))
		return nil, err
	}

	f.Allowed.SetField(alias, alias)
	return
}
예제 #5
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.NewError(err, "Error evaluating VALUES."))
				return
			}

			val, err := pair.Value.Evaluate(parent, context)
			if err != nil {
				context.Error(errors.NewError(err, "Error evaluating VALUES."))
				return
			}

			av := value.NewAnnotatedValue(nil)
			av.SetAttachment("key", key)
			av.SetAttachment("value", val)

			if !this.sendItem(av) {
				return
			}
		}
	})
}
예제 #6
0
파일: from.go 프로젝트: amarantha-k/query
/*
Qualify all identifiers for the parent expression. Checks is
a unnest alias exists and if it is a duplicate alias.
*/
func (this *Unnest) Formalize(parent *expression.Formalizer) (f *expression.Formalizer, err error) {
	f, err = this.left.Formalize(parent)
	if err != nil {
		return
	}

	this.expr, err = f.Map(this.expr)
	if err != nil {
		return
	}

	alias := this.Alias()
	if alias == "" {
		err = errors.NewError(nil, "UNNEST term must have a name or alias.")
		return nil, err
	}

	_, ok := f.Allowed.Field(alias)
	if ok {
		err = errors.NewError(nil, fmt.Sprintf("Duplicate UNNEST alias %s.", alias))
		return nil, err
	}

	f.Keyspace = ""
	f.Allowed.SetField(alias, alias)
	return
}
예제 #7
0
func (this *InitialProject) processTerms(item value.AnnotatedValue, context *Context) bool {
	n := len(this.plan.Terms())

	var f map[string]interface{}
	if item.Type() == value.OBJECT {
		f = item.Copy().Fields()
	}

	if f == nil {
		f = make(map[string]interface{}, n)
	}

	pv := value.NewAnnotatedValue(f)
	pv.SetAttachments(item.Attachments())

	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.NewError(err, "Error evaluating 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.NewError(err, "Error evaluating 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)
}
예제 #8
0
파일: order.go 프로젝트: amarantha-k/query
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 := strconv.Itoa(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.NewError(e, "Error evaluating 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.NewError(e, "Error evaluating 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
}
예제 #9
0
파일: merge.go 프로젝트: amarantha-k/query
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.NewError(e, "Error evaluatating MERGE key."))
		return false
	}

	ka := kv.Actual()
	k, ok := ka.(string)
	if !ok {
		context.Error(errors.NewError(nil,
			fmt.Sprintf("Invalid MERGE key %v of type %T.", ka, ka)))
		return false
	}

	bvs, err := this.plan.Keyspace().Fetch([]string{k})
	if err != nil {
		context.Error(err)
		return false
	}

	if len(bvs) > 0 {
		bv := bvs[0].Value

		// Matched; join source and target
		if update != nil {
			item.SetAttachment("target", bv)
		}

		abv := value.NewAnnotatedValue(bv)
		item.SetField(this.plan.KeyspaceRef().Alias(), abv)

		// 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 true
}
예제 #10
0
func (this *builder) VisitKeyspaceTerm(node *algebra.KeyspaceTerm) (interface{}, error) {
	node.SetDefaultNamespace(this.namespace)
	keyspace, err := this.getTermKeyspace(node)
	if err != nil {
		return nil, err
	}

	if node.Keys() != nil {
		scan := NewKeyScan(node.Keys())
		this.children = append(this.children, scan)
	} else {
		if this.subquery {
			return nil, errors.NewError(nil, fmt.Sprintf(
				"FROM in subquery must use KEYS clause: FROM %s.",
				node.Keyspace()))
		}

		scan, err := this.selectScan(keyspace, node)
		if err != nil {
			return nil, err
		}

		this.children = append(this.children, scan)
	}

	fetch := NewFetch(keyspace, node)
	this.subChildren = append(this.subChildren, fetch)
	return nil, nil
}
예제 #11
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.NewError(e, "Error evaluating 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
			}
		}
	})
}
예제 #12
0
파일: json.go 프로젝트: amarantha-k/query
func Run(mockServer *server.Server, q string) ([]interface{}, []errors.Error, errors.Error) {

	var metrics value.Tristate
	base := server.NewBaseRequest(q, nil, nil, nil, "json", value.FALSE, metrics, value.TRUE, nil, "", nil)

	mr := &MockResponse{
		results: []interface{}{}, warnings: []errors.Error{}, done: make(chan bool),
	}

	query := &MockQuery{
		BaseRequest: *base,
		response:    mr,
	}

	select {
	case mockServer.Channel() <- query:
		// Wait until the request exits.
		<-query.CloseNotify()
	default:
		// Timeout.
		return nil, nil, errors.NewError(nil, "Query timed out")
	}

	// wait till all the results are ready
	<-mr.done
	return mr.results, mr.warnings, mr.err
}
예제 #13
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.Error(errors.NewError(e, "Error evaluating GROUP key."))
			return false
		}
	}

	// Get or seed the group value
	gv := this.groups[gk]
	if gv != nil {
		context.Error(errors.NewError(nil, "Duplicate final GROUP."))
		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.Error(errors.NewError(
					e, "Error updating GROUP value."))
				return false
			}

			aggregates[agg.String()] = v
		}

		return true
	default:
		context.Error(errors.NewError(nil, fmt.Sprintf(
			"Invalid or missing aggregates of type %T.", aggregates)))
		return false
	}
}
예제 #14
0
파일: limit.go 프로젝트: amarantha-k/query
func (this *Limit) beforeItems(context *Context, parent value.Value) bool {
	val, e := this.plan.Expression().Evaluate(parent, context)
	if e != nil {
		context.Error(errors.NewError(e, "Error evaluating 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.NewError(nil, fmt.Sprintf("Invalid LIMIT value %v.", actual)))
	return false
}
예제 #15
0
func (this *Context) Recover() {
	err := recover()
	if err != nil {
		buf := make([]byte, 1<<16)
		n := runtime.Stack(buf, false)
		s := string(buf[0:n])
		logging.Severep("", logging.Pair{"panic", err},
			logging.Pair{"stack", s})
		os.Stderr.WriteString(s)
		os.Stderr.Sync()

		switch err := err.(type) {
		case error:
			this.Fatal(errors.NewError(err, fmt.Sprintf("Panic: %v", err)))
		default:
			this.Fatal(errors.NewError(nil, fmt.Sprintf("Panic: %v", err)))
		}
	}
}
예제 #16
0
func (this *Set) processItem(item value.AnnotatedValue, context *Context) bool {
	clone, ok := item.GetAttachment("clone").(value.AnnotatedValue)
	if !ok {
		context.Error(errors.NewError(nil,
			fmt.Sprintf("Invalid UPDATE clone of type %T.", clone)))
		return false
	}

	var e error
	for _, t := range this.plan.Node().Terms() {
		clone, e = setPath(t, clone, item, context)
		if e != nil {
			context.Error(errors.NewError(e, "Error evaluating SET clause."))
			return false
		}
	}

	item.SetAttachment("clone", clone)
	return this.sendItem(item)
}
예제 #17
0
func (this *SendUpdate) beforeItems(context *Context, parent value.Value) bool {
	if this.plan.Limit() == nil {
		return true
	}

	limit, err := this.plan.Limit().Evaluate(parent, context)
	if err != nil {
		context.Error(errors.NewError(err, ""))
		return false
	}

	switch l := limit.Actual().(type) {
	case float64:
		this.limit = int64(l)
	default:
		context.Error(errors.NewError(nil, fmt.Sprintf("Invalid LIMIT %v of type %T.", l, l)))
		return false
	}

	return true
}
예제 #18
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.NewError(err, "Error evaluating span."))
		close(conn.EntryChannel())
		return
	}

	this.plan.Index().Scan(dspan, this.plan.Distinct(), this.plan.Limit(),
		context.ScanConsistency(), context.ScanVector(), conn)
}
예제 #19
0
파일: filter.go 프로젝트: amarantha-k/query
func (this *Filter) processItem(item value.AnnotatedValue, context *Context) bool {
	val, e := this.plan.Condition().Evaluate(item, context)
	if e != nil {
		context.Error(errors.NewError(e, "Error evaluating filter."))
		return false
	}

	if val.Truth() {
		return this.sendItem(item)
	} else {
		return true
	}
}
예제 #20
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.Error(errors.NewError(e, "Error evaluating 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)
		gv.SetAttachment("aggregates", aggregates)
		for _, agg := range this.plan.Aggregates() {
			aggregates[agg.String()] = agg.Default()
		}
	}

	// Cumulate aggregates
	aggregates := gv.GetAttachment("aggregates").(map[string]value.Value)
	for _, agg := range this.plan.Aggregates() {
		v, e := agg.CumulateInitial(item, aggregates[agg.String()], context)
		if e != nil {
			context.Error(errors.NewError(e, "Error updating GROUP value."))
			return false
		}

		aggregates[agg.String()] = v
	}

	return true
}
예제 #21
0
func GetKeyspace(namespace, keyspace string) (Keyspace, errors.Error) {
	datastore := GetDatastore()
	if datastore == nil {
		return nil, errors.NewError(nil, "Datastore not set.")
	}

	ns, err := datastore.NamespaceByName(namespace)
	if err != nil {
		return nil, err
	}

	return ns.KeyspaceByName(keyspace)
}
예제 #22
0
func (this *Unset) processItem(item value.AnnotatedValue, context *Context) bool {
	clone, ok := item.GetAttachment("clone").(value.AnnotatedValue)
	if !ok {
		context.Error(errors.NewError(nil,
			fmt.Sprintf("Invalid UPDATE clone of type %T.", clone)))
		return false
	}

	for _, t := range this.plan.Node().Terms() {
		unsetPath(t, clone, context)
	}

	return this.sendItem(item)
}
예제 #23
0
/*
Qualify identifiers for the keyspace. It also makes sure that the
keyspace term contains a name or alias.
*/
func (this *KeyspaceRef) Formalize() (f *expression.Formalizer, err error) {
	keyspace := this.Alias()
	if keyspace == "" {
		err = errors.NewError(nil, "Keyspace term must have a name or alias.")
		return
	}

	allowed := value.NewValue(make(map[string]interface{}))
	allowed.SetField(keyspace, keyspace)

	f = expression.NewFormalizer()
	f.Keyspace = keyspace
	f.Allowed = allowed
	return
}
예제 #24
0
파일: base.go 프로젝트: amarantha-k/query
func (this *base) requireKey(item value.AnnotatedValue, context *Context) (string, bool) {
	mv := item.GetAttachment("meta")
	if mv == nil {
		context.Error(errors.NewError(nil, "Unable to find meta."))
		return "", false
	}

	meta := mv.(map[string]interface{})
	key, ok := meta["id"]
	if !ok {
		context.Error(errors.NewError(nil, "Unable to find key."))
		return "", false
	}

	act := value.NewValue(key).Actual()
	switch act := act.(type) {
	case string:
		return act, true
	default:
		e := errors.NewError(nil, fmt.Sprintf("Unable to process non-string key %v of type %T.", act, act))
		context.Error(e)
		return "", false
	}
}
예제 #25
0
func (this *UnionScan) processKey(item value.AnnotatedValue, context *Context) bool {
	m := item.GetAttachment("meta")
	meta, ok := m.(map[string]interface{})
	if !ok {
		context.Error(errors.NewError(nil,
			fmt.Sprintf("Missing or invalid meta %v of type %T.", m, m)))
		return false
	}

	k := meta["id"]
	key, ok := k.(string)
	if !ok {
		context.Error(errors.NewError(nil,
			fmt.Sprintf("Missing or invalid primary key %v of type %T.", k, k)))
		return false
	}

	if this.values[key] != nil {
		return true
	}

	this.values[key] = item
	return this.sendItem(item)
}
예제 #26
0
func (this *Explain) 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

		bytes, err := json.Marshal(this.plan)
		if err != nil {
			context.Fatal(errors.NewError(err, "Failed to marshal JSON."))
			return
		}

		value := value.NewAnnotatedValue(bytes)
		this.sendItem(value)

	})
}
예제 #27
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 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.NewError(err, "Error evaluating 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)
	}
}
예제 #28
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.NewError(e, "Error evaluating filter term."))
			return nil, false
		}
	}

	return cv, true
}
예제 #29
0
파일: let.go 프로젝트: amarantha-k/query
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.SetAttachments(item.Attachments())

	for _, b := range this.plan.Bindings() {
		v, e := b.Expression().Evaluate(item, context)
		if e != nil {
			context.Error(errors.NewError(e, "Error evaluating LET."))
			return false
		}

		lv.SetField(b.Variable(), v)
	}

	return this.sendItem(lv)
}
예제 #30
0
func (this *SendUpdate) flushBatch(context *Context) bool {
	if len(this.batch) == 0 {
		return true
	}

	pairs := make([]datastore.Pair, len(this.batch))

	for i, av := range this.batch {
		key, ok := this.requireKey(av, context)
		if !ok {
			return false
		}

		pairs[i].Key = key
		clone := av.GetAttachment("clone")
		switch clone := clone.(type) {
		case value.AnnotatedValue:
			pairs[i].Value = this.unwrapTop(clone)
		default:
			context.Error(errors.NewError(nil, fmt.Sprintf(
				"Invalid UPDATE value of type %T.", clone)))
			return false
		}
	}

	pairs, e := this.plan.Keyspace().Update(pairs)

	// Update mutation count with number of updated docs
	context.AddMutationCount(uint64(len(pairs)))

	if e != nil {
		context.Error(e)
	}

	for _, av := range this.batch {
		p := av.GetAttachment("clone")
		if !this.sendItem(p.(value.AnnotatedValue)) {
			break
		}
	}

	this.batch = nil
	return true
}