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

Reference

Introduction

EBX Script is a simple and quite powerful language intended to be used anywhere where Java is currently needed like EBX customization (computed values, table trigger, script task…​).

It is based on the DSL (Domain Specific Language). DSL is a procedural and strongly statically typed language.

To write a script, the EBX IDE can be used. It is an integrated development environment that provides tools and features to assist in defining scripts for function fields, table triggers and script tasks. It includes an editor with various features like syntax highlighting, contextual code completion, source compiling and publishing.

When a new function field or a table trigger is created using the DMA , a default script is created in the EBX IDE.

When a script task is created using the IDE, it can be specified in the Workflow Model .

Lexical structure

Introduction

A script has following structure:

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

<model usage statement 1>
<model usage statement 2>
...
<model usage statement M>

<function or procedure definition 1>
<function or procedure definition 2>
...
<function or procedure definition M>

For more information, see Types declared in a data modelUnit and function and procedure .

The following example is a script of a function field.

// This field returns the full address for current record.
export function getValue(): string
begin
  var address := _ebx.record.FirstName | ' ' | _ebx.record.LastName;

  for street in record.OfficeAddress.Street do
  begin
    address |= '\n' | street;
  end;

  address |= '\n' | _ebx.record.OfficeAddress.ZipCode | ' ' | _ebx.record.OfficeAddress.City;
  address |= '\n' | _ebx.record.OfficeAddress.Country;

  return address;
end

The following example is a script of a table trigger.

 //This trigger adds the full name of current record.
export procedure onBeforeCreate()
begin
_ebx.record.fullName := _ebx.record.firstName | ' ' | _ebx.record.lastName;
end

Character set

The Unicode character set is supported.

Character case sensitivity

The DSL is case-sensitive.

Comments

A single line comment extends from // to the end of the current line:

// This is a comment
if _ebx.record.LastName = 'Doe' then // This is another comment.
  return true;

A multi-line comment extends from /* and ends with */ :

/* This is an example of a multi-line
   comment */
if _ebx.record.isActive then
  return false;

Keywords

The reserved keywords are: andornotusesasfrommodelexporttypeoftableofprimarykeyofmutableimmutablemodifiableunmodifiablepersistedfunctionprocedureconstvarifthenelseforwhilein , do , begin , end , return , true , false , raise , null .

Reserved keywords cannot be used as plain (unquoted) identifiers.

Identifiers

Unquoted identifier

An unquoted identifier is an unlimited-length sequence of letters, digits, or underscore ( _ ). The first character must be a letter or an underscore.

Valid letters are a to z and A to Z . Valid digits are 0 to 9 .

An unquoted identifier may not be equal to a reserved keyword.

Quoted identifiers

A quoted identifier is an unlimited length of any Unicode character except double quote ( " ).

Quoted identifiers must be used surrounded by double quotes.

An unquoted identifier can be used surrounded by double quotes.This means that identifier "a_name" is equal to a_name.

Quoted identifiers can be reserved keywords.

References

References to data models

A script may declare references to data models.

For data models deployed as an XSD file, supported syntaxes are:

references model short_name from module module_name as alias;
references model short_name from module module_name;
references model file_path from module module_name as alias;

The short name is the name of the file without the path and extension. For exemple the short name of /WEB-INF/ebx/schemas/Directory.xsd is Directory .

If no alias is specified, the alias is assumed to be equal to the short name or the file path.

It is possible to declare a data model from current module by using one of the following syntaxes:

references model short_name from module . as alias;
references model short_name from module .;
references model file_path from module . as alias;

For embedded models, use one of the following syntaxes:

references model short_name as alias;
references model short_name;

Data model references samples:

references model Directory from module "ebx-test" as dic;
references model Directory from module "ebx-test";
references model "/WEB-INF/ebx/schemas/userservice/Directory.xsd" from module "ebx-test" as dic;

references model Directory from module . as dic;
references model Directory from module .;
references model "/WEB-INF/ebx/schemas/userservice/Directory.xsd" from module . as dic;

references model catalog as cat;
references model catalog;

References to datasets

A script may declare references to datasets. Supported syntaxes are:

references dataset dataset_name from dataspace dataspace_name as alias;
references dataset dataset_name from dataspace dataspace_name;

references dataset dataset_name from snapshot snapshot_name as alias;
references dataset dataset_name from snapshot snapshot_name;

If no alias is specified, the alias is assumed to be equal to the dataset name.

Declaring a reference to a dataset also declares a reference to its data model with same alias. Dataset references sample:

references dataset catalog from dataspace database_catalogue as s1;

Types

Predefined types

The following predefined types are supported:

TypeKeywordPropertiesEBX® corresponding types

Boolean

boolean

xs:boolean

Decimal (unlimited precision)

decimal

xs:decimal

Integer (32 bits)

int

xs:int

xs:integer

String

string

length (int greater or equal to 0)

xs:string

xs:Name

osd:text

osd:html

osd:email

osd:password 1

osd:color

osd:dataspaceKey

osd:datasetName

Timestamp (millisecond precision and without time-zone)

timestamp

year

month (1 to 12)

day (1 to 31)

hour (0 to 23)

minute (0 to 59)

second (0.000 to 59.999)

xs:dateTime

Date (without time-zone)

date

year

month (1 to 12)

day (1 to 31)

xs:date

Time (millisecond precision)

time

hour (0 to 23)

minute (0 to 59)

second (0.000 to 59.999)

xs:time

Locale

locale

osd:locale

URI (Uniform Resource Identifier )

uri

xs:anyURI

Resource

resource

osd:resource

Dataspace

dataspace

name

identifier (the name prefixed by 'B' or 'V')

isSnapshot (Is true if the dataspace is a snapshot)

Dataset

dataset

name

dataspace

Transaction

transaction

dataspace

isAllPrivileges (read/write boolean property)

executionInformation (read/write string property)

executionTimestamp

executionUUIDString

1 It is not possible to define a function field for type osd:password .

Complex types

A complex type is the type of a group (complex) node defined in an EBX® schema.

For more information, see the chapter complex variables

List types

The DSL supports lists. Declare a list by using the following syntax:

list<item_type>

A list is unmodifiable by default. You can declare a modifiable list by using following syntax:

modifiable list<item_type>

An item cannot be added, removed, or replaced if the list is unmodifiable.

Use indexed notation to set or get a value. (The first index is 0):

// Set first value of cities.
cities[0] := 'Paris';

// Get the second item of cities.
return cities[1];

An index can be any expression of int or decimal type. If the index is a decimal, the fractional part is ignored.

A get expression returns null if the index is null, negative, or out of range.

A set expression reports an error at runtime if the index is null, negative, or out of range.

The property size returns the size of the list:

var size := cities.size;

You can iterate a list.For more information, see for loops .

Multi-value schema fields

Schema fields that are multi-valued are considered of list type.

A multi-valued schema field is a field that has its maximum number of values (maxOccurs) greater than one or set to "unbounded".

Indexed notation is used to access or set a value. The first index is 0. In the following example, record field 'OfficeAddress/street' is multi-valued:

// Return the second line of the street part of the address.
return OfficeAddress.street[1].

The typeof keyword can be used with multi-valued fields (see chapter keyword typeof ).

Keyword typeof

Use the keyword typeof to specify a type depending on a field or variable.

For example, to reference the type of record field OfficeAddress , use the following syntax:

typeof record.OfficeAddress

If a field is multi-valued, it is considered a list. You can reference the type of an item of the list using following syntax:

typeof record.Addresses[*]

Types declared in a data model

To reference the type of a field in current data model that has path /root/User/Address , use the following syntax:

var address: .User.Address;

Note that '/' are replaced by '.' and that first step is omitted.

To get the type of a field in from a data model that has path /root/Sales/Amount in a data model declared with alias 'hist', use the following syntax:

var amount: hist.Sales.Amount

If a field is multi-valued, it is considered a list. You can reference the type of an item of the list using following syntax:

var products: hist.Sales.products[*]

Record, table, primary key

If path "/root/test/table" of a data model sample is for a model, use one of the following syntaxes for specifying a record:

var immutableRecord1: sample.test.table;
var immutableRecord2: immutable sample.test.table
var mutableRecord: mutable sample.test.table

When no modifier is specified, a type is immutable.

Use the following syntax for specifying a table:

var aTable: tableof sample.test.table;
aTable := db.findTable<.directory.Customer>(_ebx.dataset);

Use one of the following syntaxes for specifying a primary key:

var immutablePrimaryKey1: primarykeyof sample.test.table;
var immutablePrimaryKey: immutable primarykeyof sample.test.table
var mutablePrimaryKey: mutable primarykeyof sample.test.table

When no modifier is specified, the primary key is immutable.

Type modifiers

A type may be:

A simple type is always immutable.

You can assign a mutable value to a variable or a return value of a compatible immutable type, but assigning an immutable value to a mutable variable or return value generates an error at compile time.

You can specify an immutable type using one of following syntax:

immutable typeof record.OfficeAddress
immutable .User.Address
immutable hist.Sales.Amount

You can specify an mutable type using one of following syntax:

mutable typeof record.OfficeAddress
mutable .User.Address
mutable hist.Sales.Amount

Some types may not support immutable or mutable keywords and generate an error at compile time.

A list may be:

You can assign a modifiable list to a variable or a return value of a compatible unmodifiable list type, but assigning an unmodifiable list to a modifiable variable or return list generates an error at compile time.

You can modify a mutable complex or list object, but other constraints may apply that can prevent modifying some attributes of an object.

You can specify an unmodifiable list type using following syntax:

unmodifiable typeof  _ebx.record.Addresses[*]
unmodifiable .User.children[*]
unmodifiable hist.Sales.products[*]

You can specify a modifiable list type using following syntax:

modifiable typeof  _ebx.record.Addresses[*]
modifiable .User.children[*]
modifiable hist.Sales.products[*]

Keyword raise

Use the keyword raise to reports an error during the execution of a trigger or a function field.

The following syntax is used to raise an error without a message:

raise code;

The following syntax is used to raise an error with a message:

raise code, message;

Example of using the keyword raise in a function field:

// this function raises an error when the name is empty.
uses core.string as string;
export function getValue(): string
begin
 var name := _ebx.record.name;
 if not string.isEmpty(name) then
  return name;

//value cannot be empty!
 raise 341i;
end

Example of using the keyword raise in a table trigger:

// this trigger checks sales amount and reports an error if the allowed amount is exceeded.
export procedure onBeforeCreate()
begin
if (_ebx.record.amount > 1000) then
raise 450 , 'Sales Amount '| _ebx.record.amount |' has exceeded the allowed amount of 1000';
end

Literals

String literal

String literals can be any sequence of Unicode characters surrounded by single quotes. The following table displays characters that need to be replaced by an escape sequence:

CharacterEscape sequence

Tab

\t

Backspace

\b

New line

\n

Carriage return

\r

Form feed

\f

Single quote

\'

Backlash

\\

Specify a character by using a Unicode escape sequence that has format \uXXXX , where XXXX is the hexadecimal code of the Unicode character.

Examples

ValueSyntax

O’Harra

'O\'Harra'

Noël

'No\u00EBl'

été

'\u00e9t\u00E9'

Note

An invalid escape or Unicode sequence generates an error at compile time.

Decimal literal

The following decimal formats are supported:

FormatExamples

Without fraction

546

-67

Floating point

54.987

-433.876

0.00054

-0.0032

Exponent notation

34.654e-5

-45E+65

1.543e23

Integer (32 bits) literal

Integer 32 bits literals have a format similar to 90324i or -543i .

The value must be between -2147483648i and 2147483647i inclusive.

Attention: If the i letter is missing the value will be considered a decimal.

Timestamp literal

Timestamp literals have the format dt(yyyy-MM-dd hh:mm:ss.sss) .

Seconds are optional. When they are not specified, 0 is assumed. Seconds can have fractions up to millisecond precision.

Any dates that are not valid in the Gregorian calendar generate errors at compile time.

Examples:

dt(2010-01-02 00:00:00.000)
dt(2019-2-3 12:56:7)
dt(2019-2-3 12:56:7.5)
dt(2019-5-7 1:6)

Date literal

Date literals have the format d(yyyy-MM-dd) .

Any dates that are not valid in the Gregorian calendar generate errors at compile time.

Examples:

d(2010-01-02)
d(2019-2-3)
dt(2019-5-7)

Time literal

Time literals have the format t(hh:mm:ss.sss) .

Seconds are optional. When they are not specified, 0 is assumed. Seconds can have fractions up to millisecond precision.

Invalid times generate an error at compile time.

Examples:

t(00:00:00)
t(12:56:7)
t(12:56:7.5)
t(1:6)

Boolean literal

A Boolean literal is either the keyword true or the keyword false .

Null literal

A null literal is the keyword null .

Use this literal only in the following situations:

Note

It is not possible to use this keyword to test if a variable or a field is null . Instead, use the function isNull() .

Operators

Precedence

By default, operation evaluation order is based on precedence and associativity. Use parentheses to explicitly indicate the order of evaluation.

The following table shows all operators, from highest to lowest precedence, and their associativity:

Precedence LevelOperatorOperand typeResult typeAssociativity

9

(access to an element of a list)

. (access to fields)

() (parenthesis)

List index must be an int or a decimal.

Can be any type.

Left to right.

8

not

boolean

boolean

7

*

/

decimal or int

decimal

Left to right.

6

+

-

decimal or int

decimal

Left to right.

5

| (string concatenation)

string

string

Left to right.

4

<

<=

>

>=

string, decimal, int, timestamp, date, time (3).

boolean

Not associative.

3

=

<>

string, decimal, int, timestamp, date, time, boolean (3).

boolean

2

and

boolean

boolean

Left to right.

1

or

boolean

boolean

Left to right.

Arithmetic operators

All arithmetic operators ( */+ and - ) are evaluated in decimal with 34 digits precision (IEEE 754R Decimal128 format). Values of ìnt type are always converted to decimal before comparison.

Result is null if any operand is null .

A decimal value is automatically converted when assigned to an int type variable. An error occurs if the value cannot be converted because it is not an integer, is greater than 2147483647, or is less than -2147483648.

String concatenation operator

The string concatenation operator ( | ) operands can be of any type and are automatically converted to a string before concatenation. The null value is replaced by the empty string.

The string concatenation operator ( | ) replaces all null operands by the empty string before executing the concatenation.

Boolean operators

Boolean operators use thread-value logic.

The truth table for the and operator is as follows:

And

true

false

null

true

true

false

null

false

false

false

false

null

null

false

null

The truth table for the or operator is as follows:

Or

true

false

null

true

true

true

true

false

true

false

null

null

true

null

null

Comparison operators

A comparison operator ( <<=>=>= and <> ) compares two operands of same type. Values of int type are always converted to decimal before comparison.

The returned value of a comparator is of boolean type. This value is true or false only if all operands are not null . It is null if any of its operand is null .

Built-in and unit functions

Built-in and unit functions usually return null if a parameter is null .

There can be exceptions, so be sure to read the API documentation .

Assignments

The following table shows all assignment operators:

OperatorOperand typeDescription

:=

Can be used with any type.

Standard assignment.

|=

string

a |= b is equivalent to a := a | b

+=

decimal, int

a += b is equivalent to a := a + b

-=

decimal, int

a -= b is equivalent to a := a - b

*=

decimal, int

a *= b is equivalent to a := a * b

/=

decimal, int

a /= b is equivalent to a := a / b

Statement blocks

A statement block is used to group multiple statements. It starts by the keyword begin and ends with the keyword end . Most statements need to be terminated by a ; :

begin
  statement_1;
  statement_2;
end

A statement block can contain one or more statement blocks that can also contain statement blocks:

begin
  statement_1;
  begin
    statement_2_1;
    statement_2_3;
    begin
      statement_3_1;
      statement_3_2;
    end
  end
  statement_3;
end

Variables and constants

Introduction

Any statement in a block can declare a variable or a constant.

A variable or a constant always has a type that is fixed when the variable is declared.

A value can be assigned to a variable using the assignment operator := .

Its is an error to assign a value of the wrong type to a variable, or to change the value of a constant after its declaration.

Assignment statements

Declaration with type detection

A variable or constant type can be detected automatically if initialized when declared. This feature is called type inference.

Syntax for a variable is:

var variable_name := a_value;

The syntax for a constant is:

const const_name := a_value;

Examples:

begin
  var firstName := 'John';        // Variable of type string.
  var age := 30i;                 // Variable of type int.
  var cost := 34.54;              // Variable of type decimal.
  var value := 43;                // Variable of type decimal not int
                                  // because the letter `i` is missing.
  var address := record.address;  // Variable of an immutable complex.

  const MAX_AGE := 100i;              // Constant of type int.
  const DEFAULT_COUNTRY := 'France'; //  Constant of type string.
end

Note

A constant is not necessarily immutable.

Explicit type definition

It is possible to explicitly specify the variable’s type.

The syntax for a variable is:

// Following variable initial value is null.
var variable_1_name : variable_1_type;

// Value a_value must be compatible with type variable_1_type.
var variable_2_name : variable_1_type := a_value;

The syntax for a constant is:

const const_name : variable_1_type := a_value;

Examples:

begin
  var firstName : string;
  firstName := 'John';

  var age : int;
  age := 30;
  var address : typeof record.address;
  address := record.address;

  const MAX_AGE : int := 100;
  const DEFAULT_COUNTRY : string := 'France';
end

Variables that are not initialized have a null value:

begin
  var firstName : string;
  if isNull(fistName) then
     do_something(); // Statement will be executed.
end

The following statements have errors:

begin
  // Following will not compile because variable is not initialized and no type
  // is defined.
  var firstName;
  // Following will not compile because variable type is decimal and value is
  // a string.
  var amount : decimal := 'test';
end

Scope

A variable or constant scope spans from its declaration to the end of the statement block where it was declared:

begin
  var firstName := 'John';
  var lastName := 'Doe';

  begin
    // Following is OK because firstName and lastName are visible.
    var fullName := firstName | ' ' | lastName;
    ....
  end

  // Following will NOT compile because fullName is out of the scope.
  var message := 'Please contact ' | fullName;
end

A variable with same name cannot exist in same block or sub blocks:

begin
  var firstName := 'John';

  begin
    var firstName := 'Bob'; // Error! Variable already declared.
    ....
  end
end

The following is correct:

begin
  begin
    var firstName := 'Bob';
    ....
  end
  // The following is not an error, because block where previous variable was
  // declared is ended.
  var firstName := 'John';
end

Complex variables

Variable or constants of complex type can be declared using type detection or typeof keyword .

Dot notation is used to access fields of a variable of complex type.

Examples:

// Declaration using type detection.
var address1 := _ebx.record.OfficeAddress;

// Declaration using typeof notation.
var address2 : typeof _ebx.record.OfficeAddress;
address2 := address1;

Each step (parts separated by a dot) is an identifier . This means that following quoted notation can be used for any step:

var city := _ebx.record."OfficeAddress".City;

This is useful for steps equal to a reserved keyword or using characters, such as the minus character ( - ) or dot ( . ), that are not compatible with unquoted identifiers.

At runtime, any step can evaluate to null . In this case the full field expression evaluates to null .

Multi-valued fields

Multi-valued fields are treated as ordered lists. Index notation [index] is used to access an item of the list. Indexes are 0 based (first index is 0).

In the following example, the field "Address" is multivalued:

var city := _ebx.record.Address[1].City;

If an index is out of bound, the indexed expression will return null . In this case the full field expression evaluates to null .

An index may be a decimal or int expression . If decimal` the fractional part will be ignored.

Predefined variables

Introduction

Predefined variables allow access to information of the context. The following predefined variables described in this section are common to contexts (function field, table trigger). They are constant and of an immutable complex type.

Note that there are some specific predefined variables for each contexts: function field, table trigger and script task.

For details on these specific variables, see the links Function fieldTable trigger and Script Task .

Dataspace

The predefined variable _ebx.dataspace provides access to information on the current dataspace.

This variable has following fields:

NameTypeDescription

name

string

The name of the dataspace. Since the dataspace namespace and the snapshot namespace are independent, the returned string is only an identifier in the context of one of the namespaces. For a global dataspace or snapshot identifier, use field id .

identifier

string

The persistent identifier of a dataspace or snapshot. Compared to name , this identifier additionally specifies whether this id is for a dataspace or a snapshot.

isSnapshot

boolean

Is true if dataspace is a snapshot and false if dataspace is a branch.

Example:

// Returns details on the current dataspace.
export function getValue(): string
begin
  if _ebx.dataspace.isSnapshot then
    return 'Snapshot: ' |  dataspace.name;
  else
    return 'Branch: ' |  dataspace.name;
end

Dataset

The predefined variable _ebx.dataset provides access to information on the current dataset.

This variable has the following fields:

NameTypeDescription

name

string

The name of the dataset

dataspace

dataspace

The dataspace of the dataset

Example:

// Returns the current dataset name.
export function getValue(): string
begin
  return _ebx.dataset.name;
end

Root

The predefined variable _ebx.root is available when the current script is for a table trigger or for a function field. It provides read-only access to the fields of current datasets.

Its fields are defined by the current EBX® schema.

Examples:

// this function field returns information on current dataset data.
export function getValue(): string
begin
	return _ebx.root.City | ' ' | _ebx.root.Region;
end
// this trigger logs information of current dataset data.
uses core.log as log;
export procedure onNewContext()
begin
	log.info(_ebx.root.City | ' ' | _ebx.root.Region);
end

Functions and procedures

Functions

Functions are methods that return a value.

A function with no parameters has the following syntax:

function function_name(): return_value_type
begin
  ....
  return a_value;
end

A function with parameters has the following syntax:

function function_name(
  parameter_1 : parameter_1_type,
  parameter_2 : parameter_2_type...,): return_value_type
begin
  ....
  return a_value;
end

It’s possible to declare a parameter constant using the const keyword:

function function_name(const parameter_1 : parameter_1_type): return_value_type
begin
  ....
  return a_value;
end

The last statement of a function must always be a return statement. The function can include as many return statement as necessary.

Example:

function getFullName(firstName: string, lastName: string): string
begin
  if isNull(firstName) then
    return lastName;

  return firstName | ' ' | lastName;
end

It is illegal to return a value different from the one declared:

function getValue(): string
begin
    return 0; // Error! Return type is decimal, not string.
end

Procedures

Procedures are methods that do not return a value.

A procedure with no parameters has the following syntax:

procedure procedure_name()
begin
  ....
end

A procedure with parameters has the following syntax:

procedure procedure_name(
  parameter_1 : parameter_1_type,
  parameter_2 : parameter_2_type...)
begin
  ....
end

It’s possible to declare a parameter constant using the const keyword:

function procedure_name(const parameter_1 : parameter_1_type): return_value_type
begin
  ....
  return a_value;
end

A procedure cannot have a return statement, but the function can include as many return statements as necessary. A procedure statement cannot return a value.

Exported function or procedures

An exported function can be called directly by EBX®. Only one exported function or procedure is allowed per script. Its signature (name, return type) depends on the context.

For details on the exported function or procedure of each context, see the Function field and the Table trigger .

Parameters

Simple type parameters are passed by value. This means that a function or a procedure receives a copy of the original value.

Complex and list types are passed by reference. This means that a function or a procedure receives the original object. If the function or procedure modifies the object, the original one is modified.

If statement

"If then" statements

An "if then" statement has the following syntax:

if condition-expression then
  then-statement

The condition expression must evaluate to a boolean type.

The 'then' statement can be a statement block .

"If then else" statements

An "if then else" statement has following syntax:

if condition-expression then
  then-statement
else
  else-statement

The condition expression must be of boolean type.

A 'then' or 'else' statement can be a statement block .

Note

Expression:

if condition-expression then
  statements-a;
else
  statements-b;

Cannot be equivalent to:

if not condition-expression then
  statements-b;
else
  statements-a;

Indeed, if the expression is null, the else statement is executed in both cases.

Loops

"For in do" loops

A "for in do" loop statement is used to select each item of a list and execute a block statement. It has following syntax:

for item_variable_name in list do
begin
  statement_a;
  statement_b;
  ...
end

The block statement is executed once for each value of the list. At each iteration, the read-only item variable takes a value of the list in the order of the list.

The name of the item variable must be unique in the current scope or an error will be generated at compile time.

If a single statement must be executed for each item, the following simpler syntax can be used:

for item_variable_name in list do statement;

The following example iterates a list of complex:

// Concatenate all city addresses in a single string.
var cities := '';
for address in _ebx.record.Addresses do
begin
  if cities <> '' then cities |= ', ';
  cities |= address.city;
end

"While do" loops

A "while do" loop statement is used to execute a statement block until a condition is true . It has following syntax:

while condition do
begin
  statement_a;
  statement_b;
  ...
end

If a single statement must be executed, the following simpler syntax can be used:

while condition do statement_a;

The following example calculates factorial of a value:

function factorial(value : decimal): decimal
begin
 var factorial := value;
 while(value > 1) do
 begin
   value -= 1;
   factorial *= value;
 end
 return factorial;
end

A decimal type is used instead of an int type to avoid out of range errors.

Units

EBX® provides an API that is packaged in "units".

A unit can define multiple function or procedures.

Except for the default one, a unit must be declared before usage. The declaration must be at the top of the script and must follow these types of syntaxes:

uses package_name.unit_name_a;
uses package_name.unit_name_b as alias_b;

Currently, package_name is always core . A unit alias must be unique in a script.

Methods can be referenced using following syntaxes:

value1 := package_name.unit_name_a.function_a();
value2 := package_name.unit_name_a.function_b(parameter1, parameter2);

value3 := alias_a.function_c();
value4 := alias_a.function_d(parameter1, parameter2);

package_name.unit_name_a.procedure_a();
package_name.unit_name_a.procedure_b(parameter1, parameter2);

alias_a.procedure_c();
alias_a.procedure_d(parameter1, parameter2);

The following example uses the core.list unit to create a list:

uses core.list as list;

export function getValue(): typeof _ebx.record.Cities
begin
  return list.of('Paris', 'Bruxelles', 'Berlin');
end

For details on the provided units, see the API Documentation .

Logging and debugging

The unit unit.log provides a function that can be used to log a message.

A message logged by scripts can be viewed using Administration>Repository management>Scripting EBX® menu.

Another useful feature is that if a runtime encounters an error while executing a script, it is usually logged with the line in the script where the error occurred.

Initial script

When a new function field or table trigger is created using the DMA , an initial script is created.

The following example is a script created for a table trigger:

uses core.datetime as datetime;
export procedure onBeforeCreate()
begin
record.inscriptionDate := datetime.now();
end

The following example is a script created for a function field of type string:

// Returns the full name.
export function getValue(): string
begin
	return _ebx.record.FirstName | ' ' | _ebx.record.LastName;
end

For details on initial script, see the Function field and the Table trigger .

Documentation > Developer Guide > EBX® Script