Triggers

A trigger can be defined as a type of action that automatically executes when an event occurs in the Gospel platform. They have the ability to take actions within the ledger based on any data the defining user can see. For example, you can set a trigger to be executed when a user tries to modify a record. 

Triggers can be set to run before a read, or before/after a create/update action. This ability to run a trigger before a read or write can be very useful when running complex, self-defined actions with the ability to reject the transaction entirely if conditions are not met.

Prerequisites

  • Trigger permissions are checked when the trigger is created/edited
  • The user creating the trigger is the owner for the trigger, unless the actor is set to the CURRENT_USER in the record definition.

Add or Edit Triggers

To create a trigger, go to, Dashboard > Triggers > Add new  

To edit a trigger, go to, Dashboard Triggers > select a trigger from the list.

The following options are displayed:

OptionsDescription

Trigger details

Trigger ID

Required. A unique ID for the trigger. Once created this field cannot be modified.

Do not trigger when listing records

If you select this option, the trigger executes only when the record is accessed individually, and not when viewing/listing all the records.

Trigger type

Required. When defining a trigger, you can specify the trigger timing, which determines whether the trigger should execute before or after the triggering statementFrom the drop-down list, select the type of trigger:

Trigger Type:

BEFORE triggers are used to update or validate record values before they are saved to Gospel. The before triggers are:

  • Run before any read or write 
  • Run before any record creation 
  • Run before any record update 
  • Run before a write is made  
  • Run before a read is made 

AFTER triggers are executed after changes have been made to Gospel. The after triggers are:

  • Run after a write is made
  • Run after every record creation
  • Run after every record update

NEVER trigger is used if you do not want a trigger to run when certain conditions are met. The never trigger is:

  • Trigger will never run
Record Type

From the drop-down list, select a record for which you want to set the trigger.

Language

You can write triggers in Stanza or Lua. Select the language in which you want to define the procedure that automatically runs when an event occurs on the platform. 

Lua v5.1 is supported in the current release.

Run When

Click the + option to add conditions, which adds further criteria to the triggering condition. 

  • Field Name: Select a field name from the drop-down list. 

The list may display fields that are set to not be displayed in the table.

  • Predicate: You can use predicates like contains, is equal to, is not equal to, contains, does not contain, etc. to apply triggers when the set conditions are met. 
  • Value: Enter a value to match the predicate settings.

Click Save to save and apply your change.

Permissions

Set the required permission to:

  • Allow a group of users to: Allows access to users in the group defined in the Group Name field

When:

  • read this definition: Allows the user to only view the definition
  • edit this definition: Allows the user to edit the definition
  • read and edit this definition: Allows the user to both view and modify the definition

Who:

  • when the user is a member of the group: Enter a group name to allow all members of the group to have access to the trigger.

Click Save to save and apply the settings.

Stanza

Stanza

The stanza of the trigger is defined in a custom language provided by Gospel. This is carefully defined to reduce both the amount of runtime it can use and the potential for the kind of catastrophic damage the injudicious use of smart contracts has caused within Ethereum. 

Literals are allowed, as are references contained in curly brackets. `records.recordDefinition` references a record loadable using the chaincode and `record` references the record that triggered the function. Calling `commit` commits changes to the record with the action type (eg insert, write, read etc) specified. Statements are on separate lines.

If a trigger runs before the insert or update action, the `reject` action command can be used to conditionally reject incorrect input. In this manner, things like the validity of enumerations can be enforced in a programmatic manner.

Aggregations are also runnable by replacing the record ID with a `withAll` or `withAny` clause and appending an aggregation as a function eg

`records.invoiceLine.withAll(invoiceId eq record.id).fields.amount.sum()`.

Comments can be created by prefixing a line with two forward slashes eg `// This is a comment`

Available predicates and aggregations match those defined elsewhere in this document as does their syntax including that of `withAll` and `withAny` clauses.

Lua

Lua can be used to define actions which are performed when a specified event is triggered. Users are expected to have previous knowledge of the principles and syntax of Lua and it is beyond the scope of this documentation. For a detailed introduction, see the Lua documentation.

When creating a trigger, you need to import the gospel module, using the local gospel = require("gospellua") in the syntax.

For detailed information on commands, functions and examples for writing the stanza, see syntax and examples.

Guidelines for Triggers

  • When loading a record or a record definition in Lua, you can verify if a field exists is in the list of fields. This can be done using the following options:
    For a record:

    record = gospel.loadRecord("DefinitionFieldTypes", "a001")
    fields = record:getFields()
    if fields['fieldName'] == nil then
        gospel.rejectTransaction("Field doesn't exist'")
        return
    end

    For a record definition:

    definition = gospel.loadRecordDefinition("DefinitionFieldTypes")
    fields = definition:getFields()
    if fields['fieldName'] == nil then
        gospel.rejectTransaction("Field doesn't exist'")
        return
    end
  • When loading a record, you should check if it exists before starting to manipulate it. You have two options:

    record = gospel.loadRecord("DefinitionFieldTypes", "doesntExist")
    if record == nil then
        gospel.rejectTransaction("Record not found")
        return
    end

    or check first if it exists before loading it

    recordExists = gospel.existsRecord("DefinitionFieldTypes", "doesntExist'")
    if recordExists == false then
        gospel.rejectTransaction("Record not found")
        return
    end
  • After rejecting a transaction you should make sure you return, to make sure it stops the trigger execution

    recordExists = gospel.existsRecord("DefinitionFieldTypes", "doesntExist'")
    if recordExists == false then
        gospel.rejectTransaction("Record not found")
        return
    end