Docs‎ > ‎Reference‎ > ‎

LogicContext object

When writing a rule in JavaScript, you can always assume that there is an object named logicContext, which has the following properties and behaviors.  Key concepts are described below; see this (LogicContextI) for detailed API documentation.

Logic Context makes visible key aspects of Logic Execution, it's a good idea to review that.

verb

The verb tells you what the current logic iteration is trying to do: insert, update or delete. This is distinct from the initial verb (see below) because the current logic iteration may have been kicked off by a rule.

For instance, an inserted row (such as an Order) might be updated later in the transaction by Item logic.  For the Order, the verb will be INSERT initially, then UPDATE as the Items are processed.  But initialVerb will remain INSERT.

if (logicContext.verb == 'UPDATE')
    log.debug('We are updating');

Initial verb

Indicates the verb initially executed on this row.  Consider inserting an Order and several Items.  The item logic will update the Order, but the Order can determine that it was initially inserted in this transaction.  For example, you might want to bypass auditing logic when an Order is inserted.

if (logicContext.initialVerb == 'INSERT')
    log.debug('This started as an Insert transaction');

Logic Nest Level

This property should only be used by advanced users who understand complex, nested logic. It indicates the depth of the nesting at the present moment.

if (logicContext.logicNestLevel > 0)  // Do something only at the top level of nesting
    return;


Use Case Name

A rule can set this property to make debugging easier. The given name will appear in the logs, which can be helpful in understanding the flow of a transaction.

logicContext.setUseCaseName('Insert log record');

User properties

These should be used with great care, because they can introduce some subtle and non-obvious dependencies between rules. Nevertheless, they can be useful in some scenarios.

User properties are only set for the duration of the transaction: as soon as the transaction ends, all user properties disappear. The next transaction, even for the same API key, will not see these values.

logicContext.setUserProperty('myFlag', true);
if (logicContext.getUserProperty('myFlag)
    log.debug('myFlag is true');

The value of a user property can be anything.


Logging


You can output messages to the log:

log.debug('Customer balance is: ' + currentObject.balance);
logicContext.logDebug('Customer balance is: ' + currentObject.balance);


This will output the given message to the transaction's log, using the User Logic logger. There are two other variations of this method: logFiner and logFinest, which use a lower level of logging.



Objects: updatable

Objects are undatable (as distinct from "get data from an arbitrary query", below).

Interacting with data

An Object Model is created for each Base Table when you connect  API Creator to your database.  This model is automatically updated (e.g., if you change the schema) when you reload your schema.  

We use the term "object" to refer to the Java Script objects created as part of the Object Model.  So, in Logic Demo, you will have Objects for customer, purchaseorder, and so forth.  

If you are using Multiple Databases, be sure to prefix your table name with the database name (e.g., main:Customer).

Create a new object

You can create a brand-new object, ready to be inserted, by using the createPersistentBean method:

var newCustomer = logicContext.createPersistentBean("Customer");
newCustomer.name = 'My new customer';
logicContext.insert(newCustomer);

Get an object by primary key

You can retrieve an existing object by its primary key with the getBeanByPrimaryKey method:

var customer = logicContext.getBeanByPrimaryKey("Customer", "123");


Note that the second argument must be a string -- it will be converted to the proper type as needed. If the primary key for the given table is a composite key, the string should contain all the values separated by a tilde (~) in the database order, with double-tilde to quote the tilde itself:

var order = logicContext.getBeanByPrimaryKey("MyTable", "456~abc");

getBeanByPrimaryKey() expects to find a valid record.  It does not return a null row when no row is found.  If you are attempting to determine whether a row actually exists, use

var customer = logicContext.getBeanByUniqueAttributes("demo:customer", ["id"], [123]);

where the arguments are:
  1. The Object Name
  2. The Attributes you are selecting against
  3. The Values used for the query
This will return single bean if found, null if not found, or throw an exception if not unique.

Alert ==> Composite key support is a planned feature, but not present as of Build 450.  You will need to use the API shown below.

Get a set of objects

You can retrieve a set of objects using a SQL where clause with the getRowsByQuery method:

var rows = logicContext.getRowsByQuery("product",
                        "select * from product where name <> 'Drill'");

for (var i = 0; i <= rows.length; i++)
   log.debug('Found product:' + rows[i].name);



Role Accessors

You can also access related parent / child data via their relationships.  Consider the following code snippet from the Bill of Materials Explosion:

The key requirement is to populate the SubItems for a kit-based Lineitem (see the database structure), by copying the ProductBillofMaterials to the subItems.  You can do this with the following explodeBillofMaterials Event rule on Lineitem:

 if (logicContext.verb == "INSERT" && row.product.count_components > 0)  {

     SysLogic.insertChildrenFrom("lineitems", row.product.components, logicContext); 

 }


The remaining logic (4 rules) is simply to properly arrange for quantities (i.e., if you buy 2 planes, you need 8 engines).  The Bill Of Materials Explosion example is an advanced example used in the Training.

In this example:
  • row.product.count_components uses a parent accessor - given a lineitem, it access the related product, and returns the value of the attribute count_components

  • row.product.components is a child accessor - it accesses the list of components for a lineitem's product

Insert an object

You can insert a new object (presumably created with createPersistentBean) using the insert method; see createPersistentBean for an example.
 
  var newPurchaseorder_audit = logicContext.createPersistentBean("purchaseorder_audit");
  newPurchaseorder_audit.amount_total = oldRow.amount_total;  // set attributes from old values
  newPurchaseorder_audit.paid = oldRow.paid;
  newPurchaseorder_audit.customer_name = oldRow.customer_name;
  newPurchaseorder_audit.order_number = oldRow.order_number;  // set the foreign key
  logicContext.insert(newPurchaseorder_audit);    

Update an object

You can update an object in an action by following these steps:
  1. before changing anything in the object, you must call the touch method
  2. you can then change any column in the row
  3. finally, you need to call the update method

var customer = logicContext.getBeanByPrimaryKey("customer", "123");
logicContext.touch(customer); // IMPORTANT!
customer.name = 'Updated customer';
logicContext.update(customer);

Touch required prior to update

Touch is required to set up the old values, required for oldRow and for optimistic locking.  You must invoke it:
  • If you read a row and then wish to update / delete it (see the example above)
  • In an Event, if you change the row and need to update it again (to re-run the rules on changes to the row made in the event)
Note that this does not apply to row, only to objects that you retrieve on your own.

Delete an object

You can delete an object with the delete method:

var customer = logicContext.getBeanByPrimaryKey("customer", "123");
logicContext.delete(customer);


Retrieve Data from an arbitrary query

You can execute an arbitrary SQL query, within the context of the transaction. You can use JDBC ? syntax for parameterized queries

// this can be used to query the database and log the results (for example) to the Logic Designer Logs
var result = SysLogic.queryDatabase('demo', 'select * from customer where balance > ?', [10]);
for (var i = 0; i < result.length; ++i) {
    var s = '';
    for (var id in result[i]) {
          s += ', ' + id + '=' + result[i][id];
    }
    log.debug(s);
}


Use REST

The services above use the server's database connection and jdbc for sql access.  You can also interact with data using REST:
  • you can invoke RESTful services (API Creator or others), as described here.

  • you can materialize a JSON string from your API Creator rows, as described here, perhaps as a payload to send to a remote system

REST vs. Object access

In most cases, you should use the object services described above:
  • REST results do not include role accessors.  They are static rows.

  • REST results are not persist-able using the (more convenient) insert, update and delete APIs noted above

  • REST results always trigger database access.  In many cases, object accessors find the desired data in memory, and you are assured of seeing other updates in the current transaction

rowToJSON

If you are simply logging, you can print rows to the log using normal logging:

log.debug("Here is my row: " + row);


You can also convert a row to a JSON structure with appropriate datatypes that can be passed to other persistent document storage systems, like this:

log.debug("JSON for object is : " + logicContext.rowToJSON(row));


The console output is:

{
"location_ident": 1,
"amount": 1.06,
"budget_date": null,
"ident": 9,
"city_ident": 1
}