Tutorial

This section gives a concise introduction to TL-Script. The details with a complete function reference can be found in the following chapters.

The TL-Script expressions in this section can be evaluated in the expert mode of the search component in a TopLogic application ("Model-based search"):

Calculating with numbers

In TL-Script, everything is a formula that calculates a result. Anything that can be entered into a calculator or into a spreadsheet cell as a formula is a TL-Script:

1 + 2

3 * (5 + 9 / 3)

The above two "scripts" return 3 and 24 as results. See also Arithmetic operations.

Calculating with text

Texts or strings are an important data type in applications besides numbers. TL-Script offers a variety of possibilities for manipulating strings.

toUpperCase("Hello world!")

toString("Hello", " ", "world", "!")

The first script returns HELLO WORLD! and the second returns the string Hello world!. Strings can be entered directly into TL-Script (see Literals) and used as inputs to functions. The predefined function toUpperCase() converts a string to uppercase. The function toString() creates a new string from its arguments by concatenating everything, see Strings.

Calculating with time

Date and time is also an important data type. Many functions therefore work with such values, see Date and Time.

dateFormat("yyyy-MM-dd HH:mm:ss XXX").format(now())

The above expression returns the current date with time in the specified format, see also Date format.

The following expression returns the current year as a number, see also toSystemCalendar and year.

today().toSystemCalendar().year()

The day of the week on which 8/5/2021 falls (as number Sunday = 1, Monday = 2, etc.), see also dayOfWeek.

date(2021, 7, 5).toSystemCalendar().dayOfWeek()

An important difference between date and time values is that a time is absolute and is only represented differently depending on the time zone. A date value, on the other hand, represents a calendar day that begins and ends at a different time depending on the time zone.

Calculating with lists and quantities

Lists and sets are collections of values. A search result is always such a collection. References in the model that allow multiple values contain collections of other objects. Depending on whether the reference is ordered or not, it is a list or a set. A set cannot contain duplicate values, a list can, see also Lists and sets.

Mostly TL-Script is used to formulate evaluations on such model references. But it is also possible to construct lists in TL-Script itself.

list("A", "B", "C").size()

The expression above gives the result 3. Here the list is constructed with the string entries "A", "B" and "C" and the length is determined from this list.

The most important operations on lists is filtering and mapping. In both cases, a function is applied to each element of the list. In filtering, the filter function decides whether the particular list element is part of the result or not.

list(3, 1, 5, 11, 7, 2, 8).filter(x -> $x > 4) 

Above expression returns the list [5, 11, 7, 8] as result. The filter function x -> $x > 4 maps each list element x to the boolean value $x > 4, i.e. checks whether the list element is greater than 4. Such a function declares a parameter (here x, the name can be freely chosen) and performs a calculation with this so named value. In the body of the function, the parameter is referred to by placing a $ sign in front of the parameter name.

Thus, the above filter expression successively assigns the values 3, 1, 5,... of the input list to the variable x and calculates the boolean value $x > 4. Whenever this value is true, the list element is included in the result. If the value is false, the list element is discarded and not included in the result.

In the mapping, a calculation is performed on each list element and the result of this calculation is included in the result.

list(5, 11, 7, 8).map(x -> $x + 2)

Here, the result is the list [7, 13, 9, 10]. The mapping function x -> $x + 2 increases its input by 2 each time. It is applied to each list element and all results calculated in this way are collected in the result.

By combining filtering and mapping, complex evaluations on collections can be formulated.

list(3, 1, 5, 11, 7, 2, 8)
  .filter(x -> $x > 4)
  .map(x -> $x + 2)

Above expression combines both calculations from above and directly returns the result list [7, 13, 9, 10], which is created by filtering and then mapping the input list. Details on lists and sets are provided in the section Lists and sets.

Interaction with application data

The most important function of TL script is to access the application model and search and evaluate application data. Suppose the following simple model of an ordering system is given. Here, an order consists of several items, each consisting of a quantity and a selected product.

All these types are defined in the module tl.tutorial.order. All model elements (modules, types and their properties) can be named directly in TL-Script. For this purpose the fully qualified name of the model element is enclosed in "`" characters. Since model elements are normal objects in TopLogic, they can also be displayed as search results.

`tl.tutorial.order`

The above expression returns the module tl.tutorial.order as a result. In the same way, you can access the type of orders or the number attribute of an order item using the following expressions:

`tl.tutorial.order:Order`

`tl.tutorial.order:Item#amount`

Access to the application data is obtained via the model elements. For example, the following expression returns the list of all purchase orders available in the system:

all(`tl.tutorial.order:Order`)

The all function takes as argument a type, here the type of purchase orders, and returns as result the list of all instances of this type .

This can be combined into an evaluation script that calculates the total value of all orders in the system:

all(`tl.tutorial.order:Order`)
  .map(order -> 
    $order
      .get(`tl.tutorial.order:Order#items`)
      .map(item -> {
        amount = $item.get(`tl.tutorial.order:Item#amount`);
        product = $item.get(`tl.tutorial.order:Item#product`);
        price = $product.get(`tl.tutorial.order:Product#price`);
        $amount * $price;
      })
      .sum()
  )
  .sum()

Here, the list of all purchase orders (all(`tl.tutorial.order:Order`)) is assumed. Each order is mapped to its order value (.map(order -> ...)) and then all these order values are summed (sum()). The mapping function, which calculates the order value of a single order, does this using the order values of its individual order items. For this the reference `tl.tutorial.order:Order#items` of the order is accessed, in order to receive the list of the order positions of this order. This list of order items is mapped to the value of the individual order item via a nested mapping and then summed to the value of the order.

The mapping function that determines the value of an order item (item -> {...}) accesses the quantity (`tl.tutorial.order:Item#amount`) and the product ordered (`tl.tutorial.order:Item#product`) in the order item ($item). Both are cached in temporary variables amount and product. The price (`tl.tutorial.order:Product#price`) of the ordered product ($product) is now queried and then multiplied by the value of the order item ($amount * $price).

The last expression in an expression chain { ...; ...; ...;} is always the result of the total expression. It is not necessary to specify an explicit "return" statement as known from other languages.

Details on this can be found in Model Access and Functions.