From fe9367fb16fe1dda7bb73bdfe57c13cd319b812d Mon Sep 17 00:00:00 2001 From: Jason Lyu Date: Fri, 14 Jul 2023 11:32:30 +0800 Subject: [PATCH] feat(sql): add `to_seconds` function (#2093) Signed-off-by: xjasonlyu --- .../sqls/functions/transform_functions.md | 8 +++++ .../sqls/functions/transform_functions.md | 8 +++++ internal/binder/function/funcs_misc.go | 12 +++++++ internal/binder/function/funcs_misc_test.go | 31 +++++++++++++++++++ 4 files changed, 59 insertions(+) diff --git a/docs/en_US/sqls/functions/transform_functions.md b/docs/en_US/sqls/functions/transform_functions.md index 2a1ffb93cc..cf75266b71 100644 --- a/docs/en_US/sqls/functions/transform_functions.md +++ b/docs/en_US/sqls/functions/transform_functions.md @@ -32,6 +32,14 @@ Convert a time value to a time in the corresponding time zone. The time zone par > Note: To use this function in an alpine-based environment, you need to ensure that the time zone data has been properly installed (e.g. `apk add tzdata`). +## TO_SECONDS + +```text +to_seconds(col) +``` + +`to_seconds` converts col to a datetime first and returns it as a Unix time, the number of seconds elapsed since January 1, 1970 UTC. + ## ENCODE ```text diff --git a/docs/zh_CN/sqls/functions/transform_functions.md b/docs/zh_CN/sqls/functions/transform_functions.md index 358188ee29..fee6132bfc 100644 --- a/docs/zh_CN/sqls/functions/transform_functions.md +++ b/docs/zh_CN/sqls/functions/transform_functions.md @@ -30,6 +30,14 @@ convert_tz(col, "Asia/Shanghai") > 注意:在基于 alpine 的环境里使用该函数,需要确保已经正确安装(`apk add tzdata`)了时区数据。 +## TO_SECONDS + +```text +to_seconds(col) +``` + +`to_seconds` 首先将 col 转换为日期时间并将其作为 Unix 时间返回,即自 1970 年 1 月 1 日 UTC 以来经过的秒数。 + ## CHR ```text diff --git a/internal/binder/function/funcs_misc.go b/internal/binder/function/funcs_misc.go index 76c63fe934..182d47ee53 100644 --- a/internal/binder/function/funcs_misc.go +++ b/internal/binder/function/funcs_misc.go @@ -91,6 +91,18 @@ func registerMiscFunc() { }, check: returnNilIfHasAnyNil, } + builtins["to_seconds"] = builtinFunc{ + fType: ast.FuncTypeScalar, + exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) { + t, err := cast.InterfaceToTime(args[0], "") + if err != nil { + return err, false + } + return t.Unix(), true + }, + val: ValidateOneArg, + check: returnNilIfHasAnyNil, + } builtins["to_json"] = builtinFunc{ fType: ast.FuncTypeScalar, exec: func(ctx api.FunctionContext, args []interface{}) (interface{}, bool) { diff --git a/internal/binder/function/funcs_misc_test.go b/internal/binder/function/funcs_misc_test.go index 236d37e7b7..a8a62100aa 100644 --- a/internal/binder/function/funcs_misc_test.go +++ b/internal/binder/function/funcs_misc_test.go @@ -147,6 +147,37 @@ func TestCoalesceExec(t *testing.T) { } } +func TestToSeconds(t *testing.T) { + f, ok := builtins["to_seconds"] + if !ok { + t.Fatal("builtin not found") + } + contextLogger := conf.Log.WithField("rule", "testExec") + ctx := kctx.WithValue(kctx.Background(), kctx.LoggerKey, contextLogger) + tempStore, _ := state.CreateStore("mockRule0", api.AtMostOnce) + fctx := kctx.NewDefaultFuncContext(ctx.WithMeta("mockRule0", "test", tempStore), 2) + tests := []struct { + args []interface{} + result interface{} + }{ + { // 0 + args: []interface{}{ + time.Unix(1e9, 0), + }, + result: int64(1e9), + }, { // 1 + args: []interface{}{ + nil, + }, + result: errors.New("unsupported type to convert to timestamp "), + }, + } + for _, tt := range tests { + result, _ := f.exec(fctx, tt.args) + assert.Equal(t, tt.result, result) + } +} + func TestToJson(t *testing.T) { f, ok := builtins["to_json"] if !ok {