From 8ac3b500773884b9e6f43a901dfc78b8d55a5929 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toma=C5=BE=20Jerman?= Date: Thu, 1 Sep 2022 15:25:21 +0200 Subject: [PATCH] WIP/POC pkg for common gval handlers --- pkg/expr/func_generic.go | 11 ++---- pkg/expr/func_time.go | 64 +++++++++------------------------ pkg/gvalfnc/generic.go | 20 +++++++++++ pkg/gvalfnc/string.go | 17 +++++++++ pkg/gvalfnc/time.go | 78 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 134 insertions(+), 56 deletions(-) create mode 100644 pkg/gvalfnc/generic.go create mode 100644 pkg/gvalfnc/string.go create mode 100644 pkg/gvalfnc/time.go diff --git a/pkg/expr/func_generic.go b/pkg/expr/func_generic.go index dd963994b..ae4d2191e 100644 --- a/pkg/expr/func_generic.go +++ b/pkg/expr/func_generic.go @@ -5,6 +5,7 @@ import ( "reflect" "github.com/PaesslerAG/gval" + "github.com/cortezaproject/corteza-server/pkg/gvalfnc" ) type ( @@ -46,15 +47,7 @@ func length(i interface{}) int { } func isNil(i interface{}) bool { - if i == nil { - return true - } - switch reflect.TypeOf(i).Kind() { - case reflect.Slice, reflect.Array, reflect.Ptr, reflect.Map: - return reflect.ValueOf(i).IsNil() - } - - return false + return gvalfnc.IsNil(i) } // empty checks values and slices diff --git a/pkg/expr/func_time.go b/pkg/expr/func_time.go index d8df175c2..11998fee2 100644 --- a/pkg/expr/func_time.go +++ b/pkg/expr/func_time.go @@ -5,8 +5,8 @@ import ( "time" "github.com/PaesslerAG/gval" + "github.com/cortezaproject/corteza-server/pkg/gvalfnc" "github.com/lestrrat-go/strftime" - "github.com/spf13/cast" ) func TimeFunctions() []gval.Language { @@ -29,11 +29,11 @@ func TimeFunctions() []gval.Language { } func now() time.Time { - return time.Now() + return gvalfnc.Now() } func isLeapYear(base interface{}) (bool, error) { - t, _, err := prepMod(base, 0) + t, _, err := gvalfnc.PrepMod(base, 0) if err != nil { return false, err } @@ -41,7 +41,7 @@ func isLeapYear(base interface{}) (bool, error) { } func isLeapDay(base interface{}) (bool, error) { - t, _, err := prepMod(base, 0) + t, _, err := gvalfnc.PrepMod(base, 0) if err != nil { return false, err } @@ -49,7 +49,7 @@ func isLeapDay(base interface{}) (bool, error) { } func isWeekDay(base interface{}) (bool, error) { - t, _, err := prepMod(base, 0) + t, _, err := gvalfnc.PrepMod(base, 0) if err != nil { return false, err } @@ -57,12 +57,12 @@ func isWeekDay(base interface{}) (bool, error) { } func earliest(f interface{}, aa ...interface{}) (*time.Time, error) { - t, _, err := prepMod(f, 0) + t, _, err := gvalfnc.PrepMod(f, 0) if err != nil { return nil, err } for _, a := range aa { - s, _, err := prepMod(a, 0) + s, _, err := gvalfnc.PrepMod(a, 0) if err != nil { return nil, err } @@ -75,12 +75,12 @@ func earliest(f interface{}, aa ...interface{}) (*time.Time, error) { } func latest(f interface{}, aa ...interface{}) (*time.Time, error) { - t, _, err := prepMod(f, 0) + t, _, err := gvalfnc.PrepMod(f, 0) if err != nil { return nil, err } for _, a := range aa { - s, _, err := prepMod(a, 0) + s, _, err := gvalfnc.PrepMod(a, 0) if err != nil { return nil, err } @@ -103,7 +103,7 @@ func modTime(base interface{}, mod interface{}) (*time.Time, error) { t *time.Time ) - t, _, err = prepMod(base, 0) + t, _, err = gvalfnc.PrepMod(base, 0) if err != nil { return nil, err } @@ -124,7 +124,7 @@ func modTime(base interface{}, mod interface{}) (*time.Time, error) { } func modDate(base interface{}, mod interface{}) (*time.Time, error) { - t, m, err := prepMod(base, mod) + t, m, err := gvalfnc.PrepMod(base, mod) if err != nil { return nil, err } @@ -134,7 +134,7 @@ func modDate(base interface{}, mod interface{}) (*time.Time, error) { } func modWeek(base interface{}, mod interface{}) (*time.Time, error) { - t, m, err := prepMod(base, mod) + t, m, err := gvalfnc.PrepMod(base, mod) if err != nil { return nil, err } @@ -144,7 +144,7 @@ func modWeek(base interface{}, mod interface{}) (*time.Time, error) { } func modMonth(base interface{}, mod interface{}) (*time.Time, error) { - t, m, err := prepMod(base, mod) + t, m, err := gvalfnc.PrepMod(base, mod) if err != nil { return nil, err } @@ -154,7 +154,7 @@ func modMonth(base interface{}, mod interface{}) (*time.Time, error) { } func modYear(base interface{}, mod interface{}) (*time.Time, error) { - t, m, err := prepMod(base, mod) + t, m, err := gvalfnc.PrepMod(base, mod) if err != nil { return nil, err } @@ -163,41 +163,11 @@ func modYear(base interface{}, mod interface{}) (*time.Time, error) { return &tmp, nil } -func prepMod(base interface{}, mod interface{}) (*time.Time, int, error) { - var ( - t *time.Time - ) - - switch auxt := base.(type) { - case time.Time: - t = &auxt - case *time.Time: - t = auxt - case string: - tt, err := cast.ToTimeE(auxt) - - if err != nil { - return nil, 0, err - } - - t = &tt - default: - return nil, 0, errors.New("unexpected input type") - } - - m, err := cast.ToIntE(mod) - if err != nil { - return nil, 0, err - } - - return t, m, nil -} - // Strftime formats time with POSIX standard format // More details here: // https://github.com/lestrrat-go/strftime#supported-conversion-specifications func strfTime(base interface{}, f string) (string, error) { - t, _, err := prepMod(base, 0) + t, _, err := gvalfnc.PrepMod(base, 0) if err != nil { return "", err @@ -212,12 +182,12 @@ func strfTime(base interface{}, f string) (string, error) { // sub returns difference between two date into milliseconds func sub(from interface{}, to interface{}) (out int64, err error) { - t1, _, err := prepMod(from, 0) + t1, _, err := gvalfnc.PrepMod(from, 0) if err != nil { return } - t2, _, err := prepMod(to, 0) + t2, _, err := gvalfnc.PrepMod(to, 0) if err != nil { return } diff --git a/pkg/gvalfnc/generic.go b/pkg/gvalfnc/generic.go new file mode 100644 index 000000000..a63f6f686 --- /dev/null +++ b/pkg/gvalfnc/generic.go @@ -0,0 +1,20 @@ +package gvalfnc + +import ( + "github.com/modern-go/reflect2" + "github.com/spf13/cast" +) + +func IsNil(i any) bool { + return reflect2.IsNil(i) +} + +func CastFloat(i any) (float64, error) { + return cast.ToFloat64E(i) +} +func CastInt(i any) (int, error) { + return cast.ToIntE(i) +} +func CastString(i any) (string, error) { + return cast.ToStringE(i) +} diff --git a/pkg/gvalfnc/string.go b/pkg/gvalfnc/string.go new file mode 100644 index 000000000..0034e4c82 --- /dev/null +++ b/pkg/gvalfnc/string.go @@ -0,0 +1,17 @@ +package gvalfnc + +import ( + "strings" + + "github.com/spf13/cast" +) + +// @todo +func ConcatStrings(parts ...any) (string, error) { + pp, err := cast.ToStringSliceE(parts) + if err != nil { + return "", err + } + + return strings.Join(pp, ""), nil +} diff --git a/pkg/gvalfnc/time.go b/pkg/gvalfnc/time.go new file mode 100644 index 000000000..ee166c833 --- /dev/null +++ b/pkg/gvalfnc/time.go @@ -0,0 +1,78 @@ +package gvalfnc + +import ( + "errors" + "time" + + "github.com/spf13/cast" +) + +func Now() time.Time { + return time.Now() +} + +func Quarter(in any) (int, error) { + t, _, err := PrepMod(in, 0) + if err != nil { + return 0, err + } + + return int(t.Month() / 4), nil +} + +func Year(in any) (int, error) { + t, _, err := PrepMod(in, 0) + if err != nil { + return 0, err + } + + return t.Year(), nil +} + +func Month(in any) (int, error) { + t, _, err := PrepMod(in, 0) + if err != nil { + return 0, err + } + + return int(t.Month()), nil +} + +func Date(in any) (int, error) { + t, _, err := PrepMod(in, 0) + if err != nil { + return 0, err + } + + return t.Day(), nil +} + +func PrepMod(base interface{}, mod interface{}) (*time.Time, int, error) { + var ( + t *time.Time + ) + + switch auxt := base.(type) { + case time.Time: + t = &auxt + case *time.Time: + t = auxt + case string: + tt, err := cast.ToTimeE(auxt) + + if err != nil { + return nil, 0, err + } + + t = &tt + default: + return nil, 0, errors.New("unexpected input type") + } + + m, err := cast.ToIntE(mod) + if err != nil { + return nil, 0, err + } + + return t, m, nil +}