Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
0b4329f
chore(deps): update dependency com.sap.cds:cds4j-api to v4 (#1901)
renovate[bot] Jun 6, 2025
c57011a
Improve microservices docu (#1900)
vl-leon Jun 6, 2025
f324b53
Removed former docs for TreeView models (#1904)
danjoa Jun 6, 2025
15b4648
nodejs: document opt out of error sanitization (#1903)
johannes-vogel Jun 6, 2025
be8a52c
chore(deps): update dependency com.sap.cds:cds-services-api to v4 (#1…
renovate[bot] Jun 6, 2025
66d5259
chore(deps): update dependency @cap-js/cds-types to v0.11.0 (#1899)
renovate[bot] Jun 6, 2025
a57352f
chore(deps): update dependency @types/express to v4.17.23 (#1907)
renovate[bot] Jun 10, 2025
271747e
chore(deps): update dependency sass to v1.89.2 (#1909)
renovate[bot] Jun 10, 2025
79e4fa0
chore(deps): update dependency @typescript-eslint/parser to v8.34.0 (…
renovate[bot] Jun 10, 2025
2a07b29
chore: Update CLI texts (#1915)
github-actions[bot] Jun 11, 2025
d409d42
nodejs: document disabling of fuzzy search (#1913)
johannes-vogel Jun 11, 2025
8fc9f38
microservices - add missing directory (#1911)
vl-leon Jun 17, 2025
77aebd9
add inc man java sample
renejeglinsky Jun 17, 2025
b097e1d
add playlist: the art and science of CAP
renejeglinsky Jun 17, 2025
ba4fe99
Show error response if content loading fails
chgeo Jun 17, 2025
f098774
Update best-practices.md (#1922)
hm23 Jun 18, 2025
27eb6ce
add link to articel
renejeglinsky Jun 18, 2025
bad287b
Merge branch 'main' of https://github.com/cap-js/docs
renejeglinsky Jun 18, 2025
c5e7432
Update Java properties w/ scheduled job
chgeo Jun 18, 2025
84c245a
Fix script name
chgeo Jun 18, 2025
5099293
Add missing install step
chgeo Jun 18, 2025
dba31b1
chore: Update Java Properties (#1924)
github-actions[bot] Jun 18, 2025
baa234c
chore: Update CLI texts (#1921)
github-actions[bot] Jun 18, 2025
647a3cb
chore(deps): update dependency cspell to v9.1.1 (#1919)
renovate[bot] Jun 18, 2025
f800ced
chore(deps): update eslint (#1918)
renovate[bot] Jun 18, 2025
f63e5d4
Slight improvement to "adding initial data" section (#1926)
qmacro Jun 18, 2025
50e4937
Don't copy artifacts from remote during local build
chgeo Jun 18, 2025
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
36 changes: 36 additions & 0 deletions .github/java-properties/update-properties.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#!/usr/bin/env node

import AdmZip from 'adm-zip'
import { join } from 'path'
import { readFile, writeFile } from 'node:fs/promises'

const props = await fetchProperties()
await writeFile(join(import.meta.dirname, '../../java/developing-applications/properties.json'), JSON.stringify(props, null, 2))

console.error(`wrote ${props.length} properties to`, join(import.meta.dirname, '../../java/developing-applications/properties.json'))

async function fetchProperties() {
const config = (await readFile(join(import.meta.dirname, '../../.vitepress/config.js'))).toString()
const version = config.match(/java_services\s*:\s*['"]([^'"]+)['"]/)[1]

const maven = process.env.MAVEN_HOST ?? 'https://repo1.maven.org/maven2'
const url = maven + `/com/sap/cds/cds-services-api/${version}/cds-services-api-${version}-sources.jar`

console.error(`fetching properties from`, url)
const headers = process.env.MAVEN_TOKEN ? { Authorization: `Bearer ${process.env.MAVEN_TOKEN}` } : {}
const resp = await fetch(url, { headers })
const jar = await resp.arrayBuffer()

return new Promise((res, rej) => {
try {
const zip = new AdmZip(Buffer.from(jar))
zip.readAsTextAsync('properties.json', (data, err) => {
if (err) return rej(err)
res(JSON.parse(data))
})
} catch (err) {
return rej(new Error(`Could not load ${url}, response: ${Buffer.from(jar)}`, {cause: err}))
// return res([])
}
})
}
3 changes: 3 additions & 0 deletions .github/workflows/PR-SAP.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ jobs:
env:
NODE_OPTIONS: "--max-old-space-size=6144"
VITE_CAPIRE_CI_HOST: "github.com"
VITE_CAPIRE_EXTRA_ASSETS: true
MAVEN_HOST: https://common.repositories.cloud.sap/artifactory/build.releases
MAVEN_TOKEN: ${{ secrets.MAVEN_TOKEN }}
- name: Find broken anchor links
working-directory: docs
run: |
Expand Down
47 changes: 0 additions & 47 deletions .github/workflows/extract-docs.yml

This file was deleted.

3 changes: 3 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ jobs:
GH_BASE: /
SITE_HOSTNAME: https://cap.js.org
VITE_CAPIRE_PREVIEW: true
VITE_CAPIRE_EXTRA_ASSETS: true
MAVEN_HOST: https://common.repositories.cloud.sap/artifactory/build.releases
MAVEN_TOKEN: ${{ secrets.MAVEN_TOKEN }}
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
Expand Down
85 changes: 85 additions & 0 deletions .github/workflows/update-content.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
name: Update Content

on:
workflow_dispatch:
schedule:
# Runs every Wednesday at 02:45 AM (UTC)
- cron: '45 2 * * 3'

permissions:
contents: write
pull-requests: write

jobs:
update-cli-texts:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '22'

- name: Extract CLI texts
run: |
npm i -g @sap/cds-dk
.github/cli/grab-cli-texts.sh

- name: Check for changes
run: |
git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
if git diff --exit-code; then
echo "No changes detected. Exiting."
exit 0
fi

- name: Create Pull Request
uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.GITHUB_TOKEN }}
branch: "update-cds-cli-texts"
commit-message: "Update CLI texts"
title: "chore: Update CLI texts"
body: "Updates the output of cds CLI texts to the latest version."

update-java-properties:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '22'

- name: Update Java Properties
run: |
npm ci
.github/java-properties/update-properties.js
env:
MAVEN_HOST: https://common.repositories.cloud.sap/artifactory/build.releases
MAVEN_TOKEN: ${{ secrets.MAVEN_TOKEN }}

- name: Check for changes
run: |
git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
if git diff --exit-code; then
echo "No changes detected. Exiting."
exit 0
fi

- name: Create Pull Request
uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.GITHUB_TOKEN }}
branch: "update-java-properties"
commit-message: "Update Java Properties"
title: "chore: Update Java Properties"
body: "Updates Java properties to the latest version."
24 changes: 13 additions & 11 deletions .vitepress/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,10 @@ config.rewrites = rewrites
// Add custom capire info to the theme config
config.themeConfig.capire = {
versions: {
java_services: '3.10.1',
java_cds4j: '3.10.1'
java_services: '4.0.2',
java_cds4j: '4.0.2'
},
gotoLinks: [],
maven_host_base: 'https://repo1.maven.org/maven2'
gotoLinks: []
}

// Add meta tag to prevent indexing of preview deployments
Expand Down Expand Up @@ -203,12 +202,15 @@ config.buildEnd = async ({ outDir, site }) => {
sitemapURL.pathname = path.join(sitemapURL.pathname, 'sitemap.xml')
await fs.writeFile(path.resolve(outDir, 'robots.txt'), `Sitemap: ${sitemapURL}\n`)

// zip assets aren't copied automatically, and `vite.assetInclude` doesn't work either
const hanaAssetDir = 'advanced/assets'
const hanaAsset = path.join(hanaAssetDir, 'native-hana-samples.zip')
await fs.mkdir(path.join(outDir, hanaAssetDir), {recursive: true})
console.debug('✓ copying HANA assets to ', path.join(outDir, hanaAsset)) // eslint-disable-line no-console
await fs.copyFile(path.join(__dirname, '..', hanaAsset), path.join(outDir, hanaAsset))
// disabled by default to avoid online fetches during local build
if (process.env.VITE_CAPIRE_EXTRA_ASSETS) {
// zip assets aren't copied automatically, and `vite.assetInclude` doesn't work either
const hanaAssetDir = 'advanced/assets'
const hanaAsset = path.join(hanaAssetDir, 'native-hana-samples.zip')
await fs.mkdir(path.join(outDir, hanaAssetDir), {recursive: true})
console.debug('✓ copying HANA assets to ', path.join(outDir, hanaAsset)) // eslint-disable-line no-console

await cdsMavenSite.copySiteAssets(path.join(outDir, 'java/assets/cds-maven-plugin-site'), site)
await fs.copyFile(path.join(__dirname, '..', hanaAsset), path.join(outDir, hanaAsset))
await cdsMavenSite.copySiteAssets(path.join(outDir, 'java/assets/cds-maven-plugin-site'), site)
}
}
11 changes: 5 additions & 6 deletions .vitepress/lib/cds-maven-site.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@ import AdmZip from 'adm-zip'
export async function copySiteAssets(outDir:string, site:SiteData) {
const { themeConfig: { capire }} = site
const version = capire.versions.java_services
const url = capire.maven_host_base + `/com/sap/cds/cds-maven-plugin/${version}/cds-maven-plugin-${version}-site.jar`
const maven = process.env.MAVEN_HOST ?? 'https://repo1.maven.org/maven2'
const url = maven + `/com/sap/cds/cds-maven-plugin/${version}/cds-maven-plugin-${version}-site.jar`
const headers = process.env.MAVEN_TOKEN ? { Authorization: `Bearer ${process.env.MAVEN_TOKEN}` } : {} as Record<string, string>

const resp = await fetch(url)
console.debug(`✓ fetching CDS Maven Site from ${url}`)
const resp = await fetch(url, { headers })
const jar = await resp.arrayBuffer()

console.debug(`✓ fetching CDS Maven Site ${version}`)
const zip = new AdmZip(Buffer.from(jar))
zip.extractAllTo(outDir, true, false)

}

2 changes: 1 addition & 1 deletion about/best-practices.md
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ Handling synchronous requests vs asynchronous event messages:
```js [Handling sync Requests]
class CatalogService { async init() {
this.on ('SubmitOrder', req => { // sync action request
const { book, quantity } = msg.data // process it...
const { book, quantity } = req.data // process it...
})
}}
```
Expand Down
65 changes: 0 additions & 65 deletions advanced/odata.md
Original file line number Diff line number Diff line change
Expand Up @@ -1138,71 +1138,6 @@ GET SalesOrganizations?$apply=
/ancestors(..., ID, filter(contains(Name, 'New York')), keep start)
```

#### Modeling Recursive Hierarchies

Recursive hierarchies are parent-child hierarchies, where each entity references its parent and through that defines the hierarchical structure. A common example is a company organization structure or HR reporting, where each employee entity references another employee a as direct report or manager.

##### Domain Model

The simplest domain model looks as follows:

```cds
entity Employee : Hierarchy {
key ID : UUID;
parent : Association to Employee;
fullName : String;
}

aspect Hierarchy {
virtual LimitedDescendantCount : Integer64;
virtual DistanceFromRoot : Integer64;
virtual DrillState : String;
virtual LimitedRank : Integer64;
}
```

The entity `Employee` has the element `ID`, which identifies the hierarchy node. The `parent` association references the same entity, which establishes the parent-child relationship.

##### Virtual Elements of a Hierarchy

The `Hierarchy` aspect defines a set of virtual elements, automatically calculated by the backend at runtime, to describe the state of the hierarchy. This information is requested by the UI to correctly render the hierarchy in a *TreeTable* during user interaction.

##### Service Model

The following service defines the projection on the domain model.

```cds
service HRService {
entity HREmployee as projection on Employee;
}
```


##### OData v4 Annotations for Fiori

To link the backend and Fiori UI, the projected service entity must be enriched with the following annotations.

```cds
annotate HRService.HREmployee with @Aggregation.RecursiveHierarchy #EmployeeHierarchy: {
$Type: 'Aggregation.RecursiveHierarchyType',
NodeProperty: ID,
ParentNavigationProperty: parent
};
```

Here the `EmployeeHierarchy` specifies a hierarchy qualifier, `NodeProperty` (identifying the hierarchy node) is linked to `ID` of the entity `HREmployee`, and the `ParentNavigationProperty` is linked to a corresponding `parent` association.

```cds
annotate HRService.HREmployee with @Hierarchy.RecursiveHierarchy #EmployeeHierarchy: {
$Type: 'Hierarchy.RecursiveHierarchyType',
LimitedDescendantCount: LimitedDescendantCount,
DistanceFromRoot: DistanceFromRoot,
DrillState: DrillState,
LimitedRank: LimitedRank
};
```

Here the same qualifier `EmployeeHierarchy` is referenced to list the names of the [virtual elements of the hierarchy](#virtual-elements-of-a-hierarchy).

### Aggregation Methods

Expand Down
2 changes: 2 additions & 0 deletions get-started/learning-sources.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ It's available in both Node.js and Java. The Node.js variant contains additional

### Incidents Mgmt {.github}

> [![]()](https://github.com/cap-java/incidents-app){.java}
> [![]()](https://github.com/cap-js/incidents-app){.node}

A reference sample application for CAP and the SAP BTP Developer Guide.
Expand Down Expand Up @@ -186,6 +187,7 @@ Based on this sample application, you find the bill of materials and a sizing ex

## Videos

- [The Art and Science of CAP](https://www.youtube.com/playlist?list=PL6RpkC85SLQAe45xlhIfhTYB9G0mdRVjI) <br> by DJ Adams and Daniel Hutzel
- [Back to basics: CAP Node.js](https://www.youtube.com/playlist?list=PL6RpkC85SLQBHPdfHQ0Ry2TMdsT-muECx) <br> by DJ Adams
- [Hybrid Testing and Alternative DBs](https://youtu.be/vqub4vJbZX8?si=j5ZkPR6vPb59iBBy) <br> by Thomas Jung
- [Consume External Services](https://youtu.be/rWQFbXFEr1M) <br> by Thomas Jung
Expand Down
4 changes: 2 additions & 2 deletions guides/databases.md
Original file line number Diff line number Diff line change
Expand Up @@ -249,13 +249,13 @@ CSV files can be found in the folders _db/data_ and _test/data_, as well as in a
::: details Adding initial data next to your data model
The content of these 'co-located' `.cds` files actually doesn't matter, but they need to be included in your data model, through a `using` clause in another file for example.

If you need to use certain CSV files exclusively for your production deployments, but not for tests, you can achieve this by including them in a separate data folder, for example, _db/hana/data_. Create an _index.cds_ file in the _hana_ folder as outlined earlier. Then, set up this model location in a dummy cds service, for example _hanaDataSrv_, using the `[production]` profile.
If you need to use certain CSV files exclusively for your production deployments, but not for tests, you can achieve this by including them in a separate data folder, for example, _db/hana/data_. Create an empty _index.cds_ file in the _hana_ folder. Then, set up this model location in a dummy cds service, for example _hanaDataSrv_, using the `[production]` profile.

```json
"cds": {
"requires": {
"[production]": {
"hanaDataSrv ": { "model": "hana" }
"hanaDataSrv ": { "model": "db/hana" }
}
}
}
Expand Down
Loading