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 .
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 model , Unit 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
The Unicode character set is supported.
The DSL is case-sensitive.
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;
The reserved keywords are: and , or , not , uses , as , frommodelexport , typeof , tableof , primarykeyof , mutable , immutable , modifiableunmodifiable , persistedfunction , procedure , const , var , if , then , else , for , while , in , do , begin , end , return , true , false , raise , null .
Reserved keywords cannot be used as plain (unquoted) identifiers.
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.
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.
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;
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;
The following predefined types are supported:
Type | Keyword | Properties | EBX® 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 .
A complex type is the type of a group (complex) node defined in an EBX® schema.
For more information, see the chapter complex variables
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 ).
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[*]
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[*]
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.
A type may be:
immutable : it is not possible to modify an item of this type.
mutable : it may be possible to modify an item of this type.
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:
unmodifiable : it is not possible to remove on insert an item. Items may be immutable or not.
modifiable : it is possible to remove on insert an item. Items may be immutable or not.
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[*]
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;
code is the error identifier. It must be an integer 32 value.
message specifies the error message to be displayed.It is an optional string value.
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
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:
Character | Escape 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
Value | Syntax |
---|---|
O’Harra | 'O\'Harra' |
Noël | 'No\u00EBl' |
été | '\u00e9t\u00E9' |
Note
An invalid escape or Unicode sequence generates an error at compile time.
The following decimal formats are supported:
Format | Examples |
---|---|
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 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 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 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 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)
A Boolean literal is either the keyword true or the keyword false .
A null literal is the keyword null .
Use this literal only in the following situations:
To set a variable or field,
As a return value.
Note
It is not possible to use this keyword to test if a variable or a field is null . Instead, use the function isNull() .
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 Level | Operator | Operand type | Result type | Associativity |
---|---|---|---|---|
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. |
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.
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 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 |
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 usually return null if a parameter is null .
There can be exceptions, so be sure to read the API documentation .
The following table shows all assignment operators:
Operator | Operand type | Description |
---|---|---|
:= | 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 |
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
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.
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.
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
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
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 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 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 field , Table trigger and Script Task .
The predefined variable _ebx.dataspace provides access to information on the current dataspace.
This variable has following fields:
Name | Type | Description |
---|---|---|
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
The predefined variable _ebx.dataset provides access to information on the current dataset.
This variable has the following fields:
Name | Type | Description |
---|---|---|
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
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 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 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.
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 .
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.
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 .
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.
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
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.
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 .
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.
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 .