Search

July 2020

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

See also: Latest Changelog

Important News and Changes❗️

Streamlined Compiler Switched on by Default

The streamlined compiler implementation is switched on by default. Learn more in the Compiler section below

Refactored Node.js Runtime — Version 4

Behind the scenes of stable APIs the Node.js runtime implementation has been improved and refactored substantially.

Learn more in the Node.js section below

CLI Commands moved to @sap/cds-dk

To minimize the footprint of the Node.js runtime, close to all CLI commands have been moved out of @sap/cds and into @sap/cds-dk now.

Learn more in the CLI section below

OData V2 Officially Supported

From now on, CAP officially supports OData V2 and SAP Fiori Elements UIs based on V2. In the beginning, we use the OData V2 proxy, which we’ll integrate intrinsically in the long run to reduce TCO.

Find details in the Serving UIs guide

HANA Cloud Edition Supported Out-of-the-Box

Already since May, CAP provides out-of-the-box support for HANA Cloud Edition. No changes are required to models or code, only a single configuration is to be added → see details in the Databases guide.

See also: Important Changes in Java

New and Revised Guides

Command Line / Toolkit

CLI Commands Moved to @sap/cds-dk❗️

As already started with the introduction of @sap/cds-dk in 2019, we now moved all CLI commands to the -dk packages, except for run and serve, which are used to launch Node.js runtime servers.

Background: We want to drastically strip down runtimes to minimum footprint.

If you already followed the recommendations to install cds-dk globally and use that in your setups accordingly, this shouldn’t affect you at all. Yet, in case you didn’t, ensure to follow these steps to avoid pitfalls:

  • In Java projects, use the new cds-maven-plugin; no other changes are necessary, as this plugin uses @sap/cds-dk out of the box.

  • In Node.js projects with existing mta.yaml files, replace all occurrences of npx cds with npx -p @sap/cds-dk cds in those files.

  • In freestyle CI setups, either (A) install cds-dk prior to the execution of build commands, that is npm i @sap/cds-dk && npm run ..., or (B) add a dev dependency to your project, for example: npm i @sap/cds-dk --save-dev.
    Note: (B) increases the installation time for every npm install call for every developer, so rather prefer option (A).

Streamlined and Modularized cds build

Builds for Node.js and SAP HANA have been optimized for better performance. In addition, we renovated our build infrastructure to allow flexible customization using respective CLI options.

For example:

# choose specific build task
cds build --for hana
# override task-specific options/defaults:
cds build --for hana --opts model=[db,srv,schema.cds]
# build with production profile:
cds build --production
# ...which is a shell-independent equivalent to:
NODE_ENV=production cds build
# Learn more with:
cds build --help

See also how database configuration uses profiles Learn more about Node.js configuration in general

Deprecated/Obsolete:

  • cds build/all → simply use cds build instead.
  • cds build --clean → is the default now.

Using await in cds repl

We now support using await directly on cds repl prompt inputs. For example:

[demo] cds repl
Welcome to cds repl v4.1.5
> m = await cds.load('*')

This feature is provided through Node.js –experimental-repl-await option.

CDS Editors & Tools

The following features are available for all editors based on our language server implementation for CDS in SAP Business Application Studio, Visual Studio Code, and Eclipse. The plugin for Eclipse is available for download at https://tools.hana.ondemand.com.

We are on VS Code Marketplace — finally ☺️

Finally, the VS Code extension for the core data services (CDS) language can be installed now from the Visual Studio Marketplace. See Getting Started > Tools for more details. If the extension is already installed and enabled in VS Code, it will be updated automatically.

(P.S. Sorry for the lengthy SAPish name ;)

Welcome Page in VS Code

The VS Code extension now comes with a welcome page, which shows latest information about CAP. It starts automatically once whenever an update arrives for the extension. Later, you can open the page through the command CDS: Show CAP Release Notes.

Issue Reporting in VS Code

You can now ask questions or report issues directly from VS Code. Just open the Report Issue dialog, select the VS Code extension, and follow the link to SAP Q&A. Please give us as much information as possible in the prefilled SAP Q&A form to enable better processing of your report.

Editor Support for doc comments (/** ... */)

Hovering over a definition now displays doc comments, if available:

As well as details for code completion:

Use the doc... snippet to create a doc comment. You can use markdown to structure a doc comment. Formatting also beautifies doc comments.

An information hint informs you about deprecation of the @cds.doc annotation. A quick fix allows you to convert a @cds.doc annotation into a doc comment.

You can specify the maximum line length of doc comments using the command CDS: Show Formatting Option Configuration. On the Other tab, edit the option Max doc comment line length.

For better visibility doc comments are highlighted differently than standard block comments.

QuickFix to Generate using Statements

You can now type an existing artifact name that isn’t yet imported (through a using statement). A quick fix for the error marker suggests possible artifacts from the workspace. Select the corresponding one to generate the using statement. The new import is inserted or merged among existing using statements, sorted alphabetically. The using statement is formatted.

More CDS Editor Improvements

  • Semantic Code Completion — Code completion now also suggests identifiers for elements, enums, actions, and parameters in annotate and extend within annotate and extend statements.

  • Syntax highlighting for identifiers — Until now identifiers, including variants delimited with \![...], haven’t been classified so themes couldn’t color them.

  • Related Info in Messages:

CDS Language & Compiler

Streamlined Compiler by Default ❗️

The already mentioned streamlined compiler implementation is now used by default. This new implementation brings significantly improved performance in compilation and bootstrapping servers, as well as reduced memory consumption at runtime.

In the unlikely case that the new default causes problems in your project, you can switch back as follows in your package.json or .cdsrc.json:

  "cds": {
    "features": { "snapi": false }
  }

Note: This fallback option will be offered only for a limited grace period. So, please make sure to switch to snapi as soon as possible.

Managed Compositions for Improved Domain Modeling

We deliver a major improvement to keep your domain models concise and comprehensible. Use Managed Compositions to nicely reflect document structures, without the need for separate entities, reverse associations, and unmanaged on conditions. For example:

entity Orders { ...
  Items : Composition of many { ...
    product : Association to Products;
    quantity : Integer;
  }
}

Managed Compositions are especially handy for many-to-many relationships:

entity Teams { ...
  members : Composition of many { key user: Association to Users; }
}
entity Users { ... }

And here’s an example of an attributed many-to-many relationship:

entity Teams { ...
  members : Composition of many {
    key user : Association to Users;
    role : String enum { Lead; Member; Collaborator; }
  }
}
entity Users { ... }

Learn more in the CDS Reference Documentations

IMPORTANT: CSN not stable yet. — Means: While you can safely use Managed Compositions as shown above, don’t rely on the current CSN output of for example, cds compile for managed compositions, as that may change.

Arrayed Elements in Entities to Avoid Joins

You can now declare arrayed elements in entities using keywords many or array of:

entity User { ...
  emails: many { kind:String; address:String } 
}

Arrayed elements are stored as JSON-stringified values in single NCLOB columns in relational tables. Node.js runtime already supports this generically; Java will follow.

Performance Benefits — On the one hand, this removes a lot of clutter from your models. On the other hand, and even more important, it greatly improves performance during data access. This results from eliminating a lot of joins to separate entities.

See also: Feature Matrix See also: Avoid Overly Normalized Models in the Domain Modeling Guide Learn more in the CDS Reference Documentations

Structs and Associations in on Conditions

We now allow comparing struct elements and managed(!) associations in on conditions of other associations. Have a look at the following example, which is only possible since this release:

entity Project { ...
  teams : Association to many Teams 
    on teams.country = $self.country;
    and teams.validity = $self.validity;
  country : Association to Country;
  validity : Validity;
}
entity Teams { ...
  country : Association to Country;
  validity : Validity;
}
type Validity : { from:Date; to:Date }

Both operands must be structurally compatible, that is both structures must be expandable to an identical set of leaf paths. Each leaf path must terminate on a builtin CDS scalar type. The original relational term of the form s1 op s2 is replaced by the resulting expression s1.leafpath_0 op s2.leafpath_0 (AND s1.leafpath_i op s2.leafpath_i)* with i < n leaf paths.

Enhanced Projection Clauses

You likely noticed already that as projection on and as SELECT from are mostly interchangeable alternatives, however the former should be preferred over the latter whenever you don’t need the full power of SQL.

This is especially true when defining projections on entities from remote services in service consumption scenarios. However, while in the past the following clauses weren’t allowed, they’re now:

  • where
  • having
  • group by
  • order by
  • limit

For example, provided content of these clauses will be translated to respective query options in OData in Service Consumption Scenarios.

Learn more in the CDS Reference Documentations

Not Null for Parameters and Return Types

Parameters and return types can now also be declared to be (not) null.

Node.js Runtime Version 4 ❗️

Behind the scenes of given APIs this release provides a broad range of major improvements. We removed inconsistencies, closed gaps and fixed several little glitches. In effect, release 4 is the basis for us to add new features and qualities faster than before, and at the same time gives you more stable and more future-proof APIs.

While public, documented APIs weren’t affected, you might nevertheless have written code, which relied on internal interfaces and behaviors, which you should correct accordingly. → see Important Changes below.

We strongly recommend doing so, and to upgrade as soon as possible, as former releases will receive only critical bug fixes from now on.

Important Changes ❗️

The following changes mostly affect undocumented, internal interfaces.

Eliminated Promise Voodoo
Former versions did quite some magic, meant to ease Promise Hell. With broad availability of async/await this became useless overhead, removed in release 4.
Now, always call cds.connect.to with await:
const srv = await cds.connect.to('some-service')
Eliminated next() Voodoo
Before, the framework called next() implicitly if an .on handler returned undefined. Now, always call next() explicitly, either with await, or with return:
this.on(..., async (req,next)=>{ /* ... */ await next(); /* ... */ })
this.on(..., (req,next)=>{ /* ... */ return next() })

See revised docs for .on handlers

Fallback: Set config cds.features.implicit_next:true to restore former behavior. But please correct your handlers, as soon as possible.

Deprecated and Removed

Important Fixes

  • $user.<attr> === undefined erroneously evaluated to true → now it’s false
  • $metadata requests erroneously got authorization-checked → not anymore
  • @restrict did permit all operations not mentioned, for example, the following annotation allowed all other operations, like UPDATE or DELETE, for every user:
    @restrict:[ {grant:'READ',to:'some-role'} ]
    
  • GET /Foo(1)/bar erroneously translated to semi joins → now correctly yields:
    {SELECT:{from:{ref:[ { id:'Foo', where:[{val:1}] }, 'bar' ]}}
    

    Refactored and Enhanced Core Services API

These enhancements are the main effects of the refactorings. They close many API gaps and glitches, and provides us with a clean core, for the things to come…

Classes cds.Service, cds.Request, and cds.Event

New Service and Request Methods

Learn more about the refactored Core Services APIs

Streamlined, Extensible Bootstrapping by cds.server

The bootstrapping process has been greatly optimized, in particular by loading only one consolidated effective model, instead of many per service independently. In effect, both, bootstrapping times, as well as memory consumption improve by magnitudes, especially with larger projects.

In addition, the built-in server.js implementation has been redesigned, and allows to plug-in custom logic, without loosing the convenience of cds watch et al:

// custom server.js
const cds = require('@sap/cds')
cds.on('bootstrap', (app)=>{ /* add your own middleware */ })
cds.on('served', ()=>{ /* add more middleware */ })
module.exports = cds.server //> delegate to default server.js

Learn more about cds.server-based bootstrapping

IMPORTANT: In case you’re using own server.js implementations, we strongly recommend revisiting these and considering refactoring them to extend the built-in one, as documented in custom server.js. This ensures you benefit from the mentioned and future optimizations.

Custom cds.Service Subclasses

Besides providing impl functions, service implementations can now provide specific subclasses of cds.Service, as shown below:

// srv/cat-service.js
const cds = require('@sap/cds')
class CatalogService extends cds.ApplicationService {
  async init(){
    this.on ('UPDATE','Books', (req)=>{...}) 
    await super.init()
    this.before ('CREATE','Books', (req)=>{...})
  }
}
module.exports = CatalogService
Common Service Factory
This is one of many more effects of the new service factory, commonly used by cds.serve and cds.connect now. This applies the same consistent ways to register new implementations via cds.requires options, model annotations @impl and @kind, or the well-known .cds/.js sibling files mechanism.

Learn more about new ways of Providing Service Implementations Learn more about new ways of Configuring Required Services

Custom Handlers on cds.connected Services

As a CAP Node.js developer, you’re used to add event handlers to provided services to add custom-specific implementations to the service. Starting with this release, you can also do the same from the consumer side to services you connected to, such as Database Services or Remote Services:

const db = await cds.connect('db')
db.prepend (()=>{
  db.on ('INSERT','Orders', req => {...})
  db.after ('READ','*', each => {...})
})

Learn more about Adding Handlers to cds.connected Services

For example, you could use that to fix gaps in our generic support, by providing your own generic handlers to our built-in database services for SQLite and HANA.

With this, we make these statements in the About CAP page even more true:

  • Every active thing in CAP is a service, that is a cds.Service, and…
  • Everything happens in response to events, that is in Event Handlers.

All service implementations essentially are just a bunch of registered event handlers. There’s actually no difference between handlers added from provider side, or from consumer side. There’s also no difference between the handlers we add to provide all the generic framework features of CAP, or the handlers you add. At the end of the day, we all eat the same dog food — with this release more than ever before.

Custom and Dummy Authentication Strategies

New Dummy Authentication Strategy
The dummy strategy creates a dummy user that passes all authorization checks. It’s meant for temporarily disabling the @requires and @restrict annotations at development time.
Custom Authentication Middleware
In case the supported authentication strategies don’t fulfill the necessary requirements, developers can provide a custom express middleware for authentication.

Learn more about the revamped Authentication framework

INSERT Queries Return Generated Keys

INSERT queries now return iterables, similar to results from SELECT queries, which allow to reflect on (generated) keys of the inserted entities, as shown in this snippet.

const [ Emily, Charlotte ] = await INSERT.into (Authors,[
   {name:'Emily Brontë'},
   {name:'Charlotte Brontë'},
])
INSERT.into(Books).columns('title','author_ID').rows(
   [ 'Wuthering Heights', Emily.ID ],
   [ 'Jayne Eyre', Charlotte.ID ],
)

Find details in the updated API docs of cds.run

Generic Support for Arrayed Elements

See Arrayed Elements in the CDS Language section

Localized Messages / i18n

Application developers can now use localized error messages. For example:

# i18n/messages_en.properties
ORDER_EXCEEDS_STOCK=The order of {0} books exceeds the stock by {1}
req.reject( 400, 'ORDER_EXCEEDS_STOCK', [ 
   order.amount, 
   order.amount - book.stock 
])

Learn more about Localized Messages

Miscellaneous

  • New srv.after('each', row => ...) — the former technique to register per-row handlers srv.after('READ', each => ...) broke when code was minified. The new method using pseudo event 'each' is minifier-safe.

  • New srv.prepend(srv => ...) — use srv.prepend(...) to register event handlers to be executed before the already registered handlers. For example, extensions of reused implementations sometimes need to use this.

  • New req.user.tenant to access the current user’s tenant ID.

  • Reflect srv.events — base class cds.Service provides a new getter srv.events to reflect on declared events in the service definition, similar to the already existing srv.entities, srv.types, and srv.operations.

  • Experimental cds.ql(req) — event handlers can now use the like of const {SELECT} = cds.ql(req) to ensure transaction-managed and tenant-isolated execution of queries, instead of srv.tx(req). Note though, that this is an experimental feature, which might change or be removed in future versions.

  • Switch on debug logs by setting the environmental variable DEBUG to y if you want to show more detailed log output.

More to Come Soon…

As stated above, this major version update was just the start, setting the stage for new features with a greatly cleaned up implementations of our Node.js runtime’s core.

In the documentation, you already find outlines, of not-yet documented or rarely filled-in guides and APIs, such as:

We didn’t document and release these APIs right now, as we want to give them some more polishing before general availability.

Stay tuned for more to come in there.

Java Runtime

Important Changes for Former Java Stack ❗️

A minimum version 1.40.6 of the former CAP Java runtime is required.
Check your project’s pom.xml and bump projects-parent-odatav2 or projects-parent to the latest version. We recommend doing this regularly.

Also, to benefit from new features, see our migration guide for the new CAP Java SDK.

Important Changes ❗️

  • The API CdsRuntime.runInRequestContext() has been deprecated and replaced by CdsRuntime.requestContext().run().
  • The API CdsRuntime.runInChangeSetContext() has been deprecated and replaced by CdsRuntime.changeSetContext().run().
  • Some error codes were incorrect and have been corrected: The codes ranging from 40008 to 40017 have been changed to 400008 to 400017 respectively, to prevent conflicts in error codes in the future.
  • The method ServiceException.getLocalizedMessage() can’t be used anymore for non-OData requests. Hence, if no active RequestContext object exists, please use the new method ServiceException.getLocalizedMessage(Locale) to explicitly set a locale. The requests locale can be obtained from the CdsRuntime using runtime.getProvidedParameterInfo().getLocale().
  • XSUAA user names aren’t normalized to lower case by default anymore (property cds.security.xsuaa.normalizeUserNames) because XSUAA delivers stable case-sensitive user names as of now.

Modeling

  • Support managed associations that don’t target key elements
    • Support using $now in on conditions of unmanaged associations

Code Generation

  • EventContext interfaces for events
  • create method for consumption interfaces for structured types

CDS Data Store

  • Managed Data
  • support using the session context variable $now, $at.from, $at.to, $user.id, and $user.locale in filters

New RequestContext API

A new RequestContext API enables accessing and modifying request metadata like user information, query parameters, and HTTP headers.

In addition, a new Provider API enables applications to control how user or request parameter information is derived from the request.

Parametrized Views

Read requests on Parameterized views are now supported in OData V4. See section CDS > Definition Language > Exposed Entities for more details.

OData Features

The following new OData V4 features have been added:

  • Updates on OData singletons and navigations from singletons to other entities are now supported.
  • The expression not is now supported in $filter requests
  • The $metadata endpoint now supports proper browser caching by setting the http header Cache-Control: max-age=0.
    • Data Aggregation ($apply)
    • support for one level of data aggregation
    • using transformations groupby, aggregate, filter, search and identity
    • using the standard aggregation methods sum, min, max, average and countdistinct
    • ordering by aggregated values
    • using $count=true together with

Fiori Drafts

You can now use field from draft enabled entities in orderBy clauses.

Miscellaneous

  • Event handler methods can now use the types CdsData, List<CdsData>, or Stream<CdsData> for method arguments.
  • Support multiple bound XSUAA service instances — The application configuration property cds.security.xsuaa.serviceName now controls which XSUAA service binding is chosen for authorization.

Bug Fixes

  • For an OData query with $count option, the inline count must be specified in the result. In the previous version, if no inline count was contained in the result, the row count was used, which could have resulted in wrong data.
  • Fixed a bug that caused queries using COUNT(*), for example, OData’s /$count to fail on SAP HANA databases.
  • Fixed a bug that caused PUT requests and actions to fail on Etag-enabled entities on SAP HANA.
  • Fields annotated with @cds.on.insert are now preserved in the draft when editing a draft enabled entity.

Performance

  • Improved performance when querying a draft enabled entity.
  • Suppress additional query for inline count if possible
  • Reduce number of queries when expanding to-one associations

Multitenancy

Building Multitenant SaaS Applications with CAP

Create cost-efficient SaaS applications with CAP and SAP HANA Cloud by leveraging the multitenancy concepts of SAP Cloud Platform and the new Service Management instance management capabilities.
The cds-mtx library offers you out-of-the-box support to switch your single tenant scenario to multitenant persistency with tenant data separation using HDI containers and to integrate it with the SAP Cloud Platform SaaS Manager. See Multitenancy for more details.