From 9897b8daded897adfc60462efe98cadbf9fcca0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SAL=C4=B0H=20=C3=96ZKARA?= Date: Tue, 28 Jul 2026 13:29:29 +0300 Subject: [PATCH 1/3] docs: add low-code expression language reference --- docs/en/low-code/expression-language.md | 101 ++++++++++++++++++++++++ docs/en/low-code/formula-properties.md | 46 +++++++++++ docs/en/low-code/index.md | 4 +- 3 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 docs/en/low-code/expression-language.md create mode 100644 docs/en/low-code/formula-properties.md diff --git a/docs/en/low-code/expression-language.md b/docs/en/low-code/expression-language.md new file mode 100644 index 0000000000..f1f11c879d --- /dev/null +++ b/docs/en/low-code/expression-language.md @@ -0,0 +1,101 @@ +```json +//[doc-seo] +{ + "Description": "Reference for the ABP Low-Code expression language used by calculated properties, mappings, defaults, and validations." +} +``` + +# Low-Code Expression Language + +The Low-Code expression language is a small, provider-safe language used in more than one designer workflow. It is used by formula properties and can also be used where the designer asks for an expression-backed value, such as mapped-property initial values or existing-data backfills. + +The v1 syntax is intentionally familiar to Excel, Airtable, and Power Fx users while remaining translatable to a server-side expression tree. Expressions are evaluated by the server; they are not JavaScript and must not contain arbitrary code, SQL, network calls, or browser APIs. + +> **Preview:** The language profile is preview functionality. The supported function set is deliberately smaller than the complete Excel or Power Fx languages. + +## Values and field references + +Use numbers, quoted strings, Boolean values, and date constructors as literals. Reference a property by its name: + +```text +UnitPrice * Quantity +If(IsActive, "Enabled", "Disabled") +Date(2026, 7, 28) +``` + +Property names containing spaces can be enclosed in single quotes: + +```text +'Unit Price' * Quantity +``` + +Names and function names are case-insensitive. A field reference is resolved against the current entity, including fields backed by JSON and fields mapped to database columns. + +## Operators + +| Purpose | Operators and forms | +| --- | --- | +| Arithmetic | `+`, `-`, `*`, `/`, `%` | +| Comparison | `=`, `<>`, `!=`, `<`, `<=`, `>`, `>=` | +| Logical | `And(a, b)`, `Or(a, b)`, `Not(a)`, `&&`, `||`, `!` | +| Text concatenation | `&` | +| Percentage | `10%` (equivalent to `10 / 100`) | + +`<>` and `!=` are equivalent not-equal operators. Use parentheses when combining arithmetic, comparison, and logical operators so the intended order is clear. + +## Functions + +The v1 profile supports the following functions: + +```text +If, Coalesce, IsBlank, +Abs, Round, Floor, Ceiling, Min, Max, +Concat, Lower, Upper, Trim, Len, +Left, Right, Mid, Substring, +Year, Month, Day, Date, DateTime +``` + +Examples: + +```text +If(Len(Name) > 5, "Long", "Short") +Coalesce(Discount, 0) +Round(UnitPrice * Quantity, 2) +Concat(FirstName, " ", LastName) +``` + +`Round(value, places)` uses midpoint-away-from-zero semantics. Numeric and date literals use invariant syntax; the browser or database locale does not change their meaning. + +## Local values with `With` + +Use `With` to name intermediate values and avoid repeating calculations: + +```text +With( + { + subtotal: UnitPrice * Quantity, + rebate: Coalesce(Discount, 0) + }, + If(subtotal > 100, Round(subtotal - rebate, 2), subtotal) +) +``` + +Local variable names must not match properties on the current entity. This rule prevents an ambiguous reference during server-side translation. + +## Where expressions run + +The expression is compiled and validated on the server. For materialized values, writes are performed as provider-side operations so filtering, sorting, paging, and projections remain database operations. The server does not load the complete table into application memory to calculate a column. + +The language does not support cross-row lookups, arbitrary SQL, JavaScript, network calls, or aggregate queries inside a row expression. Use a relation/query endpoint or a custom server endpoint for those scenarios. + +## Validation errors + +The designer checks syntax, field references, function names, result type, dependencies, and provider translation before publishing an expression. Common errors are: + +* unknown property or function +* incompatible result type +* a `With` variable that collides with an entity property +* an operation that the active provider cannot translate +* a missing expression in a Formula backfill configuration + +See [Formula Properties](formula-properties.md) for the materialized-column workflow and storage behavior. diff --git a/docs/en/low-code/formula-properties.md b/docs/en/low-code/formula-properties.md new file mode 100644 index 0000000000..dd97163c04 --- /dev/null +++ b/docs/en/low-code/formula-properties.md @@ -0,0 +1,46 @@ +```json +//[doc-seo] +{ + "Description": "Define provider-side calculated properties in the ABP Low-Code System with Power Fx-like expressions." +} +``` + +# Formula Properties + +Formula properties are calculated properties in the Low-Code property model. Their values are materialized by the server, so filtering, sorting, paging, and projections continue to use the database provider instead of loading the whole entity set into application memory. + +> **Preview:** Formula properties and the expression profile are preview features. Supported functions and provider translation may change before general availability. + +## Create a formula property + +In the Low-Code Designer, open the normal **Add Property** flow, select the result type, and enable **Calculate with a formula**. The formula result uses the selected property type: + +* String +* Int or Long +* Decimal or Money +* Boolean +* Date or DateTime + +Formula values are server-authoritative. Values supplied by the client are ignored for the calculated property. + +## Expression syntax + +See the [Low-Code Expression Language](expression-language.md) reference for operators, functions, literals, `With`, and provider translation rules. + +## Storage and mapping + +Formula storage is independent of the expression language. A formula property can be JSON-backed or mapped to a physical database column. Mapped properties use the public property name as their column identity and are recalculated on create, update, and deployment backfill. + +Formula properties may reference both mapped and JSON-backed fields. For existing-data mapping, choose a fixed value or **Formula** backfill. Required database columns remain nullable during schema evolution unless an explicit backfill is requested. + +## Query and performance behavior + +Formula updates are set-based and provider-side. The server recalculates affected rows and refreshes only the bounded saved-key batch needed by the current operation. It does not fetch the entire table into memory. + +Materialized results can be used by normal database filtering, sorting, paging, count, projection, and supported aggregates. Cross-row lookups, arbitrary SQL, network calls, and aggregate queries inside a row formula are outside the v1 profile. + +## Validation and deployment + +The Designer validates syntax, referenced fields, result type, dependencies, and provider-translatable operations before deployment. A syntactically valid expression is not active until deployment/backfill succeeds. Failed deployments can be retried from the Designer. + +Common validation errors include unknown fields or functions, result type mismatches, a `With` variable colliding with a property name, unsupported provider operations, and a missing expression when Formula backfill is selected. diff --git a/docs/en/low-code/index.md b/docs/en/low-code/index.md index b428132003..0a422c107d 100644 --- a/docs/en/low-code/index.md +++ b/docs/en/low-code/index.md @@ -109,7 +109,9 @@ The screens below follow that common designer flow from data to page setup to fo ![Page setup in the designer](images/designer-page-filters.png) -![Form setup in the designer](images/designer-forms.png) +![Form setup in the designer](images/designer-forms.png) + +For calculated fields that are materialized and remain queryable like normal properties, see [Formula Properties](formula-properties.md). For the shared syntax used by formulas, mappings, defaults, and backfills, see the [Low-Code Expression Language](expression-language.md) reference. ## React Runtime From 0a4cd88571140704b97b643bfbe6674292ad62cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SAL=C4=B0H=20=C3=96ZKARA?= Date: Tue, 4 Aug 2026 12:52:25 +0300 Subject: [PATCH 2/3] docs: align calculated properties with virtual formulas --- docs/en/low-code/expression-language.md | 88 ++++++++++++++--------- docs/en/low-code/formula-properties.md | 93 +++++++++++++++++++------ docs/en/low-code/index.md | 2 +- 3 files changed, 127 insertions(+), 56 deletions(-) diff --git a/docs/en/low-code/expression-language.md b/docs/en/low-code/expression-language.md index f1f11c879d..ff49b45d2e 100644 --- a/docs/en/low-code/expression-language.md +++ b/docs/en/low-code/expression-language.md @@ -1,59 +1,73 @@ ```json //[doc-seo] { - "Description": "Reference for the ABP Low-Code expression language used by calculated properties, mappings, defaults, and validations." + "Description": "Reference for the provider-safe ABP Low-Code expression language used by virtual calculated properties and formula backfills." } ``` # Low-Code Expression Language -The Low-Code expression language is a small, provider-safe language used in more than one designer workflow. It is used by formula properties and can also be used where the designer asks for an expression-backed value, such as mapped-property initial values or existing-data backfills. +The Low-Code expression language is a provider-safe scalar profile used by virtual calculated properties and by the one-time **Formula** option for existing-data backfill. Its syntax is intentionally familiar to Power Fx users, but it is a smaller language designed for server validation and database-provider translation. -The v1 syntax is intentionally familiar to Excel, Airtable, and Power Fx users while remaining translatable to a server-side expression tree. Expressions are evaluated by the server; they are not JavaScript and must not contain arbitrary code, SQL, network calls, or browser APIs. +Expressions are not JavaScript. They cannot contain arbitrary code, SQL, network calls, browser APIs, side effects, or unsupported Power Fx table and record operations. -> **Preview:** The language profile is preview functionality. The supported function set is deliberately smaller than the complete Excel or Power Fx languages. +> **Preview:** The language profile is preview functionality. The supported syntax and function set may change before general availability. ## Values and field references -Use numbers, quoted strings, Boolean values, and date constructors as literals. Reference a property by its name: +Use invariant numeric literals, quoted strings, Boolean values, and date constructors. Reference a property by name: ```text UnitPrice * Quantity If(IsActive, "Enabled", "Disabled") -Date(2026, 7, 28) +Date(2026, 8, 4) ``` -Property names containing spaces can be enclosed in single quotes: +Property and local names that are not simple identifiers can be enclosed in single quotes. Escape a single quote by doubling it: ```text 'Unit Price' * Quantity +'Manager''s Price' * Quantity ``` -Names and function names are case-insensitive. A field reference is resolved against the current entity, including fields backed by JSON and fields mapped to database columns. +Names and function names are case-insensitive. Fields may be JSON-backed or mapped to database columns. + +### Related fields + +Use dot notation to traverse a configured foreign key and read a scalar field from the related record: + +```text +CustomerId.CreditLimit +If(CustomerId.IsPreferred, Amount * 90%, Amount) +``` + +Related paths may also contain quoted identifiers. The Designer loads the available fields for each relationship level and applies the backend's configured maximum traversal depth. Missing related values produce a blank result where the expression is nullable. ## Operators | Purpose | Operators and forms | | --- | --- | -| Arithmetic | `+`, `-`, `*`, `/`, `%` | -| Comparison | `=`, `<>`, `!=`, `<`, `<=`, `>`, `>=` | -| Logical | `And(a, b)`, `Or(a, b)`, `Not(a)`, `&&`, `||`, `!` | +| Arithmetic | `+`, `-`, `*`, `/` | +| Comparison | `=`, `==`, `<>`, `!=`, `<`, `<=`, `>`, `>=` | +| Logical | `And(a, b, ...)`, `Or(a, b, ...)`, `Not(a)`, `&&`, `||`, `!` | | Text concatenation | `&` | | Percentage | `10%` (equivalent to `10 / 100`) | -`<>` and `!=` are equivalent not-equal operators. Use parentheses when combining arithmetic, comparison, and logical operators so the intended order is clear. +`<>` and `!=` are equivalent not-equal operators. `=` and `==` are equivalent equality operators. `%` is the postfix percentage operator, not a modulo operator. Use parentheses when combining operations so the intended precedence is explicit. + +Division returns a nullable Decimal result because division by zero produces blank rather than forcing client-side evaluation. ## Functions -The v1 profile supports the following functions: +The current scalar profile supports these functions: -```text -If, Coalesce, IsBlank, -Abs, Round, Floor, Ceiling, Min, Max, -Concat, Lower, Upper, Trim, Len, -Left, Right, Mid, Substring, -Year, Month, Day, Date, DateTime -``` +| Category | Functions | +| --- | --- | +| Conditional and blank values | `If(condition, trueValue, falseValue)`, `Coalesce(value, fallback)`, `IsBlank(value)` | +| Logical | `And(condition1, condition2, ...)`, `Or(condition1, condition2, ...)`, `Not(condition)` | +| Numeric | `Abs(number)`, `Round(number, places)`, `Min(left, right)`, `Max(left, right)` | +| Text | `Lower(text)`, `Upper(text)`, `Trim(text)`, `Len(text)`, `Left(text, length)`, `Right(text, length)`, `Mid(text, start[, length])` | +| Date and time | `Year(value)`, `Month(value)`, `Day(value)`, `Date(year, month, day)`, `DateTime(year, month, day, hour, minute, second[, millisecond])` | Examples: @@ -61,14 +75,17 @@ Examples: If(Len(Name) > 5, "Long", "Short") Coalesce(Discount, 0) Round(UnitPrice * Quantity, 2) -Concat(FirstName, " ", LastName) +FirstName & " " & LastName +Mid(ProductCode, 2, 3) ``` -`Round(value, places)` uses midpoint-away-from-zero semantics. Numeric and date literals use invariant syntax; the browser or database locale does not change their meaning. +`Round` uses midpoint-away-from-zero semantics. `Mid` uses a one-based start position. `Date` and `DateTime` require literal numeric components in the provider-neutral profile. Numeric and date literals use invariant syntax; browser and database locale settings do not change their meaning. + +Functions from the full Power Fx language that are not listed here are rejected. For example, `Floor`, `Ceiling`, `Concat`, and `Substring` are not aliases for the supported scalar functions. ## Local values with `With` -Use `With` to name intermediate values and avoid repeating calculations: +Use `With` to define immutable local values and avoid repeating an expression: ```text With( @@ -80,22 +97,29 @@ With( ) ``` -Local variable names must not match properties on the current entity. This rule prevents an ambiguous reference during server-side translation. +A `With` record supports up to 16 bindings, and `With` expressions can be nested up to 8 levels. A local name must not collide with a property on the current entity. Bindings in the same record do not see one another; nest another `With` when a later value must use an earlier local. ## Where expressions run -The expression is compiled and validated on the server. For materialized values, writes are performed as provider-side operations so filtering, sorting, paging, and projections remain database operations. The server does not load the complete table into application memory to calculate a column. +For a calculated property, the expression is expanded into the EF Core query. It can therefore participate in provider-side filtering, sorting, paging, count, projection, grouping, and supported aggregates without creating a physical column or loading the complete table into memory. -The language does not support cross-row lookups, arbitrary SQL, JavaScript, network calls, or aggregate queries inside a row expression. Use a relation/query endpoint or a custom server endpoint for those scenarios. +For an ordinary property mapping that uses **Formula** existing-data backfill, the same scalar profile is compiled into a provider-side update that initializes existing rows once. The mapped property then stores the result; this is separate from a virtual calculated property. + +Related-record aggregates are not written inside a formula expression. Create a [Rollup Property](formula-properties.md#create-a-rollup-property) for `Count`, `Sum`, `Average`, `Min`, or `Max` over related records. ## Validation errors -The designer checks syntax, field references, function names, result type, dependencies, and provider translation before publishing an expression. Common errors are: +The Designer validates syntax, field and related-field references, function arity and argument types, inferred result type, dependency cycles, server-only exposure, and translation by the active database provider. Validation covers transitive calculated dependencies, not only the expression currently being edited. + +Common errors include: -* unknown property or function -* incompatible result type -* a `With` variable that collides with an entity property +* unknown fields or functions +* incompatible branch or result types +* a local name that collides with an entity property +* a circular formula or rollup dependency +* a related path that exceeds backend query capabilities * an operation that the active provider cannot translate -* a missing expression in a Formula backfill configuration -See [Formula Properties](formula-properties.md) for the materialized-column workflow and storage behavior. +Provider translation failure is a validation error. The runtime does not fall back to evaluating the entire entity set in application memory. + +See [Calculated and Rollup Properties](formula-properties.md) for the Designer workflows and query behavior. diff --git a/docs/en/low-code/formula-properties.md b/docs/en/low-code/formula-properties.md index dd97163c04..1bb62f1161 100644 --- a/docs/en/low-code/formula-properties.md +++ b/docs/en/low-code/formula-properties.md @@ -1,46 +1,93 @@ ```json //[doc-seo] { - "Description": "Define provider-side calculated properties in the ABP Low-Code System with Power Fx-like expressions." + "Description": "Create virtual formula and rollup properties in the ABP Low-Code System with provider-translated expressions and related-record aggregates." } ``` -# Formula Properties +# Calculated and Rollup Properties -Formula properties are calculated properties in the Low-Code property model. Their values are materialized by the server, so filtering, sorting, paging, and projections continue to use the database provider instead of loading the whole entity set into application memory. +Calculated properties are server-authoritative, virtual properties in the Low-Code entity model. They are evaluated as part of the database query and do not create physical database columns. -> **Preview:** Formula properties and the expression profile are preview features. Supported functions and provider translation may change before general availability. +The Designer supports two kinds of calculated property: -## Create a formula property +* **Calculated Property** evaluates a scalar formula from fields on the current record, other calculated properties, or fields reached through a foreign key. +* **Rollup Property** aggregates records from an entity that has a foreign key to the current entity. -In the Low-Code Designer, open the normal **Add Property** flow, select the result type, and enable **Calculate with a formula**. The formula result uses the selected property type: +Both kinds can participate in filtering, sorting, paging, count, projection, grouping, and supported aggregates while the work remains in the database provider. The complete entity set is not loaded into application memory to calculate the values. -* String -* Int or Long -* Decimal or Money -* Boolean -* Date or DateTime +> **Preview:** Calculated properties, rollups, and the expression profile are preview features. Supported operations and provider translation may change before general availability. -Formula values are server-authoritative. Values supplied by the client are ignored for the calculated property. +## Availability -## Expression syntax +Calculated and rollup properties can be authored in a writable Runtime JSON-backed layer that supports direct model changes. The corresponding commands are disabled when the selected Designer layer does not support them. -See the [Low-Code Expression Language](expression-language.md) reference for operators, functions, literals, `With`, and provider translation rules. +## Create a calculated property -## Storage and mapping +In the Low-Code Designer: -Formula storage is independent of the expression language. A formula property can be JSON-backed or mapped to a physical database column. Mapped properties use the public property name as their column identity and are recalculated on create, update, and deployment backfill. +1. Open **Data**, select an entity, and open its **Properties** tab. +2. Open **Add Property** and select **Calculated Property**. +3. Enter the property name and an optional display name. +4. Enter an expression such as `Round(UnitPrice * Quantity, 2)`. +5. Review the inferred result type and validation result, then select **Create Calculated Property**. -Formula properties may reference both mapped and JSON-backed fields. For existing-data mapping, choose a fixed value or **Formula** backfill. Required database columns remain nullable during schema evolution unless an explicit backfill is requested. +The result type is inferred from the expression. Supported property types are String, Int, Long, Decimal, Money, Boolean, Date, and DateTime. Decimal and Money results can also define display precision, and Money results can define a currency symbol. -## Query and performance behavior +Formula properties may use both JSON-backed and database-mapped scalar fields. Use dot notation to read a scalar field through a foreign key: -Formula updates are set-based and provider-side. The server recalculates affected rows and refreshes only the bounded saved-key batch needed by the current operation. It does not fetch the entire table into memory. +```text +CustomerId.CreditLimit +Round(CustomerId.CreditLimit - CurrentBalance, 2) +``` + +The formula editor offers fields, related fields, local values, and supported functions as suggestions. See the [Low-Code Expression Language](expression-language.md) reference for the complete scalar syntax. + +Client applications cannot set a calculated property. Enable **Server only** when the result must also be omitted from client-facing metadata and responses. A client-visible formula cannot expose a server-only dependency; a server-only formula may use server-only fields. + +## Create a rollup property + +A rollup evaluates a correlated aggregate over related records. For example, an `Order` can expose the sum of `OrderItem.LineTotal` values when `OrderItem.OrderId` is a foreign key to `Order`. + +1. Open **Add Property** and select **Rollup Property**. +2. Select the **Source Entity** that contains the related records. +3. Select the **Relation Field** whose foreign key points to the current entity. +4. Select an operation: `Count`, `Sum`, `Average`, `Min`, or `Max`. +5. For every operation except `Count`, select the **Value Field**. +6. Review validation and select **Create Rollup Property**. + +`Count` returns a Long value and does not use a value field. `Sum` and `Average` require a numeric value field. `Min` and `Max` preserve a compatible scalar type. A rollup value may be a normal field or a formula property, but it cannot be another rollup. + +## Storage and query behavior + +Calculated and rollup properties always remain virtual: + +* `isMappedToDbField` is false. +* Values are not stored in JSON or in a physical column. +* No schema migration, synchronization job, or existing-data backfill is required. +* Required, unique, default-value, and client-write settings do not apply. + +At query time, the EF Core provider expands formulas into SQL-translatable expressions and rollups into correlated aggregate expressions. Calculated dependencies are expanded recursively. Calculations that are not needed by search, filtering, or sorting can be evaluated after page selection while still remaining provider-side. + +This is different from the one-time **Formula** option used to backfill an ordinary property while mapping it to a database field. That workflow writes existing rows; a calculated property remains virtual and is evaluated from current data whenever it is queried. + +## Validation and dependency safety + +Before a calculated property is saved, the Designer validates: + +* syntax, field paths, functions, and argument types +* inferred result type and display metadata +* direct and transitive dependencies +* circular dependencies across formulas and rollups +* server-only dependency exposure +* translation by the active database provider + +Saving publishes the calculated metadata only after the complete affected dependency closure passes provider validation. Renaming or deleting fields that are still referenced is guarded so an existing calculation is not silently broken. -Materialized results can be used by normal database filtering, sorting, paging, count, projection, and supported aggregates. Cross-row lookups, arbitrary SQL, network calls, and aggregate queries inside a row formula are outside the v1 profile. +Provider-specific translation remains authoritative. An expression that is syntactically valid but cannot be translated by the active provider is rejected instead of falling back to full-table client-side evaluation. -## Validation and deployment +## Current limitations -The Designer validates syntax, referenced fields, result type, dependencies, and provider-translatable operations before deployment. A syntactically valid expression is not active until deployment/backfill succeeds. Failed deployments can be retried from the Designer. +Formula expressions are scalar. They do not contain arbitrary aggregate subqueries; use a Rollup Property for a supported related-record aggregate. Arbitrary SQL, JavaScript, network calls, browser APIs, side effects, and unsupported Power Fx table or record operations are not allowed. -Common validation errors include unknown fields or functions, result type mismatches, a `With` variable colliding with a property name, unsupported provider operations, and a missing expression when Formula backfill is selected. +Related-field access must follow configured foreign keys and stay within the query capability exposed by the backend. Rollups require a source-side Guid foreign key that points to the entity receiving the rollup. diff --git a/docs/en/low-code/index.md b/docs/en/low-code/index.md index 0a422c107d..fc665e7bf0 100644 --- a/docs/en/low-code/index.md +++ b/docs/en/low-code/index.md @@ -111,7 +111,7 @@ The screens below follow that common designer flow from data to page setup to fo ![Form setup in the designer](images/designer-forms.png) -For calculated fields that are materialized and remain queryable like normal properties, see [Formula Properties](formula-properties.md). For the shared syntax used by formulas, mappings, defaults, and backfills, see the [Low-Code Expression Language](expression-language.md) reference. +For virtual fields calculated from the current record, related records, or related-record aggregates, see [Calculated and Rollup Properties](formula-properties.md). For the provider-safe scalar syntax used by calculated properties and formula backfills, see the [Low-Code Expression Language](expression-language.md) reference. ## React Runtime From ee2b71c2d10c7e165457c50607353e31b7809c75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SAL=C4=B0H=20=C3=96ZKARA?= Date: Tue, 4 Aug 2026 13:07:54 +0300 Subject: [PATCH 3/3] docs: complete calculated property support matrix --- docs/en/low-code/expression-language.md | 9 +++++++++ docs/en/low-code/formula-properties.md | 11 ++++++++++- docs/en/low-code/index.md | 4 ++-- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/docs/en/low-code/expression-language.md b/docs/en/low-code/expression-language.md index ff49b45d2e..8878241349 100644 --- a/docs/en/low-code/expression-language.md +++ b/docs/en/low-code/expression-language.md @@ -11,6 +11,8 @@ The Low-Code expression language is a provider-safe scalar profile used by virtu Expressions are not JavaScript. They cannot contain arbitrary code, SQL, network calls, browser APIs, side effects, or unsupported Power Fx table and record operations. +An expression can contain up to 4096 characters. + > **Preview:** The language profile is preview functionality. The supported syntax and function set may change before general availability. ## Values and field references @@ -105,6 +107,13 @@ For a calculated property, the expression is expanded into the EF Core query. It For an ordinary property mapping that uses **Formula** existing-data backfill, the same scalar profile is compiled into a provider-side update that initializes existing rows once. The mapped property then stores the result; this is separate from a virtual calculated property. +During JSON-to-database mapping, use `Self` to read the property's current JSON value before it is moved to the database column: + +```text +Coalesce(Self, "Unknown") +Self & " migrated" +``` + Related-record aggregates are not written inside a formula expression. Create a [Rollup Property](formula-properties.md#create-a-rollup-property) for `Count`, `Sum`, `Average`, `Min`, or `Max` over related records. ## Validation errors diff --git a/docs/en/low-code/formula-properties.md b/docs/en/low-code/formula-properties.md index 1bb62f1161..540f97f90f 100644 --- a/docs/en/low-code/formula-properties.md +++ b/docs/en/low-code/formula-properties.md @@ -49,6 +49,8 @@ Client applications cannot set a calculated property. Enable **Server only** whe A rollup evaluates a correlated aggregate over related records. For example, an `Order` can expose the sum of `OrderItem.LineTotal` values when `OrderItem.OrderId` is a foreign key to `Order`. +`Sum` is a rollup operation, not a function that can be written inside a scalar formula. The relationship is evaluated in the reverse direction: the source entity contains the foreign key that points to the entity receiving the rollup. + 1. Open **Add Property** and select **Rollup Property**. 2. Select the **Source Entity** that contains the related records. 3. Select the **Relation Field** whose foreign key points to the current entity. @@ -56,7 +58,14 @@ A rollup evaluates a correlated aggregate over related records. For example, an 5. For every operation except `Count`, select the **Value Field**. 6. Review validation and select **Create Rollup Property**. -`Count` returns a Long value and does not use a value field. `Sum` and `Average` require a numeric value field. `Min` and `Max` preserve a compatible scalar type. A rollup value may be a normal field or a formula property, but it cannot be another rollup. +| Operation | Value field | Result | +| --- | --- | --- | +| `Count` | Not used | Long | +| `Sum` | Int, Long, Decimal, or Money | Preserves a compatible numeric range | +| `Average` | Int, Long, Decimal, or Money | Decimal, or Money for a Money value | +| `Min` / `Max` | String, Int, Long, Decimal, Money, Boolean, Date, or DateTime | Preserves a compatible scalar type | + +A rollup value may be a normal field or a formula property, but it cannot be another rollup. Formulas can reference other calculated properties, including rollup results, and the complete dependency graph is validated for cycles and provider translation. ## Storage and query behavior diff --git a/docs/en/low-code/index.md b/docs/en/low-code/index.md index fc665e7bf0..432e35d874 100644 --- a/docs/en/low-code/index.md +++ b/docs/en/low-code/index.md @@ -109,8 +109,8 @@ The screens below follow that common designer flow from data to page setup to fo ![Page setup in the designer](images/designer-page-filters.png) -![Form setup in the designer](images/designer-forms.png) - +![Form setup in the designer](images/designer-forms.png) + For virtual fields calculated from the current record, related records, or related-record aggregates, see [Calculated and Rollup Properties](formula-properties.md). For the provider-safe scalar syntax used by calculated properties and formula backfills, see the [Low-Code Expression Language](expression-language.md) reference. ## React Runtime