@@ -822,8 +822,9 @@ In `functions.go`, add to `collectionLib.CompileOptions()`:
822822 cel.Overload (" default_any_any" ,
823823 []*cel.Type {cel.DynType , cel.DynType },
824824 cel.DynType ,
825+ cel.OverloadIsNonStrict (),
825826 cel.BinaryBinding (func (lhs, rhs ref.Val ) ref.Val {
826- if types.IsError (lhs) || types.IsUnknown (lhs) {
827+ if types.IsError (lhs) || types.IsUnknown (lhs) || lhs == types. NullValue {
827828 return rhs
828829 }
829830 return lhs
@@ -836,20 +837,20 @@ In `functions.go`, add to `collectionLib.CompileOptions()`:
836837 cel.ListType (cel.DynType ),
837838 cel.UnaryBinding (func (val ref.Val ) ref.Val {
838839 list := val.(traits.Lister )
839- var result []ref. Val
840+ var result []any
840841 it := list.Iterator ()
841842 for it.HasNext () == types.True {
842843 item := it.Next ()
843844 if sub , ok := item.(traits.Lister ); ok {
844845 subIt := sub.Iterator ()
845846 for subIt.HasNext () == types.True {
846- result = append (result, subIt.Next ())
847+ result = append (result, refToNative ( subIt.Next () ))
847848 }
848849 } else {
849- result = append (result, item)
850+ result = append (result, refToNative ( item) )
850851 }
851852 }
852- return types.DefaultTypeAdapter .NativeToValue (nativeSlice ( result) )
853+ return types.DefaultTypeAdapter .NativeToValue (result)
853854 }),
854855 ),
855856 ),
@@ -974,11 +975,13 @@ func (l *jsonLib) CompileOptions() []cel.EnvOption {
974975 cel.DynType ,
975976 cel.UnaryBinding (func (val ref.Val ) ref.Val {
976977 s := string (val.(types.String ))
978+ dec := json.NewDecoder (strings.NewReader (s))
979+ dec.UseNumber ()
977980 var result any
978- if err := json. Unmarshal ([] byte (s), &result); err != nil {
981+ if err := dec. Decode ( &result); err != nil {
979982 return types.NewErr (" jsonDecode: %v " , err)
980983 }
981- return types.DefaultTypeAdapter .NativeToValue (result)
984+ return types.DefaultTypeAdapter .NativeToValue (normalizeJSONNumbers ( result) )
982985 }),
983986 ),
984987 ),
@@ -1091,11 +1094,20 @@ func (l *timeLib) CompileOptions() []cel.EnvOption {
10911094 cel.TimestampType ,
10921095 cel.UnaryBinding (func (val ref.Val ) ref.Val {
10931096 s := string (val.(types.String ))
1094- t , err := time.Parse (time.RFC3339 , s)
1095- if err != nil {
1096- return types.NewErr (" parseTimestamp: %v " , err)
1097+ layouts := []string {
1098+ time.RFC3339 ,
1099+ time.RFC3339Nano ,
1100+ " 2006-01-02T15:04:05" ,
1101+ " 2006-01-02" ,
1102+ " 01/02/2006" ,
1103+ " Jan 2, 2006" ,
1104+ }
1105+ for _ , layout := range layouts {
1106+ if t , err := time.Parse (layout, s); err == nil {
1107+ return types.Timestamp {Time: t}
1108+ }
10971109 }
1098- return types.Timestamp {Time: t}
1110+ return types.NewErr ( " parseTimestamp: unable to parse %q (tried RFC3339, ISO 8601 date, and common formats) " , s)
10991111 }),
11001112 ),
11011113 ),
@@ -1258,27 +1270,29 @@ In `examples/data-transform-api-to-db.yaml`:
12581270``` yaml
12591271name : data-transform-api-to-db
12601272description : >
1261- Fetches user data from an API, transforms each record using CEL
1262- expressions to match a database schema, and inserts the normalized
1263- records into Postgres. Demonstrates map(), obj(), toLower(), and
1264- type coercion without requiring an AI model.
1273+ Fetches a user from an API, transforms the record using CEL expressions
1274+ to match a database schema, and inserts the normalized data into Postgres.
1275+ Demonstrates toLower() and string functions without requiring an AI model.
12651276
12661277steps :
1267- - name : fetch-users
1278+ - name : fetch-user
12681279 action : http/request
12691280 timeout : " 15s"
12701281 params :
12711282 method : GET
1272- url : " https://jsonplaceholder.typicode.com/users"
1283+ url : " https://jsonplaceholder.typicode.com/users/1 "
12731284 headers :
12741285 Accept : " application/json"
12751286
1276- - name : store-users
1287+ - name : store-user
12771288 action : postgres/query
12781289 credential : app-db
12791290 params :
12801291 query : " INSERT INTO users (username, email, city) VALUES ($1, $2, $3)"
1281- params : " {{ steps['fetch-users'].output.json.map(u, [u.username.toLower(), u.email.toLower(), u.address.city]) }}"
1292+ args :
1293+ - " {{ steps['fetch-user'].output.json.username.toLower() }}"
1294+ - " {{ steps['fetch-user'].output.json.email.toLower() }}"
1295+ - " {{ steps['fetch-user'].output.json.address.city }}"
12821296` ` `
12831297
12841298- [ ] **Step 2: Create AI enrichment example**
@@ -1346,7 +1360,7 @@ steps:
13461360 query: >
13471361 INSERT INTO urgent_tickets (priority, category, products, raw_body)
13481362 VALUES ($1, $2, $3, $4)
1349- params :
1363+ args :
13501364 - "{{ steps.classify.output.json.priority }}"
13511365 - "{{ steps.classify.output.json.category }}"
13521366 - "{{ jsonEncode(steps.classify.output.json.products) }}"
0 commit comments