Cloud Software Group, Inc. EBX®
Documentation > Developer Guide > EBX® Script > Usage
Navigation modeDocumentation > Developer Guide > EBX® Script > Usage

Constraint validation

Introduction

EBX® Script lets you define validation constraints on data models. Constraints are rules on a data model that ensure users enter only valid, accurate, and logically consistent data. You can define constraints at different levels: table, record, table field and dataset field.

When a constraint detects invalid data, it can add a custom message to the validation report. You choose the message text and severity level.

You create constraints in the Advanced controls view of the Data Model Assistant (DMA) . EBX® generates an initial script that you can edit in the EBX® Script IDE, which provides contextual code completion.

Use the EBX® script API core.message to manage localized user messages in constraints. This API provides several methods to create and add user-friendly messages to the validation report.

Initial script

When you create a validation constraint using the Advanced controls in the DMA , EBX® generates an initial script. The initial script contains the correct structure and the necessary exported procedures for the constraint type.

Structure

A constraint’s initial script has the following structure:

<unit usage statement 1>
<unit usage statement 2>
...
<unit usage statement N>

export procedure constraint_signature_name()
begin
  ...
  <statement 1>
  <statement 2>
  ...
end

export procedure setup()
begin
  ...
  <statement 1>
  ...
end

The following script example shows a constraint on an employee in a department. It checks whether the employee number is less than 100. If it is, a warning message is added to the context of the validation report.

export procedure checkRecord(record : .Department)
begin

if (record.Number < 100i) then
 begin
  var message:='The employee number of the department '|record.Name |' is under 100';
  msg.addWarning(message);
 end
end

export procedure setup()
begin
    // Initialization can be added here
  ...
end

Exported procedures

EBX® calls exported procedures directly when evaluating a constraint. Each constraint script can declare only the exported procedures that are relevant to its type (two or three procedures, depending on the constraint type). The exported procedure setup( ) is mandatory. EBX® calls it to initialize the constraint context. Use it to perform initialization tasks, such as declaring the constraint’s dependencies.

EBX® includes the following constraint types:

The signatures of constraint procedures are the following:

Note: The exported procedure signature (name) depends on the constraint’s type and should not be changed. The exported procedure setup( ) is mandatory and should not be changed.

Predefined variables

Predefined variables give you access to information that is available in the constraint context. The following predefined variables can be used depending on the constraint type.

Dataset

The predefined variable _ebx.dataset provides access to information on the current dataset. It is a common predefined variable for all EBX® Script usages (trigger, function field, etc.). For more details, see the Reference section. It is also available for all constraint types.

Example:

uses core.message as msg;
// This constraint adds information about the name of the current dataset.
export procedure checkTable()
begin

msg.adInfo('The dataset name is: ' | _ebx.dataset.name);

end
export procedure setup()
begin
  ...
end

Dataspace

The predefined variable _ebx.dataspace allows read access to the current dataspace. It is common predefined variable for all script usages (trigger, function field, …​). For more details, see the Reference . It is also available for all constraint types.

Example:

uses core.message as msg;
// This constraint adds information about the name of the current dataspace.
export procedure check()
begin

msg.addInfo('The dataspace name is: ' | _ebx.dataspace.name);

end
export procedure setup()
begin
  ...
end

Root

The predefined variable _ebx.root provides read-only access to the current root of the dataset. It is available for all constraint types. The fields under the root are defined by the current EBX® schema.

Example:

uses core.message as msg;
// This constraint adds information about the reference code.
export procedure check()
begin

msg.addInfo('Reference code '|_ebx.root.code);

end
export procedure setup()
begin
  ...
end

Constraint types

A validation constraint defines specific rules to ensure data consistency within a data model. It can be applied at different levels of the data model (table, record, or field). When a validation constraint is violated, a customized error message with a user-defined severity level can be added to the validation report. Below are examples of validation constraints at different levels.

Constraint on table

Table-level check

This constraint type checks the entire table and adds messages when errors are detected. The whole table is checked at once. You can select specific records to be checked using SQL queries and XPath expressions.

Example:

uses core.message as msg;

export procedure checkTable()
begin

// This constraint checks the customers with an empty address and adds an error message.
// A localized user message ('The address is mandatory.') is created from a resource bundle.
var userMessage:= msg.ofBundleError('bundle1/path1','address.mandatory');

// Adds an error message for each customer with an empty address.
msg.addXPathMessage('osd:is-empty(Address)',userMessage);
end

export procedure checkRecord(record :.Employee)
begin
end

export procedure setup()
begin
  ...
end

Record-level check

This constraint supports record-level checks, in addition to the table-level check. It allows you to define custom validations for specific records. This helps detect errors when users input data or when modifying records.

The record parameter in the checkRecord method provides read-only access to the current record. It is available at record-level check for the constraint type Constraint on Table . The fields of the record are defined by the current EBX® schema.

Example 1:

uses core.string as str;
uses core.message as msg;

export procedure checkRecord(record :.Employee)
begin

// This constraint checks if the email ends with tibco.com and adds a warning message if not.
if (not(str.endsWith(record.Email,'tibco.com'))) then
  begin
    msg.addWarning('The email '|record.Email |' should end with tibco.com');
  end
end
end

export procedure setup()
begin
  ...
end

Example 2:

uses core.message as msg;
export procedure checkTable()
begin
end

export procedure checkRecord(record : .Product)
begin

// This constraint checks if the price of the product is under a threshold.
if (record.Price < _ebx.root.PriceThreshold) then
 begin
   var message:='The price of the product '|record.Price |' is under the threshold '|_ebx.root.PriceThreshold;
   msg.addWarning(message);
 end

end
export procedure setup()
begin
  ...
end

Constraint on field

This constraint type defines a field-level check. It ensures that the field satisfies a specific condition. A localized message can be added if the field is invalid. You can define this constraint type on a dataset field, or at a table field.

Dataset field-level check

This constraint type defines a dataset field-level check. Use the predefined variable _ebx.root to access other dataset fields.

Example:

uses core.message as msg;
export procedure check()
begin

// This constraint checks if the image height is between 150 and 500.
if (_ebx.root.image.height > 150 and _ebx.root.image.height < 500) then
  begin
    // add a warning message
    var message:='Image height should be between 150 and 500. Current height is '|_ebx.root.image.height;
    msg.addWarning(message);
  end

end
export procedure setup()
begin
  ...
end

Table field-level check

This constraint type defines a table field-level check. It ensures that the field satisfies a specific condition for each record in the table. A localized message can be added if the field is invalid. The variable record is passed by parameter in the check() . It provides read-only access to the current field’s containing record.

Example:

uses core.message as msg;
// This constraint checks if the project's completed tasks are under 10 and adds an info message
export procedure check(record : .Project)
begin
if (record.Number < 10) then
 begin
  msg.addInfo('Completed tasks is under 10'|record.ProjectId);
 end
end

export procedure setup()
begin
end

Constraint on null

This constraint type defines a dataset or table field-level check on whether a field contains a value. You can add a message if the field is null.

Dataset field-level check

Example:

uses core.message as msg;
// This constraint adds an error message if the project code is missing.
export procedure checkNull()
begin

//Add a message from a bundle with one parameter: 'The code of the project {0} is mandatory'
var message:= msg.ofBundleError('bundle1/path1','project.code.mandatory',_ebx.root.project.name);
msg.addMessage(message);

end
export procedure setup()
begin
  ...
end

Table field-level check

Example:

uses core.message as msg;
// This constraint checks that the publication year is present for the Book.
// If the publication year is missing, an error message is added to the validation report.
export procedure checkNull(record : .Book)
begin
  msg.addError('Publication year is mandatory');
end

export procedure setup()
begin
end

Constraint dependencies

The constraint validation result can depend on updates, insertions or deletions of specific fields. In these cases, you can explicitly declare the field’s dependencies during the initialization of the constraint. Declaring constraint dependencies helps to minimize the number of calls to constraints during the validation process.

You do not have to specify dependencies. However, explicit dependencies improve performance when you validate large volumes of data or when the validation logic is expensive.

The EBX® Script API core.validation provides several methods for declaring a constraint’s dependencies.

Warning: you cannot specify dependencies on computed values or inherited fields.

Insertion, deletion and modification dependency

The validation result of the constraint depends on insertions, modifications and deletions of the specified field.

Example:

uses core.validation as v;
export procedure checkTable()
begin
  ...
end
export procedure checkRecord(record :.Product)
begin
  ...
end

export procedure setup()
begin
  // Declare that this constraint depends on the current record's 'Price' and 'Quantity' fields.
  v.addDependencyToInsertDeleteAndModify('/root/Product/Price');
  v.addDependencyToInsertDeleteAndModify('/root/Product/Quantity');
end

Insertion and deletion dependency

The validation result of the constraint depends on insertions and deletions of the specified table.

Example:

uses core.validation as v;
export procedure checkTable()
begin
  ...
end
export procedure checkRecord(record : .Customers)
begin
  ...
end
export procedure setup()
begin
  // Declares that this constraint depends on the 'Orders' table.
  v.addDependencyToInsertAndDelete('/root/Orders');
end

Modification dependency

The validation result of the constraint depends on the value of the specified field.

Example:

uses core.message as msg;
uses core.validation as v;
export procedure check()
begin
    ...
end

export procedure setup()
begin
 // Declares that this constraint depends on modification of the code field.
 v.addDependencyToModify('/root/Code');
end

Dependency on another dataset

The validation result of the constraint depends on the insertions, modifications and deletions of the specified field or table in specified dataset and dataspace.

Example:

uses core.validation as v;
export procedure checkTable()
begin
  ...
end
export procedure checkRecord(record : .Customers)
begin
  ...
end
export procedure setup()
begin
  // Declare that this constraint depends on the 'Status' field of another dataset and dataspace.
  v.addDependencyToInsertAndDeleteAndModifyInOtherDataset("/root/Orders/Status", 'otherDataset', 'otherDataspace');
  v.addDependencyToInsertAndDeleteInOtherDataset('/root/Items','otherDataset','otherDataspace');
end
Documentation > Developer Guide > EBX® Script > Usage