Functions and Rules in Lumeer are made extremely easy to set. They are configured in a visual way that is natural to humans so that every Function and Rule are easily understood. Functions and Rules in Lumeer share the same concepts and there are only a few general principles that are good to know.
Following is an example of quite a complex Rule. As you can see, it is sort of a puzzle.
Every single piece of the puzzle is called a Block. Blocks can have ears (on the left side), arrows (at the bottom), round holes (on the right side) and triangle shaped holes (at the top). As in an ordinary puzzle, there are no ears or holes at the edge of the whole Rule or Function and the outer edge is all smooth.
THE FLOW OF INFORMATION
Creating custom Rules and Functions is easier when we understand the flow of information between Blocks.
Values (i.e. content of cells in the Table perspective) are always collected on a single line of Blocks from right to left. The following Block produces a value on its lefts side (hence the ear on the left side) and must be connected to a Block with a whole on its right side (i.e. a Block that accepts some input).
As mentioned, a hole on the right side of a Block expects a value to be connected. In the following example, you can see a Block that expects a value on its right side (a list of values, to be precise), it transforms the values (in this particular example, it computes the sum of the values) and provides them on its output on the left side.
There are no blocks with a bottom arrow and an upper triangular hole in Functions. Thus the next section applies only to Rules.
This section applies only to Rules.
There is a second type of flow, it is a time flow or time sequence and it flows from top to bottom. Individual lines of Blocks form commands that are executed in a sequence from top to bottom. This can be seen in Figure 1. The flow is as follows:
The pink Block set k to is executed. This Block sets a variable k to the value of the Block connected on its right side. In this case k is set to a text “Recipe: “. More on variables can be found in a later section.
Then the red block for each record i in is executed. This block takes an input value (a list of records) and executes its inner commands for each record in the list. The following sequence of commands is then executed repeatedly:
Append Value of the Ingredient attribute to the variable k.
Append the text “, “ to the variable k.
Now there is a list of ingredients from all the Records in the light Table linked to the master Record from the dark Table in the variable k. The next Block set Content of accepts two inputs. First the document that it works with, and second the value to set to the document’s attribute (value of the k variable) selected in the dropdown box (i.e. Content).
This section applies only to Rules as there are no variables in Functions.
There are commands that can set and read variables. You can imagine a variable as a side note or a post-it next to your computer where you note down some value. Every post-it represents a single variable and it has a title, or a name if you will, to differentiate individual post-its among each other. These variables simplify the overall Rule configuration so that we don’t need to repeat a set of Blocks every time we need to access a value. Changing the variable does not change the original record.
No matter whether it is a Function or a Rule, there is always an encapsulating block. The first example shows an encapsulating Block for a Rules and the second one is for Functions.
Anything you add to the canvas needs to be connected to or wrapped within the encapsulating block in the end. Blocks scattered on the canvas are ignored and can cause a Function or Rule not to work properly.
In order to easily understand how work with your user data, we need to establish a common terminology. If you are not already familiar with terms like Table, Record, Attribute, Value, please refer to the chapter Accessing Data in Basic Principles Guide.
The best way to start your Rule or Function is with a Block that represents current Record also referred to as Document. In Rules, there are two such Blocks. One with the label newDocument, and another with the label oldDocument. These two Blocks represent the state of the Document before and after an update so that both Values are available and we can compare whether a specific Attribute has changed. If case of Functions, there is just thisDocument.
In case of Rules reacting to the Document creation, the oldDocument is empty. In case of a Rule reacting to the Document deletion, the newDocument is empty.
Such a block represents a whole Document. The Document is present on its output which is the ear on the left side. To read a Value of a specific Attribute, we need a Getter Block.
Now, we have a single Value of the State Attribute on the left ear of the green Getter Block. Let’s see how we could obtain linked Documents. For that purpose we can reconnect our Document Block to a Link Block.
There is now an important difference. On the ear on the left side of the gray Link Block, there is a list of Documents. That is because a single Document can always be linked to multiple Documents. Also notice how the flow of information goes from right to left. It is actually the opposite way than how information are represented in the connected tables.
Pro tip: Why is that? If we changed the direction of information flow in Blocks, we would need to flip the encapsulating blocks. That way, they would look very unnatural. Also, the equation in Functions would be exactly the opposite as in mathematics (e.g. f(y)=x instead of y=f(x)).
The fact that there are multiple Documents influences subsequent Block. Let’s connect the Getter Block.
Because the Getter Block started with a list of Document on its input, it also returns a list of Values of the selected Attribute (“Last Name”) on its left side. We can now use various other Blocks to concatenate the strings, compute the sum of a list etc.
There is one drawback though. If we use the same approach to obtain several lists of Values, we can never figure out what Values in these two lists are originally from a single Document. For this purpose, it is useful to use a Loop Block and iterate over the Documents. Inside of the loop, we can access all Attributes of every single Document in the list, one after another.
The situation can be seen in Figure 9. The Rule starts by setting a Variable crossProduct to zero. Then it iterates over all Documents connected to the current Document in the employees Table via “employees positions” Link. The Blocks inside of the loop Block (for each…) are executed for each of the linked Documents. The Blocks add (change) the multiplication of Attributes Salary and Conversion to the crossProduct Variable. The Variable i represents a single Document inside of the loop. So when we read two different Attributes of this Variable, they always belong to the same Document.
The last Figure (Figure 10) is a cheat sheet illustrating how data are represented by Blocks.