Skip to content

    March 2022

    Welcome to the notes for the March 2022 release for the CAP framework. Find the most noteworthy news and changes in the following sections.

    Find bugfixes and enhancements in the Changelog.

    Database Integrity Constraints

    CDS can now automatically generate native database referential integrity constraints for managed to-one Associations and Compositions:

    entity Books {
      author : Association to Authors;
    entity Authors {
      key ID : Integer;

    Association author triggers the generation of a constraint:

    CONSTRAINT Books_author ON Books
      FOREIGN KEY(author_ID) REFERENCES Authors(ID)

    Database constraints are available for SQL dialects hana and sqlite.

    Switch them on with the configuration cds.env.features.assert_integrity that can have the values:

    • 'db': Database constraints
    • 'app': Runtime checks (default, only effective in Node.js runtime)
    • false: No database constraints and no runtime checks

    The Node.js runtime features integrity checks in the application. We intend to replace these rather expensive checks in the application by database constraints with the next major release in 2022. For the migration period until then you can choose what kind of integrity checks are performed.

    Generation of database constraints is of course also possible on the CAP Java stack, where no runtime checks are available.

    Learn more about Database Constraints.

    Native Database Clauses

    Using the annotations @sql.prepend and @sql.append, you can add arbitrary SQL snippets to the DDL statements that are generated by the compiler. This allows you to use database features that are not natively supported by CDS.


    @sql.append: ```sql
                 GROUP TYPE foo
                 GROUP SUBTYPE bar
    entity E {
      @sql.append: 'FUZZY SEARCH INDEX ON'
      text: String(100);


    create table E (
      text nvarchar(100) FUZZY SEARCH INDEX ON
    ) GROUP TYPE foo

    If you use native database clauses in entities where schema evolution has been enabled using annotation @cds.persistence.journal, see Schema Evolution Support of Native Database Clauses.

    ❗ Warning The compiler doesn’t check or process the provided SQL snippets in any way. You are responsible to ensure that the resulting statement is valid and doesn’t negatively impact your database or your application. We don’t provide support for problems caused by using this feature.

    Learn more about Native Database Clauses.

    Native HANA Functions with non-standard syntax

    CDS now supports SAP HANA aggregate functions with an additional order by clause in the argument list, like:

    first_value(name order by price desc)

    Learn more about Native SAP HANA Functions.

    CDS Language

    Simplified Syntax for Extending or Annotating Elements

    Until now, for annotating or extending elements of an entity, you had to “repeat” the relevant part of the entity definition:

    annotate Foo with {
      nestedStructField {
        existingField @title:'Nested Field';
    extend Foo with {
      extend nestedStructField {
        newField : String;

    This is a bit cumbersome if you only want to annotate or extend single elements. You can now directly address the element you want to annotate or extend:

    annotate Foo:nestedStructField.existingField with @title:'Nested Field';
    extend Foo:nestedStructField with { newField : String; }

    Learn more about annotate. Learn more about extend.

    Default in Type Definitions

    A default value can now be specified also in scalar custom type definitions:

    type CreatedAt : Timestamp default $now;

    Learn more about Defaults.

    Node.js SDK

    Important Changes ❗️

    • Fixed: Keys of an entity were always fetched in addition. This does not happen anymore. Example:

      let { CatalogService } =
      let books = await'title').from('Books')

      → formerly this returned:

      books = [{ ID:201, title:'Wuthering Heights' }, ...]

      → now it is:

      books = [{ title:'Wuthering Heights' }, ...]

      If you need the keys in the result, make sure you request them explicitly in the query as well.

    Driver-Agnostic Results for Stored Procedures

    We added a driver-agnostic way for SAP HANA procedure calls with table output data.


    // P1 -> table output, P2 -> primitive output, P3 -> input
    > await' CALL PROC(P1 => ?,P2 => ?,P3 => ?)', 42)
      P1: [...]
      P2: 4711

    Java SDK

    Important Changes ❗️

    Elements with type UUID that are annotated with @odata.Type:'Edm.String' are not normalized anymore. The comparison is case sensitive and arbitrary values can be stored (example).

    Relaxed Deep Insert/Update

    If the data of deep Insert or deep Update contains values of an associated entity but the (forward mapped) association does not cascade the Insert/Update operation, only the association itself is updated, but not the values of the associated entity.

    Assumed you have the following model:

    entity Orders {
      key id : UUID;
      book : Association to Books; // not cascading
    entity Books {
      key id : Integer;
      title : String;

    In addition, you run this code:

    Map<String, Object> order = Map.of("book",
        Map.of("id", 17, "title", "Capricorn"));
    CqnInsert insert = Insert.into("Orders").entry(order);;

    This creates a new order and associates this order to the book with id 17. But it doesn’t create the book.

    Collectors for AND and OR

    New methods CQL.withAnd() and CQL.withOr() allow to use a Collector to connect a stream of CQN predicates with AND or OR:

    List<Map<String, Object>> values = ...
    Stream<CqnPredicate> predicates =;
    CqnPredicate filter = predicates.collect(CQL.withOr());

    Learn more about Connecting Streams of Predicates

    Additional Values for Managed Data

    The annotations @cds.on.insert and @cds.on.update now support additional values. The special references $user.locale and $user.tenant allow to automatically set respective tenant or locale from the user info.

    The value $uuid can be used to automatically set a generated UUID value.

    The following snippets are equivalent:

    entity Orders {
      @cds.on.insert : '$uuid'
      id : String;
    entity Orders {
      @odata.Type : 'Edm.String'
      id : UUID;

    Security & Compliance

    Default Mock Users to Ease Testing

    In case mock user security configuration is active, default mock users reflecting pseudo roles are available by default now. They are named authenticated, system, and privileged and can be used with an empty password. For instance, requests sent during a Spring MVC unit test with annotation @WithMockUser("authenticated") will pass authorization checks that require authenticated-user.

    Learn more mock user authentication.

    Improved Propagation of Authentication Information

    The AuthenticationInfo (e.g. storing a JWT) can now be accessed from the RequestContext and EventContext and is provided as a Spring bean:

    @Autowired AuthenticationInfo authInfo;
    JwtTokenAuthenticationInfo jwtTokenInfo =;
    String jwtToken = jwtTokenInfo.getToken();

    It is also propagated to child threads when propagating the RequestContext.

    Learn more in Reading Request Contexts.

    Fine-Grained Control of Outbox Usage

    Added properties cds.auditlog.outbox and<key>.outbox that control the usage of the Outbox for Auditlog/Messaging events.

    Learn more about CDS Properties.


    • @Core.ContentID is now present on OData V4 error responses. For batch requests this allows to relate the error messages of an OData change set to the individual request that causes the error.

    • When using SAP HANA Cloud, you can now enable a shared connection pool using property cds.multiTenancy.dataSource.combinePools.enabled without having to specify all database instances using property cds.multiTenancy.dataSource.hanaDatabaseIds.

    • Added integration with Cloud SDK’s RequestHeaderFacade ensuring HTTP headers are propagated to Cloud SDK.

    • The goal install-cdsdk of the cds-maven-plugin provides the new parameter arguments to pass additional arguments to the command line.

    Preview on Save in VS Code

    The preview for a .cds file is now automatically refreshed each time you save the corresponding .cds file:

    Update preview on save

    You can disable this behavior with setting Cds > Preview: Refresh On Save.

    Simplified Deploy Guides

    We have reworked and simplified the Deploy and Operate guides. Most notably, the Deploy to Cloud Foundry and SaaS Deployment cookbooks are much simpler to execute, as they make use of the project facets below.

    Improved cds add <facets>

    We’ve enhanced the CAP project facets to ease application setup for various configurations and deployment scenarios:

    • cds add xsuaa prepares for JWT authentication via XSUAA.
    • cds add mtx configures your application for SaaS deployments.
    • cds add approuter allows for serving your application’s UI using SAP approuter.
    • cds add kibana-logging sets up your application for the BTP logging service and the Kibana dashboard.
    • cds add mta creates the mta.yaml deployment descriptor as before, but in addition, the other templates update mta.yaml if needed.

    The --for <profile> parameter allows to specify the Node.js configuration profile. For example, cds add mtx --for production only adds multitenancy configuration to the [production] profile.

    Take a look at the revised deploy guides to see the facets in context.

    Names Check in cds lint

    A new lint rule warns about entities and elements that start with $.
    Such names may conflict with reserved variables that also start with $ (like $self).

    Learn more about CDS Lint.

    Security in Multitenancy

    Tokens downloaded to the command line client are now reduced in scope. That means, they only contain those scopes necessary for client operation. This follows the principle of least privileges and aims to reduce the risk of token misuse.

    The optional ExtendCDSdelete scope is not part of the token unless the user is assigned that scope. If the ExtendCDSdelete scope is not assigned when activating a new extension, requests to delete a previous version of an extension are rejected.

    If the user’s privileges change, for example, by assigning the ExtendCDSdelete scope via a role collection, the user has to run cds logout and then cds login. This fetches a token containing the extended set of scopes.