Skip to content
Search

    December 2021

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

    Find bugfixes and enhancements in the Changelog.


    Exists Predicates in CQL

    This release adds thorough support for exists predicates with path expressions, to CDS compiler, as well as Node.js and Java runtimes. Exists path predicates allow to express complex relationships while hiding the complexity of nested subselects. For example:

    SELECT FROM Authors WHERE exists books.pages[wordcount > 1000]
    

    Learn more about the Exists Predicates in CQL.

    Exists predicates can also be nested. The previous example is equivalent to:

    SELECT FROM Authors WHERE exists books [
      where exists pages [
        where wordcount > 1000
      ]
    ]
    

    Paths inside infix filters aren’t yet supported.

    Support in CDS Compiler

    The CDS compiler translates this into plain SQL like that:

    SELECT FROM sap_capire_bookshop_Authors a
    WHERE EXISTS (
      SELECT 1 from sap_capire_bookshop_Books b
      WHERE b.author_ID = a.ID and EXISTS (
        SELECT 1 from sap_capire_bookshop_BookPages p
        WHERE p.book_ID = b.ID
      )
    )
    

    Support in Runtimes

    The EXISTS predicate is also supported by the CAP Node.js and CAP Java runtimes. In CAP Java EXISTS is expressed by the anyMatch predicate. In an OData request a Lambda Operator is used.

    Instance-based Authorization

    The EXISTS predicate is especially useful when enforcing instance-based access control:

    @restrict: [{ grant: 'READ',
      where: 'exists teams.members [userId = $user and role = `Editor`]'
    }]
    entity Projects {
      // ...
      teams : Association to many Teams;
    }
    
    

    Learn more about Exists Predicate in the Authorization guide.

    In the example, only those users may read projects’ data, which are associated members with role Editor.

    Declarative Audit Logging in Java

    Audit logs of type “Personal data access” and “Personal data modification” are now automatically created in case the model is annotated with @PersonalData and @AuditLog as described in section Audit Logging:

    annotate Authors with
    @PersonalData : { EntitySemantics : 'DataSubject'}
    @AuditLog.Operation : { Read : true, Update : true }
    {
      ID @PersonalData.FieldSemantics : 'DataSubjectID';
      name @PersonalData.IsPotentiallyPersonal;
    }
    

    In the example, modifying the field Authors.name generates a log event of type DataModificationLog.

    For more information, see the respective section for Java.

    SQL Window Functions

    CQL now supports the syntax for SQL window functions:

    select from Foo {
      ...,
      sum(x) over (partition by a order by b
                     rows between unbounded preceding and current row) as s
    }
    

    No semantic checks are performed for the window functions, they are simply translated to SQL. Consult the documentation of your database for more information about the supported window functions.

    Learn more about representing SQL window functions in CXN.

    GraphQL Schema Using CLI (experimental)

    The GraphQL schema used in the experimental GraphQL Adapter can be generated stand-alone via cds compile -2 gql.

    Node.js Runtime

    Important Changes ❗️

    From this release on, debug logs of cds.DatabaseService and cds.RemoteService have sanitized values in production. The sanitization can be deactivated:

    cds.env.log.sanitize_values = false
    

    In production, it’s strongly recommended to use log level info or higher.

    Generic Providers

    The media type of a stream property is now updated based on the content type header of the PUT .../<stream property> request. With this, only one request is needed to update both, the media data and the media type.

    Further, the Node.js runtime now supports filtering based on the count of records in a collection. For example, you can get all hard-working authors via GET /Author?$filter=books/$count gt 10.

    Developer Experience

    For the December release, we added some improvements with regard to developer experience.

    • Typically, running with mocks in production isn’t sensible and, hence, the command line option --with-mocks was ignored. However, there may be some scenarios during development that would benefit from this option.

      cds.env.features.with_mocks = true now allows --with-mocks in production.

    • Authorization-related local development was tricky if the respective (mock) user had a tenant other than anonymous, as, by default, a new, empty SQLite database would have been created during cds watch. Now, in single tenant mode, the default SQLite database is used regardless of context.tenant.

    • The npm module passport is no longer required for authentication strategies dummy and mock. See Authentication Strategies for more details.

    • Requests to remote services are logged (similar to the debug logs for executed SQL statements) if the log level for module remote is set to debug. See Module Names Used by the Runtime for more details.

    Java SDK

    Important Changes ❗️

    Use Double Star (**) to Exclude Paths

    To exclude complete namespaces from code generation with the CDS Maven Plugin, now ** placeholder must be used. Adjust the configuration in the pom.xml accordingly.

    Configure DB Connection Properties in MT Scenario

    Pool configurations of multitenant database bindings now support map-based parameters. This enables additional connection properties to be specified. For Hikari connection pool, you can use cds.datasource.<binding-name>.hikari.data-source-properties.<key>: <value>.

    For instance, to configure the packet size of connections created by SAP HANA JDBC driver, add following configuration to your application.yaml file:

    cds:
      datasource:
        <binding-name>:
          hikari:
            data-source-properties:
              packetSize: 300000
    

    Learn more about datasource configuration.

    CSV Import of Array-Typed Elements

    Values for elements with arrayed types can now be specified in CSV files for test data import. The values need to be presented as JSON arrays as shown in the following example:

    entity Samples : cuid {
        records : array of {
            index: Integer;
            flag: Boolean
        }
    }
    

    A CSV file Samples.csv in folder db/data containing a single entity instance to be imported could look like this:

    ID;records
    08[...]15;[{"index": 1, "flag": true}, {"index": 2, "flag": false}]
    

    Learn more about providing initial data.

    OData

    Expose a Service with OData V2 and V4 in Parallel

    In CAP Java, you can expose a service with OData versions V2 and V4 in parallel. Formerly this wasn’t possible when using the MTX sidecar. This limitation has now been lifted.

    Remote Service Consumption

    You can now configure Cloud SDK’s destination retrieval strategy and the token exchange strategy for a Remote Service by setting cds.remote.services.<key>.destination.retrievalStrategy resp. cds.remote.services.<key>.destination.tokenExchangeStrategy.

    CQL Runtime

    Null Values in Results

    Clarification: The result row of a query execution may contain null values. Therefore, the containsKey method is not appropriate to check if a value is present in a result row and isn’t equal to null.

    Aliased Expands

    Expands in CQL Select statements can now have an alias:

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

    Associations on the Select List

    Managed to-one associations and compositions can now be added to the select list of Select statements.

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

    Reflection API: get/find Elements by Path

    When using the Reflection API, you can now specify a path to reflect on elements of a structured type or of an associated entity. Considering the following model:

    entity People {
         key id : UUID;
         name : { first : String; last : String; };
         car : Composition of one { brand : String; color : String; };
    }
    

    The following snippets are equivalent.

    Long version:

    @Autowired
    CdsModel model;
    
    CdsEntity people = model.getEntity("People");
    
    CdsElement name = people.getElement("name");
    CdsStructuredType nameType = name.getType().as(CdsStructuredType.class);
    CdsElement firstName = nameType.getElement("first");
    
    CdsElement car = people.getElement("car");
    CdsStructuredType carType = car.getType(CdsAssociationType.class).getTarget();
    Optional<CdsElement> colorOfCar = carType.findElement("color");
    

    New short version:

    @Autowired
    CdsModel model;
    
    CdsEntity people = model.getEntity("People");
    CdsElement firstName = people.getElement("name.first");
    Optional<CdsElement> colorOfCar = people.findElement("car.color");
    

    CDS Maven Plugin: Include/Exclude Definitions

    The CDS Maven Plugin now allows to selectively include and exclude definitions during code generation. With the following configuration of the generate goal, Java artifacts are generated for the definitions of the CatalogService but not for definitions of the namespace localized:

    <plugin>
        <groupId>com.sap.cds</groupId>
        <artifactId>cds-maven-plugin</artifactId>
        <version>${cds.services.version}</version>
        <executions>
            <execution>
                <goals>
                    <goal>generate</goal>
                </goals>
                <configuration>
                    <includes>
                        <include>CatalogService.**</include>
                    </includes>
                    <excludes>
                        <exclude>localized.**</exclude>
                    </excludes>
                </configuration>
            </execution>
        </executions>
    </plugin>
    

    New Lint Rule for CSV Files

    A new CDS lint rule validates header lines of CSV files for whether the columns match to CDS entities. In addition, quick fixes suggest the correct names in VS Code:

    CDS lint result for CSV file

    To get the VS Code integration for this rule, run cds add lint once in your project.

    Learn more about CDS Lint.

    Hybrid Testing: K8s and Java

    You can bind to Kubernetes service bindings and secrets and run your CAP Java applications with bindings using cds bind --exec now. Examples for important use cases have been added to the hybrid testing guide.

    CDS Editor Performance Optimizations

    The following applies to CDS editors in SAP Business Application Studio and Visual Studio Code.

    The editor is now faster at startup and requires less memory.

    Progress is now indicated when configuration was changed, and during references and workspace symbols.