Skip to content
Merged

@assert #2216

Changes from 7 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
58b81af
content
StefanHenke Nov 19, 2025
6ca8d04
Update guides/providing-services.md
StefanHenke Nov 20, 2025
f5f5f84
incorporate feedback
StefanHenke Nov 20, 2025
1953da0
fix cds syntax
StefanHenke Nov 20, 2025
c17c192
Update guides/providing-services.md
StefanHenke Nov 21, 2025
7bffed3
real life samples
StefanHenke Nov 21, 2025
e77e067
fix cds syntac
StefanHenke Nov 21, 2025
baa450c
Update guides/providing-services.md
StefanHenke Nov 24, 2025
7c18cb5
Update guides/providing-services.md
StefanHenke Nov 24, 2025
c368a2b
Update guides/providing-services.md
StefanHenke Nov 24, 2025
1069742
Update guides/providing-services.md
rjayasinghe Nov 27, 2025
a929b44
Update guides/providing-services.md
rjayasinghe Nov 27, 2025
9be2cc2
Apply suggestion from @agoerler
rjayasinghe Nov 27, 2025
5b9016d
Apply suggestion from @schwma
rjayasinghe Nov 27, 2025
bcb4ab3
Apply suggestion from @patricebender
rjayasinghe Nov 27, 2025
846d465
Apply suggestion from @Akatuoro
rjayasinghe Nov 27, 2025
e536412
rephrase first section of @assert docu
rjayasinghe Nov 25, 2025
53cd987
move section about i18n and message keys down to error function
rjayasinghe Nov 27, 2025
caa6f57
Merge remote-tracking branch 'origin/main' into assert-docs
rjayasinghe Nov 28, 2025
45b6781
use smaller code box instead of disfunctional code focus
rjayasinghe Nov 28, 2025
884a35c
remove section about error function
rjayasinghe Nov 28, 2025
fafff8f
apply review comments
rjayasinghe Nov 28, 2025
90a9715
Update guides/providing-services.md
StefanHenke Dec 1, 2025
9cb4a42
Update guides/providing-services.md
StefanHenke Dec 1, 2025
f3148de
incorporate feedback
StefanHenke Dec 1, 2025
60f8d3c
Merge remote-tracking branch 'origin' into assert-docs
StefanHenke Dec 1, 2025
d055d98
:Merge remote-tracking branch 'origin/assert-docs' into assert-docs
StefanHenke Dec 1, 2025
4d4891d
revert ternary comment
StefanHenke Dec 1, 2025
4b0360d
fix code snippets
StefanHenke Dec 2, 2025
b605960
remove parenthesis
StefanHenke Dec 2, 2025
9fef206
Merge remote-tracking branch 'origin/main' into assert-docs
agoerler Dec 11, 2025
dfcdbd7
add disclaimers
agoerler Dec 11, 2025
9824347
Apply suggestions from code review
agoerler Dec 11, 2025
00cc8cc
Apply suggestions from code review
StefanHenke Dec 12, 2025
3cdf60d
fix linting issues
StefanHenke Dec 12, 2025
2e55c00
fix ternary expressions
StefanHenke Dec 12, 2025
9eb51b2
incorporate feedback
StefanHenke Dec 15, 2025
22dfb34
Merge branch 'main' into assert-docs
StefanHenke Dec 15, 2025
9526c32
incorporate latest feedback
StefanHenke Dec 15, 2025
cd4accc
incorporate latest feedback
StefanHenke Dec 15, 2025
278095c
incorporate latest feedback
StefanHenke Dec 15, 2025
aa58ba8
Apply suggestions from code review
renejeglinsky Dec 15, 2025
9e8459d
Merge branch 'main' into assert-docs
danjoa Dec 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions guides/providing-services.md
Original file line number Diff line number Diff line change
Expand Up @@ -939,6 +939,86 @@ Cross-service checks are not supported. It is expected that the associated entit
The `@assert.target` check constraint relies on database locks to ensure accurate results in concurrent scenarios. However, locking is a database-specific feature, and some databases don't permit to lock certain kinds of objects. On SAP HANA, for example, views with joins or unions can't be locked. Do not use `@assert.target` on such artifacts/entities.
:::

### `@assert` <Beta/>

Annotate an element with `@assert` to define an expression for more complex validations that need to be fulfilled before data gets persisted. If the validation should fail, the expression must return the error message to be sent to the client, or `null` if the validation passed.

The returned error can be either a static message or a message key to support i18n. If a message key is used, the message is looked up in the message bundle of the service.
[Learn more about localized messages](./i18n){.learn-more}

The following example ensures that the `quantity` of the ordered book is validated against the actual `stock`. If there is not enough available in the stock, a static error message is returned.

```cds
entity Books : cuid {
title : String;
stock : Integer;
}

entity Orders : cuid {
Items : Composition of many OrderItems
on Items.parent = $self;
}

entity OrderItems : cuid {
parent : Association to Orders;
book : Association to Books;
@assert: (case
when book.stock <= amount then 'Stock exceeded'
end)
quantity : Integer;
amount : Decimal(9, 2);
}
```

Alternatively, the same condition can be simplified by using the ternary operator:

```cds
entity OrderItems : cuid {

@assert: ((book.stock <= amount) ? 'Stock exceeded' : null)
quantity : Integer;
}
```

By using multiple `when` sections, multiple conditions can be included in a single annotation. Each condition returns its own error message to precisely describe the error.

```cds
entity OrderItems : cuid {

@assert: (case
when book.stock = 0 then 'Stock is zero'
when book.stock <= amount then 'Stock exceeded'
end)
quantity : Integer;
}
```

With the help of the function `error(message, parameters, targets)`, it is possible to specify parameters as well as explicit target elements for the message. Each parameter can be represented by an expression.
In its simplest form, this is the actual value of an entity field. The evaluating runtime will take care of replacing the placeholders in the message with the provided parameters.

In the following example, it is expected that the error message with key `error.author.date` is defined to have two parameters which are filled with the concrete values of the elements `dateOfBirth` and `dateOfDeath`. The third parameter ensures that both fields are set as targets and thus marked erroneous.

```cds
entity Authors : cuid, managed {

@assert: (case
when dateOfBirth > dateOfDeath then error('error.author.date', (dateOfBirth, dateOfDeath), (dateOfBirth, dateOfDeath))
end)
dateOfBirth : Date;
dateOfDeath : Date;
}
```

Refer to [Expressions as Annotation Values](../cds/cdl.md#expressions-as-annotation-values) for detailed rules on expression syntax.

::: info Expression Evaluation
Expressions are evaluated *after* the request has been applied to the underlying datastore. The affected entities are the entities being part of the request and identified by their primary keys. The evaluating runtime constructs and executes statements with the annotation-provided expressions and the respective primary key values for the given entities. Depending on the structure and cardinality of the request data it can be one or more statements being executed.
:::

::: warning Limitations
- Validations will only be enforced in `CREATE` and `UPDATE` statements that contain all key fields (including deep insert and deep update)
- Only elements with simple types (like, `String`, `Integer`, `Boolean`) can be annotated with `@assert`. Elements typed with structured or arrayed types are not supported
:::

<div id="assertconstraints" />

Expand Down