Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Move DB agnostic sections out of sqlite database guide #973

Merged
merged 18 commits into from
Nov 8, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 0 additions & 82 deletions guides/databases-sqlite.md
Original file line number Diff line number Diff line change
Expand Up @@ -382,88 +382,6 @@ SELECT.from.localized(Books)
SELECT.one.localized(Books)
```



### Standard Operators {.impl .node}

The new database services guarantee identical behavior of these logic operators:

- `==`, `=` — with `= null` being translated to `is null`
- `!=`, `<>` — with `!=` translated to `IS NOT` in SQLite

* `<`, `>`, `<=`, `>=`, `IN`, `LIKE` — are supported as is in standard SQL

In particular, the translation of `!=` to `IS NOT` in SQLite — or to `IS DISTINCT FROM` in standard SQL, or to an equivalent polyfill in SAP HANA — greatly improves the portability of your code.

> These operators are available for runtime queries, but not in CDS files.


### Standard Functions {.impl .node}

A specified set of standard functions is now supported in a **database-agnostic**, hence portable way, and translated to database-specific variants or polyfills. These functions are by and large the same as specified in OData:

* `concat(x,y,...)` — concatenates the given strings
* `contains(x,y)` — checks whether `y` is contained in `x`, may be fuzzy
* `search(xs,y)` — checks whether `y` is contained in any of `xs`, 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)` — extracts a substring from `x` starting at `i` with length `n` <sup>1</sup>
* `indexof(x,y)` — returns the (zero-based) 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)` — returns ceiled `x`
* `session_context(v)` — with standard variable names → [see below](#session-variables)
* `year` `month`, `day`, `hour`, `minute`, `second` — return parts of a datetime

> <sup>1</sup> Argument `n` is optional.
> These functions are only supported within runtime queries, but not in CDS files.

The database service implementation translates these to the best-possible native SQL functions, thus enhancing the extent of **portable** queries.

CQL query:

```sql
SELECT from Books where search((title,descr),'y')
```

Translated native SQLite query:

```sql
SELECT * from sap_capire_bookshop_Books
WHERE ifnull(instr(lower(title),lower('y')),0)
OR ifnull(instr(lower(descr),lower('y')),0)
```

> Note: only single values are supported for the second argument `y`.

::: warning Case-sensitive

You have to write these functions exactly as given; all-uppercase usages aren't supported.

:::



### SAP HANA Functions {.impl .node}

In addition to the standard functions, which all new database services support, the new SQLite service also supports these common SAP HANA functions, to further increase the scope for portable testing:

- `years_between`
- `months_between`
- `days_between`
- `seconds_between`
- `nano100_between`

With open source and the new database service architecture, we also have methods in place to enhance this list by custom implementation.

> Both usages are allowed here: all-lowercase as given above, as well as all-uppercase.





### Session Variables {.impl .node}

The new SQLite service can leverage [*better-sqlite*](https://www.npmjs.com/package/better-sqlite3)'s user-defined functions to support *session context* variables. In particular, the pseudo variables `$user.id`, `$user.locale`, `$valid.from`, and `$valid.to` are available in native SQL queries as shown below:
Expand Down
79 changes: 79 additions & 0 deletions guides/databases.md
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,85 @@ Select.from(AUTHOR)

</div>

### Standard Operators {.impl .node}

The new database services guarantee identical behavior of these logic operators:

`<`, `>`, `<=`, `>=`, `<>`, `=`, `IN`, `LIKE` — are supported as is in standard SQL.

With special mappings for the following boolean operators:

| Operator | `@cap-js/sqlite` | `@cap-js/hana` | `@cap-js/postgres` |
|-----------|------------------|----------------|---------------------|
| `= NULL` | `is NULL` | `is NULL` | `is NULL` |
| `!=` | `<>` | `!=` | `<>` |
| `!= NULL` | `is not NULL` | `is not NULL` | `is not NULL` |


In particular, the translation of `!=` to `IS NOT` in SQLite — or to an equivalent polyfill in SAP HANA — greatly improves the portability of your code.
patricebender marked this conversation as resolved.
Show resolved Hide resolved

> These operators are available for runtime queries, but not in CDS files.
patricebender marked this conversation as resolved.
Show resolved Hide resolved


### Standard Functions {.impl .node}

A specified set of standard functions is now supported in a **database-agnostic**, hence portable way, and translated to database-specific variants or polyfills. These functions are by and large the same as specified in OData:

* `concat(x,y,...)` — concatenates the given strings
* `contains(x,y)` — checks whether `y` is contained in `x`, may be fuzzy
* `search(xs,y)` — checks whether `y` is contained in any of `xs`, 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)` — extracts a substring from `x` starting at `i` with length `n` <sup>1</sup>
* `indexof(x,y)` — returns the (zero-based) 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)` — returns ceiled `x`
* `session_context(v)` — with standard variable names → [see below](#session-variables)
renejeglinsky marked this conversation as resolved.
Show resolved Hide resolved
* `year` `month`, `day`, `hour`, `minute`, `second` — return parts of a datetime

> <sup>1</sup> Argument `n` is optional.
> These functions are only supported within runtime queries, but not in CDS files.

The database service implementation translates these to the best-possible native SQL functions, thus enhancing the extent of **portable** queries.

CQL query:

```sql
SELECT from Books where search((title,descr),'y')
```

Translated native SQLite query:

```sql
SELECT * from sap_capire_bookshop_Books
WHERE ifnull(instr(lower(title),lower('y')),0)
OR ifnull(instr(lower(descr),lower('y')),0)
```

> Note: only single values are supported for the second argument `y`.

::: warning Case-sensitive

You have to write these functions exactly as given; all-uppercase usages aren't supported.

:::

### SAP HANA Functions {.impl .node}

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`
- `months_between`
- `days_between`
- `seconds_between`
- `nano100_between`

With open source and the new database service architecture, we also have methods in place to enhance this list by custom implementation.

> Both usages are allowed here: all-lowercase as given above, as well as all-uppercase.


### Native DB Queries
Expand Down
Loading