March 2023
Welcome to the release of CAP. Find the most noteworthy news and changes in the following sections.Calculated Elements beta
Elements can be specified with a calculation expression, in which you can refer to other elements of the same entity. There are different flavors of calculated elements, which are provided as a series of features in the next releases. As a first part, this release includes calculated elements with a value expression with "on-read" semantics.
entity Employees {
key ID : UUID;
firstName : String;
lastName : String;
name : String = firstName || ' ' || lastName;
}
These calculated elements essentially are a convenience feature. They serve as a "predefined" calculation expressions that can be used in views or projections on top of the entity instead of writing the expressions there.
service Srv {
entity EmployeesWithName as projection on Employees { ID, name };
}
A request to read name
of EmployeesWithName
returns the concatenated name.
Using such a calculated element in a view/projection is equivalent to writing the expression directly into the select list, both with respect to semantics and to performance. The definition above is equivalent to
service Srv {
entity EmployeesWithName as projection on Employees {
ID,
firstName || ' ' || lastName as name : String
}
}
WARNING
Currently, a calculated element in an entity can't be accessed directly in an OData request or in custom code. It must always be accessed via a view/projection, as shown in the example.
Learn more about Calculated Elements.
New cds-plugin
technique
Both @sap/cds
and @sap/cds-dk
now provide a simple way for plugins: It searches in the projects dependencies for packages with a module cds-plugin.js
. If that exists it will be loaded. Here's an example usage of that concept in our GraphQL adapter implementation:
// cds-plugin.js
const cds = require('@sap/cds')
const protocols = cds.env.protocols ??= {}
if (!protocols.graphql) protocols.graphql = {
path: "/graphql", impl: "@cap-js/graphql"
}
Within that module you can basically plug in to everything, similar to what projects can do in local
server.js
files.
Main benefit of that is that adding a feature, like graphql in this case, to a project just requires a simple npm add
, with no additional configuration required:
npm add @cap-js/graphql
New SQLite Service beta
We have completely rebuilt our SQLite Database Service with a streamlined design based on a new database services architecture and the better-sqlite3 driver. The most noteworthy improvements from users' perspective are:
Full support for path expressions, including infix filters, and exists predicates. For example, queries like that are possible now:
jsSELECT.from (Books, b => { b.ID, b.title, b.author.name }) .where ('genre.name=','Drama')
sqlSELECT `from ${Authors} { ID, name, books[where title like '%a%']{ title } }`
Standard functions like
contains
,concat
,startswith
, ... are now supported in database-agnostic ways.Common SAP HANA functions like
days_between
,months_between
,years_between
are supported to enhance testing for SAP HANA-based production scopes.Deep Read queries with expands are executed as single native database queries using
json_object
functions.
So overall, feature scope has been greatly enhanced, as well as quite some performance improvements. For example, in combination with lean draft we saw this for displaying the initial list page of Travels in cap/sflight:
Old: >250ms
New: ~15ms
WARNING
IMPORTANT: This is a beta feature, which is available already now to get early feedback from you. All the Important Disclaimers and Legal Information apply!
The new service will become the default for SQLite in the upcoming major release.
Find more information, in particular instructions about how to use it in the README of the @cap-js/sqlite
package npmjs.com.
Lean Draft beta
We have revamped our implementation for draft-enabled entities. While the old implementation was spread all over our code base, the new one is implemented in a modular, non-intrusive fashion.
Benefits for draft usages are more intuitive handler registrations and clear distinction of the request target (active or draft instances) within the custom handlers, as illustrated in this sample:
List status: All
triggersREAD
requests to the active and draft entities.jssrv.on('READ', '<entity>', /* handle only active instances */) srv.on('READ', '<entity>.drafts', /* handle only draft instances */)
EDIT
triggers aREAD
on the active instance followed by aCREATE
on the draft instance.
Non-intrusive means there's no support for draft in the new database services anymore, hence, New SQLite Service requires lean draft. So it's automatically switched on when using new SQLite service, you can also switch it on for old db services with:
{ ...,
"cds": {
"fiori": {
"lean_draft": true
}
}
}
As a reference, we've created a branch in SFlight, that shows some of the changes. Simply start cds watch --profile lean-draft
to see it in action or cds watch --profile lean-draft,better-sqlite
to also use the new SQLite Database Service.
We've also implemented a compatibility mode which mitigates most of the changes. It can be enabled via compatibility flag cds.fiori.draft_compat = true
. The SFlight main branch works without any changes when started with cds watch --profile lean-draft,draft-compat
.
WARNING
IMPORTANT: This is a beta feature, which available already now to get early feedback from you. All the Important Disclaimers and Legal Information apply!
More details will follow soon.
CAP Security Guide
"How can we develop and run a CAP application in a secure manner?"
"What has CAP in store to protect against typical attack patterns?"
"What is expected to meet production-level security requirements?"
"How are platform security services involved?"
These are typical questions asked by developers, operators, and security experts. The new CAP Security Guide addresses all of these questions and helps you to find your way around the challenging topic of security.
CDS Language and Compiler
Ternary Conditional Operator
Use the new ternary conditional operator <cond> ? <expr> : <expr>
to improve the readability of your sources.
This operator is only available as syntactical variant on CDL level. In CSN, it is represented by the same token stream as the corresponding CASE
expression.
Example:
SELECT FROM Books {
(stock>100 ? 0.3 : 0.1) as discount_ternary,
CASE WHEN stock>100 THEN 0.3 ELSE 0.1 END as discount_case
}
A ternary conditional operator must always be enclosed in parentheses.
Node.js
Important Changes ❗️
Changed Behavior for Plain SQL Queries
Plain SQL queries now have req.event === undefined
, formerly this had nondeterministic values. If you require to intercept plain SQL queries, you can register a custom handler using event *
. This change also affects the return of plain SQL INSERT queries that formerly returned an InsertResult
. From now on, they return the database driver result.
Change your start script to cds-serve
With the next major version, the cds
executable of @sap/cds
will be removed. This is to avoid further conflicts with the same executable in @sap/cds-dk
.
If you used cds run
or cds serve
commands in your package.json
, make sure to update it and use the successor cds-serve
:
npm pkg set scripts.start="cds-serve"
This results in the following configuration:
"scripts": {
"start": "cds-serve"
}
Access Targeted Instances with req.subject
This API simplifies the access of the targeted instances within custom implementation. It's handy for custom actions but is also available for the other events.
Example of SFlight application:
this.on ('acceptTravel', req => {
return UPDATE (req.subject) .with ({TravelStatus_code:'A'})
})
It can also be used for operating on draft enabled entities as showcased in SFlight.
For more details, see Node.js > cds.Requests > req.subject
Java
Important Changes ❗️
Minimum CloudSDK version is now 4.10
.
Retrieving SAP HANA Database ID
The TenantProviderService now provides, as part of the TenantInfo
class, the id of the database on which a specific tenant has been onboarded. If the information is not available null
is returned:
@Autowired ServiceCatalog serviceCatalog;
TenantProviderService tenantProvider =
serviceCatalog.getService(TenantProviderService.class, TenantProviderService.DEFAULT_NAME);
tenantProvider.readTenantsInfo().forEach(tenantInfo -> {
String tenantId = tenantInfo.getTenant();
String dbId = tenantInfo.get("database_id");
});
Auditlog with IAS
Audit Log integration now supports writing entries on behalf of a named user when the CAP application is using IAS instead of XSUAA.
Propagation of Correlation ID
If the execution of a RequestContext
is dispatched to a different thread, the correlation id of the parent thread is now always propagated to the new thread. If the receiving thread already had a correlation id it will be restored once the execution of the RequestContext
is completed.
Deployment Service
The DeploymentService API no longer validates the subscription and deployment scope. The scopes are now only validated on incoming HTTP requests (for example, SaaS Registry subscription), that trigger the DeploymentService
API internally. In case the MtSubscriptionService
compatibility mode is used, the scopes are still enforced when using the API.
Two new main methods com.sap.cds.framework.spring.utils.Subscribe
and com.sap.cds.framework.spring.utils.Unsubscribe
allow triggering subscriptions or unsubscriptions as tasks.
Simplified Configuration Properties
- Some new CDS properties are introduced. The previous properties are still supported for backwards compatibility.
- The properties
cds.dataSource.csv*
are moved into a newcds.dataSource.csv.*
sub-section. - The new property
cds.multiTenancy.healthcheck.interval
allows to specify the health check interval as a duration. Use it in favor of the deprecated propertycds.multiTenancy.healthcheck.intervalMillis
, which specifies the health check interval in ms:cds.multiTenancy.healthcheck.interval: 5m
Tools
Update to Cloud Foundry CLI 8 ❗️
The usage of Cloud Foundry CLI versions < 8 is deprecated and will be removed in the near future. Please update your local installations accordingly.
For now, you'll get a warning when using an older version of the cf
CLI in cds deploy
:
[Warning] You are using Cloud Foundry client version 7.8.9.
We recommend version 8 or higher. Deployment will stop in the near future
for Cloud Foundry client versions < 8.
Learn more about upgrading to cf CLI v8.
Extension Point Validation by cds build
cds build
now validates the extension point restrictions defined by the SaaS application provider. If any restriction is violated, the extension build aborts and the errors are logged.
Improved Code Completion in VS Code for using
Paths with Support for Mono Repos
Code completion for paths of using
statements now accounts for the (dev)dependencies
of the corresponding package.json file.
Improved Visualization of Model File Dependencies
Visualize CDS file dependencies command now highlights sub modules of mono repos.