From bba4c0a63006e936644301483d6f7a0d29283f37 Mon Sep 17 00:00:00 2001 From: Asdine El Hrychy Date: Sun, 25 Jul 2021 22:35:18 -0400 Subject: [PATCH] Add typeof function --- internal/expr/functions/builtins.go | 41 +++++++++++++++++++ internal/expr/functions/builtins_test.go | 5 +++ .../functions/testdata/builtin_functions.sql | 36 ++++++++++++++++ 3 files changed, 82 insertions(+) create mode 100644 internal/expr/functions/testdata/builtin_functions.sql diff --git a/internal/expr/functions/builtins.go b/internal/expr/functions/builtins.go index 785e2a3e2..15bdb559d 100644 --- a/internal/expr/functions/builtins.go +++ b/internal/expr/functions/builtins.go @@ -11,6 +11,13 @@ import ( ) var builtinFunctions = Definitions{ + "typeof": &definition{ + name: "typeof", + arity: 1, + constructorFn: func(args ...expr.Expr) (expr.Function, error) { + return &TypeOf{Expr: args[0]}, nil + }, + }, "pk": &definition{ name: "pk", arity: 0, @@ -60,6 +67,40 @@ func BuiltinDefinitions() Definitions { return builtinFunctions } +type TypeOf struct { + Expr expr.Expr +} + +func (t *TypeOf) Eval(env *environment.Environment) (types.Value, error) { + v, err := t.Expr.Eval(env) + if err != nil { + return nil, err + } + + return types.NewTextValue(v.Type().String()), nil +} + +// IsEqual compares this expression with the other expression and returns +// true if they are equal. +func (t *TypeOf) IsEqual(other expr.Expr) bool { + if other == nil { + return false + } + + o, ok := other.(*TypeOf) + if !ok { + return false + } + + return expr.Equal(t.Expr, o.Expr) +} + +func (t *TypeOf) Params() []expr.Expr { return []expr.Expr{t.Expr} } + +func (t *TypeOf) String() string { + return stringutil.Sprintf("typeof(%v)", t.Expr) +} + // PK represents the pk() function. // It returns the primary key of the current document. type PK struct{} diff --git a/internal/expr/functions/builtins_test.go b/internal/expr/functions/builtins_test.go index c98723605..7ba5e6e43 100644 --- a/internal/expr/functions/builtins_test.go +++ b/internal/expr/functions/builtins_test.go @@ -2,6 +2,7 @@ package functions_test import ( "bytes" + "path/filepath" "testing" "github.com/genjidb/genji/document" @@ -56,3 +57,7 @@ func TestPk(t *testing.T) { }) } } + +func TestBuiltinFunctions(t *testing.T) { + testutil.ExprRunner(t, filepath.Join("testdata", "builtin_functions.sql")) +} diff --git a/internal/expr/functions/testdata/builtin_functions.sql b/internal/expr/functions/testdata/builtin_functions.sql new file mode 100644 index 000000000..191c1ca3f --- /dev/null +++ b/internal/expr/functions/testdata/builtin_functions.sql @@ -0,0 +1,36 @@ +-- test: typeof +! typeof() + +! typeof(a) +'field not found' + +> typeof(1) +'integer' + +> typeof(1 + 1) +'integer' + +> typeof(2.0) +'double' + +> typeof(2.0) +'double' + +> typeof(true) +'bool' + +> typeof('hello') +'text' + +> typeof('\xAA') +'blob' + +> typeof([]) +'array' + +> typeof({}) +'document' + +> typeof(NULL) +'null' +