From 2ae77c30eedcee694d2f96674acfc2770546b6e8 Mon Sep 17 00:00:00 2001 From: Daniel Hutzel Date: Mon, 2 Dec 2024 14:34:55 +0100 Subject: [PATCH 1/9] Simplified hash links --- .vitepress/theme/styles.scss | 1 + advanced/fiori.md | 4 +-- advanced/hana.md | 10 +++---- cds/annotations.md | 4 +-- cds/cdl.md | 36 ++++++++++++++--------- cds/cql.md | 7 +++-- cds/csn.md | 8 ++--- guides/providing-services.md | 26 ++++++++-------- guides/using-services.md | 2 +- java/change-tracking.md | 4 +-- java/cqn-services/persistence-services.md | 4 +-- java/developing-applications/building.md | 12 ++++---- 12 files changed, 65 insertions(+), 53 deletions(-) diff --git a/.vitepress/theme/styles.scss b/.vitepress/theme/styles.scss index 75ac9b266..b2d8a9209 100644 --- a/.vitepress/theme/styles.scss +++ b/.vitepress/theme/styles.scss @@ -45,6 +45,7 @@ --vp-c-text-1: #000; h1, h2, h3, h4, h5 { color: rgba(60, 60, 67) } + h6 { color: transparent; position: absolute; margin-top: -7.7em; right: 0px; } // we use h6 for alternative anchor targets /* inverts image colors in dark mode */ diff --git a/advanced/fiori.md b/advanced/fiori.md index cdea58cf5..c9c93fc87 100644 --- a/advanced/fiori.md +++ b/advanced/fiori.md @@ -461,12 +461,12 @@ If you're editing data in multiple languages, the _General_ tab in the example a You can add [custom handlers](../guides/providing-services#custom-logic) to add specific validations, as usual. In addition, for a draft, you can register handlers to the `PATCH` events to validate input per field, during the edit session, as follows. -###### ... in Java +##### ... in Java You can add your validation logic before operation event handlers. Specific events for draft operations exist. See [Java > Fiori Drafts > Editing Drafts](../java/fiori-drafts#draftevents) for more details. -###### ... in Node.js +##### ... in Node.js You can add your validation logic before the operation handler for either CRUD or draft-specific events. See [Node.js > Fiori Support > Handlers Registration](../node.js/fiori#draft-support) for more details about handler registration. diff --git a/advanced/hana.md b/advanced/hana.md index f2b9ea68e..b000cb117 100644 --- a/advanced/hana.md +++ b/advanced/hana.md @@ -20,13 +20,13 @@ You create a new database object or there's an existing object (table, view, tab ### Add Existing SAP HANA Objects from Other HDI Containers -To access database artifacts residing in other HDI containers, you need the permissions granted for that container and you need to introduce them into your own container using synonyms. This synonym establishes a link between both needed HDI containers. The _.hdbsynonym_ file you create for this, [is a native SAP HANA object in your project](#create-native-sap-hana-object). +To access database artifacts residing in other HDI containers, you need the permissions granted for that container and you need to introduce them into your own container using synonyms. This synonym establishes a link between both needed HDI containers. The _.hdbsynonym_ file you create for this, [is a native SAP HANA object in your project](#create-native-sap-hana-objects). ::: tip Synonyms can be used to rename database objects. ::: -### Create Native SAP HANA Object in Your Project { #create-native-sap-hana-object} +### Create Native SAP HANA Objects To create SAP HANA native tables or use SAP HANA native features, use the folder _db/src_ at design time and build, for example, your _.hdbtable_ or _.hdbsynonym_ files. This folder stays untouched during the `cds` build and the content is copied over to the _gen/db/src_ folder during the build. Use this process for all tables and features that can't be modeled using _CDS_. @@ -50,7 +50,7 @@ Steps to match the signature of a database object in a facade entity: * For a view, table function, or calculation view with parameters, check that the parameter names and types match, too. Functions with table-like input parameters are not supported. -> Note: If a field of that entity is defined as `not null` and you want to disable its runtime check, you can add [`@assert.notNull: false`](../guides/providing-services#assert-notNull). This is important if you want to use, for example [SAP HANA history tables](https://help.sap.com/docs/SAP_HANA_PLATFORM/6b94445c94ae495c83a19646e7c3fd56/d0b2c5142a19405fb912f71782cd0a84.html). +> Note: If a field of that entity is defined as `not null` and you want to disable its runtime check, you can add [`@assert.notNull: false`](../guides/providing-services#assert-notnull). This is important if you want to use, for example [SAP HANA history tables](https://help.sap.com/docs/SAP_HANA_PLATFORM/6b94445c94ae495c83a19646e7c3fd56/d0b2c5142a19405fb912f71782cd0a84.html). As a result, the database name is defined by the name of the entity or its elements, after applying the SQL name mapping. @@ -396,7 +396,7 @@ FROM AddressUDF() AS AddressUDF_0; This section describes how associations and compositions to artifacts with `@cds.persistence.skip/exists` are treated during the generation of the database model with `forHana`. -###### `@cds.persistence.skip` +##### `@cds.persistence.skip` Denotes that the artifact isn't available in the database but eventually implemented by custom code. No association can point to a nonexisting database object and no query can be executed against such a nonexisting source. As `@cds.persistence.skip` is *propagated*, projections also don't become part of the database schema. @@ -430,7 +430,7 @@ view ItemSelection as select from Items; The view `Orders` will be rejected with an error message as `items.name` isn't resolvable to a valid JOIN expression and view `ItemSelection` is effectively annotated with `@cds.persistence.skip`. -###### `@cds.persistence.exists` +##### `@cds.persistence.exists` Denotes that there already exists a native database object, which should be used during runtime. diff --git a/cds/annotations.md b/cds/annotations.md index 68a35a0f8..ed733d3c5 100644 --- a/cds/annotations.md +++ b/cds/annotations.md @@ -40,12 +40,12 @@ uacp: Used as link target from Help Portal at https://help.sap.com/products/BTP/ |---------------------|----------------------------------------------------------------------| | `@readonly ` | see [Input Validation](../guides/providing-services#readonly) | | `@mandatory` | see [Input Validation](../guides/providing-services#mandatory) | -| `@assert.unique` | see [Input Validation](../guides/providing-services#unique) | +| `@assert.unique` | see [Input Validation](../guides/providing-services#assert-unique) | | `@assert.integrity` | see [Input Validation](../guides/databases#db-constraints) | | `@assert.target` | see [Input Validation](../guides/providing-services#assert-target) | | `@assert.format` | see [Input Validation](../guides/providing-services#assert-format) | | `@assert.range` | see [Input Validation](../guides/providing-services#assert-range) | -| `@assert.notNull` | see [Input Validation](../guides/providing-services#assert-notNull) | +| `@assert.notNull` | see [Input Validation](../guides/providing-services#assert-notnull) | diff --git a/cds/cdl.md b/cds/cdl.md index 6f74e7d8e..ef7e8e24f 100644 --- a/cds/cdl.md +++ b/cds/cdl.md @@ -32,8 +32,8 @@ The *Conceptual Definition Language (CDL)* is a human-readable language for defi - [Keywords & Identifiers](#keywords-identifiers) - [Built-in Types](#built-in-types) - [Literals](#literals) -- [Model Imports](#imports) -- [Namespaces](#namespace) +- [Model Imports](#model-imports) +- [Namespaces](#namespaces) - [Comments](#comments) @@ -146,7 +146,7 @@ Within those strings, escape sequences from JavaScript, such as `\t` or `\u0020` -### Model Imports {#imports} +### Model Imports @@ -208,7 +208,7 @@ To allow for loading from precompiled _.json_ files it's recommended to **omit _ ### Namespaces -#### The `namespace` Directive {#namespace} +#### The `namespace` Directive To prefix the names of all subsequent definitions, place a `namespace` directive at the top of a model. This is comparable to other languages, like Java. @@ -348,21 +348,24 @@ In CAP Java, doc comments are automatically enabled by the [CDS Maven Plugin](.. ## Entities & Type Definitions -- [Entity Definitions](#entities) -- [Type Definitions](#types) +- [Entity Definitions](#entity-definitions) +- [Type Definitions](#type-definitions) - [Structured Types](#structured-types) - [Arrayed Types](#arrayed-types) - [Virtual Elements](#virtual-elements) - [Calculated elements](#calculated-elements) - [Default Values](#default-values) -- [Type References](#typereferences) +- [Type References](#type-references) - [Constraints](#constraints) - [Enums](#enums) -### Entity Definitions {#entities} + +### Entity Definitions +{#entities} + Entities are structured types with named and typed elements, representing sets of (persisted) data that can be read and manipulated using usual CRUD operations. They usually contain one or more designated primary key elements: @@ -379,7 +382,9 @@ define entity Employees { > The `define` keyword is optional, that means `define entity Foo` is equal to `entity Foo`. -### Type Definitions {#types} +### Type Definitions +{#types} + You can declare custom types to reuse later on, for example, for elements in entity definitions. Custom-defined types can be simple, that is derived from one of the predefined types, structure types or [Associations](#associations). @@ -486,7 +491,8 @@ entity Employees { -### Calculated Elements {#calculated-elements} + +### Calculated Elements Elements of entities and aspects can be specified with a calculation expression, in which you can refer to other elements of the same entity/aspect. @@ -625,7 +631,7 @@ type Complex { ``` -### Type References {#typereferences} +### Type References If you want to base an element's type on another element of the same structure, you can use the `type of` operator. @@ -1670,7 +1676,7 @@ the `extend` from `c.cds` is applied, as it is the last in the dependency chain. ### The `annotate` Directive {#annotate} -The `annotate` directive allows to annotate already existing definitions that may have been [imported](#imports) from other files or projects. +The `annotate` directive allows to annotate already existing definitions that may have been [imported](#model-imports) from other files or projects. ```cds annotate Foo with @title:'Foo'; @@ -1880,7 +1886,8 @@ entity C { /*...*/ }; ::: -### (Auto-) Redirected Associations {#auto-redirect} +### (Auto-) Redirected Associations +{#auto-redirect} When exposing related entities, associations are automatically redirected. This ensures that clients can navigate between projected entities as expected. For example: @@ -1938,7 +1945,8 @@ service AdminService { -### Auto-Exposed Entities {#auto-expose} +### Auto-Exposed Entities +{#auto-expose} Annotate entities with `@cds.autoexpose` to automatically expose them in services containing entities with associations referring to them. diff --git a/cds/cql.md b/cds/cql.md index dd57db843..22c941803 100644 --- a/cds/cql.md +++ b/cds/cql.md @@ -14,7 +14,9 @@ CDS Query Language (CQL) is based on standard SQL, which it enhances by... [[toc]] -## Postfix Projections {#postfix-projections} + +## Postfix Projections +{#postfix-projections} CQL allows to put projections, that means, the `SELECT` clause, behind the `FROM` clause enclosed in curly braces. For example, the following are equivalent: @@ -25,7 +27,8 @@ SELECT name, address.street from Authors SELECT from Authors { name, address.street } ``` -### Nested Expands {#nested-expands} +### Nested Expands +{#nested-expands} Postfix projections can be appended to any column referring to a struct element or an association and hence be nested. This allows **expand** results along associations and hence read deeply structured documents: diff --git a/cds/csn.md b/cds/csn.md index 5f12ce5d6..039fb6e6e 100644 --- a/cds/csn.md +++ b/cds/csn.md @@ -189,7 +189,7 @@ Foo2 = { type:"cds.String", kind:"type" } ``` -## Type Definitions {#type-definitions} +## Type Definitions [type definitions]: #type-definitions @@ -216,8 +216,6 @@ Custom-defined types are entries in [`definitions`](#definitions) with an option #### Properties -[kind]: #kind -[type]: #type * `kind` – omitted or _`"type"`_ * `type` – the base type, this definition is derived from @@ -233,7 +231,6 @@ Custom-defined types are entries in [`definitions`](#definitions) with an option ### Scalar Types -[scalar]: #scalar-types Scalar types always have property `type` specified, plus optional type-specific parameter properties. @@ -432,9 +429,8 @@ Use the `projection` property for views if you don't need the full power of SQL. ## Associations -[Associations]: #associations -Associations are like [scalar type definitions][scalar] with `type` being `cds.Association` or `cds.Composition` plus additional properties specifying the association's `target` and optional information like `on` conditions or foreign `keys`. +Associations are like [scalar type definitions](#scalar-types) with `type` being `cds.Association` or `cds.Composition` plus additional properties specifying the association's `target` and optional information like `on` conditions or foreign `keys`. ### Basic to-one Associations diff --git a/guides/providing-services.md b/guides/providing-services.md index 6177e51cf..d0847176f 100644 --- a/guides/providing-services.md +++ b/guides/providing-services.md @@ -15,7 +15,8 @@ uacp: Used as link target from Help Portal at https://help.sap.com/products/BTP/ [[toc]] -## Intro: Core Concepts {#introduction} +## Intro: Core Concepts +{#introduction} The following sections give a brief overview of CAP's core concepts. @@ -160,7 +161,8 @@ The CAP runtimes for [Node.js](../node.js/) and [Java](../java/) provide a wealt In effect, a service definition [as introduced above](#service-definitions) is all we need to run a full-fledged server out of the box. The need for coding reduces to real custom logic specific to a project's domain → section [Custom Logic](#custom-logic) picks that up. -### Serving CRUD Requests {#serving-crud} +### Serving CRUD Requests +{#serving-crud} The CAP runtimes for [Node.js](../node.js/) and [Java](../java/) provide generic handlers, which automatically serve all CRUD requests to entities for CDS-modelled services on top of a default [primary database](databases). @@ -728,7 +730,7 @@ Pessimistic locking is not supported by SQLite. H2 supports exclusive locks only CAP runtimes automatically validate user input, controlled by the following annotations. -### `@readonly` {#readonly} +### `@readonly` Elements annotated with `@readonly`, as well as [_calculated elements_](../cds/cdl#calculated-elements), are protected against write operations. That is, if a CREATE or UPDATE operation specifies values for such fields, these values are **silently ignored**. @@ -738,7 +740,7 @@ The same applies for fields with the [OData Annotations](../advanced/odata#annot ::: -### `@mandatory` {#mandatory} +### `@mandatory` Elements marked with `@mandatory` are checked for nonempty input: `null` and (trimmed) empty strings are rejected. @@ -761,7 +763,7 @@ In addition to server-side input validation as introduced above, this adds a cor -### `@assert.unique` {#unique} +### `@assert .unique` Annotate an entity with `@assert.unique.`, specifying one or more element combinations to enforce uniqueness checks on all CREATE and UPDATE operations. For example: @@ -790,7 +792,7 @@ You don't need to specify `@assert.unique` constraints for the primary key eleme -### `@assert.target` {#assert-target} +### `@assert.target` Annotate a [managed to-one association](../cds/cdl#managed-associations) of a CDS model entity definition with the `@assert.target` annotation to check whether the target entity referenced by the association (the reference's target) @@ -813,7 +815,7 @@ If the reference's target doesn't exist, an HTTP response content adheres to the standard OData specification for an error [response body](https://docs.oasis-open.org/odata/odata-json-format/v4.01/cs01/odata-json-format-v4.01-cs01.html#sec_ErrorResponse). -#### Example {#assert-target-example} +#### Example Add `@assert.target` annotation to the service definition as previously mentioned: @@ -867,7 +869,7 @@ Cross-service checks are not supported. It is expected that the associated entit The `@assert.target` check constraint relies on database locks to ensure accurate results in concurrent scenarios. However, locking is a database-specific feature, and some databases don't permit to lock certain kinds of objects. On SAP HANA, for example, views with joins or unions can't be locked. Do not use `@assert.target` on such artifacts/entities. ::: -### `@assert.format` {#assert-format} +### `@assert .format` Allows you to specify a regular expression string (in ECMA 262 format in CAP Node.js and java.util.regex.Pattern format in CAP Java) that all string input must match. @@ -877,7 +879,7 @@ entity Foo { } ``` -### `@assert.range` {#assert-range} +### `@assert .range` Allows you to specify `[ min, max ]` ranges for elements with ordinal types — that is, numeric or date/time types. For `enum` elements, `true` can be specified to restrict all input to the defined enum values. @@ -914,8 +916,7 @@ Support for open intervals and infinity has been added to CAP Node.js, i.e. `@sa ::: - -### `@assert.notNull` {#assert-notNull} +### `@assert .notNull` Annotate a property with `@assert.notNull: false` to have it ignored during the generic not null check, for example if your persistence fills it automatically. @@ -1339,7 +1340,8 @@ To disable this default behavior, you can set the environment variable c -## Single-Purposed Services {.best-practice} +## Single-Purposed Services +{.best-practice} We strongly recommend designing your services for single use cases. diff --git a/guides/using-services.md b/guides/using-services.md index 399e8fa7a..69d775245 100644 --- a/guides/using-services.md +++ b/guides/using-services.md @@ -234,7 +234,7 @@ To work with remote services, add the following dependency to your Maven project -## Local Mocking {#local-mocking} +## Local Mocking When developing your application, you can mock the remote service. diff --git a/java/change-tracking.md b/java/change-tracking.md index 596810f74..e31edcf89 100644 --- a/java/change-tracking.md +++ b/java/change-tracking.md @@ -276,7 +276,7 @@ If you change the values of the `OrderItems` entity directly via an OData reques ## Reacting on Changes -You can write an event handler to observe the change log entries. Keep in mind, that the change log entries +You can write an event handler to observe the change log entries. Keep in mind, that the change log entries are created for each statement and this event will not be bound to any kind of transaction or a batch operation. ```java @@ -285,7 +285,7 @@ import cds.gen.sap.changelog.Changes; @Component @ServiceName("ChangeTrackingService$Default") public class ChangeTrackingHandler implements EventHandler { - + @After(event = "createChanges") void afterCreate(EventContext context) { Result result = (Result) context.get("result"); diff --git a/java/cqn-services/persistence-services.md b/java/cqn-services/persistence-services.md index 7efa46778..1205d9c22 100644 --- a/java/cqn-services/persistence-services.md +++ b/java/cqn-services/persistence-services.md @@ -150,7 +150,7 @@ cds.sql.hana.optimizationMode: legacy Use the [hints](../working-with-cql/query-execution#hana-hints) `hdb.USE_HEX_PLAN` and `hdb.NO_USE_HEX_PLAN` to overrule the configured optimization mode per statement. ::: warning Rare error in `HEX` mode -In some corner cases, particularly when using [native HANA views](../../advanced/hana#create-native-sap-hana-object), queries in `HEX` optimization mode may fail with a "hex enforced but cannot be selected" error. This is the case if the statement execution requires the combination of HEX only features with other features that are not yet supported by the HEX engine. If CAP detects this error it will, as a fallback, execute the query in _legacy_ mode. +In some corner cases, particularly when using [native HANA views](../../advanced/hana#create-native-sap-hana-objects), queries in `HEX` optimization mode may fail with a "hex enforced but cannot be selected" error. This is the case if the statement execution requires the combination of HEX only features with other features that are not yet supported by the HEX engine. If CAP detects this error it will, as a fallback, execute the query in _legacy_ mode. If you know upfront that a query can't be executed by the HEX engine, you can add a `hdb.NO_USE_HEX_PLAN` hint to the query, so the SQL generator won't use features that require the HEX engine. ::: @@ -547,7 +547,7 @@ cds: ### Native SQL with JDBC Templates { #jdbctemplate} -The JDBC template is the Spring API, which in contrast to the CQN APIs allows executing native SQL statements and call stored procedures (alternative to [Native HANA Object](../../advanced/hana#create-native-sap-hana-object)). It seamlessly integrates with Spring's transaction and connection management. The following example shows the usage of `JdbcTemplate` in the custom handler of a Spring Boot enabled application. It demonstrates the execution of the stored procedure and native SQL statement. +The JDBC template is the Spring API, which in contrast to the CQN APIs allows executing native SQL statements and call stored procedures (alternative to [Native HANA Object](../../advanced/hana#create-native-sap-hana-objects)). It seamlessly integrates with Spring's transaction and connection management. The following example shows the usage of `JdbcTemplate` in the custom handler of a Spring Boot enabled application. It demonstrates the execution of the stored procedure and native SQL statement. ```java @Autowired diff --git a/java/developing-applications/building.md b/java/developing-applications/building.md index 7d963c3a2..c3131f6c5 100644 --- a/java/developing-applications/building.md +++ b/java/developing-applications/building.md @@ -17,7 +17,8 @@ One of the key [CAP design principles](../../about/#open-and-opinionated) is to Giving a clear guidance for cutting-edge technologies on the one hand and still keeping the door wide open for custom choice on the other hand, demands a highly flexible CAP Java runtime stack. The [modular architecture](#modular_architecture) reflects this requirement, allowing a fine-grained and flexible [configuration](#stack_configuration) based on standard or custom modules. -## Modular Stack Architecture { #modular_architecture} +## Modular Stack Architecture +{ #modular_architecture} ### Overview @@ -56,7 +57,7 @@ You can recognize five different areas of the stack, which comprise components a * [Application features](#application-features) are optional application extensions, for instance to add multitenancy capabilities or a platform service integration. -### Application Framework { #application-framework} +### Application Framework Before starting the development of a new CAP-based application, an appropriate application framework to build on needs to be chosen. The architecture of the chosen framework not only has a strong impact on the structure of your project, but it also affects efforts for maintenance as well as support capabilities. @@ -75,7 +76,7 @@ In this case, a solution based on plain Java Servlets could be favorable. Lastly, in case you want to run your application on a 3rd party application framework, you're free to bundle it with CAP modules and provide the glue code, which is necessary for integration. -### Protocol Adapters { #protocol-adapters} +### Protocol Adapters The CAP runtime is based on an [event](../../about/best-practices#events) driven approach. @@ -339,7 +340,8 @@ It supports the following command-line options: | `-DcdsdkVersion=` | Sets the provided cds-dk version in the project. If not specified, the default of CAP Java is used. | -## Building Projects with Maven { #maven-build-options } +## Building Projects with Maven +{ #maven-build-options } You can build and run your application by means of the following Maven command: @@ -348,7 +350,7 @@ mvn spring-boot:run ``` -### CDS Maven Plugin { #cds-maven-plugin} +### CDS Maven Plugin CDS Maven plugin provides several goals to perform CDS-related build steps. For instance, the CDS model needs to be compiled to a CSN file which requires a Node.js runtime with module `@sap/cds-dk`. From b482c283fb168bfcd91f218c01e2b94adfe53fef Mon Sep 17 00:00:00 2001 From: Daniel Hutzel Date: Mon, 2 Dec 2024 14:35:13 +0100 Subject: [PATCH 2/9] Fixed relative lnks --- about/best-practices.md | 56 ++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/about/best-practices.md b/about/best-practices.md index 9a53e6c4f..058798433 100644 --- a/about/best-practices.md +++ b/about/best-practices.md @@ -22,13 +22,13 @@ The CAP framework features a mix of proven and broadly adopted open-source and S The major building blocks are as follows: -- [**Core Data Services** (CDS)](/cds/) — CAP's universal modeling language, and the very backbone of everything; used to capture domain knowledge, generating database schemas, translating to and from various API languages, and most important: fueling generic runtimes to automatically serve request out of the box. +- [**Core Data Services** (CDS)](../cds/) — CAP's universal modeling language, and the very backbone of everything; used to capture domain knowledge, generating database schemas, translating to and from various API languages, and most important: fueling generic runtimes to automatically serve request out of the box. -- [**Service Runtimes**](/guides/providing-services.md) for [Node.js](/node.js/) and [Java](/java/) — providing the core frameworks for services, generic providers to serve requests automatically, database support for SAP HANA, SQLite, and PostgreSQL, and protocol adaptors for REST, OData, GraphQL, ... +- [**Service Runtimes**](../guides/providing-services.md) for [Node.js](../node.js/) and [Java](../java/) — providing the core frameworks for services, generic providers to serve requests automatically, database support for SAP HANA, SQLite, and PostgreSQL, and protocol adaptors for REST, OData, GraphQL, ... -- [**Platform Integrations**](/plugins/) — providing CAP-level service interfaces (*'[Calesi](#the-calesi-effect)'*) to cloud platform services in platform-agnostic ways, as much as possible. Some of these are provided out of the box, others as plugins. +- [**Platform Integrations**](../plugins/) — providing CAP-level service interfaces (*'[Calesi]()'*) to cloud platform services in platform-agnostic ways, as much as possible. Some of these are provided out of the box, others as plugins. -- [**Command Line Interface** (CLI)](/tools/) — the swiss army knife on the tools and development kit front, complemented by integrations and support in *SAP Build Code*, *Visual Studio Code*, *IntelliJ*, and *Eclipse*. +- [**Command Line Interface** (CLI)](../tools/) — the swiss army knife on the tools and development kit front, complemented by integrations and support in [*SAP Build Code*](), *Visual Studio Code*, *IntelliJ*, and *Eclipse*. In addition, there is a fast-growing number of [plugins] contributed by open-source and inner-source [communities](/resources/#public-resources) that enhance CAP in various ways, and integrate with additional tools and environments; the [*Calesi* plugins](#the-calesi-effect) are among them. @@ -62,7 +62,7 @@ We'll dive into each of these concepts in the following sections below, starting ## Domain Models -[CDS](/cds/) is CAP's universal modeling language to declaratively capture knowledge about an application's domain. Data models capture the *static* aspects of a domain, using the widely used technique of *entity-relationship modelling*. For example, a simple domain model as illustrated in this ER diagram: +[CDS](../cds/) is CAP's universal modeling language to declaratively capture knowledge about an application's domain. Data models capture the *static* aspects of a domain, using the widely used technique of [*entity-relationship modelling*](). For example, a simple domain model as illustrated in this ER diagram: ![bookshop-erm.drawio](assets/bookshop-erm.drawio.svg) @@ -87,18 +87,18 @@ entity Authors : cuid, managed { ::: -[Type `Country` is declared to be an association to `sap.common.Countries`.](/cds/common#type-country) {.learn-more} +[Type `Country` is declared to be an association to `sap.common.Countries`.](../cds/common#type-country) {.learn-more} ### Definition Language (CDL) -We use CDS's [*Conceptual Definition Language (CDL)*](/cds/cdl) as a *human-readable* way to express CDS models. Think of it as a *concise*, and more *expressive* derivate of [SQL DDL](https://wikipedia.org/wiki/Data_definition_language). +We use CDS's [*Conceptual Definition Language (CDL)*](../cds/cdl) as a *human-readable* way to express CDS models. Think of it as a *concise*, and more *expressive* derivate of [SQL DDL](https://wikipedia.org/wiki/Data_definition_language). -For processing at runtime CDS models are compiled into a *machine-readable* plain object notation, called *CSN*, which stands for [*Core Schema Notation (CSN)*](/cds/csn). For deployment to databases, CSN models are translated into native SQL DDL. Supported databases are *[SQLite]* and *[H2]* for development, and *[SAP HANA]* and *[PostgreSQL]* for production. +For processing at runtime CDS models are compiled into a *machine-readable* plain object notation, called *CSN*, which stands for [*Core Schema Notation (CSN)*](../cds/csn). For deployment to databases, CSN models are translated into native SQL DDL. Supported databases are *[SQLite]* and *[H2]* for development, and *[SAP HANA]* and *[PostgreSQL]* for production. ![cdl-csn.drawio](assets/cdl-csn.drawio.svg) -See also *[On the Nature of Models](/cds/models)* in the CDS reference docs. {.learn-more} +See also *[On the Nature of Models](../cds/models)* in the CDS reference docs. {.learn-more} @@ -232,7 +232,7 @@ service BookshopService { Most frequently, services expose denormalized views of underlying domain models. They act as facades to an application's core domain data. The service interface results from the _inferred_ element structures of the given projections. -For example, if we take the [*bookshop* domain model](/get-started/in-a-nutshell#capture-domain-models) as a basis, we could define a service that exposes a flattened view on books with authors names as follows (note and click on the *⇒ Inferred Interface* tab): +For example, if we take the [*bookshop* domain model](../get-started/in-a-nutshell#capture-domain-models) as a basis, we could define a service that exposes a flattened view on books with authors names as follows (note and click on the *⇒ Inferred Interface* tab): ::: code-group @@ -260,7 +260,7 @@ service CatalogService { ::: ::: tip **Single-purposed Services** -The previous example follows the recommended best practice of a *[single-purposed service](/guides/providing-services#single-purposed-services)* which is specialized on *one* specific use case and group of users. Learn more about that in the [Providing Services](/guides/providing-services) guide. +The previous example follows the recommended best practice of a *[single-purposed service](../guides/providing-services#single-purposed-services)* which is specialized on *one* specific use case and group of users. Learn more about that in the [Providing Services](../guides/providing-services) guide. ::: ### Service Providers @@ -480,7 +480,7 @@ entity ListOfBooks as projection on underlying.Books { } ``` -We use [CDS's *Conceptual Query Language (CQL)*](/cds/cql) to write queries in a human-readable way. For reasons of familiarity, CQL is designed as a derivate of SQL, but used in CAP independent of SQL and databases. For example to derive new types as projections on others, or sending OData or GraphQL queries to remote services. +We use [CDS's *Conceptual Query Language (CQL)*](../cds/cql) to write queries in a human-readable way. For reasons of familiarity, CQL is designed as a derivate of SQL, but used in CAP independent of SQL and databases. For example to derive new types as projections on others, or sending OData or GraphQL queries to remote services. Here's a rough comparison of [CQL] with [GraphQL], [OData], and [SQL]: @@ -505,7 +505,7 @@ As apparent from this comparison, we can regard CQL as a superset of the other q ### Queries at Runtime -CAP also uses queries at runtime: an OData or GraphQL request is essentially a query which arrives at a service interface. Respective protocol adapter translate these into *machine-readable* runtime representations of CAP queries (→ see [*Core Query Notation, CQN*](/cds/cqn)), which are then forwarded to and processed by target services. Here's an example, including CQL over http: +CAP also uses queries at runtime: an OData or GraphQL request is essentially a query which arrives at a service interface. Respective protocol adapter translate these into *machine-readable* runtime representations of CAP queries (→ see [*Core Query Notation, CQN*](../cds/cqn)), which are then forwarded to and processed by target services. Here's an example, including CQL over http: ::: code-group @@ -579,7 +579,8 @@ This thoroughly agnostic design is the key enabling quality for several of the m -### ⇒ Hexagonal Architecture {#hexagonal} +### ⇒ Hexagonal Architecture +{#hexagonal} The *[Hexagonal Architecture](https://alistair.cockburn.us/hexagonal-architecture/)* (aka *Ports and Adapters Architecture/Pattern*) as first proposed by Alistair Cockburn in 2005, is quite famous and fancied these days (rightly so). As Cockburn introduces it, its intent is to: @@ -646,18 +647,21 @@ Not only do we address the very same goals, we can also identify several symmetr [Also take notice of the *Squared Hexagons* section in the Anti Patterns guide](bad-practices#squared-hexagons) {.learn-more} -### ⇒ Inner Loop Development {#inner-loop} +### ⇒ Inner Loop Development +{#inner-loop} The database-agnostic design allows us to use in-memory SQLite or H2 databases at development time, as well as for level 1 functional tests, while using SAP HANA for production. This not only speeds up development turnaround times by magnitudes, it also minimises development costs in a similar scale. - +### ⇒ Evolution w/o Disruption +{#evolution} -### ⇒ Late-cut Microservices {#late-cut-mss} +### ⇒ Late-cut Microservices +{#late-cut-mss} -This agnostic design allows [mocking remote services](/guides/using-services#local-mocking), as well as doing late changes to service topologies. For example, you can — and always should — start with co-located services in a single process, while being able to deploy them to separate micro services later on, when you know more about your app and how to scale which parts of it. +This agnostic design allows [mocking remote services](../guides/using-services#local-mocking), as well as doing late changes to service topologies. For example, you can — and always should — start with co-located services in a single process, while being able to deploy them to separate micro services later on, when you know more about your app and how to scale which parts of it. ::: - ## Served Out Of The Box The CAP runtimes in Node.js and Java provide many generic implementations for recurring tasks and best practices, distilled from proven SAP applications. Benefits are significantly **accelerated** development, **minimized boilerplate** code, as well as **increased quality** through single points to fix and optimize, hence **reduced technical debt**. -#### Automatically Serving Requests +### CAP's Generic Service Providers -- [Serving CRUD Requests](/guides/providing-services#generic-providers) -- [Serving Nested Documents](/guides/providing-services#deep-reads-writes) -- [Serving Media Data](/guides/providing-services#serving-media-data) -- [Serving Draft Choreography](/advanced/fiori#draft-support) +- [Serving CRUD Requests](../guides/providing-services#generic-providers) +- [Serving Nested Documents](../guides/providing-services#deep-reads-writes) +- [Serving Media Data](../guides/providing-services#serving-media-data) +- [Serving Draft Choreography](../advanced/fiori#draft-support) #### Handling Recurring Tasks -- [Implicit Pagination](/guides/providing-services#implicit-pagination) -- [Input Validation](/guides/providing-services#input-validation) -- [Authentication](/node.js/authentication) -- [Authorization](/guides/security/authorization) -- [Localization / i18n](/guides/i18n) -- [Concurrency Control](/guides/providing-services#concurrency-control) +- [Implicit Pagination](../guides/providing-services#implicit-pagination) +- [Input Validation](../guides/providing-services#input-validation) +- [Authentication](../node.js/authentication) +- [Authorization](../guides/security/authorization) +- [Localization / i18n](../guides/i18n) +- [Concurrency Control](../guides/providing-services#concurrency-control) #### Enterprise Best Practices -- [Common Reuse Types & Aspects](/cds/common) -- [Managed Data](/guides/domain-modeling#managed-data) -- [Localized Data](/guides/localized-data) -- [Temporal Data](/guides/temporal-data) -- [Verticalization & Extensibility](/guides/extensibility/) +- [Common Reuse Types & Aspects](../cds/common) +- [Managed Data](../guides/domain-modeling#managed-data) +- [Localized Data](../guides/localized-data) +- [Temporal Data](../guides/temporal-data) +- [Verticalization & Extensibility](../guides/extensibility/) -#### Intrinsic Cloud Qualities +### CAP-level Integrations ('Calesi') -- Multitenancy -- Extensibility -- Security -- Scalability -- Resilience +- [Open Telemetry → SAP Cloud Logging, Dynatrace, ...](../plugins/#telemetry) +- [Attachments → SAP Object Store](../plugins/#attachments) +- [Attachments → SAP Document Management Service](../plugins/#@cap-js/sdm) +- [Messaging → SAP Cloud Application Event Hub](../plugins/#event-broker-plugin) +- [Change Tracking](../plugins/#change-tracking) +- [Notifications](../plugins/#notifications) +- [Audit Logging](../plugins/#audit-logging) +- [Personal Data Management](../guides/data-privacy/) -#### **CAP-level Service Integrations ('Calesi')** +[Find more in the **CAP Plugins** page](../plugins/){.learn-more} -- [Open Telemetry → SAP Cloud Logging, Dynatrace, ...](/plugins/#telemetry) -- [Attachments → SAP Object Store](/plugins/#attachments) -- [Attachments → SAP Document Management Service](/plugins/#@cap-js/sdm) -- [Messaging → SAP Cloud Application Event Hub](/plugins/#event-broker-plugin) -- [Change Tracking](/plugins/#change-tracking) -- [Notifications](/plugins/#notifications) -- [Audit Logging](/plugins/#audit-logging) -- [Personal Data Management](/guides/data-privacy/) +[See also the **Features Overview**](./features){.learn-more} + + +### Intrinsic Extensibility + +SaaS customers, verticalization partners, or your teams can... + +- Add/overide annotations, translations, initial data +- Add extension fields, entities, relationships +- Add custom logic → in-app + side-by-side +- Bundle and share that as reuse extension packages +- Feature-toggle such pre-built extension packages per tenant + +All of that done in the same ways that you can do that in your developments + +- Using the same techniques of CDS Aspects and Event Handlers +- Including adaption ad extensions of reuse types/models +- Including extensions to framework-provided services + +And all of that available out-of-the-box, i.e. without you having to create extension points. You would want to restrict who can extend what, though. -[Find more in the **CAP Plugins** page](/plugins/){.learn-more} -[See also the **Features Overview**](./features){.learn-more} - +### Less Code → Less Mistakes -## Open _and_ Opinionated +### Single Points to Fix +### Minimized Lock-Ins -That might sound like a contradiction, but isn't: While CAP certainly gives *opinionated* guidance, we do so without sacrificing openness and flexibility. At the end of the day, you stay in control of which tools or technologies to choose, or which architecture patterns to follow as depicted in the table below. +### Evolution w/o Disruption -| CAP is *Opinionated* in... | CAP is *Open* as... | -| ------------------------------------------------------------ | ------------------------------------------------------------ | -| **Higher-level concepts and APIs** abstracting from and avoiding lock-ins to low-level platform features and protocols | All abstractions follow a glass-box pattern that allows unrestricted access to lower-level things, if required | -| **Best Practices served out of the box** with generic solutions for many recurring tasks | You can always handle things your way in [custom handlers](/guides/providing-services#custom-logic), decide whether to adopt CQRS or Event Sourcing, for example ... while CAP simply tries to get the tedious tasks out of your way. | -| **Out-of-the-box support** for
**[SAP Fiori](https://developers.sap.com/topics/ui-development.html)** and **[SAP HANA](https://developers.sap.com/topics/hana.html)** | You can also choose other UI technologies, like [Vue.js](/get-started/in-a-nutshell#vue), or databases, by providing new database integrations. | -| **Dedicated tools support** provided in [SAP Business Application Studio](/tools/cds-editors#bas) or [Visual Studio Code](/tools/cds-editors#vscode). | CAP doesn't depend on those tools. Everything in CAP can be done using the [`@sap/cds-dk`](/tools/cds-cli) CLI and any editor or IDE of your choice. | - \ No newline at end of file +- AI provides tremendous boosts to productivity → for example: + - **Coding Assicts** → e.g. by [Copilot](https://en.wikipedia.org/wiki/Microsoft_Copilot) in `.cds`, `.js`, even `.md` sources + - **Code Analysis** → detecting [bad practices](bad-practices) → guiding to [best practices](best-practices) + - **Code Generation** → e.g. for tests, test data, ... + - **Project Scaffolding** → for quick head starts + - **Search & Learning Assists** → like Maui, ... +- But doesn't replace the need for **Human Intelligence**! + - There's a different between a GPT-generated one-off thesis and long-lived enterprise software, which needs to adapt and scale to new requirements +- **CAP itself** is a major contribution to AI → its simple, clear concepts, uniform ways to implement and consume services, capire, its openness and visibility in public world, ... + + + +## Caveats + +- From 84e210263b825dfe7a02aa50c55bc4334b5cd59f Mon Sep 17 00:00:00 2001 From: Daniel Hutzel Date: Mon, 2 Dec 2024 14:42:51 +0100 Subject: [PATCH 4/9] fixed more hash links --- cds/annotations.md | 2 +- cds/cdl.md | 4 ++-- guides/databases.md | 2 +- guides/providing-services.md | 4 ++-- java/working-with-cql/query-api.md | 2 +- java/working-with-cql/query-execution.md | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cds/annotations.md b/cds/annotations.md index ed733d3c5..88e837ee9 100644 --- a/cds/annotations.md +++ b/cds/annotations.md @@ -41,7 +41,7 @@ uacp: Used as link target from Help Portal at https://help.sap.com/products/BTP/ | `@readonly ` | see [Input Validation](../guides/providing-services#readonly) | | `@mandatory` | see [Input Validation](../guides/providing-services#mandatory) | | `@assert.unique` | see [Input Validation](../guides/providing-services#assert-unique) | -| `@assert.integrity` | see [Input Validation](../guides/databases#db-constraints) | +| `@assert.integrity` | see [Input Validation](../guides/databases#database-constraints) | | `@assert.target` | see [Input Validation](../guides/providing-services#assert-target) | | `@assert.format` | see [Input Validation](../guides/providing-services#assert-format) | | `@assert.range` | see [Input Validation](../guides/providing-services#assert-range) | diff --git a/cds/cdl.md b/cds/cdl.md index ef7e8e24f..a404526f2 100644 --- a/cds/cdl.md +++ b/cds/cdl.md @@ -363,7 +363,7 @@ In CAP Java, doc comments are automatically enabled by the [CDS Maven Plugin](.. -### Entity Definitions +### Entity Definitions {#entities} Entities are structured types with named and typed elements, @@ -875,7 +875,7 @@ This example is equivalent to the [unmanaged example above](#unmanaged-associati key element `address_ID` being added automatically upon activation to a SQL database. The names of the automatically added foreign key elements cannot be changed. -> Note: For adding foreign key constraints on database level, see [Database Constraints.](../guides/databases#db-constraints). +> Note: For adding foreign key constraints on database level, see [Database Constraints.](../guides/databases#database-constraints). If the target has a single primary key, a default value can be provided. This default applies to the generated foreign key element `address_ID`: diff --git a/guides/databases.md b/guides/databases.md index 685a1f589..31e1514f7 100644 --- a/guides/databases.md +++ b/guides/databases.md @@ -807,7 +807,7 @@ Find here a collection of resources on selected databases and their reference do -## Database Constraints {#db-constraints} +## Database Constraints The information about foreign key relations contained in the associations of CDS models can be used to generate foreign key constraints on the database tables. Within CAP, referential consistency is established only at commit. The ["deferred" concept for foreign key constraints](https://www.sqlite.org/foreignkeys.html) in SQL databases allows the constraints to be checked and enforced at the time of the [COMMIT statement within a transaction](https://www.sqlite.org/lang_transaction.html) rather than immediately when the data is modified, providing more flexibility in maintaining data integrity. diff --git a/guides/providing-services.md b/guides/providing-services.md index d0847176f..f8eb4c858 100644 --- a/guides/providing-services.md +++ b/guides/providing-services.md @@ -792,7 +792,7 @@ You don't need to specify `@assert.unique` constraints for the primary key eleme -### `@assert.target` +### `@assert .target` Annotate a [managed to-one association](../cds/cdl#managed-associations) of a CDS model entity definition with the `@assert.target` annotation to check whether the target entity referenced by the association (the reference's target) @@ -808,7 +808,7 @@ supported, in this case, you will get an error. The `@assert.target` check constraint is meant to **validate user input** and not to ensure referential integrity. Therefore only `CREATE`, and `UPDATE` events are supported (`DELETE` events are not supported). To ensure that every non-null foreign key in a table has a corresponding primary key in the associated/referenced target table -(ensure referential integrity), the [`@assert.integrity`](databases#db-constraints) constraint must be used instead. +(ensure referential integrity), the [`@assert.integrity`](databases#database-constraints) constraint must be used instead. If the reference's target doesn't exist, an HTTP response (error message) is provided to HTTP client applications and logged to stdout in debug mode. The HTTP response body's diff --git a/java/working-with-cql/query-api.md b/java/working-with-cql/query-api.md index 1768f570d..2bed83504 100644 --- a/java/working-with-cql/query-api.md +++ b/java/working-with-cql/query-api.md @@ -534,7 +534,7 @@ Object authorId = book.get("author.Id"); // path access ``` ::: tip -Only to-one associations that are mapped via the primary key elements of the target entity are supported on the select list. The execution is optimized and gives no guarantee that the target entity exists, if this is required use expand or enable [integrity constraints](../../guides/databases#db-constraints) on the database. +Only to-one associations that are mapped via the primary key elements of the target entity are supported on the select list. The execution is optimized and gives no guarantee that the target entity exists, if this is required use expand or enable [integrity constraints](../../guides/databases#database-constraints) on the database. ::: diff --git a/java/working-with-cql/query-execution.md b/java/working-with-cql/query-execution.md index 099dc7863..37142d96d 100644 --- a/java/working-with-cql/query-execution.md +++ b/java/working-with-cql/query-execution.md @@ -194,7 +194,7 @@ For inactive draft entities `@cascade` annotations are ignored. ::: ::: warning _❗ Warning_ -The @cascade annotation is not respected by foreign key constraints on the database. To avoid unexpected behaviour you might have to disable a FK constraint with [`@assert.integrity:false`](../../guides/databases#db-constraints). +The @cascade annotation is not respected by foreign key constraints on the database. To avoid unexpected behaviour you might have to disable a FK constraint with [`@assert.integrity:false`](../../guides/databases#database-constraints). ::: #### Deep Insert / Upsert { #deep-insert-upsert} From 0374ea20bf21ca788f7d1e6d43623acfe2de5af6 Mon Sep 17 00:00:00 2001 From: Steffen Waldmann Date: Mon, 2 Dec 2024 17:19:14 +0100 Subject: [PATCH 5/9] Suggest `url` instead of `database` for `cds.requires.db.credentials` (#1489) --- node.js/cds-connect.md | 4 ++-- node.js/cds-env.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/node.js/cds-connect.md b/node.js/cds-connect.md index c8dedd993..e1c3062e9 100644 --- a/node.js/cds-connect.md +++ b/node.js/cds-connect.md @@ -637,7 +637,7 @@ One prominent exception of that, which you would frequently add to your _package "[development]": { "kind": "sqlite", "credentials": { - "database": "db/bookshop.db" + "url": "db/bookshop.sqlite" } } } @@ -694,7 +694,7 @@ The latter is appropriate in test suites. In productive code, you never provide }, "db": { "credentials": { - "database": "sqlite.db" + "url": "db.sqlite" } } } diff --git a/node.js/cds-env.md b/node.js/cds-env.md index c17c66bcd..965802780 100644 --- a/node.js/cds-env.md +++ b/node.js/cds-env.md @@ -105,7 +105,7 @@ For example, given the following sources: "db": { "kind": "sql", "model": "./db", - "credentials": { "database": ":memory:" } + "credentials": { "url": ":memory:" } } } } From ddd906afac205c7f87b442cdc30299d08946b3f2 Mon Sep 17 00:00:00 2001 From: Steffen Waldmann Date: Mon, 2 Dec 2024 17:20:44 +0100 Subject: [PATCH 6/9] Remove superfluous content from Troubleshooting (#1488) --- get-started/troubleshooting.md | 71 +++------------------------------- 1 file changed, 5 insertions(+), 66 deletions(-) diff --git a/get-started/troubleshooting.md b/get-started/troubleshooting.md index 7f3c8c884..9fceb5a02 100644 --- a/get-started/troubleshooting.md +++ b/get-started/troubleshooting.md @@ -15,7 +15,7 @@ uacp: This page is linked from the Help Portal at https://help.sap.com/products/ ## Setup {#setup} -### Can't start VSCode from Command Line on macOS {#vscode-macos} +### Can't start VS Code from Command Line on macOS {#vscode-macos} In order to start VS Code via the `code` CLI, users on macOS must first run a command (*Shell Command: Install 'code' command in PATH*) to add the VS Code executable to the `PATH` environment variable. Read VS Code's [macOS setup guide](https://code.visualstudio.com/docs/setup/mac) for help. @@ -284,8 +284,8 @@ The project skeleton generated by the CAP Java archetype adds the relevant Sprin However, using an SQL database in CAP Java is fully optional. You can also develop CAP applications that don't use persistence at all. To remove the SQL database support, you need to exclude the JDBC-related dependencies of Spring Boot and CAP Java. This means that CAP Java won't create a Persistence Service instance. -::: tip -Keep in mind, that the default event handlers of Application Services delegate to the Persistence Service. You need to implement your own custom handlers in case you remove the SQL database support. +::: tip Default Application Service event handlers delegate to Persistence Service +You need to implement your own custom handlers in case you remove the SQL database support. ::: You can exclude those dependencies from the `cds-starter-spring-boot` dependency in the `srv/pom.xml`: @@ -378,7 +378,7 @@ In case you want a visual interface tool to work with SQLite, you can use [SQLTo To configure this service in the SAP BPT cockpit on trial, refer to the [SAP HANA Cloud Onboarding Guide](https://www.sap.com/documents/2021/09/7476f8c4-f77d-0010-bca6-c68f7e60039b.html). See [SAP HANA Cloud](https://help.sap.com/docs/HANA_CLOUD) documentation or visit the [SAP HANA Cloud community](https://pages.community.sap.com/topics/hana/cloud) for more details. -::: tip +::: warning HANA needs to be restarted on trial accounts On trial, your SAP HANA Cloud instance will be automatically stopped overnight, according to the server region time zone. That means you need to restart your instance every day before you start working with your trial. ::: @@ -393,7 +393,7 @@ On trial, your SAP HANA Cloud instance will be automatically stopped overnight, | _Solution_ | Add an _undeploy.json_ file to the root of your database module (the _db_ folder by default). This file defines the files **and data** to be deleted. See section [HDI Delta Deployment and Undeploy Allow List](https://help.sap.com/docs/HANA_CLOUD_DATABASE/c2b99f19e9264c4d9ae9221b22f6f589/ebb0a1d1d41e4ab0a06ea951717e7d3d.html) for more details. ::: tip -If you want to keep the data from _.csv_ files and data you've already added, see [SAP Note 2922271](https://launchpad.support.sap.com/#/notes/2922271) for more details. +If you want to keep the data from _.csv_ files and data you've already added, see [SAP Note 2922271](https://me.sap.com/notes/2922271) for more details. ::: You can apply this solution also when using the `cds-mtxs` library. You can either set the options via the environment variable [`HDI_DEPLOY_OPTIONS`](https://help.sap.com/docs/SAP_HANA_PLATFORM/4505d0bdaf4948449b7f7379d24d0f0d/a4bbc2dd8a20442387dc7b706e8d3070.html), the CDS configuration or you can add them to the model update request as `hdi` parameter: @@ -434,13 +434,6 @@ Options in [Saas Provisioning Service upgrade API](../guides/multitenancy/mtxs#e } ``` -### How Do I Resolve Service Creation Errors? - -- If there's more than one SAP HANA database mapped to your Cloud Foundry space, service creation fails. In this case, you need to specify the database: `cf create-service [...] -c "{\"database_id\":\"XXX\" }"` where `XXX` is the ID of the database instance. -- On trial landscapes, you need to use `hanatrial` instead of `hana` as service type: `cf create-service hanatrial [...]` -- When using the `cds-mtx` library with more than one SAP HANA database mapped to your Cloud Foundry space, you can add the service creation parameters via the environment variable `CDS_MTX_PROVISIONING_CONTAINER="{\"provisioning_parameters\":{\"database_id\":\"XXX\"}}"`, where `XXX` represents the ID of the database instance. You can also pass the ID of the database with the subscription request. - - ### How Do I Resolve Deployment Errors? #### Deployment fails — _Cyclic dependencies found_ or _Cycle between files_ @@ -545,60 +538,6 @@ Please check the [configuration for extensibility](../guides/extensibility/custo If data loss is intended, you can disable the check by adding cds.requires.cds.xt.DeploymentService.upgrade.skipExtensionCheck = true to the configuration. ::: -## MTX (legacy) - -This refers to potential problems with the **deprecated** [@sap/cds-mtx](../guides/multitenancy/old-mtx-apis) package. - -### How do I set up MTX with App Router? { #mtx-as-sidecar-with-approuter} - -See [Deploy to Cloud Foundry](../guides/deployment/to-cf) for the basic project and deployment setup. - -### I get a 401 error when logging in to MTX through App Router { #mtx-sidecar-approuter-401} - -See [App Router configuration](../guides/multitenancy/old-mtx-apis#approuter-config) to ensure a correct handling of authentication by both `@sap/approuter` and `@sap/cds-mtx`. - -When logging in, remember to specify the same subdomain you used to get a passcode. Normally this will be the subdomain of the customer subaccount: - -```sh -cds login … -s -``` - -Alternatively, without login: - -```sh -cds extend … -s -``` - -### I get errors with response code 429 from the service-manager service when subscribing a tenant - -You can reduce the number of request by adapting the configuration of the `@sap/instance-manager` library. See also [`@sap/instance-manager` documentation](https://www.npmjs.com/package/@sap/instance-manager). - ```json - "cds": { - "mtx": { - "provisioning": { - "instancemanageroptions": { - "polling_interval_millis": 3000 - } - } - } - } - ``` - -### I get errors with response code 429 from the service-manager service when running a tenant upgrade for all tenants - -You can disable the database clustering for the update. - ```json - "cds": { - "mtx": { - "jobs": { - "clusterbydb": false - } - } - } - ``` -This setting requires at least `@sap/cds-mtx@2.6.2`. - - ## MTA { #mta} ### Why Does My MTA Build Fail? From 3837462067dd1a81641aacae22dbb5ec2d1377c2 Mon Sep 17 00:00:00 2001 From: Daniel Hutzel Date: Mon, 2 Dec 2024 21:45:40 +0100 Subject: [PATCH 7/9] Refactor styles and improve documentation clarity in CAP overview --- .vitepress/theme/styles.scss | 2 +- about/bad-practices.md | 50 ++++++++++++++++++------------------ about/best-practices.md | 34 ++++-------------------- about/index.md | 16 +++++++++--- 4 files changed, 43 insertions(+), 59 deletions(-) diff --git a/.vitepress/theme/styles.scss b/.vitepress/theme/styles.scss index b2d8a9209..e49c35f61 100644 --- a/.vitepress/theme/styles.scss +++ b/.vitepress/theme/styles.scss @@ -347,7 +347,7 @@ main { .prefer::before { content: 'Prefer: '; color: #0a0 } .avoid::before { content: 'Avoid: '; color: #e00 } - .good .green { color:#0a0 }; + .good, .green { color:#0a0 }; .bad, .red, .important { color:darkred; .dark & { color:#e00 } } .grey { color:#777 }; diff --git a/about/bad-practices.md b/about/bad-practices.md index 7b3cd4727..9ffe7acc3 100644 --- a/about/bad-practices.md +++ b/about/bad-practices.md @@ -66,31 +66,31 @@ Alternative frameworks or toolsets follow code generation approaches. Swagger do -| Feature | Swagger | CAP | -|--------------------------------------|:----------------------------------------------------:|:-----------------------------------------:| -| Lines of code for service definition | **~555**{.h3}
written in YAML {.red} | **~11**{.h3}
written in CDS {.green} | -| Lines of code for implementation | **~500**{.h3}
generated
boilerplate {.red} | **0**{.h3} {.green} | -| Size of framework library | 16 MB {.red} | 10 MB {.green} | -| CRUDQ served on DB, including... | ❌ | ✅ | -| Deep Reads & Writes | ❌ | ✅ | -| Deep Hierarchies | ❌ | ✅ | -| Aggregations | ❌ | ✅ | -| Pagination | ❌ | ✅ | -| Sorting | ❌ | ✅ | -| Search | ❌ | ✅ | -| Filtering | ❌ | ✅ | -| Primary Keys | ❌ | ✅ | -| Access Control | ❌ | ✅ | -| Localized Data | ❌ | ✅ | -| Managed Data | ❌ | ✅ | -| Media Data | ❌ | ✅ | -| Temporal Data | ❌ | ✅ | -| Fiori Draft Handling | ❌ | ✅ | -| Exclusive Locking | ❌ | ✅ | -| Conflict Detection (via ETags) | ❌ | ✅ | -| Data Replication (upcomming) | ❌ | ✅ | -| Data Privacy | ❌ | ✅ | -| ... | ❌ | ✅ | +| Feature | Swagger | CAP | +|--------------------------------------|:--------------------:|:---------------------:| +| Lines of code for service definition | **~555**{.h3}{.red} | **~11**{.h3} {.green} | +| Lines of code for implementation | **~500**{.h3} {.red} | **0**{.h3} {.green} | +| Size of framework library | 16 MB {.red} | 10 MB {.green} | +| CRUDQ served on DB, including... | | ✓ | +| Deep Reads & Writes | | ✓ | +| Deep Hierarchies | | ✓ | +| Aggregations | | ✓ | +| Pagination | | ✓ | +| Sorting | | ✓ | +| Search | | ✓ | +| Filtering | | ✓ | +| Primary Keys | | ✓ | +| Access Control | | ✓ | +| Localized Data | | ✓ | +| Managed Data | | ✓ | +| Media Data | | ✓ | +| Temporal Data | | ✓ | +| Fiori Draft Handling | | ✓ | +| Exclusive Locking | | ✓ | +| Conflict Detection (via ETags) | | ✓ | +| Data Replication (upcomming) | | ✓ | +| Data Privacy | | ✓ | +| ... | | ✓ |
diff --git a/about/best-practices.md b/about/best-practices.md index 058798433..26c97e278 100644 --- a/about/best-practices.md +++ b/about/best-practices.md @@ -579,8 +579,11 @@ This thoroughly agnostic design is the key enabling quality for several of the m -### ⇒ Hexagonal Architecture -{#hexagonal} + + +## Hexagonal Architecture + + The *[Hexagonal Architecture](https://alistair.cockburn.us/hexagonal-architecture/)* (aka *Ports and Adapters Architecture/Pattern*) as first proposed by Alistair Cockburn in 2005, is quite famous and fancied these days (rightly so). As Cockburn introduces it, its intent is to: @@ -647,34 +650,7 @@ Not only do we address the very same goals, we can also identify several symmetr [Also take notice of the *Squared Hexagons* section in the Anti Patterns guide](bad-practices#squared-hexagons) {.learn-more} -### ⇒ Inner Loop Development -{#inner-loop} - -The database-agnostic design allows us to use in-memory SQLite or H2 databases at development time, as well as for level 1 functional tests, while using SAP HANA for production. This not only speeds up development turnaround times by magnitudes, it also minimises development costs in a similar scale. - -### ⇒ Evolution w/o Disruption -{#evolution} - -### ⇒ Late-cut Microservices -{#late-cut-mss} - -This agnostic design allows [mocking remote services](../guides/using-services#local-mocking), as well as doing late changes to service topologies. For example, you can — and always should — start with co-located services in a single process, while being able to deploy them to separate micro services later on, when you know more about your app and how to scale which parts of it. -::: - - ## Intrinsic Extensibility diff --git a/about/index.md b/about/index.md index c3d355fe9..22c36b591 100644 --- a/about/index.md +++ b/about/index.md @@ -12,7 +12,7 @@ Value Propositions {.subtitle} ## What is CAP? -The _Cloud Application Programming Model_ (CAP) is a framework of languages, libraries, and tools for building *enterprise-grade* cloud applications. It guides developers along a *golden path* of proven [best practices](best-practices), served [out-of-the-box](#served-out-of-the-box), and hence greatly reduces boilerplate code and tedious recurring tasks. +The _Cloud Application Programming Model_ (CAP) is a framework of languages, libraries, and tools for building *enterprise-grade* cloud applications. It guides developers along a *golden path* of proven [best practices](best-practices), served [out of the box](#served-out-of-the-box), and hence greatly reduces boilerplate code and tedious recurring tasks. In effect, CAP-based projects benefit from a primary [focus on domain](#focus-on-domain) in close collaboration with domain experts, and from [accelerated development](#grow-as-you-go) at minimised costs. CAP's *agnostic design* shields developers from overly technical disciplines, and fosters evolution w/o disruption in a world of rapidly changing technologies. @@ -21,13 +21,17 @@ In effect, CAP-based projects benefit from a primary [focus on domain](#focus-on ## Jumpstart & Grow As You Go... ###### grow-as-you-go -### Jumpstart Development + + +### Jumpstarting Projects Following the principle of **convention over configuration**, there's no need to set up things upfront. CAP allows you to **jumpstart** projects within seconds and have a team starting development right away, using generic providers, on top of a lightweight in-memory database → see [*Getting Started in a Nutshell*](../get-started/in-a-nutshell). -### Fast Turnarounds +### Accelerated Inner Loops + +CAP offers mocks for many platform features, which allow fast dev-test-run cycles with minimal development environment complexity — aka *Airplane Mode*. -CAP also offers **mocks for many platform features**, which allow **fast dev-test-run cycles** with minimal development environment complexity — aka *Airplane Mode*. Similarly, CAP facilitates **integration scenarios** by importing an API from, for example, an SAP S/4HANA backend or from SAP Business Accelerator Hub and running mocks for this locally. +Similarly, CAP facilitates integration scenarios by importing an API from, for example, an SAP S/4HANA backend or from SAP Business Accelerator Hub and running mocks for this locally. ### Loose Coupling @@ -37,6 +41,10 @@ Finally, projects are encouraged to **parallelize workloads**. For example, foll Over time, you **add things gradually**, only when they're needed. For example, you can move ahead to running your apps in close-to-productive setups for integration tests and delivery, without any change in models or code. +### Growing as You Go... + + + ### Late-cut Microservices From 914783191243a10977ebee79a0b19b8bf9178a2e Mon Sep 17 00:00:00 2001 From: Daniel Hutzel Date: Mon, 2 Dec 2024 22:07:29 +0100 Subject: [PATCH 8/9] more fixed links --- about/best-practices.md | 10 +++++----- about/features.md | 28 ++++++++++++++-------------- about/index.md | 4 ++-- cds/cxn.md | 16 ++-------------- guides/providing-services.md | 2 +- links.md | 34 ---------------------------------- 6 files changed, 24 insertions(+), 70 deletions(-) delete mode 100644 links.md diff --git a/about/best-practices.md b/about/best-practices.md index 26c97e278..8031cb0f1 100644 --- a/about/best-practices.md +++ b/about/best-practices.md @@ -7,7 +7,7 @@ status: released Key Concepts & Qualities {.subtitle} -[[toc]] +[[toc]] @@ -30,7 +30,7 @@ The major building blocks are as follows: - [**Command Line Interface** (CLI)](../tools/) — the swiss army knife on the tools and development kit front, complemented by integrations and support in [*SAP Build Code*](), *Visual Studio Code*, *IntelliJ*, and *Eclipse*. -In addition, there is a fast-growing number of [plugins] contributed by open-source and inner-source [communities](/resources/#public-resources) that enhance CAP in various ways, and integrate with additional tools and environments; the [*Calesi* plugins](#the-calesi-effect) are among them. +In addition, there is a fast-growing number of [plugins](../plugins/) contributed by open-source and inner-source [communities](/resources/#public-resources) that enhance CAP in various ways, and integrate with additional tools and environments; the [*Calesi* plugins](#the-calesi-effect) are among them. @@ -94,7 +94,7 @@ entity Authors : cuid, managed { We use CDS's [*Conceptual Definition Language (CDL)*](../cds/cdl) as a *human-readable* way to express CDS models. Think of it as a *concise*, and more *expressive* derivate of [SQL DDL](https://wikipedia.org/wiki/Data_definition_language). -For processing at runtime CDS models are compiled into a *machine-readable* plain object notation, called *CSN*, which stands for [*Core Schema Notation (CSN)*](../cds/csn). For deployment to databases, CSN models are translated into native SQL DDL. Supported databases are *[SQLite]* and *[H2]* for development, and *[SAP HANA]* and *[PostgreSQL]* for production. +For processing at runtime CDS models are compiled into a *machine-readable* plain object notation, called *CSN*, which stands for [*Core Schema Notation (CSN)*](../cds/csn). For deployment to databases, CSN models are translated into native SQL DDL. Supported databases are [*SQLite*](../guides/databases-sqlite.md) and *[H2](../guides/databases-h2.md)* for development, and [_SAP HANA_](../guides/databases-hana.md) and [_PostgreSQL_](../guides/databases-postgres.md) for production. ![cdl-csn.drawio](assets/cdl-csn.drawio.svg) @@ -482,7 +482,7 @@ entity ListOfBooks as projection on underlying.Books { We use [CDS's *Conceptual Query Language (CQL)*](../cds/cql) to write queries in a human-readable way. For reasons of familiarity, CQL is designed as a derivate of SQL, but used in CAP independent of SQL and databases. For example to derive new types as projections on others, or sending OData or GraphQL queries to remote services. -Here's a rough comparison of [CQL] with [GraphQL], [OData], and [SQL]: +Here's a rough comparison of [CQL](../cds/cql.md) with [GraphQL](http://graphql.org), [OData](https://www.odata.org), and [SQL](https://en.wikipedia.org/wiki/SQL): @@ -632,7 +632,7 @@ Let's do a quick time travel by a rough summary of the respective entries in the #### Hexagonal Architecture by CAP -CAP's [agnostic design principles](#agnostic-by-design) are very much in line with the goals of Hexagonal Architecture, and actually give you exactly what these are aiming for: as your applications greatly stay *agnostic* to protocols, and other low-level details, which could lock them in to one specific execution environment, they can be "*developed and tested in isolation*", which in fact is one of CAP's [key guiding principles](#inner-loop) and [value propositions](../about/). Moreover, they become [*resilient* to disrupting changes](../about/best-practices#evolution) in "the outside". +CAP's [agnostic design principles](#agnostic-by-design) are very much in line with the goals of Hexagonal Architecture, and actually give you exactly what these are aiming for: as your applications greatly stay *agnostic* to protocols, and other low-level details, which could lock them in to one specific execution environment, they can be "*developed and tested in isolation*", which in fact is one of CAP's [key value propositions](./index#accelerated-inner-loops). Moreover, they become [*resilient* to disrupting changes](./index#evolution-wo-disruption) in "the outside". Not only do we address the very same goals, we can also identify several symmetries in the way we address and achieve these goals as follows: diff --git a/about/features.md b/about/features.md index 3d2eb2e0b..7b68fe6aa 100644 --- a/about/features.md +++ b/about/features.md @@ -99,20 +99,20 @@ Following is an index of the features currently covered by CAP, with status and ### Providing Services -| Core Framework Features | CDS | Node.js | Java | -|----------------------------------------------------------------------------------------|:-----:|:-------:|:----:| -| [Automatically Serving CRUD Requests](../guides/providing-services#generic-providers) | | | | -| [Deep-Read/Write Structured Documents](../guides/providing-services#deep-reads-writes) | | | | -| [Automatic Input Validation](../guides/providing-services#input-validation) | | | | -| [Auto-filled Primary Keys](../guides/domain-modeling#prefer-uuids-for-keys) | | | | -| [Implicit Paging](../guides/providing-services#implicit-pagination) | | | | -| [Implicit Sorting](../guides/providing-services#implicit-sorting) | | | | -| [Access Control](../guides/security/authorization) | | | | -| [Arrayed Elements](../cds/cdl#arrayed-types) | | | | -| [Streaming & Media Types](../guides/providing-services#serving-media-data) | | | | -| [Conflict Detection through _ETags_](../guides/providing-services#etag) | | | | -| [Authentication via JWT](../guides/security/authorization#prerequisite-authentication) | | | | -| [Basic Authentication](../guides/security/authorization#prerequisite-authentication) | | | | +| Core Framework Features | CDS | Node.js | Java | +|-------------------------------------------------------------------------------------------|:-----:|:-------:|:----:| +| [Automatically Serving CRUD Requests](../guides/providing-services#generic-providers) | | | | +| [Deep-Read/Write Structured Documents](../guides/providing-services#deep-reads-nd-writes) | | | | +| [Automatic Input Validation](../guides/providing-services#input-validation) | | | | +| [Auto-filled Primary Keys](../guides/domain-modeling#prefer-uuids-for-keys) | | | | +| [Implicit Paging](../guides/providing-services#implicit-pagination) | | | | +| [Implicit Sorting](../guides/providing-services#implicit-sorting) | | | | +| [Access Control](../guides/security/authorization) | | | | +| [Arrayed Elements](../cds/cdl#arrayed-types) | | | | +| [Streaming & Media Types](../guides/providing-services#serving-media-data) | | | | +| [Conflict Detection through _ETags_](../guides/providing-services#etag) | | | | +| [Authentication via JWT](../guides/security/authorization#prerequisite-authentication) | | | | +| [Basic Authentication](../guides/security/authorization#prerequisite-authentication) | | | |
diff --git a/about/index.md b/about/index.md index 22c36b591..e3a17a7fd 100644 --- a/about/index.md +++ b/about/index.md @@ -29,7 +29,7 @@ Following the principle of **convention over configuration**, there's no need to ### Accelerated Inner Loops -CAP offers mocks for many platform features, which allow fast dev-test-run cycles with minimal development environment complexity — aka *Airplane Mode*. +CAP offers mocks for many platform features, which allow fast dev-test-run cycles with minimal development environment complexity — aka *Airplane Mode*. Similarly, CAP facilitates integration scenarios by importing an API from, for example, an SAP S/4HANA backend or from SAP Business Accelerator Hub and running mocks for this locally. @@ -94,7 +94,7 @@ Benefits are significantly **accelerated** development, **minimized boilerplate* ### CAP's Generic Service Providers - [Serving CRUD Requests](../guides/providing-services#generic-providers) -- [Serving Nested Documents](../guides/providing-services#deep-reads-writes) +- [Serving Nested Documents](../guides/providing-services#deep-reads-and-writes) - [Serving Media Data](../guides/providing-services#serving-media-data) - [Serving Draft Choreography](../advanced/fiori#draft-support) diff --git a/cds/cxn.md b/cds/cxn.md index d27818cdf..15c8c7503 100644 --- a/cds/cxn.md +++ b/cds/cxn.md @@ -9,10 +9,6 @@ uacp: Used as link target from Help Portal at https://help.sap.com/products/BTP/ # Expression Notation (CXN) { #expressions} -[expression]: #expressions -[expr]: #expressions -[CQN]: ./cqn - Expressions in CDS definitions and queries can be one of: @@ -33,7 +29,6 @@ expr = // one of... ## Literal Values -[val]: #literal-values Literal values are represented as `{val:...}` with property `val` holding the actual literal value as specified in JSON. @@ -56,7 +51,6 @@ cds.parse.expr(`timestamp'2023-04-15T13:05:23Z'`) == {val: '2023-04-15T13:05:23 ## References -[ref]: #references A reference is represented as `{ ref: … }` with property `ref`. This property holds an array of reference segments as plain identifier strings. Only in case of infix filters and/or arguments, the property holds an object `{ id: 'identifier', … }` and all properties except `id` are optional, as shown in the following snippet: @@ -85,7 +79,6 @@ cqn4(`foo[where a=1 group by b having b>2 order by c limit 7].bar`) ## Function Calls -[func]: #functions Function calls are represented as follows: @@ -116,8 +109,6 @@ cqn4(`new ST_Point(2, 3)`) ## Lists { #lists} -[list]: #lists - Lists or tupels are represented as `{list:...}`, with property `list` holding an array of the list entries. Examples: @@ -129,8 +120,6 @@ cds.parse.expr(`(foo, bar)`) == {list: [{ref: ['foo']}, {ref: ['bar']}]} ## Operator Expressions { #operators} -[xpr]: #operators -[_xpr]: #operators Operators join one or more expressions into complex ones, represented as `{xpr:...}`. The property `xpr` holds a sequence of operators and operands. @@ -141,7 +130,7 @@ _operand = expr _operator = string ``` -* *Operands* can be any kind of [expression] +* *Operands* can be any kind of expression * *Operators* are represented as plain strings, like `'='` or `'and'` * Parentheses `( ... )` around sub-expressions are represented as nested `xpr` @@ -179,7 +168,6 @@ cds.parse.expr(`x<10 ? y : z`) ==//> returns: ## Binding Parameters -[param]: #parameters Binding parameters for prepared statements are represented as `{ref:..., param:true}` with values for `ref` as follows. @@ -196,4 +184,4 @@ cds.parse.expr(`x=?`) == [{ref:['x']}, '=', {ref:['?'], param:true}] ## Sub Queries -[See CQN][CQN]{.learn-more} +[See CQN](cqn){.learn-more} diff --git a/guides/providing-services.md b/guides/providing-services.md index f8eb4c858..69d08b0a3 100644 --- a/guides/providing-services.md +++ b/guides/providing-services.md @@ -182,7 +182,7 @@ filtering and sorting is not available for `virtual` elements. ::: -### Deep Reads / Writes +### Deep Reads and Writes CDS and the runtimes have advanced support for modeling and serving document-oriented data. The runtimes provide generic handlers for serving deeply nested document structures out of the box as documented in here. diff --git a/links.md b/links.md deleted file mode 100644 index ae12e91a5..000000000 --- a/links.md +++ /dev/null @@ -1,34 +0,0 @@ - - - -[PostgreSQL]: /guides/databases-postgres -[SAP HANA]: /guides/databases-hana -[SQLite]: /guides/databases-sqlite -[H2]: /guides/databases-h2 - -[Getting Started]: /get-started/ -[Cookbook]: /guides/ -[Advanced]: /guides/ -[Node.js runtime]: /node.js/ -[Java runtime]: /java/ -[CAP Plugins]: /plugins/ -[Plugins]: /plugins/ -[Tools]: /tools/ - -[CDS]: /cds/ -[CDL]: /cds/cdl -[CSN]: /cds/csn -[CQL]: /cds/cql -[CQN]: /cds/cqn - -[cap/samples]: https://github.com/sap-samples/cloud-cap-samples -[cap/sflight]: https://github.com/sap-samples/cap-sflight - -[bookshop]: /get-started/in-a-nutshell - -[Node.js]: https://nodejs.org/ -[Java]: https://www.oracle.com/java/ -[GraphQL]: https://graphql.org/ -[OData]: https://www.odata.org/ -[REST]: https://restfulapi.net/ -[SQL]: https://en.wikipedia.org/wiki/SQL \ No newline at end of file From 0f6d1db1669e6469b95c96174bd74bd1ce51a275 Mon Sep 17 00:00:00 2001 From: hjboth <124381150+hjboth@users.noreply.github.com> Date: Tue, 3 Dec 2024 07:53:58 +0100 Subject: [PATCH 9/9] Add `$Null()` as value alternative (#1361) also add header line to get a link target for the special null case, makes it much easier to locate that snippet in answers and within capire itself. --------- Co-authored-by: Andre Meyering --- advanced/odata.md | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/advanced/odata.md b/advanced/odata.md index ec2151848..13f1ad0ec 100644 --- a/advanced/odata.md +++ b/advanced/odata.md @@ -336,14 +336,16 @@ Primitive annotation values, meaning Strings, Numbers, `true`, and `false` are m ``` -Rendering a `null` value must be done as dynamic expression or as an [annotation expression](#expression-annotations): +#### Null Value { #null-value } + +A `null` value can be set either as an [annotation expression](#expression-annotations) or as a [dynamic expression](#dynamic-expressions): ```cds -@Some.Null: { $edmJson: { $Null } } -// or -@Some.Null: (null) +@Some.NullXpr: (null) // annotation expression, short form +@Some.NullFunc: ($Null()) // annotation expression, functional form +@Some.NullDyn: { $edmJson: { $Null } } // dynamic expression ``` -Both result in the following: +All three expressions result in the following rendering: ```xml @@ -662,7 +664,8 @@ The following operators and clauses of CDL are supported: * Logical: `and`, `or`, `not` * Relational: `=`, `<>`, `!=`, `<`, `<=`, `>`, `>=`, `in`, `between ... and ...` * Unary `+` and `-` -* Arithmetic: `+`, `-`, `*`, `/`, `||` +* Arithmetic: `+`, `-`, `*`, `/` +* Concat: `||` * `cast(...)` Example: @@ -718,7 +721,7 @@ service S { In addition, the following functions are supported: -* `$Null()` representing the `null` value +* `$Null()` representing the `null` value [`Null`]([annotation expression](#null-value)). * `Div(...)` (or `$Div(...)`) and `Mod(...)` (or `$Mod(...)`) for integer division and modulo * [`Has(...)`](https://docs.oasis-open.org/odata/odata/v4.02/csd01/part2-url-conventions/odata-v4.02-csd01-part2-url-conventions.html#Has) (or `$Has(...)`) * the functions listed in sections