Comment on page
Business Rules
This tutorial is intended to assist developers with the writing of business rules using the SanteDB Jint business rules engine (the default business rules engine in SanteDB).
SanteDB can run rules in the user interface on demand (which run in the user's browser) otherwise they are run in the dCDR and iCDR using a C# to JavaScript interpreter bridge named JINT. The JINT library.
- SanteDB < 2.0.x use JINT 2.0 which is compatible with ECMA Script 5.1
- SanteDB > 2.1.x use JINT 3.0 Beta which is compatible with a subset of ECMA Script 6 functions (see: https://github.com/sebastienros/jint/blob/main/README.md)
SanteDB provides a series of extension points where developers can write custom triggers to modify, extend, add, or remove data from resources. These changes are used to implement business rules on the series of objects the subscribe to. Some examples might be:
- Interpreting an observation based on some pre-defined lookup tables
- Merging patients before they are persisted based on specified criteria
- Validating that a substance administration is correct before persisting it
This article covers writing business rules in JavaScript in your applets. While this method is convenient and allows sharing of a single business rule implementation in all dCDR instances and the iCDR, if you require higher performing business rules on the iCDR, consider implementing a Business Rules Servicein C# instead.
Business rules subscribe to persistence events on the repository layer of the architecture. Whenever a piece of data is modified, these events fire, and the correlated business rules are triggered.
From a technical standpoint, SanteDB (and the disconnected client) compile JavaScript into .NET code at runtime. An entire BRE script is executed on application startup (or server startup) and here the script is free to subscribe to a series of events.
These events are:
Event | Description |
BeforeInsert | Fired before data is persisted to the database |
AfterInsert | Fired after data has successfully been persisted to the database |
BeforeUpdate | Fired before data is updated in the database |
AfterUpdate | Fired after data has successfully been updated in the database |
BeforeObsolete | Fired prior to data being obsoleted in the database |
AfterObsolete | Fired after data has been obsoleted in the database |
BeforeQuery | Fired before a query is run allowing the rule to change query |
AfterQuery | Fired after a query has been executed and results are ready |
Business rules which are executed before persistence (BeforeInsert, BeforeObsolete, BeforeUpdate) have the opportunity to change data that is about to be persisted. This is done by returning data from the function which is to be updated.
Business rules which are executed after persistence (AfterInsert, AfterObsolete, AfterUpdate) may also change data, however it is important to note that these are done as a separate transaction as the rules are executed after the operation has been committed to the database. This means that any operation where the "After" trigger fails, will result in a 422 response to the client, whilst the data is persisted to the database.
If your trigger requires operation within the master transaction, however you want to ensure the persistence is completed, you can return a Bundle (for a transaction) and push additional operations to the scoped bundle.
Business rules are loaded from the rules/ folder of your applet. This tutorial will create a rule which will add a tag to a patient called "ReviewState" and will set it to "NotReviewed". This operation will illustrate the BeforeInsert rule and AfterUpdate rules.
- 1.Create an empty JavaScript file in the rules/ folder of your applet
- 2.We need to call the SanteDBBre.AddBusinessRule() function to register our rule, we're subscribing to "Patient"s.SanteDBBre.AddBusinessRule("id", "Patient", "BeforeInsert", [], function(patient) {});The AddBusinessRule function accepts a callback which is to be called whenever the trigger "BeforeInsert" on a Patient is called. The [ ] is reserved for filter properties which prevent the filter from being called.
- 3.Next, we want to add a tag to this patient object, this is done using the standard SanteDB JavaScript bridge functionality you write your regular applet controller code in:SanteDBBre.AddBusinessRule("my_patient_rule", "Patient", "BeforeInsert", [], function(patient) {patient.tag = patient.tag || {};// ensure the rule has not been runif(patient.tag["ReviewState"] === undefined)patient.tag["ReviewState"] = 'NotReviewed';return patient;