fn: add objects.fields

This commit is contained in:
Asdine El Hrychy
2023-12-03 09:17:22 +04:00
parent 31dbf28801
commit 13a91997e7
5 changed files with 194 additions and 2 deletions

View File

@@ -3,9 +3,10 @@ package doc
type functionDocs map[string]string type functionDocs map[string]string
var packageDocs = map[string]functionDocs{ var packageDocs = map[string]functionDocs{
"strings": stringsDocs,
"math": mathDocs,
"": builtinDocs, "": builtinDocs,
"math": mathDocs,
"strings": stringsDocs,
"objects": objectsDocs,
} }
var builtinDocs = functionDocs{ var builtinDocs = functionDocs{
@@ -39,3 +40,7 @@ var stringsDocs = functionDocs{
"ltrim": "The ltrim function returns arg1 with leading characters removed. space by default or arg2", "ltrim": "The ltrim function returns arg1 with leading characters removed. space by default or arg2",
"rtrim": "The rtrim function returns arg1 with trailing characters removed. space by default or arg2", "rtrim": "The rtrim function returns arg1 with trailing characters removed. space by default or arg2",
} }
var objectsDocs = functionDocs{
"fields": "The fields function returns the top-level fields of arg1 if arg1 evals to object, otherwise it returns null. It returns an array of TEXT.",
}

View File

@@ -29,6 +29,7 @@ func DefaultPackages() Packages {
"": BuiltinDefinitions(), "": BuiltinDefinitions(),
"math": MathFunctions(), "math": MathFunctions(),
"strings": StringsDefinitions(), "strings": StringsDefinitions(),
"objects": ObjectsDefinitions(),
} }
} }

View File

@@ -0,0 +1,73 @@
package functions
import (
"fmt"
"github.com/chaisql/chai/internal/environment"
"github.com/chaisql/chai/internal/expr"
"github.com/chaisql/chai/internal/object"
"github.com/chaisql/chai/internal/types"
)
var objectsFunctions = Definitions{
"fields": &definition{
name: "fields",
arity: 1,
constructorFn: func(args ...expr.Expr) (expr.Function, error) {
return &ObjectFields{Expr: args[0]}, nil
},
},
}
func ObjectsDefinitions() Definitions {
return objectsFunctions
}
// ObjectFields implements the objects.fields function
// which returns the list of top-level fields of an object.
// If the argument is not an object, it returns null.
type ObjectFields struct {
Expr expr.Expr
}
func (s *ObjectFields) Eval(env *environment.Environment) (types.Value, error) {
val, err := s.Expr.Eval(env)
if err != nil {
return nil, err
}
if val.Type() != types.ObjectValue {
return types.NewNullValue(), nil
}
obj := types.As[types.Object](val)
var fields []string
err = obj.Iterate(func(k string, _ types.Value) error {
fields = append(fields, k)
return nil
})
if err != nil {
return nil, err
}
return types.NewArrayValue(object.NewArrayFromSlice(fields)), nil
}
func (s *ObjectFields) IsEqual(other expr.Expr) bool {
if other == nil {
return false
}
o, ok := other.(*ObjectFields)
if !ok {
return false
}
return expr.Equal(s.Expr, o.Expr)
}
func (s *ObjectFields) Params() []expr.Expr { return []expr.Expr{s.Expr} }
func (s *ObjectFields) String() string {
return fmt.Sprintf("objects.fields(%v)", s.Expr)
}

View File

@@ -0,0 +1,78 @@
-- setup:
CREATE TABLE test(
a TEXT,
b INT,
c BOOL,
d DOUBLE,
e ARRAY,
f OBJECT
);
INSERT INTO test (a, b, c, d, e, f) VALUES (
"FOO",
42,
true,
42.42,
["A", "b", "C", "d", "E"],
{
a: "HELLO",
b: "WorlD"
}
);
-- test: TEXT value
SELECT objects.fields(a) FROM test;
/* result:
{
"objects.fields(a)": NULL
}
*/
-- test: INT value
SELECT objects.fields(b) FROM test;
/* result:
{
"objects.fields(b)": NULL
}
*/
-- test: BOOL value
SELECT objects.fields(c) FROM test;
/* result:
{
"objects.fields(c)": NULL
}
*/
-- test: DOUBLE value
SELECT objects.fields(d) FROM test;
/* result:
{
"objects.fields(d)": NULL
}
*/
-- test: ARRAY value
SELECT objects.fields(e) FROM test;
/* result:
{
"objects.fields(e)": NULL
}
*/
-- test: OBJECT value
SELECT objects.fields(f) FROM test;
/* result:
{
"objects.fields(f)": ["a", "b"]
}
*/
-- test: wildcard
SELECT objects.fields(*) FROM test;
/* result:
{
"objects.fields(*)": ["a", "b", "c", "d", "e", "f"]
}
*/

View File

@@ -0,0 +1,35 @@
-- test: objects.fields
> objects.fields({})
[]
> objects.fields({a: 1})
['a']
> objects.fields({a: 1, b: {c: 2}})
['a', 'b']
> objects.fields(NULL)
NULL
> objects.fields(true)
NULL
> objects.fields(false)
NULL
> objects.fields(1)
NULL
> objects.fields(1.0)
NULL
> objects.fields('hello')
NULL
> objects.fields('\xAA')
NULL
> objects.fields([])
NULL