From 8cdad22630c23e843a8115eccfd720e820fc1cdc Mon Sep 17 00:00:00 2001 From: Patrice Bender Date: Tue, 1 Apr 2025 16:49:39 +0200 Subject: [PATCH 01/18] feat: standard database functions everywhere The cds-compiler and the node database services now are on-par with regard to the supported standard database functions. With this change we move the standard database function section out of the "runtime" part. Once CAP Java closed the gap, we can remove the disclaimer that this is only available for cds-compiler + node database services --- guides/databases.md | 193 ++++++++++++++++++++++++++++++-------------- 1 file changed, 134 insertions(+), 59 deletions(-) diff --git a/guides/databases.md b/guides/databases.md index 5e2979bf3..ce2648f29 100644 --- a/guides/databases.md +++ b/guides/databases.md @@ -22,9 +22,9 @@ impl-variants: true
-### Migrating to New Database Services? {.node} +### Migrating to the `@cap-js/` Database Services? {.node} -With CDS 8, the new database services for SQLite, PostgreSQL, and SAP HANA are now generally available. It's highly recommended to migrate. You can find instructions in the [migration guide](databases-sqlite#migration). Although the guide is written in the context of the new SQLite Service, the same hints apply to PostgreSQL and SAP HANA. +With CDS 8, the [`@cap-js`](https://github.com/cap-js/cds-dbs) database services for SQLite, PostgreSQL, and SAP HANA are generally available. It's highly recommended to migrate. You can find instructions in the [migration guide](databases-sqlite#migration). Although the guide is written in the context of the SQLite Service, the same hints apply to PostgreSQL and SAP HANA. ### Adding Database Packages {.node} @@ -358,63 +358,6 @@ The operator mappings are available for runtime queries only, but not in CDS fil ::: -### Functions Mappings for Runtime Queries {.node} - -A specified set of standard functions is supported in a **database-agnostic**, hence portable way, and translated to database-specific variants or polyfills. -Note that these functions are only supported within runtime queries, but not in CDS files. -This set of functions are by large the same as specified in OData: - -* `concat(x,y,...)` — concatenates the given strings or numbers -* `trim(x)` — removes leading and trailing whitespaces -* `contains(x,y)` — checks whether `y` is contained in `x`, may be fuzzy -* `startswith(x,y)` — checks whether `y` starts with `x` -* `endswith(x,y)` — checks whether `y` ends with `x` -* `matchespattern(x,y)` — checks whether `x` matches regex `y` -* `substring(x,i,n?)` 1 — - Extracts a substring from `x` starting at index `i` (0-based) with optional length `n`. - * **`i`**: Positive starts at `i`, negative starts `i` before the end. - * **`n`**: Positive extracts `n` items; omitted extracts to the end; negative is invalid. -* `indexof(x,y)` 1 — returns the index of the first occurrence of `y` in `x` -* `length(x)` — returns the length of string `x` -* `tolower(x)` — returns all-lowercased `x` -* `toupper(x)` — returns all-uppercased `x` -* `ceiling(x)` — rounds the input numeric parameter up to the nearest numeric value -* `floor(x)` — rounds the input numeric parameter down to the nearest numeric value -* `round(x)` — rounds the input numeric parameter to the nearest numeric value. - The mid-point between two integers is rounded away from zero, i.e. 0.5 is rounded to 1 and ‑0.5 is rounded to -1. -* `year(x)` `month(x)`, `day(x)`, `hour(x)`, `minute(x)`, `second(x)` — - returns parts of a datetime for a given `cds.DateTime` / `cds.Date` / `cds.Time` -* `time(x)`, `date(x)` - returns a string representing the `time` / `date` for a given `cds.DateTime` / `cds.Date` / `cds.Time` -* `fractionalseconds(x)` - returns a a `Decimal` representing the fractions of a second for a given `cds.Timestamp` -* `maxdatetime()` - returns the latest possible point in time: `'9999-12-31T23:59:59.999Z'` -* `mindatetime()` — returns the earliest possible point in time: `'0001-01-01T00:00:00.000Z'` -* `totalseconds(x)` — returns the duration of the value in total seconds, including fractional seconds. The [OData spec](https://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part2-url-conventions.html#sec_totalseconds) defines the input as EDM.Duration: `P12DT23H59M59.999999999999S` -* `now()` — returns the current datetime -* `min(x)` `max(x)` `sum(x)` `average(x)` `count(x)`, `countdistinct(x)` — aggregate functions -* `search(xs,y)` — checks whether `y` is contained in any of `xs`, may be fuzzy → [see Searching Data](../guides/providing-services#searching-data) -* `session_context(v)` — with standard variable names → [see Session Variables](#session-variables) -> 1 These functions work zero-based. E.g., `substring('abcdef', 1, 3)` returns 'bcd' - -> You have to write these functions exactly as given; all-uppercase usages aren't supported. - -In addition to the standard functions, which all `@cap-js` database services support, `@cap-js/sqlite` and `@cap-js/postgres` also support these common SAP HANA functions, to further increase the scope for portable testing: - -* `years_between` — Computes the number of years between two specified dates. -* `months_between` — Computes the number of months between two specified dates. -* `days_between` — Computes the number of days between two specified dates. -* `seconds_between` — Computes the number of seconds between two specified dates. -* `nano100_between` — Computes the time difference between two dates to the precision of 0.1 microseconds. - -The database service implementation translates these to the best-possible native SQL functions, thus enhancing the extent of **portable** queries. -With open source and the new database service architecture, we also have methods in place to enhance this list by custom implementation. - -> For the SAP HANA functions, both usages are allowed: all-lowercase as given above, as well as all-uppercase. - -::: warning Runtime Only -The function mappings are available for runtime queries only, but not in CDS files. -::: - - ### Session Variables {.node} The API shown below, which includes the function `session_context()` and specific pseudo variable names, is supported by **all** new database services, that is, *SQLite*, *PostgreSQL* and *SAP HANA*. @@ -940,6 +883,138 @@ Instead, they protect the integrity of your data in the database layer against p → Use [`@assert.target`](providing-services#assert-target) for corresponding input validations. ::: +## Standard Database Functions + +A specified set of standard functions - inspired by [OData](https://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part2-url-conventions.html#sec_StringandCollectionFunctions) and [SAP HANA](https://help.sap.com/docs/HANA_SERVICE_CF/7c78579ce9b14a669c1f3295b0d8ca16/f12b86a6284c4aeeb449e57eb5dd3ebd.html?locale=en-US) - is supported in a **database-agnostic**, hence portable way, and translated to database-specific variants or polyfills. + +### OData standard functions + +The cds-compiler and all CAP Node.js database services come with out of the box support for common OData functions. + +::: warning Case Sensitivity +The OData function mappings are case-sensitive and must be written as in the list below. +::: + +#### String Functions + +- `concat(x, y, ...)` + Concatenates the given strings or numbers. + +- `trim(x)` + Removes leading and trailing whitespaces. + +- `contains(x, y)` + Checks whether `y` is contained in `x` (fuzzy matching may apply). + +- `startswith(x, y)` + Checks whether `y` starts with `x`. + +- `endswith(x, y)` + Checks whether `y` ends with `x`. + +- `matchespattern(x, y)` + Checks whether `x` matches the regular expression `y`. + +- `substring(x, i, n?)` 1 + Extracts a substring from `x` starting at index `i` (0-based) with an optional length `n`. + - `i`: + - Positive: starts at index `i` + - Negative: starts `i` positions before the end + - `n`: + - Positive: extracts `n` characters + - Omitted: extracts until the end of the string + - Negative: invalid + +- `indexof(x, y)` 1 + Returns the index of the first occurrence of `y` in `x`. + +- `length(x)` + Returns the length of the string `x`. + +- `tolower(x)` + Converts all characters in `x` to lowercase. + +- `toupper(x)` + Converts all characters in `x` to uppercase. + +1 These functions work zero-based. E.g., `substring('abcdef', 1, 3)` returns 'bcd' + +#### Numeric Functions + +- `ceiling(x)` + Rounds the numeric parameter up to the nearest integer. + +- `floor(x)` + Rounds the numeric parameter down to the nearest integer. + +- `round(x)` + Rounds the numeric parameter to the nearest integer. + The midpoint between two integers is rounded away from zero (e.g., `0.5` → `1` and `-0.5` → `-1`). + +#### Date and Time Functions + +- `year(x)`, `month(x)`, `day(x)`, `hour(x)`, `minute(x)`, `second(x)` + Extracts specific parts of a datetime value for a given `cds.DateTime`, `cds.Date`, or `cds.Time`. + +- `time(x)`, `date(x)` + Returns a string representing the time or date from a given `cds.DateTime`, `cds.Date`, or `cds.Time`. + +- `fractionalseconds(x)` + Returns a `Decimal` representing the fractional seconds for a given `cds.Timestamp`. + +- `maxdatetime()` + Returns the latest possible point in time: `'9999-12-31T23:59:59.999Z'`. + +- `mindatetime()` + Returns the earliest possible point in time: `'0001-01-01T00:00:00.000Z'`. + +- `totalseconds(x)` + Returns the duration of the value in total seconds, including fractional seconds. + Refer to the [OData spec](https://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part2-url-conventions.html#sec_totalseconds) for more details on EDM.Duration (e.g., `P12DT23H59M59.999999999999S`). + +- `now()` + Returns the current datetime. + +#### Aggregate Functions + +- `min(x)`, `max(x)`, `sum(x)`, `average(x)`, `count(x)`, `countdistinct(x)` + Standard aggregate functions used to calculate minimum, maximum, sum, average, count, and distinct count of values. + + +### SAP HANA Functions + +In addition to the OData standard functions, the cds-compiler and all CAP Node.js database services come with +out of the box support for some common SAP HANA functions, to further increase the scope for portable testing: + +::: warning Upper- and Lowercase are supported +For the SAP HANA functions, both usages are allowed: all-lowercase as given above, as well as all-uppercase. +::: + +- `years_between` + Computes the number of years between two specified dates. +- `months_between` + Computes the number of months between two specified dates. +- `days_between` + Computes the number of days between two specified dates. +- `seconds_between` + Computes the number of seconds between two specified dates. +- `nano100_between` + Computes the time difference between two dates to the precision of 0.1 microseconds. + +The cds-compiler / the database service implementation translates these to the best-possible native SQL functions, thus enhancing the extent of **portable** queries. With open source and the new database service architecture, we also have methods in place to enhance this list by custom implementation. + +### Special Runtime Functions + +In addition to the OData and SAP HANA standard functions, the **CAP runtimes** provides special functions that are only available for runtime queries: + +- `search(xs, y)` + Checks whether `y` is contained in any element of `xs` (fuzzy matching may apply). + See [Searching Data](../guides/providing-services#searching-data) for more details. + +- `session_context(v)` + Utilizes standard variable names to maintain session context. + Refer to [Session Variables](#session-variables) for additional information. + ## Using Native Features { #native-db-functions} From dc8994bf2e2b282c784b39123988ff83eb3c7030 Mon Sep 17 00:00:00 2001 From: Patrice Bender Date: Tue, 1 Apr 2025 16:59:32 +0200 Subject: [PATCH 02/18] be more precise --- guides/databases.md | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/guides/databases.md b/guides/databases.md index ce2648f29..e22e6c4d9 100644 --- a/guides/databases.md +++ b/guides/databases.md @@ -954,10 +954,10 @@ The OData function mappings are case-sensitive and must be written as in the lis #### Date and Time Functions - `year(x)`, `month(x)`, `day(x)`, `hour(x)`, `minute(x)`, `second(x)` - Extracts specific parts of a datetime value for a given `cds.DateTime`, `cds.Date`, or `cds.Time`. + Extracts and returns specific date / time parts as integer value from a given `cds.DateTime`, `cds.Date`, or `cds.Time`. - `time(x)`, `date(x)` - Returns a string representing the time or date from a given `cds.DateTime`, `cds.Date`, or `cds.Time`. + Extracts and returns a time or date from a given `cds.DateTime`, `cds.Date`, or `cds.Time`. - `fractionalseconds(x)` Returns a `Decimal` representing the fractional seconds for a given `cds.Timestamp`. @@ -968,13 +968,6 @@ The OData function mappings are case-sensitive and must be written as in the lis - `mindatetime()` Returns the earliest possible point in time: `'0001-01-01T00:00:00.000Z'`. -- `totalseconds(x)` - Returns the duration of the value in total seconds, including fractional seconds. - Refer to the [OData spec](https://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part2-url-conventions.html#sec_totalseconds) for more details on EDM.Duration (e.g., `P12DT23H59M59.999999999999S`). - -- `now()` - Returns the current datetime. - #### Aggregate Functions - `min(x)`, `max(x)`, `sum(x)`, `average(x)`, `count(x)`, `countdistinct(x)` @@ -1015,7 +1008,8 @@ In addition to the OData and SAP HANA standard functions, the **CAP runtimes** p Utilizes standard variable names to maintain session context. Refer to [Session Variables](#session-variables) for additional information. - +- `now()` + Returns the current datetime. ## Using Native Features { #native-db-functions} From fa71952f39d67c4d691d6cd27ddbaf07dbdd0f29 Mon Sep 17 00:00:00 2001 From: Patrice Bender Date: Fri, 25 Apr 2025 13:59:47 +0200 Subject: [PATCH 03/18] fixes --- guides/databases.md | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/guides/databases.md b/guides/databases.md index e22e6c4d9..14bed3b1b 100644 --- a/guides/databases.md +++ b/guides/databases.md @@ -897,25 +897,25 @@ The OData function mappings are case-sensitive and must be written as in the lis #### String Functions -- `concat(x, y, ...)` +- `concat(x, y, ...)` Concatenates the given strings or numbers. -- `trim(x)` +- `trim(x)` Removes leading and trailing whitespaces. -- `contains(x, y)` +- `contains(x, y)` Checks whether `y` is contained in `x` (fuzzy matching may apply). -- `startswith(x, y)` +- `startswith(x, y)` Checks whether `y` starts with `x`. -- `endswith(x, y)` +- `endswith(x, y)` Checks whether `y` ends with `x`. -- `matchespattern(x, y)` +- `matchespattern(x, y)` Checks whether `x` matches the regular expression `y`. -- `substring(x, i, n?)` 1 +- `substring(x, i, n?)` 1 Extracts a substring from `x` starting at index `i` (0-based) with an optional length `n`. - `i`: - Positive: starts at index `i` @@ -941,19 +941,19 @@ The OData function mappings are case-sensitive and must be written as in the lis #### Numeric Functions -- `ceiling(x)` +- `ceiling(x)` Rounds the numeric parameter up to the nearest integer. -- `floor(x)` +- `floor(x)` Rounds the numeric parameter down to the nearest integer. -- `round(x)` +- `round(x)` Rounds the numeric parameter to the nearest integer. The midpoint between two integers is rounded away from zero (e.g., `0.5` → `1` and `-0.5` → `-1`). #### Date and Time Functions -- `year(x)`, `month(x)`, `day(x)`, `hour(x)`, `minute(x)`, `second(x)` +- `year(x)`, `month(x)`, `day(x)`, `hour(x)`, `minute(x)`, `second(x)` Extracts and returns specific date / time parts as integer value from a given `cds.DateTime`, `cds.Date`, or `cds.Time`. - `time(x)`, `date(x)` @@ -983,15 +983,15 @@ out of the box support for some common SAP HANA functions, to further increase t For the SAP HANA functions, both usages are allowed: all-lowercase as given above, as well as all-uppercase. ::: -- `years_between` +- `years_between` Computes the number of years between two specified dates. -- `months_between` +- `months_between` Computes the number of months between two specified dates. -- `days_between` +- `days_between` Computes the number of days between two specified dates. -- `seconds_between` +- `seconds_between` Computes the number of seconds between two specified dates. -- `nano100_between` +- `nano100_between` Computes the time difference between two dates to the precision of 0.1 microseconds. The cds-compiler / the database service implementation translates these to the best-possible native SQL functions, thus enhancing the extent of **portable** queries. With open source and the new database service architecture, we also have methods in place to enhance this list by custom implementation. @@ -1000,7 +1000,7 @@ The cds-compiler / the database service implementation translates these to the b In addition to the OData and SAP HANA standard functions, the **CAP runtimes** provides special functions that are only available for runtime queries: -- `search(xs, y)` +- `search(xs, y)` Checks whether `y` is contained in any element of `xs` (fuzzy matching may apply). See [Searching Data](../guides/providing-services#searching-data) for more details. @@ -1008,7 +1008,7 @@ In addition to the OData and SAP HANA standard functions, the **CAP runtimes** p Utilizes standard variable names to maintain session context. Refer to [Session Variables](#session-variables) for additional information. -- `now()` +- `now()` Returns the current datetime. ## Using Native Features { #native-db-functions} From f6a4de8e0090521b46232c978dcfd0fd8b538d22 Mon Sep 17 00:00:00 2001 From: Patrice Bender Date: Fri, 25 Apr 2025 15:07:12 +0200 Subject: [PATCH 04/18] some more suggestions --- guides/databases.md | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/guides/databases.md b/guides/databases.md index 14bed3b1b..26760971c 100644 --- a/guides/databases.md +++ b/guides/databases.md @@ -885,16 +885,36 @@ Instead, they protect the integrity of your data in the database layer against p ## Standard Database Functions -A specified set of standard functions - inspired by [OData](https://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part2-url-conventions.html#sec_StringandCollectionFunctions) and [SAP HANA](https://help.sap.com/docs/HANA_SERVICE_CF/7c78579ce9b14a669c1f3295b0d8ca16/f12b86a6284c4aeeb449e57eb5dd3ebd.html?locale=en-US) - is supported in a **database-agnostic**, hence portable way, and translated to database-specific variants or polyfills. +A specified set of standard functions - inspired by [OData](https://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part2-url-conventions.html#sec_StringandCollectionFunctions) and [SAP HANA](https://help.sap.com/docs/hana-cloud-database/sap-hana-cloud-sap-hana-database-sql-reference-guide/alphabetical-list-of-functions?locale=en-US) - is supported in a **database-agnostic**, hence portable way, and translated to the best-possible native SQL functions or polyfills . ### OData standard functions The cds-compiler and all CAP Node.js database services come with out of the box support for common OData functions. ::: warning Case Sensitivity -The OData function mappings are case-sensitive and must be written as in the list below. +The OData function mappings are case-sensitive and must be written as in the list below. ::: +e.g. + +```cds +entity V as select from Books { + startswith(title, 'Raven') as lowerCase, // mapped to native SQL equivalent + startsWith(title, 'Raven') as camelCase, // passed as-is +} +``` + +```sql +CREATE VIEW V AS SELECT + (CASE WHEN locate(title, 'Raven') = 1 THEN TRUE ELSE FALSE END) AS lowerCase, + -- the below will most likely fail on SAP HANA + startsWith(title, 'Raven') AS camelCase +FROM Books; +``` + +💡 If you have your own User-Defined Functions (UDFs) with the same name, you can still use them, +by deviating from the casing given below. + #### String Functions - `concat(x, y, ...)` @@ -994,22 +1014,20 @@ For the SAP HANA functions, both usages are allowed: all-lowercase as given abov - `nano100_between` Computes the time difference between two dates to the precision of 0.1 microseconds. -The cds-compiler / the database service implementation translates these to the best-possible native SQL functions, thus enhancing the extent of **portable** queries. With open source and the new database service architecture, we also have methods in place to enhance this list by custom implementation. - ### Special Runtime Functions In addition to the OData and SAP HANA standard functions, the **CAP runtimes** provides special functions that are only available for runtime queries: -- `search(xs, y)` - Checks whether `y` is contained in any element of `xs` (fuzzy matching may apply). +- `search(x, y)` + Checks whether `y` is contained in any element of `x` (fuzzy matching may apply). See [Searching Data](../guides/providing-services#searching-data) for more details. -- `session_context(v)` +- `session_context()` Utilizes standard variable names to maintain session context. Refer to [Session Variables](#session-variables) for additional information. - `now()` - Returns the current datetime. + Returns the current timestamp. ## Using Native Features { #native-db-functions} From cea35b41852ebcb85a68267690709eb38ba9df4a Mon Sep 17 00:00:00 2001 From: Patrice Bender Date: Fri, 25 Apr 2025 15:52:29 +0200 Subject: [PATCH 05/18] added hana functions links --- guides/databases.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/guides/databases.md b/guides/databases.md index 26760971c..25e8bb561 100644 --- a/guides/databases.md +++ b/guides/databases.md @@ -1004,15 +1004,15 @@ For the SAP HANA functions, both usages are allowed: all-lowercase as given abov ::: - `years_between` - Computes the number of years between two specified dates. + Computes the number of years between two specified dates. ([link](https://help.sap.com/docs/hana-cloud-database/sap-hana-cloud-sap-hana-database-sql-reference-guide/years-between-function-datetime?locale=en-US)) - `months_between` - Computes the number of months between two specified dates. + Computes the number of months between two specified dates. ([link](https://help.sap.com/docs/hana-cloud-database/sap-hana-cloud-sap-hana-database-sql-reference-guide/months-between-function-datetime?locale=en-US)) - `days_between` - Computes the number of days between two specified dates. + Computes the number of days between two specified dates. ([link](https://help.sap.com/docs/hana-cloud-database/sap-hana-cloud-sap-hana-database-sql-reference-guide/days-between-function-datetime?locale=en-US)) - `seconds_between` - Computes the number of seconds between two specified dates. + Computes the number of seconds between two specified dates. ([link](https://help.sap.com/docs/hana-cloud-database/sap-hana-cloud-sap-hana-database-sql-reference-guide/seconds-between-function-datetime?locale=en-US)) - `nano100_between` - Computes the time difference between two dates to the precision of 0.1 microseconds. + Computes the time difference between two dates to the precision of 0.1 microseconds. ([link](https://help.sap.com/docs/hana-cloud-database/sap-hana-cloud-sap-hana-database-sql-reference-guide/nano100-between-function-datetime?locale=en-US)) ### Special Runtime Functions From ad564e10f5c4d08c50ed3b6c7532eb3c6d82d15a Mon Sep 17 00:00:00 2001 From: Patrice Bender Date: Fri, 25 Apr 2025 17:02:48 +0200 Subject: [PATCH 06/18] how to turn them on --- guides/databases.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/guides/databases.md b/guides/databases.md index 25e8bb561..65fa22584 100644 --- a/guides/databases.md +++ b/guides/databases.md @@ -885,7 +885,20 @@ Instead, they protect the integrity of your data in the database layer against p ## Standard Database Functions -A specified set of standard functions - inspired by [OData](https://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part2-url-conventions.html#sec_StringandCollectionFunctions) and [SAP HANA](https://help.sap.com/docs/hana-cloud-database/sap-hana-cloud-sap-hana-database-sql-reference-guide/alphabetical-list-of-functions?locale=en-US) - is supported in a **database-agnostic**, hence portable way, and translated to the best-possible native SQL functions or polyfills . +A specified set of standard functions - inspired by [OData](https://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part2-url-conventions.html#sec_StringandCollectionFunctions) and [SAP HANA](https://help.sap.com/docs/hana-cloud-database/sap-hana-cloud-sap-hana-database-sql-reference-guide/alphabetical-list-of-functions?locale=en-US) - is supported in a **database-agnostic**, hence portable way, and translated to the best-possible native SQL functions or polyfills. + +To enable the mapping, set: + +```json +"cds": { + "cdsc": { + "standardDatabaseFunctions": true + } +} +``` + ### OData standard functions From 7cb9ea354eba7bbbbd390d419ec00130d22968a9 Mon Sep 17 00:00:00 2001 From: Patrice Bender Date: Mon, 28 Apr 2025 13:35:05 +0200 Subject: [PATCH 07/18] add disclaimer like suggested --- guides/databases.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/guides/databases.md b/guides/databases.md index 65fa22584..82fa31194 100644 --- a/guides/databases.md +++ b/guides/databases.md @@ -887,15 +887,15 @@ Instead, they protect the integrity of your data in the database layer against p A specified set of standard functions - inspired by [OData](https://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part2-url-conventions.html#sec_StringandCollectionFunctions) and [SAP HANA](https://help.sap.com/docs/hana-cloud-database/sap-hana-cloud-sap-hana-database-sql-reference-guide/alphabetical-list-of-functions?locale=en-US) - is supported in a **database-agnostic**, hence portable way, and translated to the best-possible native SQL functions or polyfills. -To enable the mapping, set: +Those functions are automatically mapped during runtime (Node.js) already today. +To switch on the same mappings for your CDL files, you have to set: + +cds.cdsc.standardDatabaseFunctions = true + +::: tip +this will be the default starting with `@sap/cds-compiler >= 9` and hence is only needed for earlier versions. +::: -```json -"cds": { - "cdsc": { - "standardDatabaseFunctions": true - } -} -``` From 6c4b0c91e91e6831089cb4aa480f6b780fbe96e0 Mon Sep 17 00:00:00 2001 From: Patrice Bender Date: Mon, 28 Apr 2025 13:50:25 +0200 Subject: [PATCH 08/18] string funcs are case-sensitive --- guides/databases.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/guides/databases.md b/guides/databases.md index 82fa31194..b2e46ada2 100644 --- a/guides/databases.md +++ b/guides/databases.md @@ -937,17 +937,20 @@ by deviating from the casing given below. Removes leading and trailing whitespaces. - `contains(x, y)` - Checks whether `y` is contained in `x` (fuzzy matching may apply). + Checks whether `y` is contained in `x` (case-sensitive). - `startswith(x, y)` - Checks whether `y` starts with `x`. + Checks whether `y` starts with `x` (case-sensitive). - `endswith(x, y)` - Checks whether `y` ends with `x`. + Checks whether `y` ends with `x` (case-sensitive). - `matchespattern(x, y)` Checks whether `x` matches the regular expression `y`. +- `indexof(x, y)` 1 + Returns the index of the first occurrence of `y` in `x` (case-sensitive). + - `substring(x, i, n?)` 1 Extracts a substring from `x` starting at index `i` (0-based) with an optional length `n`. - `i`: @@ -958,9 +961,6 @@ by deviating from the casing given below. - Omitted: extracts until the end of the string - Negative: invalid -- `indexof(x, y)` 1 - Returns the index of the first occurrence of `y` in `x`. - - `length(x)` Returns the length of the string `x`. From 655939db75eed1ff3adf758e3af2f983cd88981d Mon Sep 17 00:00:00 2001 From: Patrice Bender Date: Mon, 28 Apr 2025 14:36:10 +0200 Subject: [PATCH 09/18] fallback anchor --- guides/databases.md | 1 + 1 file changed, 1 insertion(+) diff --git a/guides/databases.md b/guides/databases.md index b2e46ada2..db5337dc1 100644 --- a/guides/databases.md +++ b/guides/databases.md @@ -884,6 +884,7 @@ Instead, they protect the integrity of your data in the database layer against p ::: ## Standard Database Functions +{ #functions-mappings-for-runtime-queries } A specified set of standard functions - inspired by [OData](https://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part2-url-conventions.html#sec_StringandCollectionFunctions) and [SAP HANA](https://help.sap.com/docs/hana-cloud-database/sap-hana-cloud-sap-hana-database-sql-reference-guide/alphabetical-list-of-functions?locale=en-US) - is supported in a **database-agnostic**, hence portable way, and translated to the best-possible native SQL functions or polyfills. From 9bf08aeb756fcf7ec692df162173f91d26f14637 Mon Sep 17 00:00:00 2001 From: Patrice Bender Date: Mon, 28 Apr 2025 15:50:20 +0200 Subject: [PATCH 10/18] add compile cmd to sample --- guides/databases.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/guides/databases.md b/guides/databases.md index db5337dc1..d3955257f 100644 --- a/guides/databases.md +++ b/guides/databases.md @@ -918,6 +918,8 @@ entity V as select from Books { } ``` +`❯ cds compile -2 sql --dialect hana` + ```sql CREATE VIEW V AS SELECT (CASE WHEN locate(title, 'Raven') = 1 THEN TRUE ELSE FALSE END) AS lowerCase, From 2ba678d4a78f8030291721166b7f620bca58d56a Mon Sep 17 00:00:00 2001 From: Patrice Bender Date: Tue, 29 Apr 2025 14:35:16 +0200 Subject: [PATCH 11/18] disclaimer for round --- guides/databases.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/guides/databases.md b/guides/databases.md index d3955257f..9a3020a67 100644 --- a/guides/databases.md +++ b/guides/databases.md @@ -986,6 +986,12 @@ by deviating from the casing given below. - `round(x)` Rounds the numeric parameter to the nearest integer. The midpoint between two integers is rounded away from zero (e.g., `0.5` → `1` and `-0.5` → `-1`). + + ::: warning `round` function with more than one argument + please note that most databases support `round` functions with multiple arguments. + The second parameter being the precision. SAP HANA even has a third argument which is the rounding mode. + If you provide more than one argument, the `round` function may behave differently depending on the database. + ::: #### Date and Time Functions From fba6aab71ba8d42ac367b80b00cb72bbc4cbba7a Mon Sep 17 00:00:00 2001 From: Patrice Bender Date: Tue, 29 Apr 2025 15:45:03 +0200 Subject: [PATCH 12/18] review suggestion --- guides/databases.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/guides/databases.md b/guides/databases.md index 9a3020a67..85e0f82cd 100644 --- a/guides/databases.md +++ b/guides/databases.md @@ -988,8 +988,8 @@ by deviating from the casing given below. The midpoint between two integers is rounded away from zero (e.g., `0.5` → `1` and `-0.5` → `-1`). ::: warning `round` function with more than one argument - please note that most databases support `round` functions with multiple arguments. - The second parameter being the precision. SAP HANA even has a third argument which is the rounding mode. + Note that most databases support `round` functions with multiple arguments, + the second parameter being the precision. SAP HANA even has a third argument which for the rounding mode. If you provide more than one argument, the `round` function may behave differently depending on the database. ::: From 096010ce4b984e6e59da4367f83b4e96ae80e5ef Mon Sep 17 00:00:00 2001 From: Patrice Bender Date: Wed, 30 Apr 2025 10:40:19 +0200 Subject: [PATCH 13/18] Update guides/databases.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: René Jeglinsky --- guides/databases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/databases.md b/guides/databases.md index 85e0f82cd..1c95857d2 100644 --- a/guides/databases.md +++ b/guides/databases.md @@ -903,7 +903,7 @@ TODO: remove the above with cds9 ### OData standard functions -The cds-compiler and all CAP Node.js database services come with out of the box support for common OData functions. +The `@sap/cds-compiler` and all CAP Node.js database services come with out of the box support for common OData functions. ::: warning Case Sensitivity The OData function mappings are case-sensitive and must be written as in the list below. From 46385f974a2e2ae40ec6a838eb754672db9c8f05 Mon Sep 17 00:00:00 2001 From: Patrice Bender Date: Wed, 30 Apr 2025 10:49:06 +0200 Subject: [PATCH 14/18] Update guides/databases.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: René Jeglinsky --- guides/databases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/databases.md b/guides/databases.md index 1c95857d2..7786acd0f 100644 --- a/guides/databases.md +++ b/guides/databases.md @@ -918,7 +918,7 @@ entity V as select from Books { } ``` -`❯ cds compile -2 sql --dialect hana` +`$ cds compile -2 sql --dialect hana` ```sql CREATE VIEW V AS SELECT From e9a63f871e3730c1fcac9f1bdfb7a81a6485845f Mon Sep 17 00:00:00 2001 From: Rene Jeglinsky Date: Wed, 30 Apr 2025 12:10:30 +0200 Subject: [PATCH 15/18] edit --- guides/databases.md | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/guides/databases.md b/guides/databases.md index 85e0f82cd..73a2fbfb6 100644 --- a/guides/databases.md +++ b/guides/databases.md @@ -909,7 +909,7 @@ The cds-compiler and all CAP Node.js database services come with out of the box The OData function mappings are case-sensitive and must be written as in the list below. ::: -e.g. +Assuming you have the following entity definition: ```cds entity V as select from Books { @@ -918,8 +918,12 @@ entity V as select from Books { } ``` +Then you compile the SAP HANA artifacts: + `❯ cds compile -2 sql --dialect hana` +This is the result: + ```sql CREATE VIEW V AS SELECT (CASE WHEN locate(title, 'Raven') = 1 THEN TRUE ELSE FALSE END) AS lowerCase, @@ -956,13 +960,11 @@ by deviating from the casing given below. - `substring(x, i, n?)` 1 Extracts a substring from `x` starting at index `i` (0-based) with an optional length `n`. - - `i`: - - Positive: starts at index `i` - - Negative: starts `i` positions before the end - - `n`: - - Positive: extracts `n` characters - - Omitted: extracts until the end of the string - - Negative: invalid + + | Parameter | Positive | Negative | Omitted + | --- | --- | --- | -- | + | `i` | starts at index `i` | starts `i` positions before the end | + | `n` | extracts `n` characters | invalid | extracts until the end of the string - `length(x)` Returns the length of the string `x`. @@ -973,7 +975,7 @@ by deviating from the casing given below. - `toupper(x)` Converts all characters in `x` to uppercase. -1 These functions work zero-based. E.g., `substring('abcdef', 1, 3)` returns 'bcd' +> 1 These functions work zero-based. For example, `substring('abcdef', 1, 3)` returns 'bcd' #### Numeric Functions @@ -1018,7 +1020,7 @@ by deviating from the casing given below. ### SAP HANA Functions -In addition to the OData standard functions, the cds-compiler and all CAP Node.js database services come with +In addition to the OData standard functions, the `@sap/cds-compiler` and all CAP Node.js database services come with out of the box support for some common SAP HANA functions, to further increase the scope for portable testing: ::: warning Upper- and Lowercase are supported From 1fc02aa814e6a67424457aeaab011ebfc44596d9 Mon Sep 17 00:00:00 2001 From: Rene Jeglinsky Date: Wed, 30 Apr 2025 12:15:43 +0200 Subject: [PATCH 16/18] acrolinx check --- guides/databases.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/guides/databases.md b/guides/databases.md index 73a2fbfb6..5d11271e9 100644 --- a/guides/databases.md +++ b/guides/databases.md @@ -28,7 +28,7 @@ With CDS 8, the [`@cap-js`](https://github.com/cap-js/cds-dbs) database services ### Adding Database Packages {.node} -Following are cds-plugin packages for CAP Node.js runtime that support respective databases: +Following are cds-plugin packages for CAP Node.js runtime that support the respective databases: | Database | Package | Remarks | | ------------------------------ | ------------------------------------------------------------ | ---------------------------------- | @@ -37,7 +37,7 @@ Following are cds-plugin packages for CAP Node.js runtime that support respectiv | **[PostgreSQL](databases-postgres)** | [`@cap-js/postgres`](https://www.npmjs.com/package/@cap-js/postgres) | maintained by community + CAP team | -> Follow the links above to find specific information for each. +> Follow the preceding links to find specific information for each. In general, all you need to do is to install one of the database packages, as follows: @@ -345,7 +345,7 @@ Select.from(AUTHOR) ### Standard Operators {.node} -The database services guarantee identical behavior of these operators: +The database services guarantee the identical behavior of these operators: * `==`, `=` — with `=` null being translated to `is null` * `!=`, `<>` — with `!=` translated to `IS NOT` in SQLite, or to `IS DISTINCT FROM` in standard SQL, or to an equivalent polyfill in SAP HANA @@ -360,8 +360,8 @@ The operator mappings are available for runtime queries only, but not in CDS fil ### Session Variables {.node} -The API shown below, which includes the function `session_context()` and specific pseudo variable names, is supported by **all** new database services, that is, *SQLite*, *PostgreSQL* and *SAP HANA*. -This allows you to write respective code once and run it on all these databases: +The API shown after this, which includes the function `session_context()` and specific pseudo variable names, is supported by **all** new database services, that is, *SQLite*, *PostgreSQL* and *SAP HANA*. +This allows you to write the respective code once and run it on all these databases: ```sql SELECT session_context('$user.id') @@ -397,7 +397,7 @@ db.queryForList("SELECT from sqlite_schema where name like ?", name); ### Reading `LargeBinary` / BLOB {.node} -Formerly, `LargeBinary` elements (or BLOBs) were always returned as any other data type. Now, they are skipped from `SELECT *` queries. Yet, you can still enforce reading BLOBs by explicitly selecting them. Then the BLOB properties are returned as readable streams. +Formerly, `LargeBinary` elements (or BLOBs) were always returned as any other data type. Now, they're skipped from `SELECT *` queries. Yet, you can still enforce reading BLOBs by explicitly selecting them. Then the BLOB properties are returned as readable streams. ```js SELECT.from(Books) //> [{ ID, title, ..., image1, image2 }] // [!code --] @@ -424,7 +424,7 @@ You can also do this manually with the CLI command `cds compile --to `. When you've created a CAP Java application with `cds init --java` or with CAP Java's [Maven archetype](../java/developing-applications/building#the-maven-archetype), the Maven build invokes the CDS compiler to generate a `schema.sql` file for your target database. In the `default` profile (development mode), an in-memory database is [initialized by Spring](https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto.data-initialization) and the schema is bootstrapped from the `schema.sql` file. -[Learn more about adding an inital database schema.](../java/cqn-services/persistence-services#initial-database-schema){.learn-more} +[Learn more about adding an initial database schema.](../java/cqn-services/persistence-services#initial-database-schema){.learn-more}
@@ -734,7 +734,7 @@ The following rules apply: - If you refer to a column name in the annotation, you need to take care of a potential name mapping yourself, for example, for structured elements. -- Annotation `@sql.prepend` is only supported for entities translating to tables. It can't be used with views nor with elements. +- Annotation `@sql.prepend` is only supported for entities translating to tables. It can't be used with views or with elements. - For SAP HANA tables, there's an implicit `@sql.prepend: 'COLUMN'` that is overwritten by an explicitly provided `@sql.prepend`. * Both `@sql.prepend` and `@sql.append` are disallowed in SaaS extension projects. @@ -766,7 +766,7 @@ ROW TABLE E ( [Learn more about Columnar and Row-Based Data Storage](https://help.sap.com/docs/hana-cloud-database/sap-hana-cloud-sap-hana-database-administration-guide/columnar-and-row-based-data-storage){.learn-more} ### Reserved Words -The CDS compiler and CAP runtimes provide smart quoting for reserved words in SQLite and in SAP HANA so that they can still be used in most situations. But in general reserved words cannot be used as identifiers. The list of reserved words varies per database. +The CDS compiler and CAP runtimes provide smart quoting for reserved words in SQLite and in SAP HANA so that they can still be used in most situations. But in general reserved words can't be used as identifiers. The list of reserved words varies per database. Find here a collection of resources on selected databases and their reference documentation: @@ -1134,7 +1134,7 @@ In case of conflicts, follow these steps to provide different models for differe ``` 4. For the Spring Boot side it's similar. If you have a local development database and a hybrid profile with a remote SAP HANA database, you only need to run in default (or any other) profile. For the SAP HANA part, the build and deploy part is done separately and the application just needs to be started using `cds bind`. -Once you have 2 non-HANA local databases you need to have 2 distinct database configurations in your Spring Boot configuration (in most cases application.yaml). +Once you have 2 non-HANA local databases, you need to have 2 distinct database configurations in your Spring Boot configuration (in most cases application.yaml). ```yaml spring: From bdabd63435e352aad2c6c0775f20a973b2595e61 Mon Sep 17 00:00:00 2001 From: Patrice Bender Date: Wed, 30 Apr 2025 12:55:44 +0200 Subject: [PATCH 17/18] typo --- guides/databases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/databases.md b/guides/databases.md index 0d657bf97..07021d72e 100644 --- a/guides/databases.md +++ b/guides/databases.md @@ -993,7 +993,7 @@ by deviating from the casing given below. ::: warning `round` function with more than one argument Note that most databases support `round` functions with multiple arguments, - the second parameter being the precision. SAP HANA even has a third argument which for the rounding mode. + the second parameter being the precision. SAP HANA even has a third argument which is the rounding mode. If you provide more than one argument, the `round` function may behave differently depending on the database. ::: From 2322e91806a9006a5bd6d49872add69b2772df75 Mon Sep 17 00:00:00 2001 From: Patrice Bender Date: Wed, 30 Apr 2025 13:08:35 +0200 Subject: [PATCH 18/18] better wording --- guides/databases.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/guides/databases.md b/guides/databases.md index 07021d72e..ab2325c95 100644 --- a/guides/databases.md +++ b/guides/databases.md @@ -934,8 +934,9 @@ CREATE VIEW V AS SELECT FROM Books; ``` -💡 If you have your own User-Defined Functions (UDFs) with the same name, you can still use them, -by deviating from the casing given below. +💡 If you want to use a DB native function or a UDF (User-Defined Function) instead of the OData function mappings, you can +do that by using a different casing than the OData function names as defined in the list below. +For example, `startsWith` instead of `startswith` will be passed as-is to the database. #### String Functions