mirror of
https://github.com/chaisql/chai.git
synced 2025-11-01 11:22:42 +08:00
fn: add objects.fields
This commit is contained in:
@@ -3,9 +3,10 @@ package doc
|
||||
type functionDocs map[string]string
|
||||
|
||||
var packageDocs = map[string]functionDocs{
|
||||
"strings": stringsDocs,
|
||||
"math": mathDocs,
|
||||
"": builtinDocs,
|
||||
"math": mathDocs,
|
||||
"strings": stringsDocs,
|
||||
"objects": objectsDocs,
|
||||
}
|
||||
|
||||
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",
|
||||
"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.",
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ func DefaultPackages() Packages {
|
||||
"": BuiltinDefinitions(),
|
||||
"math": MathFunctions(),
|
||||
"strings": StringsDefinitions(),
|
||||
"objects": ObjectsDefinitions(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
73
internal/expr/functions/object.go
Normal file
73
internal/expr/functions/object.go
Normal 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)
|
||||
}
|
||||
78
internal/sqltests/SELECT/objects/fields.sql
Normal file
78
internal/sqltests/SELECT/objects/fields.sql
Normal 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"]
|
||||
}
|
||||
*/
|
||||
35
internal/sqltests/expr/objects.sql
Normal file
35
internal/sqltests/expr/objects.sql
Normal 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
|
||||
|
||||
Reference in New Issue
Block a user