Developing APIs‎ > ‎Extensibility‎ > ‎

The logicContext Object

When writing a rule in JavaScript, you can assume that there is a logicContext object. Logic context makes visible key aspects of logic execution. This object provides access to runtime services and state and services to create, read, update, and delete rows.

For more information:

  • About detailed API documentation, see LogicContextI.
  • About logic execution, see Logic Execution.
Limitation: The logicContext is not available to rules tied to non-persistent attributes or JIT (just-it-time) compilation.

verb Property

The verb property tells you what the current logic iteration is trying to do (INSERT, UPDATE, or DELETE).

Example:

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

The verb property is distinct from the initialVerb property. A rule might have kicked of the current logic iteration. For instance, Item logic might update an inserted row (such as Order) later in the transaction. For the Order, the verb is INSERT initially, then UPDATE as the Items are processed. The initialVerb property remains INSERT.

For more information about the initialVerb property, see "The initialVerb Property" section.

initialVerb Property

The initialVerb property indicates the verb that is initially executed on a row.

Example:

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

Consider inserting an Order and several Items. The item logic updates 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.

logicNestLevel Property

(For advanced users)

The logicNestLevel property indicates the depth of the nesting.

Prerequisite: You understand complex nested logic.

Example:

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

setUseCaseName Method

You can make debugging easier by creating a rule that sets the setUseCaseName method. The given name appears in the logs, which can be helpful in understanding the flow of a transaction.

Example:

logicContext.setUseCaseName('Insert log record');

setUserProperty Method

The setUserProperty method sets user properties for the duration of the transaction. When the transaction ends, the user properties disappear. The next transaction, even for the same API key, does not see these values. The value of a user property can be anything.

Example:

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

Important! Use the setUserProperty method with great care. This method can introduce some subtle and non-obvious dependencies between rules. Nevertheless, they can be useful in some scenarios.

logDebug Method

You can output messages to the log by creating a rule that sets the logDebug method.

Example:

The following code snippet outputs the given message to the transaction's log, using the User Logic logger:

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

Note: You cannot use this method (and other methods) in formulas that are used by non-persistent attributes. Use the log.debug method instead. The other variations of this method, logFiner and logFinest, use a lower level of logging.

Objects: updatable

You can update objects. This method is distinct from the queryDatabase method.

Interact with Data

When you create an API and connect to your database, API Creator creates a JavaScript object model from your schemaAPI Creator defines a row object type (class) for each base table. API Creator updates this model automatically (for example, if you change the schema) when you reload your schema.

The term "object" refers to the Java Script objects created as part of the JavaScript object model. For example, the Logic demo includes the customer and purchaseorder objects.

If you are using multiple databases, prefix your table name with the database name (for example, main:Customer). If your API later adds a second database, including a database prefix avoids requiring that you revise these table references.

For more information:

createPersistentBean Method

You can create a new object, ready to be inserted, using the createPersistentBean() method.

Example:

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

getBeanByPrimaryKey Method

You can retrieve an existing object by its primary key with the getBeanByPrimaryKey() method.

Example:

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

The second argument must be a string. The argument is converted to the proper type as needed. If the primary key for the given table is a composite key, separate the values by a tilde (~) in the database order, with double-tilde (~~) to quote the tilde itself:

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

The getBeanByPrimaryKey() method expects to find a valid record. If a row is not found, it does not return a null row. To determine whether a row actually exists, use:

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

where the arguments are:

  • The Object Name.
  • The Attributes you are selecting against.
  • The Values used for the query.
This code snippet returns single bean if found, null if not found, or throw an exception if not unique.

getRowsByQuery Method

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

Example:

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);

insertChildrenFrom Method

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

The 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);
   }

In this example:

  • row.product.count_components uses a parent accessor. Given a lineitem, it accesses the related product and returns the value of the count_components attribute.
  • row.product.components is a child accessor. It accesses the list of components for a lineitem's product.

The remaining logic (four rules) is to properly arrange for quantities (that is, if you buy two planes, you need eight engines).

Note: The Bill Of Materials Explosion example is an advanced example used in the training.

For more information:

insert Method

You can insert a new object (presumably created with the createPersistentBean method) 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);    

touch Method

You can update an object in an action.
  1. Call the touch method.
    Note: The touch method is required to set up the old values, required for oldRow, and required for optimistic locking. This requirement applies only to objects that you retrieve on your own. You must invoke this method:
    • If you read a row and then wish to update/delete it.
      For more information about an example, see the "Insert an Object" example.
    • 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.
  2. Change any column in the row.
  3. Call the update method.

Example:

The following code snippet updates an object, calling the touch method and the update method:

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

delete Method

You can delete an object with the delete method:

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

queryDatabase Method

You can issue an arbitrary SQL query, within the context of the transaction, using the queryDatabase method. You can use JDBC ? syntax for parameterized queries:

// Use this to query the database and log the results (for example) to the API Creator 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);
}

transformCurrentRow Method

The logicContext object's transformCurrentRow method transforms a table row to a resource instance and is typically called in a table event. This provides transformation logic to select/rename attributes and related objects.

For more information:

Interact with Data using REST

The previous services use the server's database connection and Java Database Connectivity (JDBC) for SQL access. You can also interact with data using REST:
  • You can invoke RESTful services (API Creator or others).
  • You can materialize a JSON string from your rows, perhaps as a payload to send to a remote system.
For more information about invoking RESTful services and materializing JSON strings from rows, see Integration.

REST vs. Object access
In most cases, use the logicContext object's services. REST results:
  • Do not include role accessors. They are static rows.
  • Are not persist-able using the (more convenient) INSERT, UPDATE, and DELETE APIs.
  • 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 Method

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

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

The following response is expected:

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

logDebug Method

You can insert a message into the log, complete with a message and the row values as reported by rules, using the logDebug method. This method is the simplest debug approach. For example:

logicContext.logDebug("My Message")

For more information about how to output messages to the log by nesting the messages inside the transaction nest level, see View Logging Information

Obtain Metadata Information

You can obtain metadata, that is, information that describes the rows in your API (as distinct from row values) using the logicContext object.

getTableDefinition Method

You can obtain information about the current table (no argument) or a designated table using the getTableDefinition([<tableName>]) method. This method returns a JavaScript object that includes:
    • Attributes: The attribute names, lengths, type, etc.
    • Parents: The tables that are parents of the current table.
    • Children: Child tables.

getResourceDefinition Method

You can obtain information about a designated resource using the getResourceDefinition(<resourceName>) method. This method returns a JavaScript object that includes:
    • Table: The table on which the resource is based.
    • Attributes: The set of attributes, including their (alias) names, base table names, whether they are part of a key, etc.
Subpages (1): transformCurrentRow