-
Notifications
You must be signed in to change notification settings - Fork 783
/
method_ctor.go
89 lines (77 loc) · 2.42 KB
/
method_ctor.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
package query
import (
"fmt"
"sort"
"golang.org/x/xerrors"
)
//------------------------------------------------------------------------------
func methodWithDynamicArgs(args []interface{}, target Function, ctor MethodCtor) Function {
return closureFn(func(ctx FunctionContext) (interface{}, error) {
dynArgs := make([]interface{}, 0, len(args))
for i, dArg := range args {
if fArg, isDyn := dArg.(Function); isDyn {
res, err := fArg.Exec(ctx)
if err != nil {
return nil, xerrors.Errorf("failed to extract input arg %v: %w", i, err)
}
dynArgs = append(dynArgs, res)
} else {
dynArgs = append(dynArgs, dArg)
}
}
dynFunc, err := ctor(target, dynArgs...)
if err != nil {
return nil, err
}
return dynFunc.Exec(ctx)
})
}
func enableMethodDynamicArgs(fn MethodCtor) MethodCtor {
return func(target Function, args ...interface{}) (Function, error) {
for _, arg := range args {
if _, isDyn := arg.(Function); isDyn {
return methodWithDynamicArgs(args, target, fn), nil
}
}
return fn(target, args...)
}
}
func checkMethodArgs(fn MethodCtor, checks ...ArgCheckFn) MethodCtor {
return func(target Function, args ...interface{}) (Function, error) {
for _, check := range checks {
if err := check(args); err != nil {
return nil, err
}
}
return fn(target, args...)
}
}
//------------------------------------------------------------------------------
// MethodCtor constructs a new method from a target function and input args.
type MethodCtor func(target Function, args ...interface{}) (Function, error)
// RegisterMethod to be accessible from Bloblang queries. Returns an empty
// struct in order to allow inline calls.
func RegisterMethod(name string, allowDynamicArgs bool, ctor MethodCtor, checks ...ArgCheckFn) struct{} {
if len(checks) > 0 {
ctor = checkMethodArgs(ctor, checks...)
}
if allowDynamicArgs {
ctor = enableMethodDynamicArgs(ctor)
}
if _, exists := methods[name]; exists {
panic(fmt.Sprintf("Conflicting method name: %v", name))
}
methods[name] = ctor
return struct{}{}
}
var methods = map[string]MethodCtor{}
// ListMethods returns a slice of method names, sorted alphabetically.
func ListMethods() []string {
methodNames := make([]string, 0, len(methods))
for k := range methods {
methodNames = append(methodNames, k)
}
sort.Strings(methodNames)
return methodNames
}
//------------------------------------------------------------------------------