Architecture - Available transformation functions
Documentation:
Grades of transformations
standardInputTransformationFunction:
These transformations takes an input which can be defined in two ways:
- value: As a constant defined in the expander using the key value
- inputPath: As a path reference to the input (model) by using the key inputPath.
If both keys are used in an expander declaration, the value found at the inputPath will be used if something is found there. If not, the transformer will default to using the value defined by value. Besides this input, the transformation might require an arbitrary number of constants given in the expander declaration.
standardOutputTransformationFunction:
These transformations only outputs a single value. The value of the output depends on the transformation, but the path to output to can be defined by:
- outputPath: An EL path to where the transformation should output it's value to.
In case the expander is nested within other expanders (eg. a valuemapper), the outputPath specified will be relative to the outputPaths specified in the outer levels as well as to the location of the outermost expander.
standardTransformationFunction:
These transformations satisfy the requirements of both standardInputTransformation and standardOutputTransformation (see above)
multiInputTransformationFunction:
These transformations allows for multiple inputs. In their default blocks, besides the gradename, they require an "inputVariables" key. The value of this should be a hash of key-value pairs, where the key is the variable name and the value is the default value to assign to the variable in case no matching constant or path is found. For each of the variables declared, the system will look up the source-model path defined by <variable>Path in the expander and the <variable> declared in the expander. The path takes priority. Example:
fluid.defaults("fluid.model.transform.scaleValue", { gradeNames: [ "fluid.multiInputTransformFunction" ], inputVariables: { value: null, factor: 1, offset: 0 } });
The above declaration defines three input variables; value, factor and offset. Taking as an example the factor, the first thing that will be looked up in the expander is the value of "factorPath". If it is defined, this path will be looked up in the source-model and this will be assigned to factor if found. If it's not found, the value (expanded if necessary) of the "factor" key of the expander will be used if found. If neither is found, the default value of 1 will be assigned to factor.
The inputVariables will be available to fluid.model.transform.scaleValue as the first argument in the form of an object keyed by variable names with the values as described above.
Transformers
Simple Value
Type: standardTransformation Inputs:
- input / inputPath
Syntax:
expander: { type: "fluid.model.transform.value", value: <constant value> }
This transformation is basically an identity function - it will output the constant value given as input.
Example:
expander: { type: "fluid.model.transform.value", value: "some constant" }
The output in this case would be: "some constant"
To Array
Type: standardTransformation Inputs:
- input / inputPath
Syntax:
expander: { type: "fluid.model.transform.arrayValue", value: <constant value> }
This transformation will turn its value into an array if it's not already an array.
Example:
expander: { type: "fluid.model.transform.arrayValue", value: "some constant" }
The above would give us: [ "some constant" ]. If the value had been an array already, it would just had been passed as is (so in the case - value: [ "some constant "] - we would have got the same output.
Count length of array
Type: standardTransformation Inputs:
- input / inputPath
Syntax:
expander: { type: "fluid.model.transform.count", value: <constant value> }
If the input is an array, the lenght of the array will be the output of this function. If the input is a primitive or object, 1 will be returned.
Example:
expander: { type: "fluid.model.transform.arrayValue", value: [ "foo", "bar" ] }
The above would give the value 2
Get first value of array
Syntax:
expander: { type: "fluid.model.transform.firstValue", value: <constant of array type> }
Will return the first entry (that does not evaluate to undefined) of the array. The input is required to be of type array.
Example:
expander: { type: "fluid.model.transform.firstValue", value: [ "foo", "bar" ] }
The above would give the value "foo".
Delete path from the output
Syntax:
expander: { type: "fluid.model.transform.delete", outputPath: <the output path to delete> }
Will delete the given path from the output.
Example:
{ "": "" expander: { type: "fluid.model.transform.delete", outputPath: foo } }
Given the model as input: { hello: "world", foo: "bar" }, the above would give the value { hello: "world" }. The "": "" in the expander would normally mean that the entire input model is copied without any transformations, but the delete expander ensures that the path "foo" is deleted.
Get first value of array
Syntax:
expander: { type: "fluid.model.transform.firstValue", value: <constant of array type> }
Will return the first entry (that does not evaluate to undefined) of the array. The input is required to be of type array.
Example:
expander: { type: "fluid.model.transform.firstValue", value: [ "foo", "bar" ] }
The above would give the value "foo".
Scale value with optional offset
type: multiInputTransformation (variables: value, factor offset)
Syntax:
expander: { type: "fluid.model.transform.scaleValue", value: <constant of array type>, factor: <the scaling factor>, offset: <the offset to use for the scaling> }
This will scale the input value using the equation: value * factor + offset. If factor is unspecified it will be interpreted as 1 and if offset is unspecified it will be interpreted as 0. Both factor and offset can references to the input model by using: factorPath and offsetPath, respectively. If both the path and constant for any of these values is defined, first the path is looked up, and if a value is found it will be used. Else the constant will be used.
Example:
expander: { type: "fluid.model.transform.scaleValue", value: 12, factor: 10, offsetPath: "some.path" offset: 100 }
In this example, if no value is found at some.path, the output will be 12*10+100 = 220. If the value 1000 is found at some.path the result would be 12*10+1000=1120.
Example:
expander: { type: "fluid.model.transform.scaleValue", value: 12, factorPath: "some.path" }
In this example, if no value is found at some.path, the factor will default to 1, outputting 12*1+0=12. If a value is found (say, 12) the output will be 12*12+0=144
Binary operation
type: multiInputTransformation (variables: left, right)
Syntax:
expander: { type: "fluid.model.transform.binaryOp", left: <constant of appropriate type>, right: <constant of appropriate type>, operator: <the operator to use> }
This will do a binary operation given the two operands (left and right) and the operator. You can reference to the input model for both left and right by using leftPath and rightPath. If both rightPath and right is given, a lookup will be done of rightPath first, and if nothing is found the constant from right will be used. Same goes for left and leftPath. Both the left and right operands are required (either in their path or constant form). The operator is also required. The result of the expansion will be the result of the binary operation. Valid operands are:
Arithmetic Operators (operands are required to be numbers, output will be a number):
- +: (Addition) Adds 2 numbers.
- -: (subtraction) As a unary operator, negates the value of its argument. As a binary operator, subtracts 2 numbers.
- *: (Multiplication) Multiplies 2 numbers.
- /: (Division) Divides 2 numbers.
- %: (Modulus) Computes the integer remainder of dividing 2 numbers.
Comparison Operators: (operands are required to be numbers, output will be boolean)
- ===: Returns true if the operands are equal.
- !==: Returns true if the operands are not equal.
- >: Returns true if left operand is greater than right operand.
- >=: Returns true if left operand is greater than or equal to right operand.
- <: Returns true if left operand is less than right operand.
- <=: Returns true if left operand is less than or equal to right operand.
Logical Operators: (both operands are required to be booleans, output will be boolean)
- &&: (Logical AND) Returns true if both logical operands are true. Otherwise, returns false.
- ||: (Logical OR) Returns true if either logical expression is true. If both are false, returns false.
Example:
expander: { type: "fluid.model.transform.binaryOp", left: 100, rightPath: "some.path", operator: "+" }
The above would give the sum (a number) of 100 and the value found in the input model at the path "some.path".
Conditional Expander
type: multiInputTransformation (variables: true, false, condition)
Syntax:
expander: { type: "fluid.model.transform.condition", condition: <boolean value> "true": <can be declared in the expander as variable or path - optional>, "false": <can be declared in the expander as variable or path - optional> }
Based on the boolean condition constant (or the path to the inputModel conditionPath) either the value or true or false (truePath/falsePath, respectively) will be the result of the expander. The condition is required and either true or false (or both) - or their path equivalents - should be set.
Example:
expander: { type: "fluid.model.transform.binaryOp", conditionPath: "some.path", "true": "It was true", "false": "It was false" }
Changing an array into an object
Syntax:
expander: { type: "fluid.model.transform.arrayToObject", inputPath: "some input path pointing to an array", key: "the variable from array to use as key" innerValue: [ (...inner expanders...) ] }
As the name suggests, the arrayToObject expander changes an array into an object. This can be useful to be able to refer to a certain EL path of an input by a key which unlike reference to an array index does not depend on the order of the array. The expander requires a key - one that is present in each of the array-entries and unique - this will be used to key the resulting object. For example:
If we have the input model:
foo: { bar: [ { product: "salad", price: 10, healthy: "yes" }, { product: "candy", price: 18, healthy: "no" } ] }
And the expander
{ expander: { type: "fluid.model.transform.arrayToObject", inputPath: "foo.bar", key: "product" } }
We are saying that we want the array found on inputPath and return an object where where the key will be the value of product and the content will be the remainder of the array entry. So the above would return:
{ salad: { price: 10, healthy: "yes" }, candy: { price: 18, healthy: "no" } }
An optional variable to the expander is the "innerValue". Any variable or expander that needs to refer to the content of the array should be declared here. The input paths within the innerValue block will be relative to the original array entry. (This behavior will be changed later with FLUID-XYZ).
As an example:
foo: { bar: [ { product: "salad", info: { price: 10, healthy: "yes" }}, { product: "candy", info: { price: 18, healthy: "no", tasty: "yes" }} ] }
And the expander
{ expander: { type: "fluid.model.transform.arrayToObject", inputPath: "foo.bar", key: "product", inputPath: [{ expander: { type: "fluid.model.transform.value", inputPath: "info.healthy", } }] } }
In the second (innermost) inputPath, we refer to info.healthy, which is relative to the path defined by our outer inputPath.
{ salad: "yes", candy: "no" }