Developers

Reading and writing data

First thing to be aware of is that all data available through global is read only – meaning you cannot update Global Data Tables through the script the same way you want to update Person Data or One To Many tables. Since you may need to use a Global Data as a counter or similar there is a different way to update Global Data values in the script. Naturally settings are also read only.

Below we will describe how it works for each object. Note how the logic for recipient, global, and settings is identical.

Reading Data

Person Data, Global Data, and Settings

The recipient, global, and settings objects act like maps, so you can get these data fields with the standard js notations.

var firstname  = recipient.FIRSTNAME;
var dayOfWeek  = global["DAY_OF_WEEK"];
var inputSetting  = settings.MY_INPUT;

If no value is present, the result will be undefined. The values are also typed, so if the data field is a number, then the value returned is a number, etc. Currently, for the settings object, all values are typed as strings.

One To Many & Global Data Tables

For One To Many and Global tables you can again similarly access the data like recipient.table.PURCHASE or global.table["PRODUCTS"] – what you are getting back can be seen as a javascript array, i.e. recipient.table.PURCHASE[0] will return the first row in the list, Agillic provide no guarantee on the ordering of the rows returned. Each row is then itself a map and can be read that way, as before we use the same types as are defined through the UI.

Reading Global Data Tables is only possible on tables that consist of under 5.000 rows.

We to support most of the methods available on arrays in Javascript:

See Mozilla Documentation here

Currently we do not have support for all the methods (coverage is currently about 80%), we have focused on the ones that makes most sense in the context or reading and writing One To Many tables, so forEach(), filter() and find() are supported. Also some of the methods are not available directly on the table but only after another method has been applied, this will be changed before we go live officially, and at that point full documentation with examples will be provided.

Here are relevant Agillic array function examples

We are using the javax.scripting library in Java to provide the bridge between the JavaScript file and Agillic. This means that the JavaScript file is executed inside our Java application. Note that features available in ES6 or later are not supported.

Target Groups

For Target Groups you can check if a recipient is a member of a specified Target Group with the standard js notations:

var isValid  = recipient.groups["All Valid Recipients"];
var isLead  = recipient.groups.LEAD;

You can think of groups as a map where all values are Booleans, reflecting a Recipient’s status of membership preloaded Target Groups. If you query the groups map for a Target Group not listed in the required target group method, your script will fail.

Writing Data

Where allowed, the actual writing of recipient data to the database is done after the script successfully completes, in a particular order:

  1. Person Data
  2. One To Many
  3. Events

Global Data values are written immediately

This ordering is done, so that any Event you achieve has access to all the previously set data in the extension, and any Side effects are also executed after this, so all modification made in the extension are accessible.

Before the script successfully completes, you are able to read the updated values in that context. For example if my Recipient has FIRSTNAME = “Foo”, and the following code is run.

function execute(recipient,global,settings) {
    logger.info("Start: "+recipient.FIRSTNAME);
    recipient.FIRSTNAME = "Bar";
    logger.info("End: "+recipient.FIRSTNAME);
    return false;
}

The logs would print:

Start: Foo
End: Bar

However, the Recipient’s FIRSTNAME is still “Foo”, due to the script returning false, stopping the database write from completing. Http extensions are the only other extension where data can be written to recipients, but has a more complex return type(although the ordering mentioned above still holds). Therefore please see the documentation about Http Extension’s execution method for more details.

Monitor and Condition Extensions cannot write data to, or apply side-effects on recipients.

Person Data

For Person Data simply assign the value:

recipient.FIRSTNAME = "Foo";    //Firstname is be "Foo"
recipient.FIRSTNAME = null;     //Firstname is now empty
recipient["FIRSTNAME"] = "Bar"; //Firstname is now "Bar"
recipient.FIRSTNAME = "";       //Firstname is now empty

The values are typed, but we attempt type conversion in the following way:

String

Anything not “like” a map, array, or list, will be simply converted to the string type – so providing the boolean will result in either the string “true” or “false”.

Number

Boolean

Date and Timestamp

As stated above the script will fail as soon as you attempt to assign the value.

Please be aware of the following:

One To Many

For One To Many, assigning a value to a field in a row is exactly the same as for Person Data, including the type conversion.

Adding a record to a table is done like this:

recipient.table.COUPONS.push({
"ID":"123",
"DESCRIPTION":"This is a coupon",
"VALUE":100
});

When adding you must provide a non-empty value for the field defined as row key in the table. Any other fields are optional, and can be added later, same type rules as above apply.

You can remove a record in two ways:

recipient.table.COUPONS.delete({"ID":"123"});
recipient.table.COUPONS[0].delete();

So either call delete on the array with an object which must at least contain the value of the primary field you want to delete, or call delete on a particular item in the array.

Please be aware that if you use any of the array functions like filter, forEach(), … then the push and delete options directly on the table object will not be available.

Event

To achieve an Event on a recipient, use:

recipient.achieveEvent("My event");

Please note that Event achieving is a list. So if you call the above code twice you will also achieve the Event twice. Events are achieved in the order they were called in the code.

Function on Global Data

There can be many reasons why you would want to update the value of a Global Data during execution, the most basic being that you have a counter which defines the max number of recipients allowed through. Since both Steps and Conditions can be evaluated multiple times in parallel it is easy to run into concurrency issues. Therefore we do not allow direct writes to Global Data, but only allow access through a function which is based on best practices for access to shared resources, and will guarantee that access is secured.

Hopefully the description and example below will make it clear how to use it, but it is slightly more advanced than the rest of the functions made available, so please reach out if you want us to review the logic.

The function is defined on the global object and is called “merge” and takes three parameters:

A simple example that decreases a Global Data called AVAILABLE_TICKETS – and defaults to 1000 tickets, and then does a post check to see if the recipient got a ticket. Of course since any number less than 0 means no more tickets we just stop the counter at -1, this code would be running inside the main method of either a step or a condition.

Flow Context

The flow context argument is a simple map that gives access to data regarding the current flow execution. It has the following fields:

Here is a basic example of usage and local test: See Example