mirror of
				https://github.com/chaisql/chai.git
				synced 2025-10-28 01:41:35 +08:00 
			
		
		
		
	fn: add objects.fields
This commit is contained in:
		| @@ -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.", | ||||||
|  | } | ||||||
|   | |||||||
| @@ -29,6 +29,7 @@ func DefaultPackages() Packages { | |||||||
| 		"":        BuiltinDefinitions(), | 		"":        BuiltinDefinitions(), | ||||||
| 		"math":    MathFunctions(), | 		"math":    MathFunctions(), | ||||||
| 		"strings": StringsDefinitions(), | 		"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
	 Asdine El Hrychy
					Asdine El Hrychy