app.ducx Expression Language is a proprietary interpreted script language that allows you to access the object model, and to invoke use cases. app.ducx expressions can be embedded in expression blocks and other language elements of the domain-specific languages of Fabasoft app.ducx. This chapter introduces the app.ducx Expression Language.
Note: The grammar of the app.ducx Expression Language can be found in chapter “Grammar of the app.ducx Expression Language”. The syntax for search queries is available in chapter “Grammar of the Kernel Interfaces Query Language”.
app.ducx Expression Language is a distinct domain-specific language of Fabasoft app.ducx. app.ducx expressions can be embedded inline in an expression block in other domain-specific languages. However, it is also possible to create separate .ducx-xp files containing app.ducx expressions. app.ducx expression language files can be referenced from other domain-specific languages using the file keyword.
The app.ducx expression language is processed by the Fabasoft app.ducx compiler and transformed into Fabasoft app.ducx Expressions, which are evaluated at runtime by the kernel.
Keywords, predefined functions and predefined variables are not case sensitive.
In the first step, the expression code is parsed. An expression can be parsed at runtime by calling the Parse method of the runtime. The Parse method returns an expression object (which is not related to an object stored in the domain). In a second step, the Evaluate method is invoked on the expression object for evaluating the expression. The scopes to be used during the evaluation of the expression must be passed to the Evaluate method. The result of the evaluation is passed back in the return value of the Evaluate method.
By selecting some expression code in any app.ducx file, this code can be executed against the installation.
Using app.ducx expression language, you can write trace messages to the Fabasoft app.ducx Tracer.
For writing messages and variable values to the trace output, you can either use the %%TRACE directive or the Trace method of the runtime.
If you pass two arguments to the Trace method of the runtime, the first argument is interpreted as a message while the second argument is treated as the actual value.
The %%TRACE directive can also be used to trace special objects like cootx to output all transaction variables defined for a transaction or coometh to output all set parameters within the implementation of a method.
Note:
Example |
---|
// Tracing string messages // Tracing variable values // Trace directives are only evaluated if the software component // Tracing local and global scope |
A name is a letter, followed by letters, digits and the underscore ‘_’ symbol. Keywords of the app.ducx languages are generally not allowed as valid identifiers with some exceptions. Names are used to reference all types of objects, i.e. use cases, functions, variables, interfaces in the Fabasoft Folio environment, optionally prefixed with a software component.
A scope is similar to a container holding a value that is accessible during the evaluation of an expression. The following distinct scopes are available to you when an expression is evaluated:
You can use the keyword this along with the corresponding operator to access the value of a scope (e.g. :>this yields the value of the local scope, and ::this the value of the global scope). However, in most cases the keyword this can be omitted. When accessing the local scope, you can also omit the operator :> in most cases.
Note: Inside the selection operator [] for selecting values of lists or compound properties, the :> operator is required to access the local scope.
The keyword declare is used to declare an identifier. The Fabasoft app.ducx compiler automatically generates identifier declarations for use case parameters to allow access to parameters over the local scope when implementing a use case in app.ducx expression language.
For the following example, assume that the local scope this contains an instance of object class APPDUCXSAMPLE@200.200:Order, and that the temporary variable @customer contains an instance of object class FSCFOLIO@1.1001:ContactPerson. APPDUCXSAMPLE@200.200:customerorders is an object list pointing to instances of object class APPDUCXSAMPLE@200.200:Order. Within the square brackets put after APPDUCXSAMPLE@200.200:customerorders, this has a different meaning as it refers to each instance stored in the object list, and not to the local scope.
Example |
---|
ContactPerson @customer; // Returns a STRINGLIST containing the names of all orders in property // Returns an OBJECTLIST containing the orders whose name is identical to |
In the following example, two strings, isbn and title, are declared in the local scope this. The temporary variable @publication is initialized with a dictionary consisting of two properties, isbn and title that in turn are initialized using the two strings isbn and title from the local scope.
Note: Within the scope of the curly braces or square brackets if used with filter expressions, when using the assignment operator “=”, this refers to the compound structure itself. To access the local scope, the :> operator must be used.
Example |
---|
string isbn = "000-0-00000-000-0"; dictionary @publication = { isbn = :>isbn, title = :>title }; |
For better readability, the "JSON" notation could be used. In this notation, the scope does not change.
Example |
---|
string isbn = "000-0-00000-000-0"; dictionary @publication = { isbn : isbn, title : title }; |
The temporary scope @this is used for storing temporary values during the evaluation of an expression. Local scope this and global scope ::this are similar to parameters, and can be populated with any valid value when the Evaluate method is called for evaluating an expression.
The scopes cannot be changed while an expression is evaluated. However, you can add or modify dictionary entries if a scope contains a dictionary.
Types can be categorized into basic types and user-defined types (such as classes, structs, and enums). In addition, types can be categorized into scalar types and list types.
The following basic types are most common and are built into the language. These types have a corresponding type definition in the object model, as shown in following table.
Basic Type | Corresponding Type Object |
---|---|
boolean | COOSYSTEM@1.1:BOOLEAN |
integer | COOSYSTEM@1.1:INTEGER |
float | COOSYSTEM@1.1:FLOAT |
string | COOSYSTEM@1.1:STRING |
date, datetime | COOSYSTEM@1.1:DATETIME |
currency | COOSYSTEM@1.1:Currency |
content | COOSYSTEM@1.1:CONTENT |
dictionary | COOSYSTEM@1.1:DICTIONARY |
object | COOSYSTEM@1.1:OBJECT |
Note: The special value null represents the absence of data for all types. It is commonly assigned to variables to indicate that they currently do not reference any valid object or value.
In addition to scalar types, list types group multiple values together. Some list types have corresponding type definitions in the object model, as shown in following table.
Keyword | PROCECO Type Definition |
---|---|
boolean[] | COOSYSTEM@1.1:BOOLEANLIST |
integer[] | COOSYSTEM@1.1:INTEGERLIST |
float[] | COOSYSTEM@1.1:FLOATLIST |
string[] | COOSYSTEM@1.1:STRINGLIST |
date[], datetime[] | COOSYSTEM@1.1:DATETIMELIST |
content[] | COOSYSTEM@1.1:CONTENTLIST |
dictionary[] | COOSYSTEM@1.1:DICTIONARYLIST |
object[] | COOSYSTEM@1.1:OBJECTLIST |
Elements of a list can be retrieved using the selection operator (see chapter “Selection Operator”).
More information about operators can be found in chapter “Operators”.
Some types support using kernel methods to work with values. The usage of the generic kernel methods may provide a more generic access to values (e.g. it is possible to set dictionary members with uncommon or reserved names).
All available kernel methods can be found in the reference documentation:
The boolean data type is used to represent logical values. Values of this type can be true or false.
Examples |
---|
boolean b1 = true; |
The integer data type represents 64 bit numbers without decimal points.
Example |
---|
integer i = 1; |
Useful explicit type conversions include the conversion from string, float, and datetime:
Example |
---|
integer i = integer("3"); // explicit conversion from string: string must be a valid floating point number |
The float data type is used to represent single-precision floating-point numbers with 9 digits of precision.
Example |
---|
float f = 3.14; |
It implicitly supports the conversion from integer and the explicit conversion from string.
Example |
---|
float f = 1; |
The string data type represents a sequence of characters and is used to store and manipulate textual data. Strings can be declared using single quotes (' '), or double quotes (" "). Strings can contain letters, numbers, symbols, and whitespace characters. They can also include special characters like newlines and tabs using escape sequences (link to XpGrammar). The implicit property length makes it possible to get the length of the string.
Examples |
---|
string firstname = "Jane"; |
It implicitly supports the conversion from integer and content. Explicit conversions include conversions from float, object, datetime, and boolean.
Examples |
---|
string s = string(3.14); // "3.14" |
The datetime data type refers to a built-in object that represents a specific date and time. It allows you to manipulate dates and times. To represent date only values you can use the keyword date. The following examples show how to assign different date values.
Examples |
---|
datetime now = coonow; // coonow holds the current date and time |
It supports the explicit conversion from string:
Examples |
---|
datetime dt = datetime("2012-01-02T14:15:22"); // string needs to be a valid date literal |
The datetime data type exposes implicit properties that can be used to access and manipulate the individual date and time components. These implicit properties are listed in the following table. All of these implicit properties are of data type integer.
Property | Description |
---|---|
year | The year property can be used for getting and setting the year. |
month | The month property can be used for getting and setting the month. |
day | The day property can be used for getting and setting the day. |
hour | The hour property can be used for getting and setting the hour. |
minute | The minute property can be used for getting and setting the minutes. |
second | The second property can be used for getting and setting the seconds. |
dayinweek | The dayinweek property can be used for getting the day of the week, with the value 0 representing Sunday and 6 representing Saturday. |
dayinyear | The dayinyear property can be used for getting the day of the year, with the possible values ranging from 1 to 366 (for a leap year). |
weekinyear | The weekinyear property can be used for getting the week of the year, with the possible values ranging from 1 to 52. |
local | The local property returns the date and time value converted to local time. |
universal | The universal property returns the date and time value converted to universal time. |
Examples |
---|
// modify the date |
It is also possible to use some arithmetic and comparison operations with date values, as shown in the following examples.
Examples |
---|
datetime before2hours = coonow; |
The currency data type is used to represent monetary values and allows to handle financial calculations related to currencies. It is composed of a currency value and a currency symbol. The currency value represents a specific amount of money. It can be a decimal or floating-point with an arbitrary number of digits. The currency symbol represents the specific currency unit.
Note: Converting a currency value to an integer or float can result in information loss since currency values can potentially have an arbitrary number of digits. To mitigate these issues, it is crucial to consider the range and precision of the target data type.
Examples |
---|
currency c1 = { currsymbol: EUR, currvalue: 3 }; |
It supports implicit conversion from integer and float and it is also possible to apply basic arithmetic operations to currencies. Even with different currency symbols., as shown in following examples.
Examples |
---|
c1 + 3; // 6 EUR |
The content data type represents arbitrary data, such as text or binary files.
It may not to be confused with the struct COOSYSTEM@1.1:Content. The struct Content holds a property of type content along with additional metadata such as the file extension.
Examples |
---|
content mycont = "Hello world!"; // Implicit conversion |
Note: When converting a string to a content as in the example above, be aware that this conversion also includes an UTF-8-byte order mark (BOM). Therefore, the value mycontsize is 15 (3 from the BOM and 12 from "Hello world!").
The dictionary data type represents key-value maps to store and retrieve values based on unique string keys. It provides an efficient way to perform lookups, insertions, and deletions.
Dictionaries associate each key with a corresponding value. Keys are unique within the dictionary. Values can be of any data type, such as integers, strings, objects, or even other dictionaries. Moreover, values can be lists.
Dictionaries can be created in the following way:
Examples |
---|
dictionary mydictionary = {}; // create an empty dictionary |
To store a value in a dictionary, you provide a key-value pair and the dictionary associates the key with the corresponding value. If the key already exists in the map, the previous value associated with that key is overwritten. If the key is new, a new entry is created in the dictionary.
Examples |
---|
mydictionary.key1 = 2; // set value of key1 |
To retrieve a value from the map, you specify the key, and the map returns the corresponding value associated with that key. If the key is not found in the dictionary, a null value is returned.
Examples |
---|
integer i = mydictionary.key1; // get value of key1 |
The object data type represents objects in general. It is valid for instances of all object classes. It allows to access the most basic properties of objects, such as the name and address. These implicit properties are listed in the following table.
Property | Description |
---|---|
address | The address property can be used to get the unique key of the object. |
identification | The identification property can be used to get the key of an object at a given time. |
name | The name property can be used to get the name of the object without transaction context. |
reference | The reference property can be used to get the reference of an object. This property is only defined for objects of classes derived from ComponentObject. |
Examples |
---|
object myobject = coouser; // assign an existing object |
It supports the explicit conversion from string:
Examples |
---|
object myobject = "COO.1.1.1.402"; // string must be a valid object address |
The any data type is a special type that represents a value of any type. When a variable is declared of type any, it allows that variable to hold any value, regardless of its type.
However, it's important to note that once a variable is assigned a specific type, it remains fixed and cannot be changed during runtime. This immutability can lead to type conversion errors if the variable is later used in operations or contexts that expect a different type.
Examples |
---|
any myinteger = 1; |
For all variables within an expression a type should be defined explicitly.
Syntax |
---|
// Declaring a variable // Declaring and initializing a variable |
Valid types are object classes and objects of the class COOSYSTEM@1.1:TypeDefinition, which includes base types as well as compound types and enumerations.
Additionally, attribute definitions (objects of type COOSYSTEM@1.1:AttributeDefinition ) can be used as types for variables.
Shortcuts are provided for basic data types as defined by the object model language as well as kernel interfaces as listed below.
Type | Description |
---|---|
runtime | The type for a runtime interface, such as the predefined symbol coort. |
transaction | The type for a transaction interface, such as the predefined symbol cootx. An interface of this type is returned, if you create a new transaction using coort.CreateTransaction(). |
method | The type for a method interface, such as the predefined symbol coometh. An interface of this type is returned, if you obtain the implementation of a use case using cooobj.GetMethod(). |
searchresult | The type for an interface for the result of an asynchronous search, as returned by coort.SearchObjectsAsync(). |
expression | The type for a Fabasoft app.ducx Expression interface, as returned by coort.Parse(). |
aggregate | The type for an aggregate interface, which can be used as a generic substitute for any compound type. |
interface | A generic type for an interface. |
Example |
---|
integer @bulksize = 150; while ((@results = @sr.GetObjects(@bulksize)) != null) { |
Sometimes the types of variables are not known or not specific enough to write expressions without warnings. This can be fixed using the keyword assume. assume tells the app.ducx compiler the correct type.
Example |
---|
usecase OnUserAndGroup(any memberof) { |
Some scopes can contain variables which are not documented. Should this be the case and the developer wants to access these variables, the keyword assume can be used, too. In this case the assume statement is written like a parameter declaration, specifying input/output modifier.
Example |
---|
usecase SetReturnURL() { |
The keyword assume can also be used to declare the types of dictionary entries, especially the cardinality.
Example |
---|
usecase UpdateUser(dictionary datainput) { |
app.ducx expression language supports a wide range of operators.
Assignment operators allow you to set property and variable values. The following table contains a list of supported assignment operators.
Operator | Description |
---|---|
= | The = operator is used for simple assignments. The value of the right operand is assigned to the left operand. |
+= | Both operands are added, and the result is assigned to the left operand. The += operator can be used with strings, numeric data types, currencies and lists. |
-= | The right operand is subtracted from the left operand, and the result is assigned to the left operand. The -= operator can be used with numeric data types, currencies, lists and dictionaries. |
*= | Both operands are multiplied, and the result is assigned to the left operand. The *= operator can be used with numeric data types, currencies, lists and dictionaries. |
/= | The left operand is divided by the right operand, and the result is assigned to the left operand. The /= operator can be used with numeric data types, currencies, lists and dictionaries. |
%= | A modulus operation is carried out, and the result is assigned to the left operand. The %= operator can only be used with numeric data types, currencies, lists and dictionaries. |
<<= | <<= is used for character- and bitwise shifting to the left. The <<= operator can be used with strings, integers, currencies and lists. |
>>= | >>= is used for character- and bitwise shifting to the right. The >>= operator can be used with strings, integers, currencies and lists. |
??= | If the left operand is null, the right operand is evaluated and assigned to the left operand. |
Example |
---|
Order @order; // A simple assignment operation // Adding an element to a list // Adding an element to a list only if it is not part of the list already |
Logical operators support short circuit evaluation semantics. The right operand is only evaluated if the result of the evaluation is not determined by the left operand already. The following table shows a list of the supported logical operators.
Operator | Description |
---|---|
and (alternatively &&) | The and operator indicates whether both operands are true. If both operands have values of true, the result has the value true. Otherwise, the result has the value false. Both operands are implicitly converted to BOOLEAN and the result data type is BOOLEAN. |
or (alternatively ||) | The or operator indicates whether either operand is true. If either operand has a value of true, the result has the value true. Otherwise, the result has the value false. Both operands are implicitly converted to BOOLEAN and the result data type is BOOLEAN. |
not (alternatively !) | The expression yields the value true if the operand evaluates to false, and yields the value false if the operand evaluates to true. The operand is implicitly converted to BOOLEAN, and the data type of the result is BOOLEAN. |
?? | The expression yields the value of the left operand if not null, otherwise the value of the right operand. |
Example |
---|
if (@orderstate == OrderState(OS_SHIPPED) and @orderdate != null or |
The following table contains a list of supported calculation operators.
Operator | Description |
---|---|
+ - * / % | The +, -, *, / and % operators are supported for numeric data types and lists. +, -, * and / are also supported for currencies (* and / need one integer or float operand). Additionally, the + operator can be used to concatenate strings. When used with lists, the following semantic applies: + (concatenation): The right operand is concatenated to the end of the left operand. - (difference): Each element from the right operand is removed from the left operand. * (union): Each element from the right operand is appended to the left operand if the element does not occur in the left operand. / (symmetric difference): The resulting list is the union of the difference of the left and the right operand and the difference of the right and the left operand: a / b == (a - b) * (b - a) == (a * b) - (b % a). % (intersection): The resulting list is the list of elements that exist in both the left and the right operand. Note: Each element in a list is treated as an individual element, even if the list contains other elements with the same value. So be careful if you use operators with lists that are not unique. Since there are two elements "2" in the left operand, these expressions are true: [1, 2, 2] - [2] == [1, 2]; [1, 2, 2] * [2] == [1, 2, 2]; When used with dictionaries, the following semantic applies: - (difference): Each entry from the right operand is removed from the left operand (regardless of the value of the entry) * (union): Each entry from the right operand is appended to the left operand if the entry does not occur in the left operand. / (symmetric difference): The resulting dictionary is the union of the difference of the left and the right operand and the difference of the right and the left operand: a / b == (a - b) * (b - a) == (a * b) - (b % a). % (intersection): The resulting dictionary contains the entries that exist in both the left and the right operand. The values are taken from the left operand. |
++ | The ++ increment operator is a unary operator that adds 1 to the value of a scalar numeric operand. The operand receives the result of the increment operation. You can put the ++ before or after the operand. If it appears before the operand, the operand is incremented. The incremented value is then used in the expression. If you put the ++ after the operand, the value of the operand is used in the expression before the operand is incremented. |
-- | The -- decrement operator is a unary operator that subtracts 1 from the value of a scalar numeric operand. The operand receives the result of the decrement operation. You can put the -- before or after the operand. If it appears before the operand, the operand is decremented. The decremented value is then used in the expression. If you put the -- after the operand, the value of the operand is used in the expression before the operand is decremented. |
<< | The << is used for character- and bitwise shifting to the left. The << operator can be used with strings, integers, currencies and lists. When used with strings, the right operand specifies the number of characters removed from the beginning of the string. When used with lists, the right operand specifies the number of elements to be removed from the top of the list. |
>> | The >> is used for character- and bitwise shifting to the right. The >> operator can be used with strings, integers, currencies and lists. When used with strings, the right operand specifies the number of spaces inserted on the left side of the string. When used with lists, the right operand specifies the number of elements to be removed from the end of the list. |
Example |
---|
@aaa = ["John", "James", "Jim", "Jamie"]; // So it is more efficient to use the difference: // Check if the last change of an object was carried out on the same date it was |
Note: If two different currencies are added or subtracted an implicit conversion is carried out. Following evaluation order is defined: The conversion table of the transaction variable TV_CURRCONVTAB is used. If TV_CURRCONVTAB is not available, the conversion table of the left operand is used. If not available, the conversion table of the right operand is used. Otherwise, an error is generated.
Examples for List Operators
The +, -, *, / and % operators (concatenation, difference, union, symmetric difference, intersection) are supported for lists. The following example shows how list operators work.
Example |
---|
[]+[1] == [1]; [1, 2, 3] - [2, 3, 4] == [1]; [1, 2, 3] * [2, 3, 4] == [1, 2, 3, 4]; [1, 2, 3] / [4, 5, 6] == [1, 2, 3, 4, 5, 6]; [1, 2, 3, 4] % [2, 3, 4] == [2, 3, 4]; |
Examples for Dictionary Operators
The -, *, / and % operators (difference, union, symmetric difference, intersection) are supported for dictionaries. These operators work on an element level, the value of a dictionary entry is not relevant. The left operand dominates. The following example shows how dictionary operators work.
Example |
---|
({}) - ({}) == ({}); ({}) * ({}) == ({}); ({}) / ({}) == ({}); ({}) % ({}) == ({}); |
Comparison operators allow you to compare two operands. The following table provides a summary of the supported comparison operators. The data type of the result is always BOOLEAN.
Operator | Description |
---|---|
== | The equality operator compares two operands and indicates whether the value of the left operand is equal to the value of the right operand. The equality operator has a lower precedence than the relational operators (<, <=, >, >=). |
!= (alternatively, <>) | The inequality operator compares two operands and indicates whether the value of the left operand is not equal to the value of the right operand. The inequality operator has a lower precedence than the relational operators (<, <=, >, >=). |
< | The relational operator < compares two operands and indicates whether the value of the left operand is less than the value of the right operand. |
<= | The relational operator <= compares two operands and indicates whether the value of the left operand is less than or equal to the value of the right operand. |
> | The relational operator > compares two operands and indicates whether the value of the left operand is greater than the value of the right operand. |
>= | The relational operator >= compares two operands and indicates whether the value of the left operand is greater than or equal to the value of the right operand. |
<=> | The relational operator <=> compares two operands. It returns -1 if the left value is lower and +1 if the left value is greater than the right value. If the values are equal, the result is 0. |
contains | The contains operator determines whether left operand contains the right operand. This operator can be used with string operands. It may be preceded by the not keyword. |
like | The like operator determines whether the left string matches the right string. The % and _ wildcards can be used in the right string operand and cannot be escaped. The like operator can be preceded by the sounds keyword for a phonetic comparison. Furthermore, it can also be preceded by the not keyword. |
in | The in operator determines whether the value of the left operand is an element of the list provided in the right operand. The in operator can also be used with a list in the left operand. It may be preceded by the not keyword. When using lists in both operands, the semantic is: [a1, a2, ... an] in [b1, b2, ... bm] -> (a1 == b1 or a1 == b2 or ... or a1 == bm) or This means, that the expression is true, if any element from the left operand is in the list of the right operand. Note:
|
includes | The includes operator determines whether the value of the right operand is an element of the list provided in the left operand. It may be preceded by the not keyword. When using lists in both operands, the semantic is: [a1, a2, ... an] includes [b1, b2, ... bm] -> (a1 == b1 or a1 == b2 or ... or a1 == bm) and This means, that the expression is true, if all elements from the right operand are in the list of the left operand. Note:
|
between and | The between and operator determines whether the value of the first operand is in the range between the values of the operands provided after the keywords between and and. If the first operand is a list, then all values of the list must be between the second and the third operand. |
is null | The is null operator returns true if the value of the left operand is undefined. |
Example |
---|
if (@points < 100) { // If @memberstatus is null this evaluates to true if (@nickname like "Bob%" or @nickname in ["Dick", "Rob"]) { |
Note:
The conditional operator ?: has three operands. It tests the result of the first operand, and then evaluates one of the other two operands based on the result of the evaluation of the first operand. If the evaluation of the first operand yields true, the second operand is evaluated. Otherwise, the third operand is evaluated.
Example |
---|
@orders = (@customer != null) ? |
The selection operator [] can be used for the following purposes:
Note:
Example |
---|
// Constructing an empty list // Constructing a list of string values // Selecting elements from a list // Selecting multiple elements from a list // Selecting elements starting from the end of the list by specifying negative indices // Example for filtering a list: This expression returns the orders that // Selecting a sub list // Selecting a sub list with negative elements // Specifying a parameter as the return value when invoking a use case // Results in the method object of the call // Results in all entries of the customization point CPSymbols |
The $ operator can be used in following cases.
By default, the kernel tries to interpret identifiers as references when evaluating expressions. In order to use an identifier that could also be a reference as name, it must be prefixed with $.
Note: The Fabasoft app.ducx compiler will attempt to automatically insert the symbol $ when serializing the expression, if it can determine the context in which the identifier is used. If it can’t calculate a definitive type, you will receive a warning.
For the following example, assume that the local scope contains a dictionary. objname can only be used as a variable when prefixed with $.
Example |
---|
// Assuming the local scope contains a dictionary: // When omitting the "$", the expression is interpreted as follows: |
If strings are prefixed with $, they can contain arguments with the syntax {~ argument ~}. All arguments in the string are evaluated, converted to string type and embedded in the string instead of the pattern.
Example |
---|
// '--Administrator, System--' // '3' |
If you need to retrieve a component object in an expression, you must prefix its reference with #. In order to use an identifier that could also be a variable as reference, it must be prefixed with #.
Note: The Fabasoft app.ducx compiler will attempt to automatically fully qualify an identifier to a reference when serializing the expression, if it can determine the context in which the identifier is used. If it can’t calculate a definitive type, you will receive a warning.
For instance, when referring to a property definition or an object class, you must prefix the reference with # in order to get the corresponding component object.
Example |
---|
// Accessing property definition COOSYSTEM@1.1:objname // Accessing object class APPDUCXSAMPLE@200.200:Order // Accessing property of undeclared object |
The app.ducx expression language comes with a set of predefined variables and functions to make programming as convenient as possible.
The following table shows the list of predefined variables that are provided automatically by the kernel when an expression is evaluated.
Variable | Description |
---|---|
coort | The coort variable can be used to access the runtime. |
cootx | The current transaction context is accessible by the cootx variable. |
cooobj | The cooobj variable holds the current object on which the evaluation of the expression is invoked. |
coometh | For use case implementations in app.ducx expression language, the coometh variable holds the so-called method context. |
coouser | The coouser variable holds the user object of the current user. |
coogroup | The coogroup variable holds the group object of the role of the current user. |
cooposition | The cooposition variable holds the position object of the role of the current user. |
cooenv | The cooenv variable holds the user environment of the current user. |
cooroot | The cooroot variable holds the desk of the current user. |
coolang | The coolang variable holds the language of the current user. |
coodomain | The coodomain variable holds the current domain. |
coonow | The coonow variable holds the current date and time. |
Example |
---|
// Using the runtime // Accessing transaction variables using the generic interface // Using the current object // Using the method context to call the super method |
The following table contains a list of implicit pseudo functions supported by app.ducx expression language. These functions can be invoked on an object.
Function | Description |
---|---|
IsClass(class) | IsClass determines whether the object class it is invoked on is derived from or identical to class. |
HasClass(class) | HasClass determines whether the object is an instance of or derived from class. |
GetClass() | GetClass returns the object class of the object. |
GetName(tx) | GetName returns the Name (COOSYSTEM@1.1:objname) of the object. |
GetAddress() | GetAddress returns the Address (COOSYSTEM@1.1:objaddress) of the object. |
GetReference() | GetReference returns the Reference (COOSYSTEM@1.1:reference) of a component object. |
GetIdentification() | GetIdentification returns the full identification of the object, which is a combination of the Address (COOSYSTEM@1.1:objaddress) and a version timestamp. |
Example |
---|
@objectclass = cooobj.GetClass(); cooobj.HasClass(#APPDUCXSAMPLE@200.200:Order) ? |
The following table lists methods that can be invoked on variables of type CONTENT.
Method | Description |
---|---|
GetFile(name, generatetemp) | GetFile copies the CooContent to a file and returns the file name. name denotes the name of the file to be created. |
SetFile(name, removeonrelease) | SetFile stores the content of a file in a CooContent. name denotes the name of the file to be used as a source. |
GetContent(tx, flags, codepage) | GetContent returns a CooContent as a String and can only be used for retrieving text-based contents. |
SetContent(tx, flags, codepage, string) | SetContent stores a String in a CooContent. |
Example |
---|
// Assuming that the global scope contains a dictionary |
The following table lists methods that can be invoked on variables of type DICTIONARY.
Method | Description |
---|---|
GetEntry(key) | GetEntry returns the list of values stored under key. Use this method for retrieving lists from a dictionary. |
GetEntryValue(key) | GetEntryValue returns value stored under key. Use this method for retrieving scalar values from a dictionary. |
GetEntryValueCount(key) | GetEntryValueCount returns the number of values of the entry specified by key. |
GetEntryCount() | GetEntryCount returns the number of entries in a dictionary. |
GetEntryKey(index) | GetEntryKey returns the key of the entry of the specified index. |
SetEntry(key, values) | SetEntry creates an entry under key for the specified values. Use this method for storing lists of values in a dictionary. |
SetEntryValue(key, inx, value) | SetEntryValue creates an entry under key for the specified value. Use this method for storing a scalar value in a dictionary. |
TestEntry(key) | TestEntry checks whether a dictionary contains an entry under key. This method returns true if the value stored under key is null. |
HasEntry(key) | HasEntry checks whether a dictionary contains an entry under key. This method returns false if the value stored under key is null. |
ClearEntry(key) | ClearEntry removes the entry stored under key from a dictionary. |
Reset() | Reset removes all entries from a dictionary. |
Backup() | Backup serializes the contents of a dictionary to a string. |
Restore(string) | Restore rebuilds a dictionary from a serialized string. |
The typeof function allows you to determine the data type of an expression. The result is a type or property definition object.
Example |
---|
// Determining the data type of the local scope // Determining the data type of the global scope // Determining the data type of a variable // Determining the data type of an expression |
The following table contains the list of string utility functions.
Function | Description |
---|---|
upper(string) | The upper function converts all characters of a string to upper case. |
lower(string) | The lower function converts all characters of a string to lower case. |
indexof(string, pattern) | The indexof function returns the character-based index of pattern within string. If the pattern is not found the function returns -1 |
strlen(string) | The strlen function returns the length of string. |
strtrim(string) | The strtrim function trims white space at the beginning and at the end of string. |
strhead(string, index) | The strhead function extracts the leftmost index characters from a string and returns the extracted substring. index is zero-based. If a negative value is supplied in index, absolute value of index is subtracted from the length of the string. If the absolute value of a negative index is larger than the length of the string, 0 is used for index. |
strtail(string, index) | The strtail function extracts the characters from a string starting at the position specified by index and returns the extracted substring. index is zero-based. If a negative value is supplied in index, the absolute value of index is subtracted from the length of the string. If the absolute value of a negative index is larger than the length of the string, 0 is used for index. |
strsplit(string, separator) | The strsplit function identifies the substrings in string that are delimited by separator, and returns a list containing the individual substrings. |
strjoin(list [, separator]) | The strjoin function concatenates the list of strings and inserts separator between the individual elements yielding a single concatenated string. If separator is not specified or null then the list elements are concatenated directly. |
strreplace(string, from [, to]) | The strreplace function replaces all occurrences of string from with string to in string. If to is not specified or null then all occurrences of from are deleted from the string. |
Example |
---|
@value = strhead("ABC", 1); // yields "A" |
In addition to the string functions provided by app.ducx expression language, the actions listed in the following table are useful for manipulating strings. For further information, refer to the Fabasoft reference documentation.
Function | Description |
---|---|
COOSYSTEM@1.1:Format(value, pattern, symbols, result) | This action takes a single value (any type) as first parameter and a formatting pattern as second parameter. The third parameter is for advanced options (code page, custom symbols for separators or the decimal point). The result is returned in the fourth parameter. Refer to the Fabasoft reference documentation for a description of the supported formatting patterns. |
COOSYSTEM@1.1:Print(string, ...) | Processes a format string or prints the object to a resulting string. If the string parameter contains a non-empty format string, this is used regardless of the object of the action. If the object is a string object, the property Print COOSYSTEM@1.1:string is used as format string. If the object is an error message, the property COOSYSTEM@1.1:errtext is used as format string. In all other cases the name of the object is used as format string. If the string contains formatting patterns starting with the "%" character these patterns are replaced by the additional parameters of the Print action. Refer to the Fabasoft reference documentation for a description of the supported formatting patterns. |
COOSYSTEM@1.1:PrintEx(string, arguments) | Uses COOSYSTEM@1.1:Print to print a format string or an object to a resulting string. Parameters for formatting are passed in a string list in the parameter arguments. Each line in the string list in the arguments parameter is evaluated as an expression. |
Example |
---|
// Get the modification date of the object as formatted string // Format an integer value with leading zeroes to yield "000123" // Format an integer value using digit grouping to yield "123,456" // Get the object's name and subject as formatted string // Assuming that StrCustomFormat is a string object containing the format pattern |
The following table shows the list of functions provided for working with lists.
Function | Description |
---|---|
count(list) | The count function returns the number of elements in list. Note: Do not use count(list) > 0 or count(list) == 0 to check whether a list is full or empty. Use the Boolean type cast list or !list instead, this is much more efficient. |
insert(list, index, value) | The insert function inserts value into list at position index. The parameter list is modified by that function; therefore, it must be assignable. index is zero-based. If a negative value is supplied in index, absolute value of index is subtracted from the length of the list. If the absolute value of a negative index is larger than the length of the list, 0 is used for index. If index is greater than the number of elements in list, value is appended at the end of list. |
delete(list, index [, count]) | The delete function deletes the value at index from list. The parameter list is modified by that function; therefore, it must be assignable. index is zero-based. If a negative value is supplied in index, absolute value of index is subtracted from the length of the list. If the absolute value of a negative index is larger than the length of the list, 0 is used for index. If count is not specified or null then one element is deleted, otherwise count specifies the number of elements following index that should be deleted. If less than count elements are available, the list is truncated at index. If count is negative, the elements before index are deleted. |
find(list, value) | The find function searches list for the element value, and returns the index of the first occurrence within the entire list. If value is not found in list, the number of elements in list is returned. |
sort(list) | The sort function sorts the elements in list. Lists of contents, dictionary or interfaces cannot be sorted. Lists of aggregates can only be sorted, if the aggregate type defines a compare action in COOSYSTEM@1.1:typecompare. Lists of objects are sorted by a defined internal order. This makes sort useful in combination with the unique function, since sort(unique(objlist)) is much faster than unique(objlist). |
unique(list) | The unique function makes the elements in list unique. |
revert(list) | The revert function reverts the elements in list. |
Example |
---|
insert(@orders, count(@orders), @neworder); |
The following table shows the list of mathematical functions supported by app.ducx expression language.
Function | Description |
---|---|
sum(list) | The sum function returns the sum of all values in list. Values can also be passed to sum as individual arguments. The sum function can only be used with numeric data types. |
avg(list) | The avg function returns the average of all values in list. Values can also be passed to avg as individual arguments. The avg function can only be used with numeric data types. |
min(list) | The min function returns the smallest value in list. Values can also be passed to min as individual arguments. The min function can be used with strings and numeric data types. |
max(list) | The max function returns the largest value in list. Values can also be passed to max as individual arguments. The max function can be used with strings and numeric data types. |
Example |
---|
@avgorderamount = avg(@customer.APPDUCXSAMPLE@200.200:customerorders. |
Additional mathematical functions are provided by the #Math object. For further information, see https://help.cloud.fabasoft.com/index.php?topic=doc/Reference-Documentation/class-fscexpext-MathFunctions.htm: new window.
The following table contains a list of supported escape sequences for special characters.
Character | ASCII representation | ASCII value | Escape sequence |
---|---|---|---|
New line | NL (LF) | 10 or 0x0a | \n |
Horizontal tab | HT | 9 | \t |
Vertical tab | VT | 11 or 0x0b | \v |
Backspace | BS | 8 | \b |
Carriage return | CR | 13 or 0x0D | \r |
Form feed | FF | 12 or 0x0C | \f |
Alert | BEL | 7 | \a |
Backslash | \ | 92 or 0x5C | \\ |
Question mark | ? | 63 or 0x3F | \? |
Single quotation mark | ' | 39 or 0x27 | \' |
Double quotation mark | " | 34 or 0x22 | \" |
Hexadecimal number | hh | \xhh | |
Null character | NUL | 0 | \0 |
Unicode character | hhhh | \uhhhh | |
Unicode sequence | hh hhhh hhh | \u{hh,hhhh,hhh} |
Note: Please be aware that strings in expressions are UTF-8. If you use hexadecimal escape sequences be sure that the resulting byte sequence is a valid UTF-8 character.
Example |
---|
@fullname = "Samuel \"Sam\" Adams"; |
Syntax |
---|
// Getting property values using the assignment operator // Setting property values using the assignment operator // Setting values of a compound property list using the assignment operator // Simple initialization of compound properties // Setting values of a compound property list using the assignment operator // Setting values of a compound property list using the assignment operator // Setting values of a compound property list using the "JavaScript" notation // Getting property values using the Get... functions // Setting property values using the Set... functions |
Note: You can set the value (currvalue) of a currency property (compound type) by just assigning a string, float or integer to the currency property (currency @cur = 7.56;). In this case it is not necessary to specify explicitly the currvalue property (@cur.currvalue = 7.56;).
You can use the assignment operator = to get and set the value of a property. Even though using the assignment operator is recommended, you may also use the following functions to get and set property values:
Value | Description |
---|---|
0x0001 | Object address |
0x0002 | Object reference |
0x0004 | Enumeration reference |
0x0010 | XML escaped |
0x0020 | HTML escaped |
0x1000 | Row list |
0x2000 | Column list |
0x8000 | No list indicator |
Example |
---|
@orders = @customer.APPDUCXSAMPLE@200.200:customerorders; @orders = @customer.GetAttribute(cootx, #APPDUCXSAMPLE@200.200: @orderdate = @order.GetAttributeValue(cootx, #APPDUCXSAMPLE@200.200: @order.APPDUCXSAMPLE@200.200:orderdate = coonow; @order.SetAttributeValue(cootx, #APPDUCXSAMPLE@200.200:orderdate, 0, @engname = @product.GetAttributeString(cootx, #mlname, #LANG_ENGLISH); @description = @product.GetAttributeStringEx(cootx, #APPDUCXSAMPLE@200.200: |
Syntax |
---|
object.usecase(value, value,… , name: value, name: value, …) |
A use case can only be invoked on an object. The full reference of the use case to be invoked must be provided, followed by the list of parameters, which must be enclosed in parentheses. Multiple parameters must be separated by commas.
You do not need to specify optional parameters. They can be omitted in the parameter list.
The parameter list consists of two parts. The first parameters are supplied by position. After that, name:value pairs can be written to set the parameters by name.
There are four methods for retrieving output parameters in app.ducx expression language:
Example |
---|
// Optional parameters can be omitted // "null" can also be passed in for optional parameters // using parameter names // Retrieving an output parameter: method 1 – using the return value @neworder = #APPDUCXSAMPLE@200.200:Order.ObjectCreate(); // Retrieving an output parameter: method 2 – specify the return value // Retrieving an output parameter: method 3 // Retrieving an output parameter: method 4 |
Syntax |
---|
// Accessing a property using a calculated identifier // Invoking a use case using a calculated identifier |
The selection operator [] can be used to specify an expression yielding a calculated identifier for accessing a property or invoking a use case.
For a calculated identifier, the expression specified in square brackets is evaluated, and then the result is interpreted as a property definition, entry key in a dictionary, an action or a use case.
Example |
---|
// Assigning a value to a calculated property // Invoking a use case using a calculated identifier |
If the expression of the selection operator [] is a list of property definitions, then the list is interpreted as a path:
Example |
---|
// Accessing a value to a calculated property path |
The selection operator [] can also be used with dictionaries, then the expression of the selection operator [] contains one or more strings identifying the entry keys in the dictionary.
Note:
The cootx variable can be used to access the current transaction context. The most important methods of a transaction are listed in the following table.
Method | Description |
---|---|
Abort() | Abort aborts the current transaction and rolls back any changes. |
Commit() | Commit closes the current transaction and stores any changes. |
CommitEx(flags) | CommitEx closes the current transaction and stores any changes. Additionally, the following flags are supported:
|
Persist(object) | Persist temporarily stores the state of the current transaction without committing the changes. |
Clone() | Clone returns a clone of the current transaction. |
HasVariable(swc, id) | HasVariable checks whether transaction variable id of software component swc contains a value. This method returns false if if the value stored is null. |
TestVariable(swc, id) | TestVariable checks whether transaction variable id of software component swc contains a value. This method returns true even if the value stored is null. |
ClearVariable(swc, id) | ClearVariable removes transaction variable id of software component swc from the transaction. |
GetVariable(swc, id) | GetVariable retrieves the list of values stored in transaction variable id of software component swc. |
SetVariable(swc, id, type, values) | SetVariable stores the specified values in transaction variable id of software component swc. |
GetVariableValueCount(swc, id) | GetVariableValueCount returns the number of values stored in transaction variable id of software component swc. |
HasVariableValue(swc, id) | HasVariableValue returns true if a transaction variable id of software component swc is available. |
GetVariableValue(swc, id) | GetVariableValue retrieves a scalar value stored in transaction variable id of software component swc. |
SetVariableValue(swc, id, type, value) | SetVariableValue stores the specified scalar value in transaction variable id of software component swc. |
GetVariableString | GetVariableString retrieves a scalar value stored in transaction variable id of software component swc in printable form. |
GetVariableStringEx | GetVariableStringEx retrieves a scalar value stored in transaction variable id of software component swc in printable form. |
GetVariableTypeDefinition(swc, id) | GetVariableTypeDefinition returns the type definition for the variable stored in transaction variable id of software component swc. |
IsClone() | IsClone returns true if the transaction is a clone transaction. |
IsModified() | IsModified checks whether objects were modified within the transaction. |
IsModifiedEx() | IsModifiedEx checks whether any data was modified within the transaction. |
IsCreated(object) | IsCreated checks whether object was created in this transaction. |
IsDeleted(object) | IsDeleted checks whether object was deleted in this transaction. |
IsChanged(object) | IsChanged checks whether object was changed in this transaction. |
IsAttributeChanged(object, property) | IsAttributeChanged checks whether property of object was changed in this transaction. |
GetTransactionFlags() | GetTransactionFlags retrieves the flags of the transaction:
|
SetTransactionFlags(flags) | SetTransactionFlags allows you to set the transaction flags (see GetTransactionFlags). |
Backup() | Backup returns a dump of the transaction as printable string. |
Restore(data) | Restore restores the transaction from data created by Backup(). |
OpenScope() | OpenScope starts a new transaction scope. |
CloseScope() | CloseScope closes the current transaction scope. |
GetMaster() | GetMaster returns the top most transaction of the transaction. |
In some scenarios it is necessary to carry out operations in a separate transaction. Any changes that have been made in a new transaction can be committed or rolled back separately from the main transaction.
Example |
---|
usecase CreateInvoice() { try { |
Note: A better and simpler way to create transactions is using the try new transaction statement.
Working With Transaction Variables
Syntax |
---|
// Retrieving the value stored in a transaction variable // Storing a value in a transaction variable |
The #TV object is a special object that provides access to transaction variables.
Note: Transaction variables can also be accessed using the cootx variable. Please refer to chapter “Predefined Variables” for further information.
Example |
---|
// Retrieving the value stored in a transaction variable // Storing a value in a transaction variable |
The app.ducx expression language supports common language constructs for control flow and expression evaluation.
Syntax |
---|
if (expression) { switch (expression) { |
You can use if statements in app.ducx expression language. The if keyword must be followed by parentheses enclosing a conditional expression, and non-optional curly braces. An if block can be followed by multiple else if blocks and an optional else block.
Example |
---|
@orderstate = @order.orderstate; if (@orderstate == OrderState(OS_PENDING)) { // lists as conditional expression are evaluated true, if the list contains at least |
Note: It is not necessary that OS_PENDING is explicitly casted (e.g. @orderstate == OS_PENDING works, too).
The switch - case - default statement can be used to evaluate the switch expression and execute the appropriate case.
Example |
---|
OrderState @orderstate; switch (@orderstate){ |
Note: Enumeration items like OS_PENDING are determined by @orderstate in the switch statement.
Syntax |
---|
for (expression) { while (expression) { do { |
The app.ducx expression language contains loops with both a constant and a non-constant number of iterations. The statements for, while, and do-while are supported. All loops have a mandatory block.
The break statement can be used to exit a loop.
The continue statement can be used to skip the remainder of the loop body and continue with the next iteration of the loop.
Note: continue inside a catch block does not apply to any enclosing loop.
Example |
---|
currency totalvalue = 0; object[] orderpositions; currency total = 0; // Iteration of a searchresult integer stock = product.itemsinstock; OrderState orderstate; |
Note: Avoid iterating through lists using a for loop with an index, since this is very inefficient in large lists.
Exceptions are used to handle exceptional or unexpected situations that may occur during the execution of a program. When an error situation arises, the code can throw an exception to indicate that something unexpected has occurred. This allows the kernel to transfer control to an appropriate exception handler, which can handle the exception gracefully.
Use try-catch-finally statements to handle exceptions. A try block must be followed by at least one catch block, followed by an optional finally block.
If an exception occurs when processing the try block, the kernel tries to locate a catch block with a condition matching the error message object of the exception. If no matching catch block is found by the kernel, the error text is handled by default (e.g. shown in the UI).
A catch block can have three distinct types of conditions:
The optional finally block is executed after the try and catch blocks have been processed, whether an exception occurred or not.
Example |
---|
try { |
Using the throw keyword, the app.ducx expression language allows you to raise an error:
Syntax |
---|
// Raising a custom error // Rethrowing an exception |
Example |
---|
// Raising a custom error using a "throw" statement // Raising a custom error, assuming that the |
To continue the execution directly after the statement raising the error the keyword continue can be used inside the catch block.
Similar to the try statement for error handling it is possible to execute a block using a separate transaction context:
Example |
---|
try new transaction { |
If the new keyword is omitted, a transaction scope is opened. A transaction scope is a sub transaction of the current transaction. When a transaction scope is committed, the changes of that scope are propagated to the surrounding transaction. These changes are only persisted if the surrounding transaction context is committed.
Example |
---|
try transaction { |
Syntax |
---|
return expression; |
The return statement can be used to stop the evaluation of an expression at any time. Each expression has a return value, which is calculated by the expression following the return keyword.
Note: It is not allowed to use return with a value in a method implementation.
Example |
---|
if (@order != null) { |
A directive is a special statement that does not influence the semantic of the expression.
Syntax |
---|
%%NAME(parameters); |
The %%TRACE directive can be used to conditionally write trace messages to the Fabasoft app.ducx Tracer.
Syntax |
---|
%%TRACE(message); |
Example |
---|
%%TRACE("Hello World!"); |
The %%FAIL directive can be used to generate a failure. The message is written to the Fabasoft app.ducx Tracer and an error (EXPRERR_FAIL) is raised.
Note: Like the %%TRACE directive, the %%FAIL directive is only evaluated if trace mode is activated for your software component.
Syntax |
---|
%%FAIL; |
Example |
---|
%%FAIL; |
The %%ASSERT directive can be used to check conditions. In case the condition returns false, a message is written to the Fabasoft app.ducx Tracer and an error (EXPRERR_ASSERT) is raised.
Note: Like the %%TRACE directive, the %%ASSERT directive is only evaluated if trace mode is activated for your software component.
Syntax |
---|
%%ASSERT(condition); |
Example |
---|
%%ASSERT(cooobj.objlock.objlocked); @expect = "Test"; |
The %%DEBUGGER directive can be used to set a breakpoint in a Fabasoft app.ducx Expression.
Syntax |
---|
%%DEBUGGER; |
The %%LOG directive can be used to log messages to Fabasoft app.telemetry. app.telemetry provides the log level LOG, IPC, NORMAL, DETAIL, and DEBUG.
Syntax |
---|
%%LOG(message); |
Example |
---|
%%LOG("Object created by " + cooobj.objcreatedby.objname); // Detail level |
app.ducx Integrated Queries can be used to search for objects. Integrated queries allow you to formulate your queries directly in the expression language. Integrated queries are composed of a series of clauses that define the data source and conditions to filter it. The basic clauses are:
Note: Integrated queries result in an asynchronous search, which means the result is of type searchresult. You can access searchresult either using the kernel interface (https://help.cloud.fabasoft.com/index.php?topic=doc/Reference-Documentation/interface-CooSearchResult.htm: new window) or by iteration (see chapter “Loops”).
A complete reference of the grammar can be found in chapter “Grammar of the app.ducx Expression Language”.
The FROM clause is the sole mandatory element in integrated queries. Below is an example of the basic structure of a query to retrieve all users of a domain:
Example |
---|
searchresult allusers = FROM User |
You can also retrieve objects of multiple classes, as demonstrated in the following example:
Example |
---|
searchresult allusersandgroups = FROM User, Group |
Additionally, you can query object list properties using the keyword IN, as demonstrated in the example below.
Example |
---|
searchresult folders = FROM COODESK@1.1:Folder IN cooroot.objchildren |
Specifying the object class in the FROM clause limits the result to objects of only that class. For example, if you specify COODESK@1.1:Folder as the object class in the FROM clause, the query result will only contain objects of that class (including derived classes). You can use the property COOSYSTEM@1.1:objclass in the WHERE clause to exclude derived classes.
The WHERE clause follows the FROM clause and makes it possible to filter objects using Boolean conditions. In order to utilize WHERE clauses you will need to introduce a condition variable (e.g. "u" in the example below) within the FROM clause that represents each element in the data source. You can then use the condition variable within the WHERE clause to access properties.
Example |
---|
searchresult allusers = FROM User u WHERE u.active searchresult someusers = FROM User u WHERE u.userfirstname == "John" |
Note: It is not possible to reference properties of condition variables which specify AttrNoSearchPossible. Further, it is not possible to access properties of objects retrieved from condition variables (e.g. u.objowner.objname).
In integrated queries, the SELECT clause precedes the FROM clause. The SELECT clause is used to specify properties that should be loaded into the cache. Per default, if you omit the SELECT clause, only the value of COOSYSTEM@1.1:objclass will be loaded.
Example |
---|
searchresult u1 = SELECT * FROM User u WHERE u.active; searchresult u2 = SELECT userfirstname, usersurname FROM User u WHERE u.active; |
You can specify options at the beginning of an integrated query to restrict the search. Integrated queries support the following options:
Example |
---|
searchresult al10 = LIMIT 10 SELECT * FROM User u WHERE u.active |
The grammar of the app.ducx Expression Language is formally defined as described below.
Grammar |
---|
Expression := { ( [ Statement ] ";" ) | BlockStatement } [ Statement ]. |
In general, the rule Char represents all printable characters and the following escape sequences:
'\\' ('a' | 'b' | 'f' | 'n' | 'r' | 't' | 'v' | 'u' | 'x' | '"' | "'" |'\\')
Moreover, the start- and end symbols (e.g., '"', "'") used for strings must be escaped in order to use them as character values inside strings. Additionally, "{" must be escaped inside string templates.
The following reserved words cannot be used as variable names.
Reserved Words |
---|
AND, and, ASC, assume, BETWEEN, between, break, BY, case, |
The Kernel Interface Query Language can be used to search for objects. To carry out a search the runtime methods SearchObjects and SearchObjectsAsync can be used. SearchObjects returns the search result array at once (10,000 objects at the maximum) whereas SearchObjectsAsync returns a searchresult, which can be used to step through the result (without limit). Additionally, the runtime method SearchValues can be used. SearchValues returns an aggregated value using COUNT, SUM, MIN or MAX. Using SearchValues, the evaluation of the query conditions occurs only in the database. For security reasons this method is only available for privileged users.
The following example shows a Fabasoft app.ducx expression that illustrates how to search for orders at once and asynchronously.
Example |
---|
integer @bulksize = 150; // Performs a search with SearchObjects // Performs an asynchronous search with SearchObjectsAsync() // Steps through the search result // Count objects with SearchValues |
A search query is built up by following parts:
Syntax |
---|
{Options} SELECT Properties FROM Classes [IN ObjectList] [WHERE Condition] |
A complete reference of the grammar can be found in chapter “Grammar of the Kernel Interfaces Query Language”.
In most cases, no options will be required.
It is useful to define properties that are accessed later on because these properties are loaded in the cache. When accessing these objects, no further server request is necessary to read the defined properties.
SELECT * loads all properties in the cache and therefore should only be used if many properties are used further on.
Objects of the defined object classes (and derived object classes) are searched. If derived object classes should not be found use the property objclass in the WHERE clause.
Example |
---|
SELECT objname FROM User WHERE .objclass = #User |
In case an IN clause is supplied the search is restricted to the objects which are contained in the list. The conditions are evaluated within the database, the FROM clause is optional. This feature can be used to filter object lists without loading all objects.
Example |
---|
// Returns all children starting with the letter A. // Returns all child folders. |
Restrictions: The CACHE keyword is not supported for list queries, this also means that only objects stored within the COO Service can be found. In case of a container-based installation, the component objects are stored within the Kernel cache of the container image, and therefore also cannot be found.
Supplying values for properties restricts the results further. Following general rules apply:
Following keywords can be used to specify a condition:
The following example shows a variety of search queries.
Example |
---|
// Returns all Note objects // Returns contact persons with "Jefferson" in COOSYSTEM@1.1:usersurname // The settings in the query scope object restrict the search // The search is restricted to the domain with object address COO.1.1900.1.1 // Returns users that are created between the last hour and last half-hour // Returns users with a task in the task list // A query scope object is used and the search is restricted to 100 result entries |
The following example shows a value query using SearchValues.
Example |
---|
// Returns the biggest content size of all content objects |
It is often necessary to use query conditions which are supplied by method parameters or even user input. Therefore, it is possible to use variables within the query to avoid building the query string which requires the use of the correct escaping rules. The values are supplied as key/value pairs (DICTIONARY), so the key can be used as variable name to reference its value. Variable names are prefixed with a dollar sign ($). Variables cannot be used to replace attributes, operators or query keywords.
Example |
---|
// Returns the first ten objects found which are named "Test" coort.SearchObjects( |
Variables can be used at the following places:
LIMIT $limit
PRELOAD $preload
TIMEOUT $timeout
SERVICES($services)
SCOPE($scope)
DOMAINS($domains)
STORES($stores)
EVALUATE $objects
FROM $classes
IN $object.attrdef
WHERE .attrdef = $value
The grammar of the app.ducx Query Language is formally defined as described below.
Grammar |
---|
app.ducx Query Language Statement := { Options } ( Query | ValueQuery | Evaluation ). |
The grammar of the app.ducx Query Language partially refers to the grammar of the Kernel Interfaces Expression Language.
Grammar |
---|
Kernel Expression Language Expression := { Statement }. |