Difference between revisions of "Architecture - Available transformation functions"

From wiki.gpii
Jump to: navigation, search
m (category added)
Line 1: Line 1:
 +
= Introduction to transformations =
  
Documentation:
+
= Outputting =
 +
 
 +
= Direct value vs. reading from path =
  
 
= Grades of transformations =
 
= Grades of transformations =
Line 7: Line 10:
  
 
These transformations takes an input which can be defined in two ways:
 
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''.  
+
*''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.
 
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.
Line 15: Line 19:
  
 
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:
 
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.
+
 
 +
*''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.
 
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.
Line 25: Line 30:
 
== multiInputTransformationFunction: ==
 
== 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:
+
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 &lt;variable&gt;Path in the expander and the &lt;variable&gt; declared in the expander. The path takes priority. Example:
 
+
<pre>fluid.defaults("fluid.transforms.scaleValue", {
<pre>
 
fluid.defaults("fluid.model.transform.scaleValue", {
 
 
     gradeNames: [ "fluid.multiInputTransformFunction" ],
 
     gradeNames: [ "fluid.multiInputTransformFunction" ],
 
     inputVariables: {  
 
     inputVariables: {  
Line 37: Line 40:
 
});
 
});
 
</pre>
 
</pre>
 +
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 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.transforms.scaleValue as the first argument in the form of an object keyed by variable names with the values as described above.
  
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 =
 
= Transformers =
  
== Simple Value ==
+
== Literal Value (fluid.transforms.literalValue) ==
  
Type: standardTransformation
+
'''Description:'''&nbsp;Returns the value given as input (or via inputPath), without attempting to do further transformations for that value. This transformation is basically an identity function - it will output the constant value given as input.
Inputs:
 
* input / inputPath
 
  
Syntax:
+
'''Type:''' standardTransformation Inputs:
<pre>  
+
 
expander: {
+
*input / inputPath&nbsp;
     type: "fluid.model.transform.value",
+
 
     value: <constant value>
+
'''Syntax:'''
 +
<pre>expander: {
 +
     type: "fluid.transforms.literalValue",
 +
     input: <constant value>
 +
}
 +
</pre>
 +
=== <br/> ===
 +
 
 +
=== Example 1: You can user literal value if you have some constant that you want to output to the document ===
 +
<pre>expander: {
 +
    type: "fluid.transforms.literalValue",
 +
    input: "some constant"
 
}
 
}
 
</pre>
 
</pre>
 +
'''Output:''' The output in this case would be:
 +
<pre>"some constant"</pre>
  
This transformation is basically an identity function - it will output the constant value given as input.
 
  
Example:
+
=== Example 2: The content of literal value will need be transformed further ===
 +
<pre>expander: {
 +
    type: "fluid.transforms.literalValue",
 +
    input: {
 +
      transform: {
 +
          type: "fluid.transforms.helloworld",
 +
          value: "I'm not interpreted"
 +
      }
 +
    }
 +
}
 +
</pre>
 +
'''Output:''' The content of value will just be output literally:
 +
<pre>transform: {
 +
    type: "fluid.transforms.helloworld",
 +
    input: "I'm not interpreted"
 +
}</pre>
 +
 
  
<pre>  
+
=== Example 3: Like all expanders - will fall back from path to direct value ===
expander: {
+
<pre>expander: {
     type: "fluid.model.transform.value",
+
     type: "fluid.transforms.literalValue",
     value: "some constant"
+
    input: "balloon",
 +
     inputPath: "some.path"
 
}
 
}
 
</pre>
 
</pre>
 +
'''Output:''' if anything is found at the path "some.path" the content of that will be output literally, else "balloon" will be output
  
The output in this case would be: "some constant"
+
== <br/> ==
  
 
== To Array ==
 
== To Array ==
  
Type: standardTransformation
+
Type: standardTransformation Inputs:
Inputs:
+
 
* input / inputPath
+
*input / inputPath
  
 
Syntax:
 
Syntax:
 
<pre>  
 
<pre>  
 
expander: {
 
expander: {
     type: "fluid.model.transform.arrayValue",
+
     type: "fluid.transforms.arrayValue",
 
     value: <constant value>
 
     value: <constant value>
 
}
 
}
 
</pre>
 
</pre>
 
 
This transformation will turn its value into an array if it's not already an array.
 
This transformation will turn its value into an array if it's not already an array.
  
Line 91: Line 121:
 
<pre>  
 
<pre>  
 
expander: {
 
expander: {
     type: "fluid.model.transform.arrayValue",
+
     type: "fluid.transforms.arrayValue",
 
     value: "some constant"
 
     value: "some constant"
 
}
 
}
 
</pre>
 
</pre>
 +
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.
  
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:
  
== Count length of array  ==
+
*input / inputPath
  
Type: standardTransformation
 
Inputs:
 
* input / inputPath
 
 
Syntax:
 
Syntax:
 
<pre>  
 
<pre>  
 
expander: {
 
expander: {
     type: "fluid.model.transform.count",
+
     type: "fluid.transforms.count",
 
     value: <constant value>
 
     value: <constant value>
 
}
 
}
 
</pre>
 
</pre>
 
 
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.
 
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.
  
Line 116: Line 145:
 
<pre>  
 
<pre>  
 
expander: {
 
expander: {
     type: "fluid.model.transform.arrayValue",
+
     type: "fluid.transforms.arrayValue",
 
     value: [ "foo", "bar" ]
 
     value: [ "foo", "bar" ]
 
}
 
}
 
</pre>
 
</pre>
 +
The above would give the value 2
  
The above would give the value 2
 
  
  
== Get first value of array ==
+
== Get first value of array ==
  
 
Syntax:
 
Syntax:
 
<pre>  
 
<pre>  
 
expander: {
 
expander: {
     type: "fluid.model.transform.firstValue",
+
     type: "fluid.transforms.firstValue",
 
     value: <constant of array type>
 
     value: <constant of array type>
 
}
 
}
 
</pre>
 
</pre>
 
 
Will return the first entry (that does not evaluate to undefined) of the array. The input is required to be of type array.
 
Will return the first entry (that does not evaluate to undefined) of the array. The input is required to be of type array.
  
Line 139: Line 167:
 
<pre>  
 
<pre>  
 
expander: {
 
expander: {
     type: "fluid.model.transform.firstValue",
+
     type: "fluid.transforms.firstValue",
 
     value: [ "foo", "bar" ]
 
     value: [ "foo", "bar" ]
 
}
 
}
 
</pre>
 
</pre>
 +
The above would give the value "foo".
  
The above would give the value "foo".
 
  
  
== Delete path from the output ==
+
== Delete path from the output ==
  
 
Syntax:
 
Syntax:
 
<pre>  
 
<pre>  
 
expander: {
 
expander: {
     type: "fluid.model.transform.delete",
+
     type: "fluid.transforms.delete",
 
     outputPath: <the output path to delete>
 
     outputPath: <the output path to delete>
 
}
 
}
 
</pre>
 
</pre>
 
 
Will delete the given path from the output.
 
Will delete the given path from the output.
  
Line 164: Line 191:
 
     "": ""
 
     "": ""
 
     expander: {
 
     expander: {
         type: "fluid.model.transform.delete",
+
         type: "fluid.transforms.delete",
 
         outputPath: foo
 
         outputPath: foo
 
     }
 
     }
 
}
 
}
 
</pre>
 
</pre>
 +
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.
  
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 ==
+
== Get first value of array ==
  
 
Syntax:
 
Syntax:
 
<pre>  
 
<pre>  
 
expander: {
 
expander: {
     type: "fluid.model.transform.firstValue",
+
     type: "fluid.transforms.firstValue",
 
     value: <constant of array type>
 
     value: <constant of array type>
 
}
 
}
 
</pre>
 
</pre>
 
 
Will return the first entry (that does not evaluate to undefined) of the array. The input is required to be of type array.
 
Will return the first entry (that does not evaluate to undefined) of the array. The input is required to be of type array.
  
Line 188: Line 214:
 
<pre>  
 
<pre>  
 
expander: {
 
expander: {
     type: "fluid.model.transform.firstValue",
+
     type: "fluid.transforms.firstValue",
 
     value: [ "foo", "bar" ]
 
     value: [ "foo", "bar" ]
 
}
 
}
 
</pre>
 
</pre>
 +
The above would give the value "foo".
  
The above would give the value "foo".
 
  
  
   
+
== Scale value with optional offset ==
== Scale value with optional offset ==
 
  
 
type: multiInputTransformation (variables: value, factor offset)
 
type: multiInputTransformation (variables: value, factor offset)
Line 204: Line 229:
 
<pre>  
 
<pre>  
 
expander: {
 
expander: {
     type: "fluid.model.transform.scaleValue",
+
     type: "fluid.transforms.scaleValue",
 
     value: <constant of array type>,
 
     value: <constant of array type>,
 
     factor: <the scaling factor>,
 
     factor: <the scaling factor>,
Line 210: Line 235:
 
}
 
}
 
</pre>
 
</pre>
 
+
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.
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:
 
Example:
 
<pre>  
 
<pre>  
 
expander: {
 
expander: {
     type: "fluid.model.transform.scaleValue",
+
     type: "fluid.transforms.scaleValue",
 
     value: 12,
 
     value: 12,
 
     factor: 10,
 
     factor: 10,
Line 224: Line 247:
 
}
 
}
 
</pre>
 
</pre>
 
 
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.
 
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:
 
Example:
<pre>
+
<pre>expander: {
expander: {
+
     type: "fluid.transforms.scaleValue",
     type: "fluid.model.transform.scaleValue",
 
 
     value: 12,
 
     value: 12,
 
     factorPath: "some.path"
 
     factorPath: "some.path"
 
}
 
}
 
</pre>
 
</pre>
 +
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
  
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 ==
+
== Binary operation ==
  
 
type: multiInputTransformation (variables: left, right)
 
type: multiInputTransformation (variables: left, right)
Line 246: Line 267:
 
<pre>  
 
<pre>  
 
expander: {
 
expander: {
     type: "fluid.model.transform.binaryOp",
+
     type: "fluid.transforms.binaryOp",
 
     left: <constant of appropriate type>,
 
     left: <constant of appropriate type>,
 
     right: <constant of appropriate type>,
 
     right: <constant of appropriate type>,
Line 252: Line 273:
 
}
 
}
 
</pre>
 
</pre>
 
 
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:
 
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):
 
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.
+
*+: (Addition) Adds 2 numbers.
* *: (Multiplication) Multiplies 2 numbers.
+
*-: (subtraction) As a unary operator, negates the value of its argument. As a binary operator, subtracts 2 numbers.
* /: (Division) Divides 2 numbers.
+
**:(Multiplication) Multiplies 2 numbers.
* %: (Modulus) Computes the integer remainder of dividing 2 numbers.
+
*/: (Division) Divides 2 numbers.
 +
*&nbsp;%: (Modulus) Computes the integer remainder of dividing 2 numbers.
  
 
Comparison Operators: (operands are required to be numbers, output will be boolean)
 
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 the operands are equal.
* >: Returns true if left operand is greater than right operand.
+
*&nbsp;!==: Returns true if the operands are not equal.
* >=: Returns true if left operand is greater than or equal to right operand.
+
*>: Returns true if left operand is greater than right operand.
* <: Returns true if left operand is less than right operand.
+
*>=: Returns true if left operand is greater than or equal to right operand.
* <=: Returns true if left operand is less 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 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.
+
*&&: (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:
 
Example:
 
<pre>  
 
<pre>  
 
expander: {
 
expander: {
     type: "fluid.model.transform.binaryOp",
+
     type: "fluid.transforms.binaryOp",
 
     left: 100,
 
     left: 100,
 
     rightPath: "some.path",
 
     rightPath: "some.path",
Line 283: Line 306:
 
}
 
}
 
</pre>
 
</pre>
 
 
The above would give the sum (a number) of 100 and the value found in the input model at the path "some.path".
 
The above would give the sum (a number) of 100 and the value found in the input model at the path "some.path".
  
Line 293: Line 315:
 
<pre>  
 
<pre>  
 
expander: {
 
expander: {
     type: "fluid.model.transform.condition",
+
     type: "fluid.transforms.condition",
 
     condition: <boolean value>
 
     condition: <boolean value>
 
     "true": <can be declared in the expander as variable or path - optional>,
 
     "true": <can be declared in the expander as variable or path - optional>,
Line 299: Line 321:
 
}
 
}
 
</pre>
 
</pre>
 
 
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.
 
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.
  
Line 305: Line 326:
 
<pre>  
 
<pre>  
 
expander: {
 
expander: {
     type: "fluid.model.transform.binaryOp",
+
     type: "fluid.transforms.binaryOp",
 
     conditionPath: "some.path",
 
     conditionPath: "some.path",
 
     "true": "It was true",
 
     "true": "It was true",
Line 311: Line 332:
 
}
 
}
 
</pre>
 
</pre>
 
 
== Changing an array into an object ==
 
== Changing an array into an object ==
  
 
Syntax:
 
Syntax:
 
+
<pre>expander: {
<pre>
+
     type: "fluid.transforms.arrayToObject",
expander: {
 
     type: "fluid.model.transform.arrayToObject",
 
 
     inputPath: "some input path pointing to an array",
 
     inputPath: "some input path pointing to an array",
 
     key: "the variable from array to use as key"
 
     key: "the variable from array to use as key"
Line 324: Line 342:
 
}
 
}
 
</pre>
 
</pre>
 
 
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:
 
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:
 
If we have the input model:
 
+
<pre>foo: {
<pre>
 
foo: {
 
 
     bar: [  
 
     bar: [  
 
         { product: "salad", price: 10, healthy: "yes" },
 
         { product: "salad", price: 10, healthy: "yes" },
Line 337: Line 352:
 
}
 
}
 
</pre>
 
</pre>
 
 
And the expander
 
And the expander
 
+
<pre>{
<pre>
 
{
 
 
     expander: {
 
     expander: {
         type: "fluid.model.transform.arrayToObject",
+
         type: "fluid.transforms.arrayToObject",
 
         inputPath: "foo.bar",
 
         inputPath: "foo.bar",
 
         key: "product"
 
         key: "product"
Line 349: Line 361:
 
}
 
}
 
</pre>
 
</pre>
 
 
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:
 
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:
 
+
<pre>{
<pre>
 
{
 
 
     salad: { price: 10, healthy: "yes" },
 
     salad: { price: 10, healthy: "yes" },
 
     candy: { price: 18, healthy: "no" }
 
     candy: { price: 18, healthy: "no" }
 
}
 
}
 
</pre>
 
</pre>
 
+
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).
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:
 
As an example:
 
+
<pre>foo: {
<pre>
 
foo: {
 
 
     bar: [  
 
     bar: [  
 
         { product: "salad", info: { price: 10, healthy: "yes" }},
 
         { product: "salad", info: { price: 10, healthy: "yes" }},
Line 371: Line 377:
 
}
 
}
 
</pre>
 
</pre>
 
 
And the expander
 
And the expander
 
+
<pre>{
<pre>
 
{
 
 
     expander: {
 
     expander: {
         type: "fluid.model.transform.arrayToObject",
+
         type: "fluid.transforms.arrayToObject",
 
         inputPath: "foo.bar",
 
         inputPath: "foo.bar",
 
         key: "product",
 
         key: "product",
 
         inputPath: [{
 
         inputPath: [{
 
             expander: {
 
             expander: {
                 type: "fluid.model.transform.value",
+
                 type: "fluid.transforms.value",
 
                 inputPath: "info.healthy",
 
                 inputPath: "info.healthy",
 
             }
 
             }
Line 390: Line 393:
 
}
 
}
 
</pre>
 
</pre>
 
+
In the second (innermost) inputPath, we refer to info.healthy, which is relative to the path defined by our outer inputPath.
In the second (innermost) inputPath, we refer to info.healthy, which is relative to the path defined by our outer inputPath.  
+
<pre>{
<pre>
 
{
 
 
     salad: "yes",
 
     salad: "yes",
 
     candy: "no"
 
     candy: "no"
 
}
 
}
 
</pre>
 
</pre>
 
 
== Changing an array to a set ==
 
== Changing an array to a set ==
  
 
Syntax:
 
Syntax:
 
+
<pre>expander: {
<pre>
+
     type: "fluid.transforms.arrayToOutputs",
expander: {
 
     type: "fluid.model.transform.arrayToOutputs",
 
 
     inputPath: "some input path pointing to an array",
 
     inputPath: "some input path pointing to an array",
 
     presentValue: "The value that the entry in the set should have if present in array",
 
     presentValue: "The value that the entry in the set should have if present in array",
Line 416: Line 414:
 
}
 
}
 
</pre>
 
</pre>
 
 
This expander can be used when one wants to create a set based on values available in an array. TODO: Add example and further descriptions. presentValue and missingValue are optional. If not defined, they'll default to true and false, respectively
 
This expander can be used when one wants to create a set based on values available in an array. TODO: Add example and further descriptions. presentValue and missingValue are optional. If not defined, they'll default to true and false, respectively
 
 
[[Category:GPII Architecture]]
 

Revision as of 10:26, 16 September 2013

Introduction to transformations

Outputting

Direct value vs. reading from path

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.transforms.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.transforms.scaleValue as the first argument in the form of an object keyed by variable names with the values as described above.


Transformers

Literal Value (fluid.transforms.literalValue)

Description: Returns the value given as input (or via inputPath), without attempting to do further transformations for that value. This transformation is basically an identity function - it will output the constant value given as input.

Type: standardTransformation Inputs:

  • input / inputPath 

Syntax:

expander: {
    type: "fluid.transforms.literalValue",
    input: <constant value>
}


Example 1: You can user literal value if you have some constant that you want to output to the document

expander: {
    type: "fluid.transforms.literalValue",
    input: "some constant"
}

Output: The output in this case would be:

"some constant"


Example 2: The content of literal value will need be transformed further

expander: {
    type: "fluid.transforms.literalValue",
    input: {
       transform: {
          type: "fluid.transforms.helloworld",
          value: "I'm not interpreted"
       }
    }
}

Output: The content of value will just be output literally:

transform: {
    type: "fluid.transforms.helloworld",
    input: "I'm not interpreted"
}


Example 3: Like all expanders - will fall back from path to direct value

expander: {
    type: "fluid.transforms.literalValue",
    input: "balloon",
    inputPath: "some.path"
}

Output: if anything is found at the path "some.path" the content of that will be output literally, else "balloon" will be output


To Array

Type: standardTransformation Inputs:

  • input / inputPath

Syntax:

 
expander: {
    type: "fluid.transforms.arrayValue",
    value: <constant value>
}

This transformation will turn its value into an array if it's not already an array.

Example:

 
expander: {
    type: "fluid.transforms.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.transforms.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.transforms.arrayValue",
    value: [ "foo", "bar" ]
}

The above would give the value 2


Get first value of array

Syntax:

 
expander: {
    type: "fluid.transforms.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.transforms.firstValue",
    value: [ "foo", "bar" ]
}

The above would give the value "foo".


Delete path from the output

Syntax:

 
expander: {
    type: "fluid.transforms.delete",
    outputPath: <the output path to delete>
}

Will delete the given path from the output.

Example:

 
{
    "": ""
    expander: {
        type: "fluid.transforms.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.transforms.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.transforms.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.transforms.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.transforms.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.transforms.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.transforms.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.transforms.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.transforms.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.transforms.binaryOp",
    conditionPath: "some.path",
    "true": "It was true",
    "false": "It was false"
}

Changing an array into an object

Syntax:

expander: {
    type: "fluid.transforms.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.transforms.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.transforms.arrayToObject",
        inputPath: "foo.bar",
        key: "product",
        inputPath: [{
            expander: {
                type: "fluid.transforms.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"
}

Changing an array to a set

Syntax:

expander: {
    type: "fluid.transforms.arrayToOutputs",
    inputPath: "some input path pointing to an array",
    presentValue: "The value that the entry in the set should have if present in array",
    missingValue: "That value that the entry should have if not present in the array",
    options: {
        "expectedArrayEntry1": "Key of set1",
        (...)
        "expectedArrayEntryN": "Key of setN",
    }
}

This expander can be used when one wants to create a set based on values available in an array. TODO: Add example and further descriptions. presentValue and missingValue are optional. If not defined, they'll default to true and false, respectively