|
@@ -16,6 +16,7 @@ package function
|
|
|
|
|
|
import (
|
|
|
"fmt"
|
|
|
+ "math"
|
|
|
"reflect"
|
|
|
"strconv"
|
|
|
|
|
@@ -238,3 +239,259 @@ func registerAnalyticFunc() {
|
|
|
},
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+func registerGlobalAggFunc() {
|
|
|
+ builtins["acc_avg"] = builtinFunc{
|
|
|
+ fType: ast.FuncTypeScalar,
|
|
|
+ exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
|
|
|
+ key := args[len(args)-1].(string)
|
|
|
+ keyCount := fmt.Sprintf("%s_count", key)
|
|
|
+ keySum := fmt.Sprintf("%s_sum", key)
|
|
|
+
|
|
|
+ v1, err := ctx.GetState(keyCount)
|
|
|
+ if err != nil {
|
|
|
+ return err, false
|
|
|
+ }
|
|
|
+ v2, err := ctx.GetState(keySum)
|
|
|
+ if err != nil {
|
|
|
+ return err, false
|
|
|
+ }
|
|
|
+ validData, ok := args[len(args)-2].(bool)
|
|
|
+ if !ok {
|
|
|
+ return fmt.Errorf("when arg is not a bool but got %v", args[len(args)-2]), false
|
|
|
+ }
|
|
|
+ if v1 == nil && v2 == nil {
|
|
|
+ if args[0] == nil || !validData {
|
|
|
+ return 0, true
|
|
|
+ }
|
|
|
+
|
|
|
+ v1 = float64(0)
|
|
|
+ v2 = float64(0)
|
|
|
+ } else {
|
|
|
+ if args[0] == nil || !validData {
|
|
|
+ count := v1.(float64)
|
|
|
+ sum := v2.(float64)
|
|
|
+ return sum / count, true
|
|
|
+ }
|
|
|
+ }
|
|
|
+ count := v1.(float64)
|
|
|
+ sum := v2.(float64)
|
|
|
+ count = count + 1
|
|
|
+ switch v := args[0].(type) {
|
|
|
+ case int:
|
|
|
+ sum += float64(v)
|
|
|
+ case int32:
|
|
|
+ sum += float64(v)
|
|
|
+ case int64:
|
|
|
+ sum += float64(v)
|
|
|
+ case float32:
|
|
|
+ sum += float64(v)
|
|
|
+ case float64:
|
|
|
+ sum += v
|
|
|
+ default:
|
|
|
+ return fmt.Errorf("the value should be number"), false
|
|
|
+ }
|
|
|
+ if err := ctx.PutState(keyCount, count); err != nil {
|
|
|
+ return err, false
|
|
|
+ }
|
|
|
+ if err := ctx.PutState(keySum, sum); err != nil {
|
|
|
+ return err, false
|
|
|
+ }
|
|
|
+ return sum / count, true
|
|
|
+ },
|
|
|
+ val: func(ctx api.FunctionContext, args []ast.Expr) error {
|
|
|
+ return nil
|
|
|
+ },
|
|
|
+ }
|
|
|
+ builtins["acc_max"] = builtinFunc{
|
|
|
+ fType: ast.FuncTypeScalar,
|
|
|
+ exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
|
|
|
+ key := args[len(args)-1].(string)
|
|
|
+ val, err := ctx.GetState(key)
|
|
|
+ if err != nil {
|
|
|
+ return err, false
|
|
|
+ }
|
|
|
+ validData, ok := args[len(args)-2].(bool)
|
|
|
+ if !ok {
|
|
|
+ return fmt.Errorf("when arg is not a bool but got %v", args[len(args)-2]), false
|
|
|
+ }
|
|
|
+ if val == nil {
|
|
|
+ if !validData {
|
|
|
+ return nil, false
|
|
|
+ }
|
|
|
+ val = float64(math.MinInt64)
|
|
|
+ }
|
|
|
+ m := val.(float64)
|
|
|
+ if !validData {
|
|
|
+ return m, true
|
|
|
+ }
|
|
|
+ switch v := args[0].(type) {
|
|
|
+ case int:
|
|
|
+ v1 := float64(v)
|
|
|
+ m = getMax(m, v1)
|
|
|
+ case int32:
|
|
|
+ v1 := float64(v)
|
|
|
+ m = getMax(m, v1)
|
|
|
+ case int64:
|
|
|
+ v1 := float64(v)
|
|
|
+ m = getMax(m, v1)
|
|
|
+ case float32:
|
|
|
+ v1 := float64(v)
|
|
|
+ m = getMax(m, v1)
|
|
|
+ case float64:
|
|
|
+ m = getMax(m, v)
|
|
|
+ default:
|
|
|
+ return fmt.Errorf("the value should be number"), false
|
|
|
+ }
|
|
|
+ if err := ctx.PutState(key, m); err != nil {
|
|
|
+ return err, false
|
|
|
+ }
|
|
|
+ return m, true
|
|
|
+ },
|
|
|
+ val: func(ctx api.FunctionContext, args []ast.Expr) error {
|
|
|
+ return ValidateLen(1, len(args))
|
|
|
+ },
|
|
|
+ }
|
|
|
+ builtins["acc_min"] = builtinFunc{
|
|
|
+ fType: ast.FuncTypeScalar,
|
|
|
+ exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
|
|
|
+ key := args[len(args)-1].(string)
|
|
|
+ val, err := ctx.GetState(key)
|
|
|
+ if err != nil {
|
|
|
+ return err, false
|
|
|
+ }
|
|
|
+ validData, ok := args[len(args)-2].(bool)
|
|
|
+ if !ok {
|
|
|
+ return fmt.Errorf("when arg is not a bool but got %v", args[len(args)-2]), false
|
|
|
+ }
|
|
|
+ if val == nil {
|
|
|
+ if !validData {
|
|
|
+ return nil, false
|
|
|
+ }
|
|
|
+ val = float64(math.MaxInt64)
|
|
|
+ }
|
|
|
+ m := val.(float64)
|
|
|
+ if !validData {
|
|
|
+ return m, true
|
|
|
+ }
|
|
|
+ switch v := args[0].(type) {
|
|
|
+ case int:
|
|
|
+ v1 := float64(v)
|
|
|
+ m = getMin(m, v1)
|
|
|
+ case int32:
|
|
|
+ v1 := float64(v)
|
|
|
+ m = getMin(m, v1)
|
|
|
+ case int64:
|
|
|
+ v1 := float64(v)
|
|
|
+ m = getMin(m, v1)
|
|
|
+ case float32:
|
|
|
+ v1 := float64(v)
|
|
|
+ m = getMin(m, v1)
|
|
|
+ case float64:
|
|
|
+ m = getMin(m, v)
|
|
|
+ default:
|
|
|
+ return fmt.Errorf("the value should be number"), false
|
|
|
+ }
|
|
|
+ if err := ctx.PutState(key, m); err != nil {
|
|
|
+ return err, false
|
|
|
+ }
|
|
|
+ return m, true
|
|
|
+ },
|
|
|
+ val: func(ctx api.FunctionContext, args []ast.Expr) error {
|
|
|
+ return ValidateLen(1, len(args))
|
|
|
+ },
|
|
|
+ }
|
|
|
+ builtins["acc_sum"] = builtinFunc{
|
|
|
+ fType: ast.FuncTypeScalar,
|
|
|
+ exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
|
|
|
+ key := args[len(args)-1].(string)
|
|
|
+ val, err := ctx.GetState(key)
|
|
|
+ if err != nil {
|
|
|
+ return err, false
|
|
|
+ }
|
|
|
+ validData, ok := args[len(args)-2].(bool)
|
|
|
+ if !ok {
|
|
|
+ return fmt.Errorf("when arg is not a bool but got %v", args[len(args)-2]), false
|
|
|
+ }
|
|
|
+ if val == nil {
|
|
|
+ if !validData {
|
|
|
+ return nil, false
|
|
|
+ }
|
|
|
+ val = float64(0)
|
|
|
+ }
|
|
|
+ accu := val.(float64)
|
|
|
+ if !validData {
|
|
|
+ return accu, true
|
|
|
+ }
|
|
|
+ switch sumValue := args[0].(type) {
|
|
|
+ case int:
|
|
|
+ accu += float64(sumValue)
|
|
|
+ case int32:
|
|
|
+ accu += float64(sumValue)
|
|
|
+ case int64:
|
|
|
+ accu += float64(sumValue)
|
|
|
+ case float32:
|
|
|
+ accu += float64(sumValue)
|
|
|
+ case float64:
|
|
|
+ accu += sumValue
|
|
|
+ default:
|
|
|
+ return fmt.Errorf("the value should be number"), false
|
|
|
+ }
|
|
|
+ if err := ctx.PutState(key, accu); err != nil {
|
|
|
+ return err, false
|
|
|
+ }
|
|
|
+ return accu, true
|
|
|
+ },
|
|
|
+ val: func(ctx api.FunctionContext, args []ast.Expr) error {
|
|
|
+ return ValidateLen(1, len(args))
|
|
|
+ },
|
|
|
+ }
|
|
|
+ builtins["acc_count"] = builtinFunc{
|
|
|
+ fType: ast.FuncTypeScalar,
|
|
|
+ exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) {
|
|
|
+ key := args[len(args)-1].(string)
|
|
|
+ val, err := ctx.GetState(key)
|
|
|
+ if err != nil {
|
|
|
+ return err, false
|
|
|
+ }
|
|
|
+ validData, ok := args[len(args)-2].(bool)
|
|
|
+ if !ok {
|
|
|
+ return fmt.Errorf("when arg is not a bool but got %v", args[len(args)-2]), false
|
|
|
+ }
|
|
|
+ if val == nil {
|
|
|
+ if !validData {
|
|
|
+ return nil, false
|
|
|
+ }
|
|
|
+ val = 0
|
|
|
+ }
|
|
|
+ cnt := val.(int)
|
|
|
+ if !validData {
|
|
|
+ return cnt, true
|
|
|
+ }
|
|
|
+ if args[0] != nil {
|
|
|
+ cnt = cnt + 1
|
|
|
+ }
|
|
|
+ if err := ctx.PutState(key, cnt); err != nil {
|
|
|
+ return err, false
|
|
|
+ }
|
|
|
+ return cnt, true
|
|
|
+ },
|
|
|
+ val: func(ctx api.FunctionContext, args []ast.Expr) error {
|
|
|
+ return ValidateLen(1, len(args))
|
|
|
+ },
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func getMax(a, b float64) float64 {
|
|
|
+ if a > b {
|
|
|
+ return a
|
|
|
+ }
|
|
|
+ return b
|
|
|
+}
|
|
|
+
|
|
|
+func getMin(a, b float64) float64 {
|
|
|
+ if a < b {
|
|
|
+ return a
|
|
|
+ }
|
|
|
+ return b
|
|
|
+}
|