Search

    November 2021

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

    Find bugfixes and enhancements in the Changelog.


    Events & Messaging General Available

    We finalized our messaging implementations now and can hereby declare first general availability. In course of this, we also documented key concepts and usage scenarios in the new comprehensive Events & Messaging Cookbook Guide:

    Messaging

    Schema Evolution General Available

    Schema Evolution on SAP HANA Cloud is finally released for productive usage now.

    CAP supports schema evolution based on migration tables for the SAP HANA database. Compatible changes including column rename can be applied to the database without any data loss and without the cost of an internal table-copy operation.

    Hybrid Tests with cds bind

    With hybrid testing, you stay in your local development environment and use services from the cloud. With the new cds bind, you connect your CAP Node.js application to Cloud Foundry services. The cds watch gets the service credentials from Cloud Foundry and keeps it until exit. There is no need to save service credentials on your hard drive anymore.

    Hybrid-Testing

    Java Runtime

    Important Changes ❗️

    • The CdsModelProvider is now also triggered when using CdsRuntime.getCdsModel(UserInfo, FeatureTogglesInfo) with a UserInfo object, where the tenant is set to null. Earlier, the method always returned the default CDS model directly.
    • CDS QL API cleanup
      • GROUP BY - groups are now represented as a List<CqnValue>
      • ORDER BY - the sort item is now represented as a CqnValue
      • CqnLimit - Using the CDS QL tree node CqnLimit is deprecated in favor of the new Select.top() and -.skip() methods.
      • Some legacy methods are deprecated in favor of cleaner substitutes. Check the build log for deprecation warnings.

    Observability

    Most features described in the Java Observability guide are now demonstrated in the Java Bookshop sample.

    Error Messages

    Built-in handlers, for example for @assert.range validation, now set the corresponding target in error messages. This ensures that error messages in SAP Fiori are shown directly at the relevant field, instead of in a generic popup.

    Remote OData

    • It’s now possible to build a destination for a Remote Service declaratively in the configuration. All destination properties supported by SAP Cloud SDK can be used under the new section cds.remote.services.<key>.destination.properties. For a full list of supported destination properties, look at SAP Cloud SDK’s com.sap.cloud.sdk.cloudplatform.connectivity.DestinationProperty class.
    • New configuration options cds.remote.services.<key>.destination.headers and cds.remote.services.<key>.destination.queries have been added and allow to configure key-value pairs of headers / queries to be added to every outgoing request of the Remote Service.

    anyMatch/allMatch Predicates

    The anyMatch/allMatch predicates can now be applied to paths with multiple segments:

    Select.from(BOOKS)
         .where(b -> b.author().books().anyMatch(b -> b.title().eq("Capire")));
    

    Path Access to Data

    The Row’s get method now supports paths, to simplify extracting values from nested maps:

    CqnSelect select = Select.from(BOOKS).columns(
         b -> b.title(), b -> b.author().expand()).byId(101);
    Row book = dataStore.execute(select).single();
    
    Object author = book.get("author.name"); // path access
    

    Enhanced QL Support for Parameters

    byParams is now also supported for Update and Delete statements, simplifying filtering by parameters as an alternative to where and CQL.param:

    // using where
    Delete.from(BOOKS)
      .where(b -> b.title().eq(param("title"))
             .and(b.author().name().eq(param("author.name"))));
    
    // using byParams
    Delete.from(BOOKS).byParams("title", "author.name");
    

    Enhanced QL Support for ORDER BY

    Use the new CQL.sort method to create a sort specification in tree style:

    CqnElementRef authorName = CQL.get("author.name");
    CqnSortSpecification sort = CQL.sort(authorName, CqnSortSpecification.Order.ASC);
    CqnSelect query = Select.from("bookshop.Books").orderBy(authorName);
    

    Modify an existing sort specification using Modifier.sort:

    CqnSelect sel = Select.from("Book").orderBy("title");
    
    CqnSelect modified = copy(sel, new Modifier() {
        @Override
        public CqnSortSpecification sort(Value<?> value, Order order) {
            return value.desc();
        }
    });
    

    Simplified Representation of top/skip

    Use the top() and skip() methods to get the values of top and skip of Select statements and expands:

    CqnSelect query = Select.from(BOOKS).orderBy(b -> b.ID()).limit(10, 50);
    assertThat(query.top()).isEqualTo(10);
    assertThat(query.skip()).isEqualTo(50);
    

    Node.js Runtime

    Important Changes ❗️

    • @sap/xsenv is no longer used for credentials look-up and can be removed from projects.

    • cds.ql: Keys passed as arguments into SELECT.from() are put into the target path (SELECT.from.ref) instead of adding a where expression at root level. This change is necessary in order to distinguish between resource paths and filters/ restrictions.

        SELECT.from('Books', 1)
      

      Result now:

        SELECT: {
          from: {
            ref: [{
              id: 'Books',
              where: [{ ref: ['ID'] }, '=', { val: 1 }]
            }]
          },
          one: true
        }
      

      Result previously:

        SELECT: {
          from: { ref: ['Books'] },
          where: [{ ref: ['ID'] }, '=', { val: 1 }] },
          one: true
        }
      

      The change can be deactivated during two-month grace period via compatibility feature flag cds.env.features.keys_into_where = true.

    Service Consumption

    There are two new configuration options for remote services:

    Further, GET requests to Remote OData Services are automatically sent as $batch if the generated URL is too long.

    Learn more in the enhanced Consuming Services Cookbook.

    Project-Specific Configuration

    New REST Adapter (beta)

    The November release includes the beta version of the new REST adapter.

    The new implementation uses the CAP-native OData URL to CQN parser. Hence, almost all OData requests are supported. For example, you can use query options like $filter and $expand, request deep resources such as GET /Foo/1/bars/2/baz, as well as (un)bound actions and functions.

    Limitations/ out of scope (compared to OData protocol adapter):

    • OData query option $apply
    • OData batch requests (/$batch; with or without atomicity groups)
    • Draft handling

    The new REST adapter can be activated via cds.env.features.rest_new_adapter = true. Don’t forget that you need to serve to rest, either via the cds.serve() API or the @protocol annotation.

    img

    GraphQL Adapter for Node.js (experimental)

    The November release includes a first experimental implementation of a generic GraphQL adapter, which turns each CAP service into a GraphQL server.

    The GraphQL adapter can be activated by setting config option:

    • cds.env.features.graphql = true

    Further, you need to install the following additional dependencies:

    • @graphql-tools/schema
    • express-graphql
    • graphql

    The adapter serves a single endpoint for all services based on the served event at /graphql. At that path, you’ll find a generated UI (via third party library) that allows you to interact with your application.

    Follow these steps to run @capire/bookshop with graphql:

    1. npm add graphql express-graphql @graphql-tools/schema
    2. cds_features_graphql=true cds w bookshop
    3. Open GraphiQL client at http://localhost:4004/graphql.
    4. Browse schema and enter queries in the GraphiQL client.

    GraphiQL

    For example, you can execute queries like the following:

    {
      CatalogService {
        Books {
          ID
          title
          genre {
            name
          }
        }
      }
    }
    

    The equivalent query in OData:

    GET /browse/Books?$select=ID,title&$expand=genre($select=name)
    

    Various limitations apply. For example, authentication and authorization are out of scope, and annotations aren’t considered during schema generation.

    Note that the GraphQL adapter isn’t supported for productive usage!

    Show/Hide Beta Features