You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: doc/spec.adoc
+51-15Lines changed: 51 additions & 15 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -64,6 +64,8 @@ json-formula functions:
64
64
65
65
* expression: A string prefixed with an ampersand (`&`) character
66
66
67
+
This specification uses the term "scalar" to refer to any value that is not an array, object or expression. Scalars include numbers, strings, booleans, and null values.
68
+
67
69
=== Type Coercion
68
70
69
71
If the supplied data is not correct for the execution context, json-formula will attempt to coerce the data to the correct type. Coercion will occur in these contexts:
@@ -73,7 +75,8 @@ If the supplied data is not correct for the execution context, json-formula will
73
75
* Operands of the union operator (`~`) shall be coerced to an array
74
76
* The left-hand operand of ordering comparison operators (`>`, `>=`, `<`, `\<=`) must be a string or number. Any other type shall be coerced to a number.
75
77
* If the operands of an ordering comparison are different, they shall both be coerced to a number
76
-
* Parameters to functions shall be coerced to the expected type as long as the expected type is a single choice. If the function signature allows multiple types for a parameter e.g. either string or array, then coercion will not occur.
78
+
* Parameters to functions shall be coerced when there is a single viable coercion available. For example, if a null value is provided to a function that accepts a number or string, then coercion shall not happen, since a null value can be coerced to both types. Conversely if a string is provided to a function that accepts a number or array of numbers, then the string shall be coerced to a number, since there is no supported coercion to convert it to an array of numbers.
79
+
* When functions accept a typed array, the function rules determine whether coercion may occur. Some functions (e.g. `avg()`) ignore array members of the wrong type. Other functions (e.g. `abs()`) coerce array members. If coercion may occur, then any provided array will have each of its members coerced to the expected type. e.g., if the input array is `[2,3,"6"]` and an array of numbers is expected, the array will be coerced to `[2,3,6]`.
77
80
78
81
The equality and inequality operators (`=`, `==`, `!=`, `<>`) do **not** perform type coercion. If operands are different types, the values are considered not equal.
79
82
@@ -114,19 +117,23 @@ In all cases except ordering comparison, if the coercion is not possible, a `Typ
114
117
| string | array | create a single-element array with the string
115
118
| boolean | array | create a single-element array with the boolean
116
119
| object | array | Not supported
117
-
| null | array | Empty array
120
+
| null | array | Not supported
118
121
| number | object | Not supported
119
122
| string | object | Not supported
120
123
| boolean | object | Not supported
121
124
| array | object | Not supported. Use: `fromEntries(entries(array))`
122
-
| null | object | Empty object
125
+
| null | object | Not supported
123
126
| number | boolean | zero is false, all other numbers are true
124
127
| string | boolean | Empty string is false, populated strings are true
125
128
| array | boolean | Empty array is false, populated arrays are true
126
129
| object | boolean | Empty object is false, populated objects are true
127
130
| null | boolean | false
128
131
|===
129
132
133
+
An array may be coerced to another type of array as long as there is a supported coercion for the array content. For examples, just as a string can be coerced to a number, an array of strings may be coerced to an array of numbers.
134
+
135
+
Note that while strings, numbers and booleans may be coerced to arrays, they may not be coerced to a different type within that array. For example, a number cannot be coerced to an array of strings -- even though a number can be coerced to a string, and a string can be coerced to an array of strings.
136
+
130
137
[discrete]
131
138
==== Examples
132
139
@@ -135,7 +142,7 @@ In all cases except ordering comparison, if the coercion is not possible, a `Typ
135
142
eval("\"$123.00\" + 1", {}) -> TypeError
136
143
eval("truth is " & `true`, {}) -> "truth is true"
137
144
eval(2 + `true`, {}) -> 3
138
-
eval(avg("20"), {}) -> 20
145
+
eval(avg(["20", "30"]), {}) -> 25
139
146
----
140
147
141
148
=== Date and Time Values
@@ -433,7 +440,7 @@ The numeric and concatenation operators (`+`, `-`, `{asterisk}`, `/`, `&`) have
433
440
434
441
* When both operands are arrays, a new array is returned where the elements are populated by applying the operator on each element of the left operand array with the corresponding element from the right operand array
435
442
* If both operands are arrays and they do not have the same size, the shorter array is padded with null values
436
-
* If one operand is an array and one is a scalar value, a new array is returned where the operator is applied with the scalar against each element in the array
443
+
* If one operand is an array and one is a scalar value, the scalar operand will be converted to an array by repeating the value to the same size array as the other operand
437
444
438
445
[source%unbreakable]
439
446
----
@@ -452,7 +459,7 @@ The union operator (`~`) returns an array formed by concatenating the contents o
@@ -735,8 +742,9 @@ operator follows these processing steps:
735
742
* The result array is returned as a <<Projections,projection>>
736
743
737
744
Once the flattening operation has been performed, subsequent operations
738
-
are projected onto the flattened array. The difference between a bracketed wildcard (`[{asterisk}]`) and flatten (`[]`) is that
739
-
flatten will first merge sub-arrays.
745
+
are projected onto the flattened array.
746
+
747
+
A bracketed wildcard (`[{asterisk}]`) and flatten (`[]`) behave similarly in that they produce a projection from an array. The only difference is that a bracketed wildcard preserves the original array structure while flatten collapses one level of array structure.
740
748
741
749
[discrete]
742
750
==== Examples
@@ -1194,27 +1202,55 @@ output.
1194
1202
return_type function_name2(type1|type2 $argname)
1195
1203
----
1196
1204
1205
+
=== Function parameters
1206
+
1197
1207
Functions support the set of standard json-formula <<Data Types, data types>>. If the resolved arguments cannot be coerced to
1198
1208
match the types specified in the signature, a `TypeError` error occurs.
1199
1209
1200
1210
As a shorthand, the type `any` is used to indicate that the function argument can be
1201
-
of any of (`array|object|number|string|boolean|null`).
1211
+
any of (`array|object|number|string|boolean|null`).
1202
1212
1203
1213
The expression type, (denoted by `&expression`), is used to specify an
1204
1214
expression that is not immediately evaluated. Instead, a reference to that
1205
-
expression is provided to the function being called. The function can then apply the expression reference as needed. It is semantically similar
1215
+
expression is provided to the function. The function can then apply the expression reference as needed. It is semantically similar
1206
1216
to an https://en.wikipedia.org/wiki/Anonymous_function[anonymous function]. See the <<_sortBy, sortBy()>> function for an example of the expression type.
1207
1217
1208
-
The result of the `functionExpression` is the result returned by the
1209
-
function call. If a `functionExpression` is evaluated for a function that
1210
-
does not exist, a `FunctionError` error is raised.
1211
-
1212
-
Functions can either have a specific arity or be variadic with a minimum
1218
+
Function parameters can either have a specific arity or be variadic with a minimum
1213
1219
number of arguments. If a `functionExpression` is encountered where the
1214
1220
arity does not match, or the minimum number of arguments for a variadic function
1215
1221
is not provided, or too many arguments are provided, then a
1216
1222
`FunctionError` error is raised.
1217
1223
1224
+
The result of the `functionExpression` is the result returned by the
1225
+
function call. If a `functionExpression` is evaluated for a function that
1226
+
does not exist, a `FunctionError` error is raised.
1227
+
1228
+
==== Array Parameters
1229
+
Many functions that process scalar values also allow for the processing of arrays of values. For example, the `round()` function may be called to process a single value: `round(1.2345, 2)` or to process an array of values: `round([1.2345, 2.3456], 2)`. The first call will return a single value, the second call will return an array of values.
1230
+
When processing arrays of values, and where there is more than one parameter, each parameter is converted to an array so that the function processes each value in the set of arrays. From our example above, the call to `round([1.2345, 2.3456], 2)` would be processed as if it were `round([1.2345, 2.3456], [2, 2])`, and the result would be the same as: `[round(1.2345, 2), round(2.3456, 2)]`.
1231
+
1232
+
Functions that accept array parameters will also accept nested arrays. With nested arrays, aggregating functions (min(), max(), avg(), sum() etc.) will flatten the arrays. e.g.
1233
+
1234
+
`avg([2.1, 3.1, [4.1, 5.1]])` will be processed as `avg([2.1, 3.1, 4.1, 5.1])` and return `3.6`.
1235
+
1236
+
Non-aggregating functions will return the same array hierarchy. e.g.
1237
+
1238
+
`upper("a", ["b"]]) => ["A", ["B"]]`
1239
+
`round([2.12, 3.12, [4.12, 5.12]], 1)` will be processed as `round([2.12, 3.12, [4.12, 5.12]], [1, 1, [1, 1]])` and return `[2.1, 3.1, [4.1, 5.1]] `
1240
+
1241
+
These array balancing rules apply when any parameter is an array:
1242
+
1243
+
* All parameters will be treated as arrays
1244
+
* Any scalar parameters will be converted to an array by repeating the scalar value to the length of the longest array
1245
+
* All array parameters will be padded to the length of the longest array by adding null values
1246
+
* The function will return an array which is the result of iterating over the elements of the arrays and applying the function logic on the values at the same index.
1247
+
1248
+
With nested arrays:
1249
+
* Nested arrays will be flattened for aggregating functions
1250
+
* Non-aggregating functions will preserve the array hierarchy and will apply the balancing rules to each element of the nested arrays
1251
+
1252
+
=== Function evaluation
1253
+
1218
1254
Functions are evaluated in applicative order:
1219
1255
- Each argument must be an expression
1220
1256
- Each argument expression must be evaluated before evaluating the
0 commit comments