예제 #1
0
// CreatePrimaryIndex implements datastore.Indexer{} interface. Create or
// return a primary index on this keyspace
func (gsi *gsiKeyspace) CreatePrimaryIndex(
	requestId, name string, with value.Value) (datastore.PrimaryIndex, errors.Error) {

	var withJSON []byte
	var err error
	if with != nil {
		if withJSON, err = with.MarshalJSON(); err != nil {
			return nil, errors.NewError(err, "GSI error marshalling WITH clause")
		}
	}
	defnID, err := gsi.gsiClient.CreateIndex(
		name,
		gsi.keyspace,       /*bucket-name*/
		string(c.ForestDB), /*using, by default always forestdb*/
		"N1QL",             /*exprType*/
		"",                 /*partnStr*/
		"",                 /*whereStr*/
		nil,                /*secStrs*/
		true,               /*isPrimary*/
		withJSON)
	if err != nil {
		return nil, errors.NewError(err, "GSI CreatePrimaryIndex()")
	}
	// refresh to get back the newly created index.
	if err := gsi.Refresh(); err != nil {
		return nil, err
	}
	index, errr := gsi.IndexById(defnID2String(defnID))
	if errr != nil {
		return nil, errr
	}
	return index.(datastore.PrimaryIndex), nil
}
예제 #2
0
/*
This method removes all the occurences of the second value from the
first array value.
*/
func (this *ArrayRemove) Apply(context Context, first, second value.Value) (value.Value, error) {
	if first.Type() == value.MISSING {
		return first, nil
	}

	if first.Type() != value.ARRAY {
		return value.NULL_VALUE, nil
	}

	if second.Type() <= value.NULL {
		return first, nil
	}

	fa := first.Actual().([]interface{})
	if len(fa) == 0 {
		return first, nil
	}

	ra := make([]interface{}, 0, len(fa))
	for _, f := range fa {
		if !second.Equals(value.NewValue(f)).Truth() {
			ra = append(ra, f)
		}
	}

	return value.NewValue(ra), nil
}
예제 #3
0
/*
Perform either case-sensitive or case-insensitive field lookup.
*/
func (this *Field) Apply(context Context, first, second value.Value) (value.Value, error) {
	switch second.Type() {
	case value.STRING:
		s := second.Actual().(string)
		v, ok := first.Field(s)

		if !ok && this.caseInsensitive {
			s = strings.ToLower(s)
			fields := first.Fields()
			for f, val := range fields {
				if s == strings.ToLower(f) {
					return value.NewValue(val), nil
				}
			}
		}

		return v, nil
	case value.MISSING:
		return value.MISSING_VALUE, nil
	default:
		if first.Type() == value.MISSING {
			return value.MISSING_VALUE, nil
		} else {
			return value.NULL_VALUE, nil
		}
	}
}
예제 #4
0
/*
This method returns an object value. The input of types
missing, null and object return themselves. For all other
values, return an _EMPTY_OBJECT value.
*/
func (this *ToObject) Apply(context Context, arg value.Value) (value.Value, error) {
	switch arg.Type() {
	case value.MISSING, value.NULL, value.OBJECT:
		return arg, nil
	}

	return _EMPTY_OBJECT, nil
}
예제 #5
0
/*
Evaluates the Is Missing comparison operation for expressions.
Return true if the input argument value is a missing value,
else return false.
*/
func (this *IsMissing) Apply(context Context, arg value.Value) (value.Value, error) {
	switch arg.Type() {
	case value.MISSING:
		return value.TRUE_VALUE, nil
	default:
		return value.FALSE_VALUE, nil
	}
}
예제 #6
0
파일: comp_le.go 프로젝트: pkdevboxy/query
func (this *LE) Apply(context Context, first, second value.Value) (value.Value, error) {
	cmp := first.Compare(second)
	switch actual := cmp.Actual().(type) {
	case float64:
		return value.NewValue(actual <= 0), nil
	}

	return cmp, nil
}
예제 #7
0
func (this *Base64) Apply(context Context, operand value.Value) (value.Value, error) {
	if operand.Type() == value.MISSING {
		return operand, nil
	}

	bytes, _ := operand.MarshalJSON() // Ignore errors from BINARY values
	str := base64.StdEncoding.EncodeToString(bytes)
	return value.NewValue(str), nil
}
예제 #8
0
func testObjectRemove(e1, e2 Expression, er value.Value, t *testing.T) {
	eop := NewObjectRemove(e1, e2)
	rv, err := eop.Evaluate(nil, nil)
	if err != nil {
		t.Errorf("received error %v", err)
	}
	if er.Collate(rv) != 0 {
		t.Errorf("mismatch received %v expected %v", rv.Actual(), er.Actual())
	}
}
예제 #9
0
func testArrayInsert_eval(e1, e2, e3 Expression, er value.Value, t *testing.T) {
	eai := NewArrayInsert(e1, e2, e3)
	rv, err := eai.Evaluate(nil, nil)
	if err != nil {
		t.Errorf("received error %v", err)
	}
	if er.Collate(rv) != 0 {
		t.Errorf("mismatch received %v expected %v", rv.Actual(), er.Actual())
	}
}
예제 #10
0
파일: agg_min.go 프로젝트: pkdevboxy/query
/*
Aggregate input partial values into cumulative result value.
If partial result is null return the current cumulative value,
and if the cumulative result is null, return the partial value.
For non null partial and cumulative values, call Collate and
return the smaller value depending on the N1QL collation order.
*/
func (this *Min) cumulatePart(part, cumulative value.Value, context Context) (value.Value, error) {
	if part == value.NULL_VALUE {
		return cumulative, nil
	} else if cumulative == value.NULL_VALUE {
		return part, nil
	} else if part.Collate(cumulative) < 0 {
		return part, nil
	} else {
		return cumulative, nil
	}
}
예제 #11
0
func (this *ParentScan) 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

		// Shallow copy of the parent includes
		// correlated and annotated aspects
		this.sendItem(parent.Copy().(value.AnnotatedValue))
	})
}
예제 #12
0
func (this *Not) Apply(context Context, arg value.Value) (value.Value, error) {
	switch arg.Type() {
	case value.MISSING, value.NULL:
		return arg, nil
	default:
		if arg.Truth() {
			return value.FALSE_VALUE, nil
		} else {
			return value.TRUE_VALUE, nil
		}
	}
}
예제 #13
0
/*
Aggregates input data by evaluating operands. For missing
item values, return the input value itself. Call
setAdd to compute the intermediate aggregate value
and return it.
*/
func (this *ArrayAggDistinct) CumulateInitial(item, cumulative value.Value, context Context) (value.Value, error) {
	item, e := this.Operand().Evaluate(item, context)
	if e != nil {
		return nil, e
	}

	if item.Type() <= value.MISSING || item.Type() == value.BINARY {
		return cumulative, nil
	}

	return setAdd(item, cumulative)
}
예제 #14
0
/*
Aggregates input data by evaluating operands. For missing
item values, return the input value itself. Call
cumulatePart to compute the intermediate aggregate value
and return it.
*/
func (this *ArrayAgg) CumulateInitial(item, cumulative value.Value, context Context) (value.Value, error) {
	item, e := this.Operand().Evaluate(item, context)
	if e != nil {
		return nil, e
	}

	if item.Type() <= value.MISSING || item.Type() == value.BINARY {
		return cumulative, nil
	}

	return this.cumulatePart(value.NewValue([]interface{}{item}), cumulative, context)
}
예제 #15
0
/*
Aggregates input data by evaluating operands.For all
values other than Number, return the input value itself.
Call setAdd to compute the intermediate aggregate value
and return it.
*/
func (this *AvgDistinct) CumulateInitial(item, cumulative value.Value, context Context) (value.Value, error) {
	item, e := this.Operand().Evaluate(item, context)
	if e != nil {
		return nil, e
	}

	if item.Type() != value.NUMBER {
		return cumulative, nil
	}

	return setAdd(item, cumulative)
}
예제 #16
0
파일: agg_sum.go 프로젝트: pkdevboxy/query
func (this *Sum) CumulateInitial(item, cumulative value.Value, context Context) (value.Value, error) {
	item, e := this.Operand().Evaluate(item, context)
	if e != nil {
		return nil, e
	}

	if item.Type() != value.NUMBER {
		return cumulative, nil
	}

	return this.cumulatePart(item, cumulative, context)
}
예제 #17
0
파일: order.go 프로젝트: jmptrader/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 := 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
}
예제 #18
0
파일: agg_avg.go 프로젝트: pkdevboxy/query
/*
Aggregates input data by evaluating operands. For all
values other than Number, return the input value itself. Call
cumulatePart to compute the intermediate aggregate value
and return it.
*/
func (this *Avg) CumulateInitial(item, cumulative value.Value, context Context) (value.Value, error) {
	item, e := this.Operand().Evaluate(item, context)
	if e != nil {
		return nil, e
	}

	if item.Type() != value.NUMBER {
		return cumulative, nil
	}

	part := value.NewValue(map[string]interface{}{"sum": item.Actual(), "count": 1})
	return this.cumulatePart(part, cumulative, context)
}
예제 #19
0
/*
This method checks to see if the values of the two input
expressions are equal, and if true then returns a positive
infinity using the math package method Inf(1). If not it
returns the first input value. Use the Equals method for the
two values to determine equality.
*/
func (this *PosInfIf) Apply(context Context, first, second value.Value) (value.Value, error) {
	eq := first.Equals(second)
	switch eq.Type() {
	case value.MISSING, value.NULL:
		return eq, nil
	default:
		if eq.Truth() {
			return _POS_INF_VALUE, nil
		} else {
			return first, nil
		}
	}
}
예제 #20
0
파일: cover.go 프로젝트: jmptrader/query
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
}
예제 #21
0
파일: agg_util.go 프로젝트: pkdevboxy/query
/*
Retrieve the set for annotated values. If the attachment type
is not a set, then throw an invalid distinct set error and
return.
*/
func getSet(item value.Value) (*value.Set, error) {
	switch item := item.(type) {
	case value.AnnotatedValue:
		ps := item.GetAttachment("set")
		switch ps := ps.(type) {
		case *value.Set:
			return ps, nil
		default:
			return nil, fmt.Errorf("Invalid DISTINCT set %v of type %T.", ps, ps)
		}
	default:
		return nil, fmt.Errorf("Invalid DISTINCT %v of type %T.", item, item)
	}
}
예제 #22
0
/*
It returns a string based on the input expr value. Values
missing, null and strings return themselves. False, true
(boolean) and numbers return their string representation.
This is done using the Sprint method defined in fmt for Go.
All other values map to null.
*/
func (this *ToString) Apply(context Context, arg value.Value) (value.Value, error) {
	switch arg.Type() {
	case value.MISSING, value.NULL, value.STRING:
		return arg, nil
	case value.BOOLEAN:
		return value.NewValue(fmt.Sprint(arg.Actual())), nil
	case value.NUMBER:
		f := arg.Actual().(float64)
		if f == -0 {
			f = 0
		}

		s := strconv.FormatFloat(f, 'f', -1, 64)
		return value.NewValue(s), nil
	case value.BINARY:
		raw, ok := arg.Actual().([]byte)
		if !ok {
			return value.NULL_VALUE, nil
		}

		s := string(raw)
		return value.NewValue(s), nil
	default:
		return value.NULL_VALUE, nil
	}
}
예제 #23
0
func testObjectAdd(e1, e2, e3 Expression, er value.Value, fail bool, t *testing.T) {
	eop := NewObjectAdd(e1, e2, e3)
	rv, err := eop.Evaluate(nil, nil)
	if err != nil {
		if fail && rv.Actual() == nil {
			return
		}
		t.Errorf("received error %v", err)
	} else if fail {
		t.Errorf("error expected, received success")
	}
	if er.Collate(rv) != 0 {
		t.Errorf("mismatch received %v expected %v", rv.Actual(), er.Actual())
	}
}
예제 #24
0
/*
Aggregates input data by evaluating operands. For missing and
null values return the input value itself. Call cumulatePart
to compute the intermediate aggregate value and return it.
*/
func (this *Count) CumulateInitial(item, cumulative value.Value, context Context) (value.Value, error) {
	if this.Operand() != nil {
		item, e := this.Operand().Evaluate(item, context)
		if e != nil {
			return nil, e
		}

		if item.Type() <= value.NULL {
			return cumulative, nil
		}
	}

	return this.cumulatePart(value.ONE_VALUE, cumulative, context)

}
예제 #25
0
/*
Aggregate input partial values into cumulative result number value.
If the partial and current cumulative result are both float64
numbers, add them and return.
*/
func (this *Count) cumulatePart(part, cumulative value.Value, context Context) (value.Value, error) {
	actual := part.Actual()
	switch actual := actual.(type) {
	case float64:
		count := cumulative.Actual()
		switch count := count.(type) {
		case float64:
			return value.NewValue(count + actual), nil
		default:
			return nil, fmt.Errorf("Invalid COUNT %v of type %T.", count, count)
		}
	default:
		return nil, fmt.Errorf("Invalid partial COUNT %v of type %T.", actual, actual)
	}
}
예제 #26
0
/*
This method evaluates the input value and returns the length
based on its type. If the input argument is a missing then
return a missing value. Convert it to a valid Go type. If
it is a string slice of interfaces or object then return
its length cast as a number float64. By default return a
null value.
*/
func (this *PolyLength) Apply(context Context, arg value.Value) (value.Value, error) {
	if arg.Type() == value.MISSING {
		return value.MISSING_VALUE, nil
	}

	switch oa := arg.Actual().(type) {
	case string:
		return value.NewValue(float64(len(oa))), nil
	case []interface{}:
		return value.NewValue(float64(len(oa))), nil
	case map[string]interface{}:
		return value.NewValue(float64(len(oa))), nil
	default:
		return value.NULL_VALUE, nil
	}
}
예제 #27
0
파일: coll_in.go 프로젝트: pkdevboxy/query
/*
IN evaluates to TRUE if the right-hand-side first value is an array
and directly contains the left-hand-side second value. If either
of the input operands are missing, return missing value, and
if the second is not an array return null. Range over the elements of the
array and check if any element is equal to the first value, return true.
For all other cases, return false.
*/
func (this *In) Apply(context Context, first, second value.Value) (value.Value, error) {
	if first.Type() == value.MISSING || second.Type() == value.MISSING {
		return value.MISSING_VALUE, nil
	} else if second.Type() != value.ARRAY {
		return value.NULL_VALUE, nil
	}

	sa := second.Actual().([]interface{})
	for _, s := range sa {
		if first.Equals(value.NewValue(s)).Truth() {
			return value.TRUE_VALUE, nil
		}
	}

	return value.FALSE_VALUE, nil
}
예제 #28
0
/*
This method ranges through the array and returns the position
of the second value in the array (first value). If the input
values are of type missing return a missing value, and for all
non array values return null. If not found then return -1.
*/
func (this *ArrayPosition) Apply(context Context, first, second value.Value) (value.Value, error) {
	if first.Type() == value.MISSING || second.Type() == value.MISSING {
		return value.MISSING_VALUE, nil
	} else if first.Type() != value.ARRAY {
		return value.NULL_VALUE, nil
	}

	fa := first.Actual().([]interface{})
	for i, f := range fa {
		if second.Equals(value.NewValue(f)).Truth() {
			return value.NewValue(float64(i)), nil
		}
	}

	return value.NewValue(float64(-1)), nil
}
예제 #29
0
/*
Directly call the evaluate method for aggregate functions and
passe in the receiver, current item and current context, for
count with an input expression operand. For a count with no
operands (count (*)), get the count from the attachment and
then evaluate.
*/
func (this *Count) Evaluate(item value.Value, context expression.Context) (result value.Value, e error) {
	if this.Operand() != nil {
		return this.evaluate(this, item, context)
	}

	// Full keyspace count is short-circuited
	switch item := item.(type) {
	case value.AnnotatedValue:
		count := item.GetAttachment("count")
		if count != nil {
			return value.NewValue(count), nil
		}
	}

	return this.evaluate(this, item, context)
}
예제 #30
0
// CreateIndex implements datastore.Indexer{} interface. Create a secondary
// index on this keyspace
func (gsi *gsiKeyspace) CreateIndex(
	requestId, name string, seekKey, rangeKey expression.Expressions,
	where expression.Expression, with value.Value) (
	datastore.Index, errors.Error) {

	var partnStr string
	if seekKey != nil && len(seekKey) > 0 {
		partnStr = expression.NewStringer().Visit(seekKey[0])
	}

	var whereStr string
	if where != nil {
		whereStr = expression.NewStringer().Visit(where)
	}

	secStrs := make([]string, len(rangeKey))
	for i, key := range rangeKey {
		s := expression.NewStringer().Visit(key)
		secStrs[i] = s
	}

	var withJSON []byte
	var err error
	if with != nil {
		if withJSON, err = with.MarshalJSON(); err != nil {
			return nil, errors.NewError(err, "GSI error marshalling WITH clause")
		}
	}
	defnID, err := gsi.gsiClient.CreateIndex(
		name,
		gsi.keyspace,       /*bucket-name*/
		string(c.ForestDB), /*using, by default always forestdb*/
		"N1QL",             /*exprType*/
		partnStr, whereStr, secStrs,
		false, /*isPrimary*/
		withJSON)
	if err != nil {
		return nil, errors.NewError(err, "GSI CreateIndex()")
	}
	// refresh to get back the newly created index.
	if err := gsi.Refresh(); err != nil {
		return nil, err
	}
	return gsi.IndexById(defnID2String(defnID))
}