snapshot of https://github.com/cortezaproject/corteza.git (2024.9.x, 2026-09-18; blobs > 131072B omitted)
Some checks failed
SonarQube / SonarQube (push) Failing after 5m28s
E2e test on main branch push / server and client test (map[name:admin port:8080]) (push) Failing after 3m33s
Server and lib tests / Library test (js) (push) Failing after 1m36s
Server and lib tests / Library test (vue) (push) Successful in 2m24s
Server and lib tests / Web client test (admin) (push) Successful in 2m52s
Server and lib tests / Web client test (compose) (push) Successful in 3m23s
Server and lib tests / Web client test (discovery) (push) Successful in 2m49s
Server and lib tests / Web client test (one) (push) Successful in 2m52s
Server and lib tests / Web client test (privacy) (push) Successful in 2m44s
Server and lib tests / Web client test (reporter) (push) Successful in 2m56s
Server and lib tests / Web client test (workflow) (push) Successful in 3m0s
Server and lib tests / Server tests (push) Failing after 4m55s
E2e test on main branch push / notify-failure (push) Failing after 9s
Server and lib tests / Send matrix testing notification (push) Successful in 2s
Mark stale issues and pull requests / stale (push) Successful in 40s
Some checks failed
SonarQube / SonarQube (push) Failing after 5m28s
E2e test on main branch push / server and client test (map[name:admin port:8080]) (push) Failing after 3m33s
Server and lib tests / Library test (js) (push) Failing after 1m36s
Server and lib tests / Library test (vue) (push) Successful in 2m24s
Server and lib tests / Web client test (admin) (push) Successful in 2m52s
Server and lib tests / Web client test (compose) (push) Successful in 3m23s
Server and lib tests / Web client test (discovery) (push) Successful in 2m49s
Server and lib tests / Web client test (one) (push) Successful in 2m52s
Server and lib tests / Web client test (privacy) (push) Successful in 2m44s
Server and lib tests / Web client test (reporter) (push) Successful in 2m56s
Server and lib tests / Web client test (workflow) (push) Successful in 3m0s
Server and lib tests / Server tests (push) Failing after 4m55s
E2e test on main branch push / notify-failure (push) Failing after 9s
Server and lib tests / Send matrix testing notification (push) Successful in 2s
Mark stale issues and pull requests / stale (push) Successful in 40s
This commit is contained in:
311
server/pkg/expr/func_arr.go
Normal file
311
server/pkg/expr/func_arr.go
Normal file
@@ -0,0 +1,311 @@
|
||||
package expr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/PaesslerAG/gval"
|
||||
)
|
||||
|
||||
func ArrayFunctions() []gval.Language {
|
||||
return []gval.Language{
|
||||
gval.Function("push", push),
|
||||
gval.Function("pop", pop),
|
||||
gval.Function("shift", shift),
|
||||
gval.Function("count", count),
|
||||
gval.Function("has", Has),
|
||||
gval.Function("hasAll", hasAll),
|
||||
gval.Function("find", find),
|
||||
gval.Function("sort", sortSlice),
|
||||
gval.Function("splice", splice),
|
||||
}
|
||||
}
|
||||
|
||||
// push adds a value to the end of slice, returns copy
|
||||
func push(arr interface{}, nn ...interface{}) (out interface{}, err error) {
|
||||
if arr == nil {
|
||||
// If base is empty, return pushed items directly
|
||||
return nn, nil
|
||||
} else if i, is := arr.([]interface{}); is {
|
||||
// Simple append if we're dealing with []interface{} base
|
||||
return append(i, nn...), nil
|
||||
} else if arr, err = toSlice(arr); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if stv, is := arr.([]TypedValue); is {
|
||||
// slice of typed values, this will make things easier
|
||||
for _, n := range nn {
|
||||
if tv, is := n.(TypedValue); is {
|
||||
stv = append(stv, tv)
|
||||
} else {
|
||||
// wrap unknown types...
|
||||
stv = append(stv, Must(Typify(n)))
|
||||
}
|
||||
}
|
||||
|
||||
return stv, nil
|
||||
}
|
||||
|
||||
var (
|
||||
c = reflect.ValueOf(arr)
|
||||
nval = reflect.MakeSlice(c.Type(), c.Len()+len(nn), c.Cap()+len(nn))
|
||||
)
|
||||
|
||||
reflect.Copy(nval, c)
|
||||
|
||||
for i, n := range nn {
|
||||
nt := reflect.ValueOf(n).Type()
|
||||
it := nval.Index(c.Len() + i).Type()
|
||||
if nt != it {
|
||||
return nil, fmt.Errorf("can not push %v to %v slice", nt, it)
|
||||
}
|
||||
|
||||
nval.Index(c.Len() + i).Set(reflect.ValueOf(n))
|
||||
}
|
||||
|
||||
return nval.Interface(), nil
|
||||
}
|
||||
|
||||
// pop takes the last value in slice, does not modify original
|
||||
func pop(arr interface{}) (out interface{}, err error) {
|
||||
if arr, err = toSlice(arr); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
c := reflect.ValueOf(arr)
|
||||
|
||||
if c.Len() == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return c.Index(c.Len() - 1).Interface(), nil
|
||||
}
|
||||
|
||||
// shifts takes the first value in slice, does not modify original
|
||||
func shift(arr interface{}) (out interface{}, err error) {
|
||||
if arr, err = toSlice(arr); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
c := reflect.ValueOf(arr)
|
||||
|
||||
if c.Len() == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return c.Index(0).Interface(), nil
|
||||
}
|
||||
|
||||
// count gets the count of occurrences in the first params(can be string, slice)
|
||||
// If given only one parameter then it returns length as count
|
||||
func count(arr interface{}, v ...interface{}) (count int, err error) {
|
||||
typeErr := fmt.Errorf("unexpected type: %T, expecting slice", arr)
|
||||
arr = UntypedValue(arr)
|
||||
|
||||
if stv, is := arr.([]TypedValue); is {
|
||||
if len(v) == 0 {
|
||||
return len(stv), nil
|
||||
}
|
||||
|
||||
for _, vv := range v {
|
||||
if occ, err := find(stv, vv); err != nil {
|
||||
return 0, err
|
||||
} else if occ != -1 {
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
var (
|
||||
occ int
|
||||
c = reflect.ValueOf(arr)
|
||||
)
|
||||
|
||||
switch c.Kind() {
|
||||
case reflect.String:
|
||||
if len(v) == 0 {
|
||||
return len(c.String()), nil
|
||||
}
|
||||
|
||||
for _, ww := range v {
|
||||
count += strings.Count(c.String(), reflect.ValueOf(ww).String())
|
||||
}
|
||||
return
|
||||
|
||||
case reflect.Slice:
|
||||
if len(v) == 0 {
|
||||
return c.Len(), nil
|
||||
}
|
||||
|
||||
for _, vv := range v {
|
||||
if occ, err = find(arr, vv); err != nil {
|
||||
return 0, err
|
||||
} else if occ != -1 {
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
return 0, typeErr
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// has finds any occurrence of the values in slice or key in a map
|
||||
func Has(arr interface{}, vv ...interface{}) (b bool, err error) {
|
||||
arr = UntypedValue(arr)
|
||||
|
||||
if isMap(arr) {
|
||||
for _, v := range vv {
|
||||
if reflect.ValueOf(arr).MapIndex(reflect.ValueOf(v)).IsValid() {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
var c int
|
||||
if c, err = count(arr, vv...); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return c > 0, nil
|
||||
}
|
||||
|
||||
// hasAll finds all the occurrences in the slice
|
||||
func hasAll(arr interface{}, v ...interface{}) (b bool, err error) {
|
||||
if arr, err = toSlice(arr); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var c int
|
||||
if c, err = count(arr, v...); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return c == len(v), nil
|
||||
}
|
||||
|
||||
// find takes a value and gets the position in slice
|
||||
// if no results, returns -1
|
||||
func find(arr interface{}, v interface{}) (p int, err error) {
|
||||
if arr, err = toSlice(arr); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for p = 0; p < reflect.ValueOf(arr).Len(); p++ {
|
||||
c := reflect.ValueOf(arr)
|
||||
|
||||
if UntypedValue(c.Index(p).Interface()) == v {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return -1, nil
|
||||
}
|
||||
|
||||
// splice slices slice
|
||||
func splice(arr interface{}, s, e float64) interface{} {
|
||||
var (
|
||||
err error
|
||||
start = int(s)
|
||||
end = int(e)
|
||||
)
|
||||
|
||||
if arr, err = toSlice(arr); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
v := reflect.ValueOf(arr)
|
||||
|
||||
if start >= v.Len() {
|
||||
return v.Interface()
|
||||
}
|
||||
|
||||
if end == -1 || end > v.Len() {
|
||||
end = v.Len()
|
||||
}
|
||||
|
||||
return v.Slice(start, end).Interface()
|
||||
}
|
||||
|
||||
// sortSlice sorts slice
|
||||
func sortSlice(arr interface{}, desc bool) (out interface{}, err error) {
|
||||
if arr, err = toSlice(arr); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// sort slice of native type values
|
||||
var (
|
||||
c = reflect.ValueOf(arr)
|
||||
v = reflect.MakeSlice(c.Type(), c.Len(), c.Cap())
|
||||
vi = v.Interface()
|
||||
)
|
||||
|
||||
reflect.Copy(v, c)
|
||||
|
||||
// sortStable sorts the slice x using the provided less
|
||||
// function, keeping equal elements in their original order
|
||||
//
|
||||
// sort the array if error is nil;
|
||||
// we trap the error(s) in the outer scope from the less function,
|
||||
// and returning the last error at a time since all error will the same in almost every scenario.
|
||||
sort.SliceStable(vi, func(i, j int) bool {
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
var (
|
||||
nVal = v.Index(i)
|
||||
mVal = v.Index(j)
|
||||
)
|
||||
if desc {
|
||||
nVal = v.Index(j)
|
||||
mVal = v.Index(i)
|
||||
}
|
||||
|
||||
switch getKind(vi) {
|
||||
case reflect.String:
|
||||
return nVal.String() < mVal.String()
|
||||
case reflect.Int, reflect.Int32, reflect.Int64:
|
||||
return nVal.Int() < mVal.Int()
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return nVal.Float() < mVal.Float()
|
||||
default:
|
||||
// sort slice of typed values
|
||||
if stv, is := vi.([]TypedValue); is {
|
||||
if casted, ok := stv[i].(Comparable); ok {
|
||||
var cmp int
|
||||
cmp, err = casted.Compare(stv[j])
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if desc {
|
||||
return cmp > 0
|
||||
} else {
|
||||
return cmp < 0
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("cannot compare %s and %s: unknown state", stv[i].Type(), stv[j].Type())
|
||||
return false
|
||||
}
|
||||
}
|
||||
err = fmt.Errorf("cannot compare %s and %s: unknown state", getKind(nVal), getKind(mVal))
|
||||
return false
|
||||
}
|
||||
})
|
||||
|
||||
// returns error from less function
|
||||
if err != nil {
|
||||
return arr, err
|
||||
}
|
||||
|
||||
return vi, nil
|
||||
}
|
||||
Reference in New Issue
Block a user