Zum Inhalt

Funktionsreferenz: Übergreifende fn-Funktionen

Die übergreifenden fn-Funktionen ermöglichen serverseitige Berechnungen, Konvertierungen und Datenfeld-Auswertungen direkt in der GraphQL-Query. Sie sind in slowFilter-Ausdrücken, in expr:-Parametern (_string, _int, _float, _if) und in verschachtelten Expressions verfügbar. Sie operieren auf Feldwerten und Konstanten und werden vom ERP-Server ausgewertet.

Grundlegende GraphQL-Kenntnisse werden vorausgesetzt. Sollten Ihnen Konzepte wie Tabellenzugriff, Filter oder slowFilter-Syntax noch nicht vertraut sein, empfehlen wir zunächst die GraphQL Doku - Abfragen (Queries).


Inhaltsverzeichnis

  1. Überblick
  2. Syntax
  3. Text-Funktionen
  4. Datum/Zeit-Funktionen
  5. Konvertierungs-Funktionen
  6. Benutzer-Funktionen
  7. Nachschlagen/Auswerten-Funktionen
  8. Praxisbeispiele
  9. Stolpersteine

1. Überblick

Die Funktionen decken folgende Bereiche ab:

Kategorie Beispiele
Text/String fnLeft, fnPos, fnLength, fnGetPosString
Datum/Zeit fnYear, fnDiffDate, fnIncDate, fnFormatDateTime
Konvertierung fnToInt, fnToDate, fnToBool, fnToText
Benutzer fnGetAktBzr, fnGetAktBzrNr, fnGetAktBzrSel
Nachschlagen/Auswerten fnDSInfo, fnEntfernung, fnGetBit, fnGetAlter, fnGetPlzInfo

fnGetBit und fnToBool können direkt als Filterbedingung verwendet werden, ohne Vergleichsoperator.

Beachten Sie

In Filtern sind fn-Funktionen nur über slowFilter verfügbar, nicht über fastFilter. Wenn ein Filter auch ohne fn-Funktionen formuliert werden kann, ist fastFilter immer vorzuziehen, weil der Server die Daten direkt auf dem Index filtert statt sie erst zu laden und dann auszuwerten.


2. Syntax

Parameter-Konvention

Alle fn-Funktionen nehmen eine positionelle Liste von Expressions als Parameter. Jeder Parameter kann ein Literal (value), ein Feldverweis (field) oder eine verschachtelte Funktion sein.

# Literal
{fnLeft: [{value: "Hallo Welt"}, {value: 5}]}

# Feldverweis
{fnLeft: [{field: fldSuchBeg}, {value: 3}]}

# Verschachtelt: erst Datum konvertieren, dann Jahr extrahieren
{fnYear: [{fnToDate: [{value: "14.04.2026"}]}]}

Verwendung in slowFilter

Expression-Funktionen werden in Vergleichsoperatoren eingebettet:

query {
  tblAddresses {
    rowsRead(slowFilter: {
      gt: [{fnLength: [{field: fldSuchBeg}]}, {value: 20}]
    }) {
      fldAdrNr
      fldSuchBeg
    }
  }
}

Verwendung in Mutations-Expressions

Expression-Funktionen können auch direkt als Mutation über die _string, _int, _float Expression-Felder auf Root-Ebene ausgewertet werden:

mutation {
  heute: _string(expr: { fnGetAktDate: [] })
  jahr:  _int(expr: { fnYear: [{fnGetAktDate: []}] })
  left:  _string(expr: { fnLeft: [{value: "Testprodukt"}, {value: 4}] })
}
{
  "heute": "15.04.2026",
  "jahr": 2026,
  "left": "Test"
}

3. Text-Funktionen

fnLeft(text, anzahl) → String

Gibt die ersten anzahl Zeichen von text zurück.

mutation {
  result: _string(expr: { fnLeft: [{value: "Testprodukt Premium"}, {value: 4}] })
}
{ "result": "Test" }

fnRight(text, anzahl) → String

Gibt die letzten anzahl Zeichen von text zurück. Gibt einen leeren String zurück wenn anzahl größer als die Textlänge ist.

mutation {
  result: _string(expr: { fnRight: [{value: "Testprodukt Premium"}, {value: 7}] })
}
{ "result": "Premium" }

fnMid(text, start, anzahl) → String

Gibt anzahl Zeichen ab Position start (1-basiert) aus text zurück.

mutation {
  result: _string(expr: { fnMid: [{value: "RE12600002"}, {value: 3}, {value: 3}] })
}
{ "result": "126" }

fnPos(suchtext, text) → Int

Sucht suchtext in text und gibt die Position zurück (1-basiert). Gibt 0 zurück wenn nicht gefunden.

mutation {
  result: _int(expr: { fnPos: [{value: "Premium"}, {value: "Testprodukt Premium"}] })
}
{ "result": 13 }

Beachten Sie

Achtung bei RTF-Feldern:

Felder wie fldBez1 sind intern RTF-Blobs. Vor der Verwendung in Text-Funktionen mit fnToText konvertieren: {fnPos: [{value: "Silber"}, {fnToText: [{field: fldBez1}]}]}

fnLength(text) → Int

Gibt die Zeichenlänge von text zurück.

mutation {
  result: _int(expr: { fnLength: [{value: "Hallo Welt"}] })
}
{ "result": 10 }

fnToString(wert) → String

Wandelt wert in einen String um. Liest Felder über ihren Rohwert. Bei RTF-Blob-Feldern wird daher der rohe RTF-Markup zurückgegeben ({\rtf1\ansi...), nicht der Klartext. Für RTF-Felder stattdessen fnToText verwenden.

mutation {
  zahl:  _string(expr: { fnToString: [{value: 42}] })
  komma: _string(expr: { fnToString: [{value: 3.14}] })
}
{ "zahl": "42", "komma": "3,14" }

fnToText(wert) → String

Wandelt wert in Klartext um. Liest Felder über ihre Display-Darstellung. Bei RTF-Blob-Feldern (z.B. fldBez1) wird dadurch das RTF-Markup entfernt und der lesbare Text extrahiert.

query {
  tblProducts {
    rowsRead(slowFilter: {
      gt: [{fnPos: [{value: "Silber"}, {fnToText: [{field: fldBez1}]}]}, {value: 0}]
    }) {
      fldArtNr
      fldBez1(as: DISPLAY_TEXT)
    }
  }
}

fnGetPosString(text, position, trennzeichen?) → String

Teilt text am trennzeichen und gibt das Token an position zurück (1-basiert, Position 0 ergibt leeren String). position muss ein Integer sein. trennzeichen ist optional, Standard ist Komma.

mutation {
  semikolon: _string(expr: {
    fnGetPosString: [{value: "Berlin;Hamburg;München"}, {value: 2}, {value: ";"}]
  })
  komma: _string(expr: {
    fnGetPosString: [{value: "Berlin,Hamburg,München"}, {value: 3}]
  })
}
{ "semikolon": "Hamburg", "komma": "München" }

4. Datum/Zeit-Funktionen

Datum erzeugen und konvertieren

Funktion Parameter Rückgabe Beschreibung
fnDate(wert) [String] Date String in Datum konvertieren
fnToDate(wert) [String] Date Alias für fnDate (gleiche Implementierung)
fnTime(wert) [String] Time String in Uhrzeit konvertieren
fnToTime(wert) [String] Time Alias für fnTime (gleiche Implementierung)
fnToDateTime(wert) [String] DateTime String in Datum+Uhrzeit konvertieren

Das Eingabeformat richtet sich nach den Ländereinstellungen des Servers. Auf einem deutschen Server:

  • Datum: "14.04.2026" oder "14.04.26"
  • Uhrzeit: "14:30:00" oder "14:30"
  • Datum+Uhrzeit: "14.04.2026 08:30:00"

ISO-Format ("2026-04-14") wird nicht akzeptiert.

mutation {
  datum: _string(expr: {
    fnFormatDateTime: [{value: "dd.mm.yyyy"}, {fnToDate: [{value: "14.04.2026"}]}]
  })
}
{ "datum": "14.04.2026" }

Datum-Bestandteile extrahieren

Funktion Parameter Rückgabe Beschreibung
fnYear(datum) [Date/DateTime] Int Jahreszahl
fnMonth(datum) [Date/DateTime] Int Monat (1–12)
fnDay(datum) [Date/DateTime] Int Tag im Monat (1–31)
fnHour(datum) [DateTime] Int Stunde (0–23)
fnMinute(datum) [DateTime] Int Minute (0–59)
fnSecond(datum) [DateTime] Int Sekunde (0–59)
mutation {
  jahr:   _int(expr: { fnYear:   [{fnGetAktDate: []}] })
  monat:  _int(expr: { fnMonth:  [{fnGetAktDate: []}] })
  tag:    _int(expr: { fnDay:    [{fnGetAktDate: []}] })
  stunde: _int(expr: { fnHour:   [{fnGetAktDate: [{value: "Time"}]}] })
  minute: _int(expr: { fnMinute: [{fnGetAktDate: [{value: "Time"}]}] })
}
{ "jahr": 2026, "monat": 4, "tag": 15, "stunde": 16, "minute": 30 }

Aktuelles Datum

Funktion Parameter Rückgabe Beschreibung
fnGetDate() [] Date Aktuelles Datum
fnGetAktDate() [] Date Aktuelles Programmdatum
fnGetAktDate("Time") ["Time"] DateTime Programmdatum mit Uhrzeit
mutation {
  datum:   _string(expr: { fnGetAktDate: [] })
  mitZeit: _string(expr: { fnGetAktDate: [{value: "Time"}] })
}
{
  "datum": "15.04.2026",
  "mitZeit": "15.04.2026 16:30:31"
}

Datum-Arithmetik

fnDiffDate(startDatum, endDatum) → Int

Berechnet die Anzahl der Tage zwischen startDatum und endDatum. Positiv wenn endDatum nach startDatum liegt.

mutation {
  tage: _int(expr: { fnDiffDate: [
    {fnToDate: [{value: "01.01.2026"}]},
    {fnToDate: [{value: "15.04.2026"}]}
  ] })
}
{ "tage": 104 }

fnIncDate(datum, tage?, monate?) → Date

Addiert Tage und/oder Monate zu einem Datum. Negative Werte subtrahieren.

mutation {
  plus7Tage: _string(expr: { fnFormatDateTime: [
    {value: "dd.mm.yyyy"},
    {fnIncDate: [{fnGetAktDate: []}, {value: 7}]}
  ] })
  plus3Monate: _string(expr: { fnFormatDateTime: [
    {value: "dd.mm.yyyy"},
    {fnIncDate: [{fnGetAktDate: []}, {value: 0}, {value: 3}]}
  ] })
}
{ "plus7Tage": "22.04.2026", "plus3Monate": "15.07.2026" }

fnGetDateQuartalAnfang(datum) → Date

Gibt den ersten Tag des Quartals zurück in dem datum liegt.

fnGetDateQuartalEnde(datum) → Date

Gibt den letzten Tag des Quartals zurück in dem datum liegt. Die Rückgabe muss mit fnFormatDateTime formatiert werden.

mutation {
  anfang: _string(expr: { fnFormatDateTime: [
    {value: "dd.mm.yyyy"},
    {fnGetDateQuartalAnfang: [{fnGetAktDate: []}]}
  ] })
  ende: _string(expr: { fnFormatDateTime: [
    {value: "dd.mm.yyyy"},
    {fnGetDateQuartalEnde: [{fnGetAktDate: []}]}
  ] })
}
{ "anfang": "01.04.2026", "ende": "30.06.2026" }

fnFormatDateTime(format, datum) → String

Formatiert datum nach der angegebenen format-Zeichenkette.

Platzhalter Bedeutung Beispiel
dd Tag mit führender Null 15
mm Monat mit führender Null 04
yyyy Vierstelliges Jahr 2026
yy Zweistelliges Jahr 26
hh Stunde mit führender Null 16
nn Minute mit führender Null 30
ss Sekunde mit führender Null 00
w Kalenderwoche 16
ddd Wochentag (Abkürzung) Di
dddd Wochentag (ausgeschrieben) Dienstag
mutation {
  iso:     _string(expr: { fnFormatDateTime: [{value: "yyyy-mm-dd"}, {fnGetAktDate: []}] })
  deutsch: _string(expr: { fnFormatDateTime: [{value: "dd.mm.yyyy hh:nn:ss"}, {fnGetAktDate: [{value: "Time"}]}] })
}
{ "iso": "2026-04-15", "deutsch": "15.04.2026 16:30:31" }

5. Konvertierungs-Funktionen

Funktion Parameter Rückgabe Beschreibung
fnToInt(wert) [Any] Int In Ganzzahl konvertieren
fnToFloat(wert) [Any] Float In Fließkommazahl konvertieren
fnToBool(wert) [Any] Boolean In Wahrheitswert konvertieren (0/1, true/false)
fnToString(wert) [Any] String In String konvertieren (bei RTF-Feldern: roher Markup)
fnToText(wert) [Any] String In Klartext konvertieren (bei RTF-Feldern: Markup entfernt)
fnToDate(wert) [String] Date In Datum konvertieren (Serverformat)
fnToTime(wert) [String] Time In Uhrzeit konvertieren
fnToDateTime(wert) [String] DateTime In Datum+Uhrzeit konvertieren
mutation {
  ganzzahl:  _int(expr: { fnToInt: [{value: "42"}] })
  kommazahl: _float(expr: { fnToFloat: [{value: "3,14"}] })
  bool:      _if(expr: { fnToBool: [{value: 1}] }) { r: _string(value: "true") }
}
{ "ganzzahl": 42, "kommazahl": 3.14, "bool": { "r": "true" } }

Beachten Sie

fnToFloat nutzt die Ländereinstellungen des Servers für das Dezimal- und Tausendertrennzeichen. Das Komma wird zusätzlich immer als Dezimaltrennzeichen akzeptiert. Auf einem deutschen Server: "3,14" → 3.14, "3.14" → 314 (Punkt = Tausender-Separator).


6. Benutzer-Funktionen

Funktion Parameter Rückgabe Beschreibung
fnGetAktBzr() [] String Benutzerkürzel des angemeldeten Benutzers
fnGetAktBzrNr() [] Int/String Nummer des angemeldeten Benutzers
fnGetAktBzrSel(n) [Int] String Selektionsfeld n des angemeldeten Benutzers
mutation {
  kuerzel:    _string(expr: { fnGetAktBzr: [] })
  nummer:     _string(expr: { fnGetAktBzrNr: [] })
  selektion1: _string(expr: { fnGetAktBzrSel: [{value: 1}] })
}
{ "kuerzel": "gql", "nummer": "2", "selektion1": "" }

Info

Die Rückgabewerte sind abhängig vom angemeldeten Benutzer.


7. Nachschlagen/Auswerten-Funktionen

fnDSInfo(feldname, schlüssel, format?, trennzeichen?) → String

Liest einen Wert aus einem Datenfeld das als Key-Value-Liste (CommaText) gespeichert ist. Nicht zu verwechseln mit DBInfo() im ERP-Feldeditor (Cross-Table-Lookup), das im GraphQL-Schema nicht verfügbar ist.

Parameter Typ Beschreibung
1 String Feldname oder Key-Value-String
2 String Schlüssel dessen Wert zurückgegeben wird (leer = gesamte Liste)
3 (optional) String "Text" für Zeilenformat, "SvlFormat" für StringValueList
4 (optional) String Trennzeichen zwischen Name und Value

Der erste Parameter kann ein Feldname des aktuellen Datensatzes sein (wird dann zur Laufzeit gelesen) oder ein direkter Key-Value-String. Wenn kein = im Wert vorkommt, wird er als Feldname interpretiert.

mutation {
  tblAddresses {
    name: _string(expr: {
      fnDSInfo: [{value: "Name=Mueller,Ort=Berlin"}, {value: "Name"}]
    })
    ort: _string(expr: {
      fnDSInfo: [{value: "Name=Mueller,Ort=Berlin"}, {value: "Ort"}]
    })
    alles: _string(expr: {
      fnDSInfo: [{value: "Name=Mueller,Ort=Berlin"}, {value: ""}]
    })
  }
}
{
  "tblAddresses": {
    "name": "Mueller",
    "ort": "Berlin",
    "alles": "Name=Mueller,Ort=Berlin"
  }
}

Im slowFilter kann der erste Parameter auch ein Feldverweis sein. Dann liest fnDSInfo den Inhalt dieses Feldes und parst ihn als Key-Value-Liste:

slowFilter: {eq: [{fnDSInfo: [{field: fldSel1}, {value: "Typ"}]}, {value: "Gold"}]}

Beachten Sie

fnDSInfo funktioniert im Tabellenkontext (Mutation auf einer Tabelle oder slowFilter), nicht in Mutations-Expressions auf Root-Ebene.

fnGetBit(wert, bitNr) → Boolean

Prüft ob das Bit an Position bitNr (0-basiert) in wert gesetzt ist.

mutation {
  bit0: _if(expr: { fnGetBit: [{value: 5}, {value: 0}] }) { r: _string(value: "gesetzt") }
  bit1: _if(expr: { fnGetBit: [{value: 5}, {value: 1}] }) { r: _string(value: "gesetzt") }
  bit2: _if(expr: { fnGetBit: [{value: 5}, {value: 2}] }) { r: _string(value: "gesetzt") }
}
{
  "bit0": { "r": "gesetzt" },
  "bit1": null,
  "bit2": { "r": "gesetzt" }
}

5 = binär 101: Bit 0 gesetzt, Bit 1 nicht, Bit 2 gesetzt. Nützlich für Felder die Bitmasken speichern (z.B. Status-Flags, Berechtigungen).

fnEntfernung(plz1, plz2, land1?, land2?) → Float

Berechnet die Entfernung zwischen zwei Postleitzahlen in Kilometern. Gibt einen negativen Wert zurück wenn die Berechnung nicht möglich ist (fehlende PLZ-Geodaten). Optional können Länderkennzeichen mitgegeben werden.

Parameter Typ Beschreibung
1 String PLZ Ausgangspunkt
2 String PLZ Zielpunkt
3 (optional) String Länderkennzeichen Ausgangspunkt
4 (optional) String Länderkennzeichen Zielpunkt
mutation {
  km: _float(expr: { fnEntfernung: [{value: "55543"}, {value: "60329"}] })
}
{ "km": -1 }

Info

Negativer Wert wenn PLZ-Geodaten auf dem Server nicht verfügbar sind.

fnGetAlter(datum) → Int

Berechnet das Alter in Jahren ausgehend von datum. Verwendet das Serverdatum als Referenz.

mutation {
  alter: _int(expr: { fnGetAlter: [{fnToDate: [{value: "15.06.1990"}]}] })
}
{ "alter": 35 }

fnGetPlzInfo(plz, feldname?) → String

Gibt zu plz Informationen aus der PLZ-Tabelle zurück.

Parameter Typ Beschreibung
1 String Postleitzahl
2 (optional) String Feldname (leer = Ortsname)
mutation {
  ort: _string(expr: { fnGetPlzInfo: [{value: "55543"}] })
}
{ "ort": "Bad Kreuznach" }

8. Praxisbeispiele

8.1 Artikel mit „Silber" in der Bezeichnung finden

Die Artikelbezeichnung (fldBez1) ist ein RTF-Blob-Feld. Vor der Textsuche muss es mit fnToText konvertiert werden. Dieses Feld ist im fastFilter nicht verfügbar.

query {
  tblProducts {
    rowsRead(slowFilter: {
      # fnPos gibt 0 zurück wenn nicht gefunden, >0 wenn gefunden
      gt: [{fnPos: [
        {value: "Silber"},
        {fnToText: [{field: fldBez1}]}  # RTF → Klartext
      ]}, {value: 0}]
    }) {
      fldArtNr
      fldBez1(as: DISPLAY_TEXT)
    }
  }
}

8.2 Adressen mit langem Suchbegriff

Zeichenlänge ist eine Berechnung die nur per slowFilter möglich ist:

query {
  tblAddresses {
    rowsRead(slowFilter: {
      gt: [
        {fnLength: [{field: fldSuchBeg}]},  # Länge berechnen
        {value: 20}                          # mit 20 vergleichen
      ]
    }) {
      fldAdrNr
      fldSuchBeg
    }
  }
}

8.3 Vorgänge aus dem aktuellen Quartal

fnGetDateQuartalAnfang und fnGetDateQuartalEnde berechnen die Quartalsgrenzen dynamisch. Im Gegensatz zu einem statischen Datumsvergleich per fastFilter passt sich der Filter automatisch an:

query {
  tblTransactions {
    rowsRead(slowFilter: {
      and: [
        # Vorgangsdatum >= Quartalsanfang
        {ge: [{field: fldDat}, {fnGetDateQuartalAnfang: [{fnGetAktDate: []}]}]},
        # Vorgangsdatum <= Quartalsende
        {le: [{field: fldDat}, {fnGetDateQuartalEnde: [{fnGetAktDate: []}]}]}
      ]
    }) {
      fldBelegNr
      fldDat
    }
  }
}

8.4 Quartalsgrenzen und Datumsarithmetik berechnen

Quartalsgrenzen, Datumsverschiebungen und Formatierungen in einer Query:

mutation {
  # Quartalsanfang und -ende für das aktuelle Datum
  quartalAnfang: _string(expr: { fnFormatDateTime: [
    {value: "dd.mm.yyyy"},
    {fnGetDateQuartalAnfang: [{fnGetAktDate: []}]}
  ] })
  quartalEnde: _string(expr: { fnFormatDateTime: [
    {value: "dd.mm.yyyy"},
    {fnGetDateQuartalEnde: [{fnGetAktDate: []}]}
  ] })
  # Datum verschieben: 7 Tage in die Zukunft
  plus7Tage: _string(expr: { fnFormatDateTime: [
    {value: "dd.mm.yyyy"},
    {fnIncDate: [{fnGetAktDate: []}, {value: 7}]}
  ] })
  # Datum verschieben: 3 Monate in die Zukunft (0 Tage, 3 Monate)
  plus3Monate: _string(expr: { fnFormatDateTime: [
    {value: "dd.mm.yyyy"},
    {fnIncDate: [{fnGetAktDate: []}, {value: 0}, {value: 3}]}
  ] })
}
{
  "quartalAnfang": "01.04.2026",
  "quartalEnde": "30.06.2026",
  "plus7Tage": "22.04.2026",
  "plus3Monate": "15.07.2026"
}

8.5 Adressen nach Suffix im Suchbegriff filtern

fnRight extrahiert die letzten Zeichen eines Feldes. Suffix-Suchen sind mit fastFilter nicht möglich:

query {
  tblAddresses {
    rowsRead(slowFilter: {
      eq: [
        {fnRight: [{field: fldSuchBeg}, {value: 8}]},  # letzte 8 Zeichen
        {value: "RECHNUNG"}                              # mit "RECHNUNG" vergleichen
      ]
    }) {
      fldAdrNr
      fldSuchBeg
    }
  }
}

8.6 Vorgänge aus einem bestimmten Monat per fastFilter-Datumsbereich

Wenn das Datum als Feld im fastFilter verfügbar ist (wie fldDat bei Vorgängen), ist ein Datumsbereich per fastFilter immer vorzuziehen:

query {
  tblTransactions {
    # fastFilter: performanter als slowFilter mit fnYear+fnMonth
    rowsRead(fastFilter: {
      and: [
        {ge: [{field: fldDat}, {value: "2026-03-01"}]},  # ab 1. März
        {lt: [{field: fldDat}, {value: "2026-04-01"}]}    # bis vor 1. April
      ]
    }) {
      fldBelegNr
      fldDat
    }
  }
}

8.7 Adressen deren Suchbegriff "GALERIE" enthält

fnPos auf einem normalen String-Feld (kein RTF, kein fnToText nötig):

query {
  tblAddresses {
    rowsRead(slowFilter: {
      gt: [{fnPos: [{value: "GALERIE"}, {field: fldSuchBeg}]}, {value: 0}]
    }) {
      fldAdrNr
      fldSuchBeg
    }
  }
}

8.8 Semikolon-getrenntes Feld aufsplitten

Ein Selektionsfeld enthält mehrere Werte getrennt durch Semikolon. Das zweite Token extrahieren:

mutation {
  token: _string(expr: {
    # "Berlin;Hamburg;München" am ";" splitten, Position 2 holen
    fnGetPosString: [{value: "Berlin;Hamburg;München"}, {value: 2}, {value: ";"}]
  })
}
{ "token": "Hamburg" }

9. Stolpersteine

Parameter-Typen beachten

Die Fehlermeldungen des Servers sind aussagekräftig:

GetAktBzrSel(): Ungültiger Parametertype. 1. Parameter Erwartet: Integer. Gefunden: ftWideString

Häufige Fehlerquellen: - Integer-Parameter als String übergeben: {value: "1"} statt {value: 1} - Datum als String statt als fnToDate-Ergebnis: {value: "14.04.2026"} statt {fnToDate: [{value: "14.04.2026"}]}