Tutorial

Dieser Abschnitt gibt eine knappe Einführung in TL-Script. Die Details mit einer kompletten Funktionsreferenz können in den nachfolgenden Kapiteln nachgelesen werden.

Die TL-Script-Ausdrücke in diesem Abschnitt können im Experten-Modus der Suchkomponente in einer TopLogic Applikation ("Modellbasierte Suche") ausgewertet werden:

Rechnen mit Zahlen

In TL-Script ist alles eine Formel, die ein Ergebnis berechnet. Alles, was man in einen Taschenrechner oder in die Zelle einer Tabellenkalkulation als Formel eintragen kann, ist ein TL-Script:

1 + 2

3 * (5 + 9 / 3)

Die obigen beiden "Skripte" liefern 3 bzw. 24 als Ergebnis. Siehe auch Arithmetische Operationen.

Rechnen mit Text

Texte bzw. Zeichenketten sind neben Zahlen ein wichiger Datentyp in Anwendungen. TL-Script bietet eine Vielzahl von Möglichkeiten für die Manipulation von Zeichenketten.

toUpperCase("Hello world!")

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

Das erste Skript liefert HELLO WORLD! und das zweite die Zeichenkette Hello world!. Zeichenketten können in TL-Script direkt eingegeben werden (siehe Literale) und als Eingaben für Funktionen verwendet werden. Die vordefinierte Funktion toUpperCase() wandelt eine Zeichenkette in Großbuchstaben um. Die Funktion toString() erzeugt aus ihren Argumenten eine neue Zeichenkette, indem sie alles hintereinanderhängt, siehe Zeichenketten.

Rechnen mit Zeit

Datum und Zeit ist ebenfalls ein wichtiger Datentyp. Viele Funktionen arbeiten daher mit solchen Werten, siehe Datum und Uhrzeit.

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

Obiger Ausdruck gibt das aktuelle Datum mit Uhrzeit in dem angegebenen Format aus, siehe auch Datumsformat.

Der folgende Ausdruck liefert das aktuelle Jahr als Zahl, siehe auch toSystemCalendar und year.

today().toSystemCalendar().year()

Der Wochentag, auf den der 5.8.2021 fällt (als Zahl Sonntag = 1, Montag = 2, usw.), siehe auch dayOfWeek.

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

Ein wichtiger Unterschied zwischen Datums- und Zeitwerten besteht darin, dass ein Zeitpunkt absolut ist und nur je nach Zeitzone anders dargestellt wird. Ein Datumswert dagegen repräsentiert einen Kalendertag, der abhängig von der Zeitzone zu einem anderen Zeitpunkt beginnt und endet.

Rechnen mit Listen und Mengen

Listen und Mengen sind Sammlungen von Werten. Ein Suchergebnis ist immer eine solche Sammlung. Referenzen im Modell, die mehrere Werte erlauben, enthalten Sammlungen von anderen Objekten. Je nachdem, ob die Referenz geordnet ist oder nicht handelt es sich um eine Liste oder eine Menge. In einer Menge können keine doppelten Werte enthalten sein, in einer Liste schon, siehe auch Listen und Mengen.

Meistens wird TL-Script dazu verwendet, Auswertungen auf solchen Modell-Referenzen zu formulieren. Es ist aber auch möglich Listen in TL-Script selbst zu konstruieren.

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

Der obige Ausdruck liefert das Ergebnis 3. Hier wird die Liste mit den Zeichenketteneinträgen "A", "B" und "C" konstruiert und von dieser Liste die Länge bestimmt.

Die wichtigsten Operationen auf Listen ist die Filterung und die Abbildung. In beiden Fällen wird eine Funktion auf jedes Element der Liste angewendet. Bei der Filterung entscheidet die Filterfunktion, ob das jeweilige Listenelement Teil des Ergebnisses ist oder nicht.

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

Obiger Ausdruck liefert die Liste 5, 11, 7, 8 als Ergebnis. Die Filterfunktion x -> $x > 4 bildet jedes Listenelement x auf den Wahrheitswert $x > 4 ab, prüft also, ob das Listenelement größer als 5 ist. Eine solche Funktion deklariert einen Parameter (hier x, der Name kann frei gewählt werden) und führt eine Berechnung mit diesem so benannten Wert aus. Im Rumpf der Funktion nimmt man Bezug auf den Parameter, indem man ein $-Zeichen vor den Parameternamen stellt.

Obiger Filter-Ausdruck belegt also nacheinander die Variable x mit den Werten 3, 1, 5,... der Eingabeliste und berechnet den Wahrheitswert $x > 4. Immer wenn dieser Wert "wahr" ist, wird das Listenelement in das Ergebnis aufgenommen. Ist der Wert "falsch", wird das Listenelement verworfen und nicht in das Ergbnis übernommen.

Bei der Abbildung wird eine Berechnung auf jedem Listenelement ausgeführt und das Ergebnis dieser Berechnung in das Ergebnis übernommen.

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

Hier ist das Ergebnis die Liste 7, 13, 9, 10. Die Abbildungsfunktion x -> $x + 2 erhöht ihre Eingabe jeweils um 2. Sie wird auf jedes Listenelement angewendet und alle so berechneten Ergebnisse werden im Ergebnis gesammelt.

Durch die Kombination von Filterung und Abbildung lassen sich komplexe Auswertungen auf Sammlungen formulieren.

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

Obiger Ausdruck kombiniert beide Berechnungen von oben und liefert direkt die Ergebnisliste 7, 13, 9, 10, die durch Filterung und anschließender Abbildung der Eingabeliste entsteht. Details zu Listen und Mengen liefert der Abschnitt Listen und Mengen.

Interaktion mit Anwendungsdaten

Die wichtigste Funktion von TL-Script ist der Zugriff auf das Anwendungsmodell und die Suche und Auswertung von Anwendungsdaten. Nehmen wir an, das folgende einfache Modell eines Bestellsystems sei gegeben. Hier besteht eine Bestellung aus mehreren Positionen, die jeweils aus einer Anzahl und einem ausgewählten Produkt bestehen.

Alle diese Typen sind im Modul tl.tutorial.order definiert. Alle Modellelemente (Module, Typen und ihre Eigenschaften) können in TL-Script direkt benannt werden. Hierfür wird der der vollqualifizierte Name des Modellelements in "`"-Zeichen eingeschlossen. Da Modellelemente in TopLogic ganz normale Objekte sind, können diese auch als Suchergebnisse dargestellt werden.

`tl.tutorial.order`

Obiger Ausdruck liefert das Modul tl.tutorial.order als Ergebnis. Genauso erhält man Zugriff auf den Typ von Bestellungen bzw. das Anzahl-Attribut einer Bestellposition über die folgenden Ausdrücke:

`tl.tutorial.order:Order`

`tl.tutorial.order:Item#amount`

Über die Modellelemente erhält man Zugriff auf die Anwendungsdaten. So liefert der folgende Ausdruck die Liste aller im System vorhandener Bestellungen:

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

Die all-Funktion nimmt als Argument einen Typ, hier den Typ der Bestellungen, und liefert als Ergebnis die Liste aller Instanzen dieses Typs .

Dies lässt sich zu einem Auswertungsskript zusammensetzen, das den Gesamtwert aller Bestellungen im System ausrechnet:

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()

Hier wird von der Liste aller Bestellungen (all(`tl.tutorial.order:Order`)) ausgegangen. Jede Bestellung wird auf ihren Bestellwert abgebildet (.map(order -> ...)) und anschließend alle diese Bestellwerte summiert (sum()). Die Abbildungsfunktion, welche den Bestellwert einer einzelnen Bestellung berechnet tut dies über die Bestellwerte ihrer einzelnen Bestellpositionen. Hierfür wird auf die Referenz `tl.tutorial.order:Order#items` der Bestellung zugegriffen, um die Liste der Bestellpositionen dieser Bestellung zu erhalten. Diese Liste von Bestellpositionen wird über eine geschachtelte Abbildung auf den Wert der einzelnen Bestellposition abgebildet und anschließend zum Wert der Bestellung summiert.

Die Abbildungsfunktion, die den Wert einer Bestellposition bestimmt (item -> {...}) greift auf die Anzahl (`tl.tutorial.order:Item#amount`) und das bestellte Produkt (`tl.tutorial.order:Item#product`) in der Bestellposition ($item) zu. Beides wird in temporären Variablen amount und product zwischengespeichert. Vom bestellten Produkt ($product) wird jetzt noch der Preis (`tl.tutorial.order:Product#price`) abgefragt und anschließend zum Wert der Bestellposition multipliziert ($amount * $price).

Der letzte Ausdruck ein einer Ausdruckskette { ...; ...; ...;} ist immer das Ergebnis des Gesamtausdrucks. Es ist nicht notwendig wie aus anderen Sprachen bekannt, ein explizites "return"-Statement anzugeben.

Details hierzu findet man in Modellzugriff und Funktionen.