Add support for in and nin ref handlers in reporter joins
This commit is contained in:
committed by
Jože Fortun
parent
8f3c3c3ea7
commit
107d7a70ce
+44
-11
@@ -219,24 +219,41 @@ func (def *Link) init(ctx context.Context, left, right Iterator) (exec *linkLeft
|
||||
}
|
||||
|
||||
func (r *rowLink) SelectGVal(ctx context.Context, k string) (interface{}, error) {
|
||||
return r.GetValue(k, 0)
|
||||
// @todo this way of determining multivalue is not entirely ok but we can get away with it
|
||||
// since we have special functions to work with those.
|
||||
// We need to somehow inform this bit as to what fields are multi value.
|
||||
row, counts := r.getGetter(k)
|
||||
if row == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
cc := counts[k]
|
||||
if cc == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if cc == 1 {
|
||||
return row.GetValue(k, 0)
|
||||
}
|
||||
|
||||
out := make([]any, cc)
|
||||
for i := uint(0); i < cc; i++ {
|
||||
out[i], _ = row.GetValue(k, i)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (r *rowLink) GetValue(name string, pos uint) (v any, err error) {
|
||||
a := r.a.CountValues()
|
||||
row, a := r.getGetter(name)
|
||||
if row == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if cc, ok := a[name]; ok {
|
||||
if pos >= cc {
|
||||
return nil, nil
|
||||
}
|
||||
return r.a.GetValue(name, pos)
|
||||
}
|
||||
|
||||
b := r.b.CountValues()
|
||||
if cc, ok := b[name]; ok {
|
||||
if pos >= cc {
|
||||
return nil, nil
|
||||
}
|
||||
return r.b.GetValue(name, pos)
|
||||
return row.GetValue(name, pos)
|
||||
}
|
||||
|
||||
return
|
||||
@@ -254,3 +271,19 @@ func (r *rowLink) CountValues() (out map[string]uint) {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// getGetter returns the ValueGetter based on if the value is in a or b
|
||||
// If neither, it returns nil
|
||||
func (r *rowLink) getGetter(k string) (row ValueGetter, cc map[string]uint) {
|
||||
cc = r.a.CountValues()
|
||||
if _, ok := cc[k]; ok {
|
||||
return r.a, cc
|
||||
}
|
||||
|
||||
cc = r.b.CountValues()
|
||||
if _, ok := cc[k]; ok {
|
||||
return r.b, cc
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -3,9 +3,11 @@ package dal
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/PaesslerAG/gval"
|
||||
"github.com/cortezaproject/corteza/server/pkg/expr"
|
||||
"github.com/cortezaproject/corteza/server/pkg/gvalfnc"
|
||||
"github.com/cortezaproject/corteza/server/pkg/ql"
|
||||
)
|
||||
@@ -125,6 +127,21 @@ var (
|
||||
OutTypeUnknown: true,
|
||||
},
|
||||
|
||||
"in": {
|
||||
Handler: func(args ...string) string {
|
||||
// The arguments must be reversed!!
|
||||
return fmt.Sprintf("has(%s, %s)", args[1], args[0])
|
||||
},
|
||||
OutTypeUnknown: true,
|
||||
},
|
||||
"nin": {
|
||||
Handler: func(args ...string) string {
|
||||
// The arguments must be reversed!!
|
||||
return fmt.Sprintf("!has(%s, %s)", args[1], args[0])
|
||||
},
|
||||
OutTypeUnknown: true,
|
||||
},
|
||||
|
||||
// - strings
|
||||
"concat": {
|
||||
Handler: func(args ...string) string {
|
||||
@@ -311,7 +328,7 @@ func newRunnerGvalParsed(n *ql.ASTNode) (out *runnerGval, err error) {
|
||||
// @note the subset is limited to simplify the (eventual) offloading to the DB.
|
||||
// At some point, more functions will be supported, and the ones which can't
|
||||
// be offloaded will be performed in some exec. step.
|
||||
func newGval(expr string) (gval.Evaluable, error) {
|
||||
func newGval(e string) (gval.Evaluable, error) {
|
||||
return gval.Full(
|
||||
// Extra functions we'll need
|
||||
// @note don't bring in all of the expr. pkg functions as we'll need to
|
||||
@@ -328,7 +345,8 @@ func newGval(expr string) (gval.Evaluable, error) {
|
||||
gval.Function("int", gvalfnc.CastInt),
|
||||
gval.Function("string", gvalfnc.CastString),
|
||||
gval.Function("concat", gvalfnc.ConcatStrings),
|
||||
).NewEvaluable(expr)
|
||||
gval.Function("has", arrHas),
|
||||
).NewEvaluable(e)
|
||||
}
|
||||
|
||||
func newQlParser(onIdent ...ql.IdentHandler) *ql.Parser {
|
||||
@@ -409,3 +427,34 @@ func (c converterGval) refHandler(n *ql.ASTNode, args ...string) (out string, er
|
||||
}
|
||||
return refToGvalExp[r].Handler(args...), nil
|
||||
}
|
||||
|
||||
// arrHas is a helper to assure the expr.Has always gets an array (or map) as
|
||||
// the first argument
|
||||
//
|
||||
// @todo this is needed because how the ValueGetters returns multi-value fields so
|
||||
// an edge case where a field would have [a] but here, it would be presented
|
||||
// as a.
|
||||
// This would become obsolete when we address the actual issue.
|
||||
func arrHas(arr interface{}, vv ...interface{}) (b bool, err error) {
|
||||
arr = expr.UntypedValue(arr)
|
||||
|
||||
if isMap(arr) {
|
||||
return expr.Has(arr, vv...)
|
||||
}
|
||||
|
||||
var (
|
||||
c = reflect.ValueOf(arr)
|
||||
)
|
||||
|
||||
switch c.Kind() {
|
||||
case reflect.Slice:
|
||||
return expr.Has(arr, vv...)
|
||||
|
||||
default:
|
||||
return expr.Has([]any{arr}, vv...)
|
||||
}
|
||||
}
|
||||
|
||||
func isMap(v interface{}) bool {
|
||||
return reflect.TypeOf(v).Kind() == reflect.Map
|
||||
}
|
||||
|
||||
+20
-2
@@ -57,8 +57,26 @@ func (r *Row) WithValue(name string, pos uint, v any) *Row {
|
||||
return r
|
||||
}
|
||||
|
||||
func (r Row) SelectGVal(ctx context.Context, k string) (interface{}, error) {
|
||||
return r.GetValue(unwrapNestedGvalIdent(k), 0)
|
||||
func (r Row) SelectGVal(ctx context.Context, wk string) (interface{}, error) {
|
||||
// @todo this way of determining multivalue is not entirely ok but we can get away with it
|
||||
// since we have special functions to work with those.
|
||||
// We need to somehow inform this bit as to what fields are multi value.
|
||||
|
||||
k := unwrapNestedGvalIdent(wk)
|
||||
cc := r.CountValues()[k]
|
||||
if cc == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if cc == 1 {
|
||||
return r.GetValue(k, 0)
|
||||
}
|
||||
|
||||
out := make([]any, cc)
|
||||
for i := uint(0); i < cc; i++ {
|
||||
out[i], _ = r.GetValue(k, i)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Reset clears out the row so the same instance can be reused where possible
|
||||
|
||||
@@ -15,7 +15,7 @@ func ArrayFunctions() []gval.Language {
|
||||
gval.Function("pop", pop),
|
||||
gval.Function("shift", shift),
|
||||
gval.Function("count", count),
|
||||
gval.Function("has", has),
|
||||
gval.Function("has", Has),
|
||||
gval.Function("hasAll", hasAll),
|
||||
gval.Function("find", find),
|
||||
gval.Function("sort", sortSlice),
|
||||
@@ -157,7 +157,7 @@ func count(arr interface{}, v ...interface{}) (count int, err error) {
|
||||
}
|
||||
|
||||
// has finds any occurrence of the values in slice or key in a map
|
||||
func has(arr interface{}, vv ...interface{}) (b bool, err error) {
|
||||
func Has(arr interface{}, vv ...interface{}) (b bool, err error) {
|
||||
arr = UntypedValue(arr)
|
||||
|
||||
if isMap(arr) {
|
||||
|
||||
Reference in New Issue
Block a user