---
title: February 2025
versions:
  cdsjs: 8.8.0+
  cdsdk: 8.8.0+
  cdsc: 5.8.0+
  cdsmtxs: 2.6.0+
  java: 3.8.0+
---

# February 2025

<ReleaseBadges />

[[toc]]

## Prepare for CDS 9

Along with new features, the next major release CDS 9 will contain some changes that you'll need to react on.
For the items listed below, you can do this already **now**, which eases the transition. You can't use the mentioned **deprecated functions** with the CDS 9 release. The corresponding compatibility flags won't be respected any longer.

> This section will be a regular part of all upcoming release notes and includes links to all changes relevant to the next major release.

### Migrate ESLint Configuration

ESLint v8 was [officially discontinued in October 2024](https://eslint.org/version-support/). To migrate your ESLint v8 configuration to ESLint v9, follow the [official migration guide](https://eslint.org/docs/latest/use/migrate-to-9.0.0).

Starting with CDS 9, [`cds lint`](/@external/tools/cds-lint/) will only support ESLint v9.

### Add Test Support Package

With CDS 9, package `@cap-js/cds-test` will be required for tests to run.  You can use it already now with `npm add -D @cap-js/cds-test`.

[Learn more about the new package.](#cds-test){.learn-more}

### Remove Compat Flags and Enable `@sap/cds 9` Features

- [**Switch on** the new CDS parser.](#new-parser)
- [**Upgrade to** `@sap/xssec 4`.](jan25#upgrade-to-sapxssec-4) _--> remove compat flag_
- [**Switch on** OData containment.](../2024/dec24#odata-containment)
- [**Adapt to changed behavior** when processing `@restrict.where` checks.](../2024/dec24#consolidated-authorization-checks)
- [**Adopt** @cap-js database services now.](../2024/jun24#new-database-services-ga)
- [**Switch on** the new protocol adapters.](../2024/jun24#new-protocol-adapters-ga) _--> remove compat flag_
- [**Switch on** lean draft.](../2024/jun24#lean-draft) _--> remove compat flag_

## CDS Language & Compiler {#cds}

### New Parser

The new CDS parser is now available, and you should start using it.

Switching to the new parser reduces installation times and speeds up parsing. It also enhances code completion. Additionally, some new features are only supported with the new parser.

Roadmap:

| Date   | Status                   | Remarks                                                |
| ------ | ------------------------ | ------------------------------------------------------ |
| Feb 25 | Released                 | opt-in usage; default still with old parser            |
| May 25 | Used by default          |                                                        |

> [!tip] The new parser doesn't come with any breaking changes...
>
> ... and is fully compatible with the old parser. Enable it now as follows:
>
> - Set option <Config showPrivate>cds.cdsc.newparser: true</Config> in your private `~/.cdsrc.json` to switch on the new parser on your local machine.
> - Switch it on in your project's development and test pipelines.
> - If that's successful, use it in production.

#### New CDS Parser Support in VS Code

The new version of our [CDS plugin for VS Code](/@external/tools/cds-editors#vscode) is able to use the [new CDS parser](./jan25#reminder-new-parser). For the current minor release, though, the default remains to use the old parser. You can switch via the user setting [`cds.compiler.useOldParser`](vscode://settings/cds.compiler.useOldParser). Please report any issues.

### Type as Projection

Define a structured type as a projection on another structured type, entity, aspect, or event,
where you pick only a subset of elements.

<!-- cds-mode: ignore -->
```cds
entity Name {
  firstName  : String @label: '...';
  middleName : String @label: '...';
  lastName   : String @label: '...';
  initials   : String @label: '...';
  title      : String @label: '...';
}

type ShortName : projection on Name {
  firstName,
  lastName
};
```


> [!tip]
> Only available with the new parser via option <Config showPrivate>cds.cdsc.newparser: true</Config>.

[Learn more about type projections.](/@external/cds/cdl#structured-types){.learn-more}


### Use Enums Like Constants

Instead of using literals, enum symbols defined in CDS can be used where the compiler can deduce the corresponding enum type. See the following example:

```cds
type Status : String enum { open; closed; in_progress; };
entity Order {
  key id : Integer;
  status : Status default #open; // [!code highlight]
}
entity OpenOrder as projection on Order {
  id,
  (status = #in_progress ? 'is in progress' : 'is open') // [!code highlight]
    as status_txt : String,
} where status = #open or status = #in_progress; // [!code highlight]
```

[Learn more about Enums.](/@external/cds/cdl#enums){.learn-more}

### Annotating Managed Associations <Beta />

When you annotate a managed annotation with an [expression-valued annotation](/@external/cds/cdl#expressions-as-annotation-values),
the annotation is now automatically copied to the respective foreign key elements in the OData API generation.

Previously, the copy mechanism has only been applied for non-expression annotations.

In the following example, the annotation is also applied to the generated foreign key element `author_ID` of `Books`:
```cds
entity Authors { key ID : Integer; name : String; }
entity Books   { author : Association to Authors; }

annotate Books:author with @Common.Text: (author.name); // [!code highlight]
```


## Node.js {#cds-js}

### Media Data in Actions and Functions

Media data like images, CSVs, and so on, can now also be used as a return type of actions and functions. The same set of [media data annotations](/@external/guides/services/media-data#annotating-media-elements) is supported.

```cds
@(Core.MediaType: 'text/csv', Core.ContentDisposition.Filename: 'Books.csv')
type csv:  LargeBinary;
entity Books { ... } actions {
  function csvExport () returns csv;
}
```

```js
this.on('csvExport', req => {
  return new Readable() // the csv stream
})
```

In addition, `req.reply` can be used to set the mime type and filename dynamically.

```js
this.on('csvExport', req => {
  req.reply(new Readable(), { mimetype, filename })
})
```

[Learn more about media streaming in general.](/@external/guides/services/media-data){.learn-more}
[Learn more about media streaming in custom handlers.](/@external/node.js/best-practices#custom-streaming-beta){.learn-more}

### Hints on SAP HANA

The new [`SELECT.hints`](/@external/node.js/cds-ql.md#hints) method of the [`cds.ql`](/@external/node.js/cds-ql.md) API passes hints to the database query optimizer that can influence the execution plan.

```js
SELECT ... .hints('IGNORE_PLAN_CACHE', 'MAX_CONCURRENCY(1)')
```

::: info SAP HANA only
Hints are only respected by the SAP HANA database service.
:::

### New Package for `cds.test` {#cds-test}

The [test support for CAP Node.js applications](/@external/node.js/cds-test) moves to its own package [`@cap-js/cds-test`](https://www.npmjs.com/package/@cap-js/cds-test).  You can start using it now, so install it as follows:

```sh
npm add -D @cap-js/cds-test
```

This package comes with dependencies you had to maintain separately until now. So get rid of the unnecessary dependencies and only maintain the `@cap-js/cds-test` package going forward.

```sh
npm rm axios chai chai-subset chai-as-promised
```

With CDS 9, the new package will be required for the `cds.test` API to work.


## Java {#cds-java}

### Important Change ❗️ { .important #important-changes-in-java}

Before this release, the comparison operator `!=` was equivalent to the not equals operator (`<>`) and evaluated on a database with _three-valued_ comparison logic.
Now, the `!=` operator is treated as equivalent with the [is not](/@external/java/working-with-cql/query-api#comparison-operators) operator and is evaluated with _Boolean_ logic.

The changed behavior might be observable in [instance-based authorization](/@external/guides/security/authorization#instance-based-auth) but only if a rule's `where` clause uses the `!=` operator. Then, you must check if Boolean or three-valued logic is appropriate. If you want to stick with three-valued logic, you need to use the `<>` operator.

### UI5 State Messages for Drafts <Beta />

CAP Java now supports persisting (error) messages for draft-enabled entities and providing _state messages_ to the UI5 OData V4 model.
To enable this feature, set the following properties in your `.cdsrc.json`:

::: code-group
```json [.cdsrc.json]
{
  "odata": {
    "containment": true
  },
  "cdsc": {
    "beta": {
      "draftMessages": true
    }
  }
}
```
:::

::: warning Document-based URLs
The state messages feature relies on UI5 to use _document URLs_. Currently UI5 only uses the document URLs when containment is enabled in the OData metadata.
Enabling containment narrows the API surface and only makes composition child entities accessible via their parent, which might be incompatible.
It's planned to provide options to instruct UI5 to use document URLs, without enforcing containment on the server-side.
:::

Setting this property adds additional elements to your draft-enabled entities and `DraftAdministrativeData`, which are required to store and serve state messages.

If this feature is activated, you can observe the following improvements, without changing the application code:

- Error messages for annotation-based validations (for example, `@mandatory` or `@assert...`) already appear while editing the draft.
- Custom validations can now be bound to the `DRAFT_PATCH` event and can write (error) messages. It's ensured that the invalid value is still persisted, as expected by the draft choreography.
- Messages no longer unexpectedly vanish from the UI after editing another field.
- Messages are automatically loaded when reopening a previously edited draft.

By default, side-effect annotations are generated in the EDMX that instruct UI5 to fetch state messages after every `PATCH` request.
In case more precise side-effect annotations are required you can disable the default side-effect annotation per entity:

```cds
annotate MyService.MyEntity with @Common.SideEffects #alwaysFetchMessages: null;
```

::: warning Requires Schema Update
Enabling draft messages requires a database schema update, as it adds an additional element to `DraftAdministrativeData`.
:::


### Hierarchy Maintenance in Tree Table

In the UI5 tree table, on SAP HANA, CAP Java now supports _hierarchy maintenance_ for [draft-enabled](/@external/guides/uis/fiori#draft-support) hierarchies. It's now possible to create new nodes and to add them as parent or child nodes to the hierarchy. You can also modify and delete nodes. In addition, one can change a parent of a child node (move a node).

If a node is deleted, its descendant nodes are only deleted if they are in a composition relationship with the deleted node.

#### Inline Editing

If a hierarchy appears on an object page, CAP Java now supports inline editing:

![expandEntireNode.png](assets/feb25/inline-edit-hierarchy.png){width=80%}

#### Order of Sibling Nodes

If a hierarchy is defined by a view _with a sort specification_, CAP Java uses this sort specification as the default sort order for sibling nodes in the hierarchy:

```cds {9}
entity Genre : cuid {
      name        : String;
      parent      : Association to Genre;
      siblingRank : Integer;  // [!code highlight]
}

service GenreAdminService {
  entity GenreHierarchy as projection on Genre
                           order by siblingRank
    actions {
      action moveSiblingAction(NextSibling : cuid);  // [!code highlight]
    };
}
```

In this example sibling nodes within the genre hierarchy are sorted by the value of the `siblingRank` property. You can use this property for a custom implementation of a
[ChangeNextSiblingAction](https://github.com/SAP/odata-vocabularies/blob/main/vocabularies/Hierarchy.md#template_changenextsiblingaction-experimental), which allows to move a sibling node to an exact position between siblings.

### Expand on Subqueries

You can now expand to-one associations from [subqueries](/@external/java/working-with-cql/query-api#from-select) if the association is selected explicitly or implicitly via select all in the inner query:

```java
CqnSelect booksOnCAP = Select.from(BOOKS).columns(
    b -> b.title(),
    b -> b.author())  // [!code highlight]
   .search("CAP")
   .orderBy(b -> b.title())
   .limit(10);
Select.from(booksOnCAP).columns(
    b -> b.get("title"),
    b -> b.to("author").expand("name"));  // [!code highlight]
```

### $expand on $apply in OData v4

CAP Java now supports `$expand` of managed to-one associations in combination with non-aggregating [$apply](/@external/guides/protocols/odata#data-aggregation) transformations such as `filter`, `search`, `top`, `skip`, and `orderby`, as well as `hierarchy` transformations such as `TopLevels`, `ancestors`, and `descendants`:

```http {6}
GET /SalesOrganizations?$apply=
     ancestors($root/SalesOrganizations,SalesOrgHierarchy,ID
     /search(\"CAP\"),keep start)
     /com.sap.vocabularies.Hierarchy.v1.TopLevels(HierarchyNodes=$root/SalesOrganizations,HierarchyQualifier='SalesOrgHierarchy',NodeProperty='ID')
&$select=DistanceFromRoot,DrillState,LimitedDescendantCount,Name,ID&$top=10
&$expand=Superordinate($select=Name)
```

### SQL Window Functions

You can now use an [SQL window function](https://help.sap.com/docs/hana-cloud-database/sap-hana-cloud-sap-hana-database-sql-reference-guide/windows-functions) to _partition_ data and compute an aggregated value per partition without grouping the data. Use the new `over` method to turn an aggregate function into window function.
The following example _partitions_ the sales by region. For every partition the sum of sales are is computed but the raw amount is preserved:

```java
Select.from(SALES)
      .columns(s -> s.region(),
               s -> s.saleId(),
               s -> s.amount(),
               s -> s.amount().sum().over(s.region()).as("sum"));  // [!code highlight]
````

This query produces such a result:

| region | saleId | amount | sum |
|--------|--------|-------:|----:|
| EU     | eu1    |     10 |  60 |
| EU     | eu2    |     30 |  60 |
| EU     | eu3    |     20 |  60 |
| UK     | uk1    |     90 |  90 |
| US     | us1    |      5 |  20 |
| US     | us2    |     15 |  20 |


### Expressions in Runtime Views

You can now use expressions in [runtime views](/@external/java/working-with-cql/query-execution#runtimeviews).

Runtime-view definition:

```cds
@cds.persistence.skip
entity BooksView as projection on Books {
    id,
    toUpper(title) as title, // [!code highlight]
    author.forename || author.surname as author, // [!code highlight]
    (stock < 10 ? 'low' : 'high') as stock : String // [!code highlight]
};
```

Allowed query:

```java
Select.from(BooksView).columns(
    b -> b.title(),  // [!code highlight]
    b -> b.author(), // [!code highlight]
    b -> b.stock()); // [!code highlight]
```

<span id="java-remote-rfc" />

### Miscellaneous

- CAP Java now offers a [typesafe API](/@external/java/change-tracking#reacting-on-changes) for the ChangeTracking Service which can be used to observe and customize detected changetracking entities.
- The `build` goal of the `cds-maven-plugin` can now be run from the root folder of the CAP Java project. It's no longer required to change into the `srv` folder to run this goal. It supports also the new parameter `goals` to let the user choose, which goals shall be executed to build the project.
- Event Handler methods can now take `CqnStatement` or one of its subtypes as argument. This works for events that operate on a `CqnStatement`, like all CRUD events or bound actions or functions. In addition, it's now also possible to use a `CqnStructuredTypeRef` as parameter type, which is useful, when handling a bound action.


## CAP Plugins

### Attachments: Multitenancy

[@cap-js/attachments](https://github.com/cap-js/attachments) now supports multitenancy with a shared object store instance. Within a shared object store instance, attachments are stored with tenant ID prefix to identify tenant-specific data.


## Tools { #tools}

### Command-line formatter

The `format-cds` command-line formatter included in _@sap/cds-lsp_ now considers ignore files (one of _.cdsignore_ and _.gitignore_). Matching files will not be formatted.

[Learn more about the CDS Source Formatter.](/@external/tools/cds-editors#cds-formatter){.learn-more}

### CDS Plugin for Community IntelliJ IDEs

We got numerous feedback for our current [IntelliJ plugin](https://github.com/cap-js/cds-intellij) only supporting _commercial_ versions of IntelliJ IDEs.
Now, we publish a version 2 of the plugin as the first preview that supports the free _Community_ editions of IntelliJ IDEs. It includes _all_ features of our previous version.

This preview version is not available on the IntelliJ Marketplace. You need to install it manually from [Github](https://github.com/cap-js/cds-intellij/releases) via _Settings -> Plugins -> Config Wheel Icon (right to Marketplace and Installed) -> Install Plugin from Disk..._

Given the early stage, we would be happy if you try this out and give us [feedback](https://github.com/cap-js/cds-intellij/issues/new/choose). Please tag the issue with the new _2.x.x Community Edition_ label.
