zurück zur Dokumentation

Formeln

Referenz der Formel-Engine: berechnete Felder, Validierungsregeln, bedingte Logik, Navigationspfade und eingebaute Funktionen.

veröffentlicht ·aktualisiert

Überblick

Formeln verwenden eine kleine, deterministische DSL (kein JavaScript, Python oder SQL). Die Grammatik ist bewusst einfach, sicher und seiteneffekt-frei. Formeln werden einmal auf dem Server in einen AST geparst, gecached und zur Laufzeit erneut ausgewertet — manchmal auf dem Server, manchmal auf dem Client, manchmal direkt in die SQL-Abfrage eingebettet.

Sie erscheinen in:

  • Berechneten Spalten — Formel-Spalten (columnType: "F"), die Werte aus anderen Feldern berechnen
  • Generated Columns — physischen Spalten (columnType: "G"), die von der Datenbank automatisch gepflegt werden, für Aggregate über Kind-Sets (z. B. SUM([lines].[amount]))
  • Standardwerten — Anfangswerte für neue Datensätze setzen
  • ValidierungsregelnCHECK-Constraints, die Geschäftslogik durchsetzen
  • Aktions-BedingungencanExecute-Formeln, die steuern, wann Aktionen verfügbar sind
  • Sicherheit auf Zeilenebene — Filterausdrücke, die einschränken, welche Datensätze ein Anwender sehen kann
  • Anzeige-StringstoString-Vorlagen mit {field}-Platzhaltern

Syntax

Feldreferenzen

Greifen Sie auf die Felder des aktuellen Datensatzes mit Klammern zu:

[quantity]
[unit_price]
[account_name]

Arithmetik

[quantity] * [unit_price]
[subtotal] + [tax_amount]
[total] - [discount]
[amount] / [count]

String-Operationen

[first_name] + ' ' + [last_name]

Vergleich

dForge verwendet SQL-artige einzelne Gleichheitszeichen für Gleichheit, nicht ==.

[amount] > 1000
[status] = 'Active'
[end_date] >= [start_date]
[category] != 'Internal'

Andere Vergleichsoperatoren: <, <=, >, >=, IN, NOT IN, BETWEEN.

Logische Operatoren

[amount] > 1000 AND [status] = 'Approved'
[type] = 'A' OR [type] = 'B'
NOT [is_archived]

Bedingte Logik

IF([amount] > 10000, 'Enterprise', IF([amount] > 1000, 'Business', 'Standard'))
IF([discount_pct] > 0, [price] * (1 - [discount_pct] / 100), [price])

IN-Operator

[status] IN ('Open', 'In Progress', 'Pending')
[type] NOT IN ('Internal', 'Test')
[amount] BETWEEN 100 AND 1000

String-Prädikate

[name] CONTAINS 'corp'
[email] STARTS_WITH 'admin@'
[file] ENDS_WITH '.pdf'

Folgen Sie Referenzen, um auf Felder verbundener Entitäten zuzugreifen. Navigieren Sie über die virtuelle Referenz-Spalte (nicht über die FK-Spalte selbst):

[customer].[name]
[customer].[industry]
[order].[customer].[email]

Navigations-Formeln sind asynchron — sie erfordern einen separaten Datenabruf. Die Plattform erkennt Navigationsmuster automatisch und löst sie nach den synchronen Formeln auf. Das Frontend cached jede referenzierte Entität, um N+1-Abrufe zu vermeiden.

So funktioniert es

  1. [customer] — die Referenz-Spalte am aktuellen Datensatz
  2. . — folgt der Referenz zur Ziel-Entität
  3. [name] — liest das Feld vom referenzierten Datensatz

Mehrstufige Navigation wird unterstützt: [order].[customer].[name] folgt zwei Referenzen. Aktuell unterstützt der Client bis zu 2 Ebenen.

Synchron vs. asynchron

Typ Wann ausgewertet Beispiel
Synchron Sofort beim Datenladen und bei Feldänderungen [quantity] * [unit_price]
Asynchron Nach synchronen Formeln, erfordert Datenabruf [account_id].[industry]

Die Plattform klassifiziert Formeln automatisch danach, ob sie Navigationsmuster ([field].[field]) enthalten.

Abhängigkeitsverfolgung

Formeln deklarieren ihre Abhängigkeiten über Feldreferenzen. Wenn sich ein Feld ändert:

  1. Alle synchronen Formeln, die davon abhängen, werden sofort neu ausgewertet
  2. Alle asynchronen Formeln, die davon abhängen, lösen einen Datenabruf aus und werten neu aus, wenn die Daten ankommen

Formeln werden topologisch nach Abhängigkeiten sortiert, um die korrekte Auswertungsreihenfolge sicherzustellen.

Eingebaute Funktionen

Datumsfunktionen

Funktion Beschreibung Beispiel
TODAY() Aktuelles Datum [due_date] >= TODAY()
NOW() Aktuelles Datum/Zeit [created_at] > NOW()
WEEKDAY(date) Wochentag (1–7) WEEKDAY(TODAY())
STARTMONTH(date) Erster Tag des Monats des Datums STARTMONTH(NOW())
ENDMONTH(date) Letzter Tag des Monats des Datums ENDMONTH(NOW())
STARTQUARTER(date) Erster Tag des Quartals des Datums STARTQUARTER(NOW())
ENDQUARTER(date) Letzter Tag des Quartals des Datums ENDQUARTER(NOW())
STARTYEAR(date) Erster Tag des Jahres des Datums STARTYEAR(NOW())

Kontext-Funktionen

Ausdruck Beschreibung
CURRENT_USER_ID() Die ID des aktuellen Anwenders
$[SettingName] Wert einer Modul-Einstellung (aufgelöst aus dem Ordner-Kontext — siehe unten)

Bedingte Funktionen

Funktion Beschreibung Beispiel
IF(cond, then, else) Bedingter Wert IF([qty] > 100, 'Bulk', 'Standard')

Aggregat-Funktionen (Generated Columns)

Aggregat-Funktionen arbeiten auf einem Set-Feld (1:N-Kind-Sammlung) und benötigen columnType: "G" — eine physische Spalte, die von der Datenbank automatisch gepflegt wird.

Funktion Beschreibung
SUM([set].[field]) Summe der Feldwerte über Kind-Datensätze
COUNT([set].[field]) Anzahl der Kind-Datensätze
AVG([set].[field]) Durchschnittswert
MIN([set].[field]) Minimalwert
MAX([set].[field]) Maximalwert

Mehrspaltige Ausdrücke innerhalb des Aggregats werden unterstützt:

SUM([lines].[quantity] * [lines].[unit_price])

Die Plattform wählt die richtige Strategie automatisch: Selbe-Zeile-Formeln werden zu PostgreSQL-GENERATED ALWAYS AS ... STORED-Spalten, während Set-Aggregate Datenbank-Trigger auf der Kind-Tabelle verwenden.

Einstellungs-Referenzen

Modul-Einstellungen sind konfigurierbare Werte, die pro Ordner überschrieben werden können. Referenzieren Sie sie in Formeln mit $[SettingName]:

[department_id] = $[DepartmentId]               -- Sicherheit auf Zeilenebene
[amount] <= $[ApprovalThreshold]                -- canExecute-Bedingung
$[DefaultWarehouseId]                            -- Standardwert

Wenn eine Formel eine Einstellung referenziert, sucht die Plattform sie im aktuellen Ordner, läuft den Ordnerbaum hinauf und fällt schließlich auf den Modul-Default zurück. Gibt NULL zurück, wenn nirgendwo ein Wert gesetzt ist.

Anwendungsbeispiele

Berechnete Summe

[quantity] * [unit_price] * (1 - [discount_pct] / 100)

Eine Formel-Spalte auf einer Rechnungsposition, die die Zeilensumme nach Rabatt berechnet.

Vollständiger Name

[first_name] + ' ' + [last_name]

Eine Formel-Spalte, die Namensteile zur Anzeige zusammenfügt.

Überfällig-Prüfung

[due_date] < TODAY() AND [status] != 'Paid'

Verwendet als Check-Constraint oder bedingte Formatierungsregel.

Phasenbasierte Betragsprognose

IF([stage] = 'Closed Won', [amount],
IF([stage] = 'Negotiation', [amount] * 0.7,
IF([stage] = 'Proposal', [amount] * 0.4,
[amount] * 0.1)))

Eine gewichtete Pipeline-Prognose basierend auf der Verkaufschancen-Phase.

Entitätsübergreifende Anzeige

[customer].[name] + ' (' + [customer].[industry] + ')'

Eine asynchrone Formel, die Kundenname und Branche aus dem verlinkten Kunden-Datensatz anzeigt.

toString-Vorlagen

Die toString-Eigenschaft auf einer Entität verwendet eine andere Syntax — {field}-Platzhalter innerhalb einer Text-Vorlage, keine Klammer-Ausdrücke:

"toString": "{invoice_number} — {customer}"
"toString": "{first_name} {last_name}"
"toString": "{product} x {quantity}"

Wenn ein Platzhalter ein Referenzfeld benennt (z. B. {customer}), löst die Plattform es rekursiv über die toString-Vorlage der referenzierten Entität auf. Das wird zur SQL-Zeit ausgewertet (über JOINs in einer einzigen Abfrage) und vermeidet N+1-Abrufe.

Formel-Spalten in Entitätsdefinitionen

Wenn Sie eine Formel-Spalte (Spaltentyp F) definieren, müssen Sie angeben:

Property Pflicht Beschreibung
formula Ja Der Ausdruckstext
baseDatatypeCd Ja Ergebnis-Datentyp: string, number, date, bool
fieldTypeCd Ja Wie das Ergebnis dargestellt wird: text, number, currency, date usw.
columnType Ja Muss "F" sein
flags Ja Üblicherweise "V" (visible) — Formel-Spalten sind nie editierbar

Check-Constraints

Entitäten können Check-Constraints mit Formel-Syntax definieren:

"constraints": {
  "positive_quantity": {
    "type": "check",
    "expression": "quantity > 0",
    "message": "Menge muss positiv sein"
  },
  "valid_date_range": {
    "type": "check",
    "expression": "end_date >= start_date",
    "message": "Enddatum muss am oder nach dem Startdatum liegen"
  }
}

Check-Constraints werden zu echten PostgreSQL-CHECK-Constraints (serverseitige Durchsetzung) und werden auch clientseitig über den Formel-Auswerter für sofortiges UI-Feedback ausgewertet. Wenn der Ausdruck false zurückgibt, wird das Speichern mit der angegebenen Fehlermeldung abgelehnt.

Wo Formeln laufen

Kontext Ausgewertet auf Warum
toString-Anzeige Server / SQL-Zeit JOINs zu referenzierten Tabellen in einer Abfrage — kein N+1
canExecute Client + Server Client für sofortigen Button-Zustand; Server prüft erneut für Sicherheit
Einfache berechnete Felder Client Sofortiges Feedback, wenn der Anwender ein Feld bearbeitet
Standardwerte Server Beim Insert angewendet
Sicherheit auf Zeilenebene Server Zur Abfragezeit durchgesetzt
Validierung / CHECK Server (und Client für UI-Feedback) Beim Speichern durchgesetzt
Generated-Column-Aggregate Datenbank PostgreSQL-Trigger oder GENERATED ALWAYS AS-Spalte
/ war das hilfreich?

Stecken Sie irgendwo fest?
Sagen Sie es uns.

Wir lesen jede Nachricht und aktualisieren die Dokumentation auf Basis dessen, was Leser fragen. Der schnellste Weg, die Dokumentation zu verbessern, ist, uns zu schreiben.