Functions

Functions are the building blocks of InterActor dashboards and applications. They perform actions such as loading data or displaying information, and can be linked to each other through Triggers. Triggers are executed at specified moments in the Function's processing, or initiated by user input, and result in the execution of linked Functions. The Triggers can carry data between one Function and the next.

Both Functions and Triggers are stored in the Neo4j graph store, with Functions represented as nodes and Triggers as relations between those nodes. the InterActor Function nodes all have a :IA_Function label, besides another label that indicates the function type. So you will find nodes with labels like :IA_Function:IA_Neo4jQuery and :IA_Function:IA_NetworkView. The Trigger relations have the relation type :TRIGGER, (:SHORTCUT or :START if connected from a dashboard).

Each Function has a set of features in common: they inherit these from the general Function definitions. A special subset of Functions are Views, they also share a set of common features, inherited from the general View definitions.

Executing

A Function can be executed by a Trigger (coming from another Function, or from the User Dashboard). When a Function is executed, it performs the action it is designed to do, and fires outgoing Trigger events when it is done. In the following example, a TableView is executed by the 'success' Trigger event from a Neo4jQuery:

Function-Trigger-Function example

During execution, the Function may fire outgoing Trigger events, which can cause connected Functions to be executed as well.

Parameters

Different Functions have different behaviours when they are executed, which can be further customized using parameters. For example, a Neo4jQuery has a cypher parameter that tells the Function the cypher query it needs to execute. Besides predefined parameters, custom parameters can also be defined. The Function itself will not behave differently based on these custom parameters, but they can be passed on to the next Function.

Setting parameters

Parameters can be set in a few different ways:

Parameter by Function node property

The most basic method to set a Function parameter is by setting it as a node property on the Function's node, with the parameter name as the key and the desired parameter value as property value. Each time the Function is executed, it will use the provided value for its parameter.

With the plain notation, the parameter value cannot be changed unless the Function node property is changed. However, it is possible to allow parameter overriding, e.g. by an incoming Trigger or user prompt, by prefixing the node property with a $ or # parameter prefix. The default value will stay the same, but if another value is provided, it will be overwritten.

In the example below, a very simple Neo4jQuery is presented with two parameters set as node properties:

  • name: a fixed parameter value that cannot be overridden
  • $cypher: a cypher statement that can be overridden by incoming Triggers or user prompts

Read on to find out more about setting parameters by Triggers or user prompts.

Function properties

Parameter by a Trigger relation property

If a Function parameter is set with a parameter prefix ($ or #), it can be overridden by an incoming Trigger to that Function. Similar to the Function node property, the Trigger relation property can specify the desired value for the parameter. The Trigger relation property, however, must have a $ or # parameter prefix. Otherwise the property is considered a Trigger matching property. Through parameters, Triggers can pass data from one Function to the next.

Parameter by a user prompt

Parameters can also be provided by user input, through user prompts. In order to prompt a user for the value of a parameter before the Function is executed, a few meta parameters can be set to the parameter, indicated by a colon (:), e.g. $cypher:prompt : "Please enter a cypher query". These prompt meta parameters must have a parameter prefix.

The options are:

Key Description Possible values
:prompt Text to display to ask the user for input. Any string
:promptDefault Default value to show in the input field. Number or string
:default Default value to use if no value is provided. Any value
:index Index to sort the input fields by (low to high) Number or string

Note: in older versions of InterActor (before 1.2.0), user prompts could be initiated by using the parameter value <required>. Although it still functions similar to :prompt (with the parameter name as text), it has been deprecated and replaced with the more feature-rich meta parameters above.

Overriding order

With multiple ways to set and override a parameter value, the order of evaluation is important to determine the final value of the parameter. The 'weakest' method sets the value first, the 'strongest' has the last override. The order of evaluation is therefore (from weak to strong):

  1. Function node-defined property with parameter prefix
  2. Function node-defined user prompt
  3. Trigger relation-defined property
  4. Trigger relation-defined user prompt
  5. Function node-defined property without parameter prefix

Parameter prefix

Besides a symbol that allows parameter overrides, the parameter prefix specifies if the parameter value should be forced into single element form ($) or list form (#). If the value to a # parameter is a single element, it will be converted into a list of one item. Similarly, if the value to a $ parameter is a list, only the first element will be used as the parameter value.

$_path parameter

A special parameter that every Function has, is the $_path parameter. In contrast to other parameters, the value of this parameter is passed automatically from Function to Function, without having to explicitly specify this. This can be used, for instance, to execute Functions based on the path through which the Function was reached. In the following example, Function A has parameters $_path.origin and $otherParameter set to some value. Whereas the $otherParameter value is lost beyond Function B, the $_path.origin value is still available at Function D.

Path example

The origin name in this example is arbitrary, and the $_path can contain any number of sub-properties that will be passed on from Function to Function.

Function instances and updating

By default, a Function will be executed. This means that an instance of the Function is created, performs its actions, fires outgoing Trigger events and, once it is done, it is destroyed. The Function node remains; this is merely a 'description' based on which new instances are created. A Function can be executed again and again, each time creating a new instance and destroying it after it has finished its processing.

A Function instance can also be told to persist after execution (using the $waitForUpdates: true parameter), keeping its data available for further processing after user input or when other Functions finish execution. Multiple instances of the same Function can co-exist. While an instance exists, it can be updated through Update Triggers. Update Triggers are similar to regular Triggers, except they specify instances of the target Function that should be updated, instead of creating a new one. The instance is specified using the $_instance parameter, which can take one of the following values:

  • _all: all open instances of the Function are updated.
  • _previous: the last Function instance on the execution path is updated.
  • Any other string: the instance with the given string as its name is updated. If it does not exist, it is created.

If the $_instance parameter is specified, a targeted instance of the Function is created (if it does not exist) or updated (changing the data instead of creating new instances every time).

If the $_instanceUpdateOnly parameter is set to true, the trigger will not create a new targeted (with $_instance) instance of a function if it does not yet exist.

While a Function instance is open, its state can be accessed from each outgoing Trigger, as further described here.

List updates

For parameters that are lists, there is a special parameter #_update available, that allows updates to specific items in the list. The #_update parameter can contain one or multiple of the following properties:

  • add: adds items to the list
  • remove: removes items from the list
  • set: adds or replaces items in the list
  • change: alters items in the list
Example: add

Suppose a Function parameter called myList contains a list of numbers: [1,2,5]. We use the #_update.add parameter to add values 3 and 5 to the list:

#_update.add.myList: [3,5]

The resulting list in myList will be: [1,2,5,3,5]. Note that there is no check for uniqueness, nor is the new list ordered. The other operators (remove, set, and change) do need to check for existing identical values.

Example: remove

Suppose a Function parameter called myList contains a list of numbers: [1,2,5]. We use the #_update.remove parameter to remove the value 2 from the list:

#_update.remove.myList: [2]

The resulting list in myList will be: [1,5]. All occurrences of the number 2 are found in the list and removed.

Value identification

The operators set, remove and change, need to find existing values in the list to either replace, remove or change them. In order to do this, the values in the list are compared to the values that are specified in the operator, to see if they are considered equal. Two values are considered equal if one of the following conditions hold:

  • They are exactly the same (for simple values such as strings, numbers and booleans)
  • The id properties of both values are exactly the same (in case both values are objects)
  • All properties of both values are exactly the same (in case both values are objects)
Example: change object

Suppose a Function parameter called myList contains a list of objects:

[
	{id: 15, name: 'Hank', age: 47},
	{id: 7, name: 'Florence', age: 21},
	{id: 51, name: 'Eddie', age: 35}
]

We use the #_update.change parameter to change Eddie's name to Ed:

#_update.change.myList: [{id:51, name:'Ed'}]

The change operator finds the object with id 51 in the list, considers it equal to the given object, and changes the name property to "Ed".

Use of change vs set

The change and set operators seem similar, in the sense that they can both change a value in the list. Consider the 'change object' example above. Suppose we want to change Eddie's information again, and use either:

#_update.set.myList: [{id:51, name:'Ed'}]

or

#_update.change.myList: [{id:51, name:'Ed'}]

The set operator will find the object with id 51 in the list, and replace it with the new object. Note that the new object does not contain an age property. Since the entire object is replaced, we have changed the name, but also removed the age property. On the other hand, the change operator will find the object with id 51 in the list, and merge the objects, i.e. replace only the properties that are defined in the new object. No properties will be removed.

The other difference is that the set operator will add the new object if no existing object with id 51 was found, whereas the change operator will not.