From 5b78fc0582a4cc8de44528fbbaf3c49c11ea2618 Mon Sep 17 00:00:00 2001 From: Robin de Silva Jayasinghe Date: Fri, 17 Oct 2025 14:16:08 +0200 Subject: [PATCH 01/10] version bump to cap java 4.x --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d5dd5ff..3cf4285 100644 --- a/pom.xml +++ b/pom.xml @@ -11,8 +11,8 @@ 1.0.0-SNAPSHOT 21 - 3.9.1 - 3.4.5 + 4.4.0 + 3.5.6 1.0.7 https://nodejs.org/dist/ UTF-8 From 53e93889395dbbc815092e59e9465a51e79a415e Mon Sep 17 00:00:00 2001 From: Robin de Silva Jayasinghe Date: Fri, 13 Feb 2026 09:00:09 +0100 Subject: [PATCH 02/10] upgraded to latest CAP Java and cds-dk versions --- package-lock.json | 1707 +++++++++++++-------------------------------- package.json | 2 +- pom.xml | 2 +- 3 files changed, 474 insertions(+), 1237 deletions(-) diff --git a/package-lock.json b/package-lock.json index a764963..2a18ffd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,33 +9,30 @@ "version": "1.0.0", "license": "ISC", "devDependencies": { - "@sap/cds-dk": "^8.6.1" + "@sap/cds-dk": "^9" } }, "node_modules/@sap/cds-dk": { - "version": "8.9.3", - "resolved": "https://registry.npmjs.org/@sap/cds-dk/-/cds-dk-8.9.3.tgz", - "integrity": "sha512-hZV6ZvxhG18zqNO6/L4b9+g2Dxq3Jk8+xMzec3S/Z05ErclDd7m9LUPisAXVRZ1D/oy52tUowClqLHhXM4LlFQ==", + "version": "9.7.1", + "resolved": "https://registry.npmjs.org/@sap/cds-dk/-/cds-dk-9.7.1.tgz", + "integrity": "sha512-pRaCBjJzLvFoCzeEvqOnJJMyzmd3PHN65YZKuH/5TzMaRSRrB++NQcXnbaDOSlLxZghSpshf7IiUwhAGNnkW7A==", "dev": true, "hasShrinkwrap": true, "license": "SEE LICENSE IN LICENSE", "dependencies": { "@cap-js/asyncapi": "^1.0.0", "@cap-js/openapi": "^1.0.0", - "@sap/cds": "^7 || ^8", - "@sap/cds-foss": "^5.0.0", - "@sap/cds-mtxs": "^1.9.0 || ^2", - "@sap/eslint-plugin-cds": "^3.0.1", + "@sap/cds": ">=8.3", + "@sap/cds-mtxs": ">=2", "@sap/hdi-deploy": "^5", "axios": "^1", - "eslint": "^9", - "express": "^4.17.3", - "hdb": "^0", + "express": "^4.22.1 || ^5", + "hdb": "^2.0.0", "livereload-js": "^4.0.1", "mustache": "^4.0.1", - "node-watch": ">=0.7", "ws": "^8.4.2", - "xml-js": "^1.6.11" + "xml-js": "^1.6.11", + "yaml": "^2" }, "bin": { "cds": "bin/cds.js", @@ -43,11 +40,12 @@ "cds-tsx": "bin/cds-tsx.js" }, "optionalDependencies": { - "@cap-js/sqlite": "^1" + "@cap-js/sqlite": ">=1" } }, "node_modules/@sap/cds-dk/node_modules/@cap-js/asyncapi": { "version": "1.0.3", + "integrity": "sha512-vZSWKAe+3qfvZDXV5SSFiObGWmqyS9MDyEADb5PLVT8kzO39qGaSDPv/GzI/gwvRfCayGAjU4ThiBKrFA7Gclg==", "dev": true, "license": "SEE LICENSE IN LICENSE", "peerDependencies": { @@ -55,21 +53,23 @@ } }, "node_modules/@sap/cds-dk/node_modules/@cap-js/db-service": { - "version": "1.20.0", + "version": "2.8.2", + "integrity": "sha512-5BUWnoRX7LQBEWvEZmq0urEkxWPIIUnV9v2uFYop19W10jtmK6bxKqk+oUGD/7o6C9GNiFcZoLpja7SFohfKOg==", "dev": true, - "license": "SEE LICENSE", + "license": "Apache-2.0", "optional": true, "dependencies": { "generic-pool": "^3.9.0" }, "peerDependencies": { - "@sap/cds": ">=7.9" + "@sap/cds": ">=9.4.5" } }, "node_modules/@sap/cds-dk/node_modules/@cap-js/openapi": { - "version": "1.2.1", + "version": "1.3.1", + "integrity": "sha512-2QqqZlOxfvp/DDmGgTdwbBAAMjaPrrdPCbNC4+z6wjn2jXXk40j0XX7DHNnF4BU8R9LFxaUCHt2x8/9PzE83uA==", "dev": true, - "license": "SEE LICENSE IN LICENSE", + "license": "Apache-2.0", "dependencies": { "pluralize": "^8.0.0" }, @@ -78,292 +78,102 @@ } }, "node_modules/@sap/cds-dk/node_modules/@cap-js/sqlite": { - "version": "1.11.0", + "version": "2.1.3", + "integrity": "sha512-JkIAR8khPEW0jgw440JrtOzsj+TacZmACJsifGnCWpgrC17f2q8r15pzrCnvvCmkLXTqUW1kRg5/B3nLbaO86Q==", "dev": true, - "license": "SEE LICENSE", + "license": "Apache-2.0", "optional": true, "dependencies": { - "@cap-js/db-service": "^1.20.0", - "better-sqlite3": "^11.0.0" - }, - "peerDependencies": { - "@sap/cds": ">=7.6" - } - }, - "node_modules/@sap/cds-dk/node_modules/@eslint-community/eslint-utils": { - "version": "4.6.1", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "@cap-js/db-service": "^2.8.2", + "better-sqlite3": "^12.0.0" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@sap/cds-dk/node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@sap/cds-dk/node_modules/@eslint-community/regexpp": { - "version": "4.12.1", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@sap/cds-dk/node_modules/@eslint/config-array": { - "version": "0.20.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/object-schema": "^2.1.6", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@sap/cds-dk/node_modules/@eslint/config-helpers": { - "version": "0.2.1", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@sap/cds-dk/node_modules/@eslint/core": { - "version": "0.13.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@sap/cds-dk/node_modules/@eslint/eslintrc": { - "version": "3.3.1", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "@sap/cds": ">=9" } }, "node_modules/@sap/cds-dk/node_modules/@eslint/js": { - "version": "9.25.1", + "version": "9.39.2", + "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@sap/cds-dk/node_modules/@eslint/object-schema": { - "version": "2.1.6", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@sap/cds-dk/node_modules/@eslint/plugin-kit": { - "version": "0.2.8", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.13.0", - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@sap/cds-dk/node_modules/@humanfs/core": { - "version": "0.19.1", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@sap/cds-dk/node_modules/@humanfs/node": { - "version": "0.16.6", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.3.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@sap/cds-dk/node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { - "version": "0.3.1", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@sap/cds-dk/node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@sap/cds-dk/node_modules/@humanwhocodes/retry": { - "version": "0.4.2", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "url": "https://eslint.org/donate" } }, "node_modules/@sap/cds-dk/node_modules/@sap/cds": { - "version": "8.9.2", + "version": "9.7.0", + "integrity": "sha512-E2ntY7l98fIIbhRbgjxL/M3+iM0mAOz8ehNu+evCUusQHveTWyx3b4DQomJaD4yOAlzMq1m26iDYQBT8HuSIpg==", "dev": true, "license": "SEE LICENSE IN LICENSE", "dependencies": { - "@sap/cds-compiler": ">=5.1", - "@sap/cds-fiori": "^1", - "@sap/cds-foss": "^5.0.0" + "@sap/cds-compiler": "^6.4", + "@sap/cds-fiori": "^2", + "express": "^4.22.1 || ^5", + "js-yaml": "^4.1.1" }, "bin": { - "cds-deploy": "lib/dbs/cds-deploy.js", - "cds-serve": "bin/serve.js", - "cds-test": "bin/test.js" + "cds-deploy": "bin/deploy.js", + "cds-serve": "bin/serve.js" }, "engines": { - "node": ">=18" + "node": ">=20" }, "peerDependencies": { "@eslint/js": "^9", - "express": "^4", - "tar": "^7" + "tar": "^7.5.6" }, "peerDependenciesMeta": { - "express": { - "optional": true - }, "tar": { "optional": true } } }, "node_modules/@sap/cds-dk/node_modules/@sap/cds-compiler": { - "version": "5.9.2", + "version": "6.7.2", + "integrity": "sha512-5UpDA7boOmwtTBWjhEDbpXKgxjqz+0zObBr12P3g5D7QIMF+hPrPG+J0Bm2AQRPE/lv8VcnzFEaMdibRgmGtUw==", "dev": true, "license": "SEE LICENSE IN LICENSE", - "dependencies": { - "antlr4": "4.9.3" - }, "bin": { "cdsc": "bin/cdsc.js", "cdshi": "bin/cdshi.js", "cdsse": "bin/cdsse.js" }, "engines": { - "node": ">=18" + "node": ">=20" } }, "node_modules/@sap/cds-dk/node_modules/@sap/cds-fiori": { - "version": "1.4.1", + "version": "2.2.0", + "integrity": "sha512-NnvpmU40Eez5Q3SkyCCLRuBd1XUjk7N+pbXcIPIkKw4rwvqR2/FbjNveRzc8mcrLcQA3/5b/CXYsafDoozUhng==", "dev": true, "license": "SEE LICENSE IN LICENSE", "peerDependencies": { - "@sap/cds": ">=7.6", - "express": ">=4" - } - }, - "node_modules/@sap/cds-dk/node_modules/@sap/cds-foss": { - "version": "5.0.1", - "dev": true, - "license": "See LICENSE in LICENSE", - "dependencies": { - "big.js": "^6.1.1", - "generic-pool": "^3.8.2", - "xmlbuilder": "^15.1.1", - "yaml": "^2.2.2" - }, - "engines": { - "node": ">=14" + "@sap/cds": ">=8" } }, "node_modules/@sap/cds-dk/node_modules/@sap/cds-mtxs": { - "version": "2.7.2", + "version": "3.7.0", + "integrity": "sha512-SojfvUrcPaVmaPpddUqosAC6Eqft+wdZMLs56C5a0XM54l3P+aWKgd4+G2IBbUjtAgeSznzmwb64dT5oOncSOQ==", "dev": true, "license": "SEE LICENSE IN LICENSE", "dependencies": { - "@sap/hdi-deploy": ">=4", - "axios": "^1" + "@sap/hdi-deploy": "^5" }, "bin": { "cds-mtx": "bin/cds-mtx.js", "cds-mtx-migrate": "bin/cds-mtx-migrate.js" - } - }, - "node_modules/@sap/cds-dk/node_modules/@sap/eslint-plugin-cds": { - "version": "3.2.0", - "dev": true, - "license": "See LICENSE file", - "dependencies": { - "@sap/cds": ">=7", - "semver": "^7.7.1" - }, - "engines": { - "node": ">=18" }, "peerDependencies": { - "eslint": ">=8" + "@sap/cds": "^9" } }, "node_modules/@sap/cds-dk/node_modules/@sap/hdi": { - "version": "4.7.0", + "version": "4.8.0", + "integrity": "sha512-tkJmY2ffm6mt4/LFwRBihlQkMxNAXa3ngvRe2N/6+qLIsUNdrH/M03S5mkygXq56K+KoVVZYuradajCusMWwsw==", "dev": true, "license": "See LICENSE file", "dependencies": { @@ -374,7 +184,7 @@ }, "peerDependencies": { "@sap/hana-client": "^2 >= 2.5", - "hdb": "^0" + "hdb": "^2 || ^0" }, "peerDependenciesMeta": { "@sap/hana-client": { @@ -386,12 +196,13 @@ } }, "node_modules/@sap/cds-dk/node_modules/@sap/hdi-deploy": { - "version": "5.4.2", + "version": "5.6.1", + "integrity": "sha512-+qQ7qwG8lko303L5yRj2dud/nDAVuVblV/mmzJT44oPbF0Nry18eD2LUS23hFeuxjRa7rYK5YKQ8ffGgWxVrYQ==", "dev": true, "license": "See LICENSE file", "dependencies": { - "@sap/hdi": "^4.7.0", - "@sap/xsenv": "^5.2.0", + "@sap/hdi": "^4.8.0", + "@sap/xsenv": "^6.0.0", "async": "^3.2.6", "dotenv": "^16.4.5", "handlebars": "^4.7.8", @@ -402,7 +213,7 @@ }, "peerDependencies": { "@sap/hana-client": "^2 >= 2.6", - "hdb": "^0" + "hdb": "^2 || ^0" }, "peerDependenciesMeta": { "@sap/hana-client": { @@ -414,108 +225,41 @@ } }, "node_modules/@sap/cds-dk/node_modules/@sap/xsenv": { - "version": "5.5.0", + "version": "6.1.0", + "integrity": "sha512-vlW4Zad3uiDqHtnYdQ0TsEIH8VIO4HmPGDowfBL5dIcHPmeKDISEQ9ibeHL5FkceqvYcXJEQAVZ5/hsHDqlXZg==", "dev": true, "license": "SEE LICENSE IN LICENSE file", "dependencies": { - "debug": "4.4.0", + "debug": "4.4.3", "node-cache": "^5.1.2", "verror": "1.10.1" }, "engines": { - "node": "^18.0.0 || ^20.0.0 || ^22.0.0" + "node": "^20.0.0 || ^22.0.0 || ^24.0.0" } }, - "node_modules/@sap/cds-dk/node_modules/@types/estree": { - "version": "1.0.7", - "dev": true, - "license": "MIT" - }, - "node_modules/@sap/cds-dk/node_modules/@types/json-schema": { - "version": "7.0.15", - "dev": true, - "license": "MIT" - }, "node_modules/@sap/cds-dk/node_modules/accepts": { - "version": "1.3.8", + "version": "2.0.0", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", "dev": true, "license": "MIT", "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" }, "engines": { "node": ">= 0.6" } }, - "node_modules/@sap/cds-dk/node_modules/acorn": { - "version": "8.14.1", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/@sap/cds-dk/node_modules/acorn-jsx": { - "version": "5.3.2", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@sap/cds-dk/node_modules/ajv": { - "version": "6.12.6", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@sap/cds-dk/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@sap/cds-dk/node_modules/antlr4": { - "version": "4.9.3", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=14" - } - }, "node_modules/@sap/cds-dk/node_modules/argparse": { "version": "2.0.1", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true, "license": "Python-2.0" }, - "node_modules/@sap/cds-dk/node_modules/array-flatten": { - "version": "1.1.1", - "dev": true, - "license": "MIT" - }, "node_modules/@sap/cds-dk/node_modules/assert-plus": { "version": "1.0.0", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", "dev": true, "license": "MIT", "engines": { @@ -524,31 +268,30 @@ }, "node_modules/@sap/cds-dk/node_modules/async": { "version": "3.2.6", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", "dev": true, "license": "MIT" }, "node_modules/@sap/cds-dk/node_modules/asynckit": { "version": "0.4.0", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true, "license": "MIT" }, "node_modules/@sap/cds-dk/node_modules/axios": { - "version": "1.8.4", + "version": "1.13.4", + "integrity": "sha512-1wVkUaAO6WyaYtCkcYCOx12ZgpGf9Zif+qXa4n+oYzK558YryKqiL6UWwd5DqiH3VRW0GYhTZQ/vlgJrCoNQlg==", "dev": true, "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", + "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, - "node_modules/@sap/cds-dk/node_modules/balanced-match": { - "version": "1.0.2", - "dev": true, - "license": "MIT" - }, "node_modules/@sap/cds-dk/node_modules/base64-js": { "version": "1.5.1", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "dev": true, "funding": [ { @@ -568,7 +311,8 @@ "optional": true }, "node_modules/@sap/cds-dk/node_modules/better-sqlite3": { - "version": "11.9.1", + "version": "12.6.2", + "integrity": "sha512-8VYKM3MjCa9WcaSAI3hzwhmyHVlH8tiGFwf0RlTsZPWJ1I5MkzjiudCo4KC4DxOaL/53A5B1sI/IbldNFDbsKA==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -576,22 +320,14 @@ "dependencies": { "bindings": "^1.5.0", "prebuild-install": "^7.1.1" - } - }, - "node_modules/@sap/cds-dk/node_modules/big.js": { - "version": "6.2.2", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/bigjs" + "engines": { + "node": "20.x || 22.x || 23.x || 24.x || 25.x" } }, "node_modules/@sap/cds-dk/node_modules/bindings": { "version": "1.5.0", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", "dev": true, "license": "MIT", "optional": true, @@ -601,6 +337,7 @@ }, "node_modules/@sap/cds-dk/node_modules/bl": { "version": "4.1.0", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dev": true, "license": "MIT", "optional": true, @@ -611,52 +348,32 @@ } }, "node_modules/@sap/cds-dk/node_modules/body-parser": { - "version": "1.20.3", + "version": "2.2.2", + "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", "dev": true, "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.13.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.3", + "http-errors": "^2.0.0", + "iconv-lite": "^0.7.0", + "on-finished": "^2.4.1", + "qs": "^6.14.1", + "raw-body": "^3.0.1", + "type-is": "^2.0.1" }, "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/@sap/cds-dk/node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/@sap/cds-dk/node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/@sap/cds-dk/node_modules/brace-expansion": { - "version": "1.1.11", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/@sap/cds-dk/node_modules/braces": { "version": "3.0.3", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "license": "MIT", "dependencies": { @@ -668,6 +385,7 @@ }, "node_modules/@sap/cds-dk/node_modules/buffer": { "version": "5.7.1", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "dev": true, "funding": [ { @@ -692,6 +410,7 @@ }, "node_modules/@sap/cds-dk/node_modules/bytes": { "version": "3.1.2", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, "license": "MIT", "engines": { @@ -700,6 +419,7 @@ }, "node_modules/@sap/cds-dk/node_modules/call-bind-apply-helpers": { "version": "1.0.2", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "dev": true, "license": "MIT", "dependencies": { @@ -712,6 +432,7 @@ }, "node_modules/@sap/cds-dk/node_modules/call-bound": { "version": "1.0.4", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "dev": true, "license": "MIT", "dependencies": { @@ -725,61 +446,25 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@sap/cds-dk/node_modules/callsites": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/@sap/cds-dk/node_modules/chalk": { - "version": "4.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, "node_modules/@sap/cds-dk/node_modules/chownr": { "version": "1.1.4", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", "dev": true, "license": "ISC", "optional": true }, "node_modules/@sap/cds-dk/node_modules/clone": { "version": "2.1.2", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", "dev": true, "license": "MIT", "engines": { "node": ">=0.8" } }, - "node_modules/@sap/cds-dk/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@sap/cds-dk/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "license": "MIT" - }, "node_modules/@sap/cds-dk/node_modules/combined-stream": { "version": "1.0.8", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dev": true, "license": "MIT", "dependencies": { @@ -789,24 +474,22 @@ "node": ">= 0.8" } }, - "node_modules/@sap/cds-dk/node_modules/concat-map": { - "version": "0.0.1", - "dev": true, - "license": "MIT" - }, "node_modules/@sap/cds-dk/node_modules/content-disposition": { - "version": "0.5.4", + "version": "1.0.1", + "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", "dev": true, "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/@sap/cds-dk/node_modules/content-type": { "version": "1.0.5", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "dev": true, "license": "MIT", "engines": { @@ -814,7 +497,8 @@ } }, "node_modules/@sap/cds-dk/node_modules/cookie": { - "version": "0.7.1", + "version": "0.7.2", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "dev": true, "license": "MIT", "engines": { @@ -822,30 +506,23 @@ } }, "node_modules/@sap/cds-dk/node_modules/cookie-signature": { - "version": "1.0.6", + "version": "1.2.2", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } }, "node_modules/@sap/cds-dk/node_modules/core-util-is": { "version": "1.0.2", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", "dev": true, "license": "MIT" }, - "node_modules/@sap/cds-dk/node_modules/cross-spawn": { - "version": "7.0.6", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/@sap/cds-dk/node_modules/debug": { - "version": "4.4.0", + "version": "4.4.3", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dev": true, "license": "MIT", "dependencies": { @@ -862,6 +539,7 @@ }, "node_modules/@sap/cds-dk/node_modules/decompress-response": { "version": "6.0.0", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", "dev": true, "license": "MIT", "optional": true, @@ -877,6 +555,7 @@ }, "node_modules/@sap/cds-dk/node_modules/deep-extend": { "version": "0.6.0", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "dev": true, "license": "MIT", "optional": true, @@ -884,13 +563,9 @@ "node": ">=4.0.0" } }, - "node_modules/@sap/cds-dk/node_modules/deep-is": { - "version": "0.1.4", - "dev": true, - "license": "MIT" - }, "node_modules/@sap/cds-dk/node_modules/delayed-stream": { "version": "1.0.0", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true, "license": "MIT", "engines": { @@ -899,23 +574,16 @@ }, "node_modules/@sap/cds-dk/node_modules/depd": { "version": "2.0.0", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" } }, - "node_modules/@sap/cds-dk/node_modules/destroy": { - "version": "1.2.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, "node_modules/@sap/cds-dk/node_modules/detect-libc": { - "version": "2.0.4", + "version": "2.1.2", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "dev": true, "license": "Apache-2.0", "optional": true, @@ -924,7 +592,8 @@ } }, "node_modules/@sap/cds-dk/node_modules/dotenv": { - "version": "16.5.0", + "version": "16.6.1", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -936,6 +605,7 @@ }, "node_modules/@sap/cds-dk/node_modules/dunder-proto": { "version": "1.0.1", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "dev": true, "license": "MIT", "dependencies": { @@ -949,11 +619,13 @@ }, "node_modules/@sap/cds-dk/node_modules/ee-first": { "version": "1.1.1", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", "dev": true, "license": "MIT" }, "node_modules/@sap/cds-dk/node_modules/encodeurl": { "version": "2.0.0", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true, "license": "MIT", "engines": { @@ -961,7 +633,8 @@ } }, "node_modules/@sap/cds-dk/node_modules/end-of-stream": { - "version": "1.4.4", + "version": "1.4.5", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", "dev": true, "license": "MIT", "optional": true, @@ -971,6 +644,7 @@ }, "node_modules/@sap/cds-dk/node_modules/es-define-property": { "version": "1.0.1", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "dev": true, "license": "MIT", "engines": { @@ -979,194 +653,49 @@ }, "node_modules/@sap/cds-dk/node_modules/es-errors": { "version": "1.3.0", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/@sap/cds-dk/node_modules/es-object-atoms": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/@sap/cds-dk/node_modules/es-set-tostringtag": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/@sap/cds-dk/node_modules/escape-html": { - "version": "1.0.3", - "dev": true, - "license": "MIT" - }, - "node_modules/@sap/cds-dk/node_modules/escape-string-regexp": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@sap/cds-dk/node_modules/eslint": { - "version": "9.25.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.20.0", - "@eslint/config-helpers": "^0.2.1", - "@eslint/core": "^0.13.0", - "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.25.1", - "@eslint/plugin-kit": "^0.2.8", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.3.0", - "eslint-visitor-keys": "^4.2.0", - "espree": "^10.3.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "node_modules/@sap/cds-dk/node_modules/eslint-scope": { - "version": "8.3.0", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@sap/cds-dk/node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@sap/cds-dk/node_modules/espree": { - "version": "10.3.0", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.14.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@sap/cds-dk/node_modules/esquery": { - "version": "1.6.0", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, + "license": "MIT", "engines": { - "node": ">=0.10" + "node": ">= 0.4" } }, - "node_modules/@sap/cds-dk/node_modules/esrecurse": { - "version": "4.3.0", + "node_modules/@sap/cds-dk/node_modules/es-object-atoms": { + "version": "1.1.1", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "estraverse": "^5.2.0" + "es-errors": "^1.3.0" }, "engines": { - "node": ">=4.0" + "node": ">= 0.4" } }, - "node_modules/@sap/cds-dk/node_modules/estraverse": { - "version": "5.3.0", + "node_modules/@sap/cds-dk/node_modules/es-set-tostringtag": { + "version": "2.1.0", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, "engines": { - "node": ">=4.0" + "node": ">= 0.4" } }, - "node_modules/@sap/cds-dk/node_modules/esutils": { - "version": "2.0.3", + "node_modules/@sap/cds-dk/node_modules/escape-html": { + "version": "1.0.3", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } + "license": "MIT" }, "node_modules/@sap/cds-dk/node_modules/etag": { "version": "1.8.1", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true, "license": "MIT", "engines": { @@ -1175,6 +704,7 @@ }, "node_modules/@sap/cds-dk/node_modules/expand-template": { "version": "2.0.3", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", "dev": true, "license": "(MIT OR WTFPL)", "optional": true, @@ -1183,105 +713,67 @@ } }, "node_modules/@sap/cds-dk/node_modules/express": { - "version": "4.21.2", - "dev": true, - "license": "MIT", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.3", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.7.1", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.3.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.12", - "proxy-addr": "~2.0.7", - "qs": "6.13.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.19.0", - "serve-static": "1.16.2", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" + "version": "5.2.1", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/express" } }, - "node_modules/@sap/cds-dk/node_modules/express/node_modules/debug": { - "version": "2.6.9", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/@sap/cds-dk/node_modules/express/node_modules/ms": { - "version": "2.0.0", - "dev": true, - "license": "MIT" - }, "node_modules/@sap/cds-dk/node_modules/extsprintf": { "version": "1.4.1", + "integrity": "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==", "dev": true, "engines": [ "node >=0.6.0" ], "license": "MIT" }, - "node_modules/@sap/cds-dk/node_modules/fast-deep-equal": { - "version": "3.1.3", - "dev": true, - "license": "MIT" - }, - "node_modules/@sap/cds-dk/node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "dev": true, - "license": "MIT" - }, - "node_modules/@sap/cds-dk/node_modules/fast-levenshtein": { - "version": "2.0.6", - "dev": true, - "license": "MIT" - }, - "node_modules/@sap/cds-dk/node_modules/file-entry-cache": { - "version": "8.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, "node_modules/@sap/cds-dk/node_modules/file-uri-to-path": { "version": "1.0.0", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", "dev": true, "license": "MIT", "optional": true }, "node_modules/@sap/cds-dk/node_modules/fill-range": { "version": "7.1.1", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "license": "MIT", "dependencies": { @@ -1292,69 +784,29 @@ } }, "node_modules/@sap/cds-dk/node_modules/finalhandler": { - "version": "1.3.1", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/@sap/cds-dk/node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/@sap/cds-dk/node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/@sap/cds-dk/node_modules/find-up": { - "version": "5.0.0", + "version": "2.1.1", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", "dev": true, "license": "MIT", "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">= 18.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@sap/cds-dk/node_modules/flat-cache": { - "version": "4.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/@sap/cds-dk/node_modules/flatted": { - "version": "3.3.3", - "dev": true, - "license": "ISC" - }, "node_modules/@sap/cds-dk/node_modules/follow-redirects": { - "version": "1.15.9", + "version": "1.15.11", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", "dev": true, "funding": [ { @@ -1373,21 +825,45 @@ } }, "node_modules/@sap/cds-dk/node_modules/form-data": { - "version": "4.0.2", + "version": "4.0.5", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", "dev": true, "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", "mime-types": "^2.1.12" }, "engines": { "node": ">= 6" } }, + "node_modules/@sap/cds-dk/node_modules/form-data/node_modules/mime-db": { + "version": "1.52.0", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@sap/cds-dk/node_modules/form-data/node_modules/mime-types": { + "version": "2.1.35", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/@sap/cds-dk/node_modules/forwarded": { "version": "0.2.0", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "dev": true, "license": "MIT", "engines": { @@ -1395,21 +871,24 @@ } }, "node_modules/@sap/cds-dk/node_modules/fresh": { - "version": "0.5.2", + "version": "2.0.0", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/@sap/cds-dk/node_modules/fs-constants": { "version": "1.0.0", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", "dev": true, "license": "MIT", "optional": true }, "node_modules/@sap/cds-dk/node_modules/function-bind": { "version": "1.1.2", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, "license": "MIT", "funding": { @@ -1418,14 +897,17 @@ }, "node_modules/@sap/cds-dk/node_modules/generic-pool": { "version": "3.9.0", + "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==", "dev": true, "license": "MIT", + "optional": true, "engines": { "node": ">= 4" } }, "node_modules/@sap/cds-dk/node_modules/get-intrinsic": { "version": "1.3.0", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1449,6 +931,7 @@ }, "node_modules/@sap/cds-dk/node_modules/get-proto": { "version": "1.0.1", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "dev": true, "license": "MIT", "dependencies": { @@ -1461,34 +944,14 @@ }, "node_modules/@sap/cds-dk/node_modules/github-from-package": { "version": "0.0.0", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", "dev": true, "license": "MIT", "optional": true }, - "node_modules/@sap/cds-dk/node_modules/glob-parent": { - "version": "6.0.2", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/@sap/cds-dk/node_modules/globals": { - "version": "14.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@sap/cds-dk/node_modules/gopd": { "version": "1.2.0", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "dev": true, "license": "MIT", "engines": { @@ -1500,6 +963,7 @@ }, "node_modules/@sap/cds-dk/node_modules/handlebars": { "version": "4.7.8", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1518,16 +982,9 @@ "uglify-js": "^3.1.4" } }, - "node_modules/@sap/cds-dk/node_modules/has-flag": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/@sap/cds-dk/node_modules/has-symbols": { "version": "1.1.0", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, "license": "MIT", "engines": { @@ -1539,6 +996,7 @@ }, "node_modules/@sap/cds-dk/node_modules/has-tostringtag": { "version": "1.0.2", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, "license": "MIT", "dependencies": { @@ -1553,6 +1011,7 @@ }, "node_modules/@sap/cds-dk/node_modules/hasown": { "version": "2.0.2", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1563,44 +1022,75 @@ } }, "node_modules/@sap/cds-dk/node_modules/hdb": { - "version": "0.19.12", + "version": "2.27.1", + "integrity": "sha512-xYL/W+fq2TyGHyzm8muolQnw8tdh4+2NQ8mQP2FpLSuhfJ8l0jQNSUZoAXic7NfMEan1Jvf8V1L4blwkgTc6+A==", "dev": true, "license": "Apache-2.0", "dependencies": { - "iconv-lite": "^0.4.18" + "iconv-lite": "0.7.0" + }, + "engines": { + "node": ">= 18" + }, + "optionalDependencies": { + "lz4-wasm-nodejs": "0.9.2" + } + }, + "node_modules/@sap/cds-dk/node_modules/hdb/node_modules/iconv-lite": { + "version": "0.7.0", + "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { - "node": ">= 0.12" + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/@sap/cds-dk/node_modules/http-errors": { - "version": "2.0.0", + "version": "2.0.1", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "dev": true, "license": "MIT", "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" }, "engines": { "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/@sap/cds-dk/node_modules/iconv-lite": { - "version": "0.4.24", + "version": "0.7.2", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", "dev": true, "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/@sap/cds-dk/node_modules/ieee754": { "version": "1.2.1", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", "dev": true, "funding": [ { @@ -1619,90 +1109,46 @@ "license": "BSD-3-Clause", "optional": true }, - "node_modules/@sap/cds-dk/node_modules/ignore": { - "version": "5.3.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/@sap/cds-dk/node_modules/import-fresh": { - "version": "3.3.1", - "dev": true, - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@sap/cds-dk/node_modules/imurmurhash": { - "version": "0.1.4", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, "node_modules/@sap/cds-dk/node_modules/inherits": { "version": "2.0.4", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true, "license": "ISC" }, "node_modules/@sap/cds-dk/node_modules/ini": { "version": "1.3.8", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true, "license": "ISC", "optional": true }, "node_modules/@sap/cds-dk/node_modules/ipaddr.js": { "version": "1.9.1", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "dev": true, "license": "MIT", "engines": { "node": ">= 0.10" } }, - "node_modules/@sap/cds-dk/node_modules/is-extglob": { - "version": "2.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@sap/cds-dk/node_modules/is-glob": { - "version": "4.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@sap/cds-dk/node_modules/is-number": { "version": "7.0.0", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, "license": "MIT", "engines": { "node": ">=0.12.0" } }, - "node_modules/@sap/cds-dk/node_modules/isexe": { - "version": "2.0.0", + "node_modules/@sap/cds-dk/node_modules/is-promise": { + "version": "4.0.0", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", "dev": true, - "license": "ISC" + "license": "MIT" }, "node_modules/@sap/cds-dk/node_modules/js-yaml": { - "version": "4.1.0", + "version": "4.1.1", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "license": "MIT", "dependencies": { @@ -1712,67 +1158,22 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/@sap/cds-dk/node_modules/json-buffer": { - "version": "3.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/@sap/cds-dk/node_modules/json-schema-traverse": { - "version": "0.4.1", - "dev": true, - "license": "MIT" - }, - "node_modules/@sap/cds-dk/node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/@sap/cds-dk/node_modules/keyv": { - "version": "4.5.4", - "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/@sap/cds-dk/node_modules/levn": { - "version": "0.4.1", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/@sap/cds-dk/node_modules/livereload-js": { "version": "4.0.2", + "integrity": "sha512-Fy7VwgQNiOkynYyNBTo3v9hQUhcW5pFAheJN148+DTgpShjsy/22pLHKKwDK5v0kOsZsJBK+6q1PMgLvRmrwFQ==", "dev": true, "license": "MIT" }, - "node_modules/@sap/cds-dk/node_modules/locate-path": { - "version": "6.0.0", + "node_modules/@sap/cds-dk/node_modules/lz4-wasm-nodejs": { + "version": "0.9.2", + "integrity": "sha512-hSwgJPS98q/Oe/89Y1OxzeA/UdnASG8GvldRyKa7aZyoAFCC8VPRtViBSava7wWC66WocjUwBpWau2rEmyFPsw==", "dev": true, "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@sap/cds-dk/node_modules/lodash.merge": { - "version": "4.6.2", - "dev": true, - "license": "MIT" + "optional": true }, "node_modules/@sap/cds-dk/node_modules/math-intrinsics": { "version": "1.1.0", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "dev": true, "license": "MIT", "engines": { @@ -1780,31 +1181,29 @@ } }, "node_modules/@sap/cds-dk/node_modules/media-typer": { - "version": "0.3.0", + "version": "1.1.0", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/@sap/cds-dk/node_modules/merge-descriptors": { - "version": "1.0.3", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@sap/cds-dk/node_modules/methods": { - "version": "1.1.2", + "version": "2.0.0", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/@sap/cds-dk/node_modules/micromatch": { "version": "4.0.8", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "license": "MIT", "dependencies": { @@ -1815,19 +1214,21 @@ "node": ">=8.6" } }, - "node_modules/@sap/cds-dk/node_modules/mime": { - "version": "1.6.0", + "node_modules/@sap/cds-dk/node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "license": "MIT", - "bin": { - "mime": "cli.js" - }, "engines": { - "node": ">=4" + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/@sap/cds-dk/node_modules/mime-db": { - "version": "1.52.0", + "version": "1.54.0", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "dev": true, "license": "MIT", "engines": { @@ -1835,18 +1236,24 @@ } }, "node_modules/@sap/cds-dk/node_modules/mime-types": { - "version": "2.1.35", + "version": "3.0.2", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "dev": true, "license": "MIT", "dependencies": { - "mime-db": "1.52.0" + "mime-db": "^1.54.0" }, "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/@sap/cds-dk/node_modules/mimic-response": { "version": "3.1.0", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", "dev": true, "license": "MIT", "optional": true, @@ -1857,19 +1264,9 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@sap/cds-dk/node_modules/minimatch": { - "version": "3.1.2", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/@sap/cds-dk/node_modules/minimist": { "version": "1.2.8", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, "license": "MIT", "funding": { @@ -1878,17 +1275,20 @@ }, "node_modules/@sap/cds-dk/node_modules/mkdirp-classic": { "version": "0.5.3", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", "dev": true, "license": "MIT", "optional": true }, "node_modules/@sap/cds-dk/node_modules/ms": { "version": "2.1.3", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true, "license": "MIT" }, "node_modules/@sap/cds-dk/node_modules/mustache": { "version": "4.2.0", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", "dev": true, "license": "MIT", "bin": { @@ -1897,17 +1297,14 @@ }, "node_modules/@sap/cds-dk/node_modules/napi-build-utils": { "version": "2.0.0", + "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", "dev": true, "license": "MIT", "optional": true }, - "node_modules/@sap/cds-dk/node_modules/natural-compare": { - "version": "1.4.0", - "dev": true, - "license": "MIT" - }, "node_modules/@sap/cds-dk/node_modules/negotiator": { - "version": "0.6.3", + "version": "1.0.0", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", "dev": true, "license": "MIT", "engines": { @@ -1916,11 +1313,13 @@ }, "node_modules/@sap/cds-dk/node_modules/neo-async": { "version": "2.6.2", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true, "license": "MIT" }, "node_modules/@sap/cds-dk/node_modules/node-abi": { - "version": "3.74.0", + "version": "3.87.0", + "integrity": "sha512-+CGM1L1CgmtheLcBuleyYOn7NWPVu0s0EJH2C4puxgEZb9h8QpR9G2dBfZJOAUhi7VQxuBPMd0hiISWcTyiYyQ==", "dev": true, "license": "MIT", "optional": true, @@ -1933,6 +1332,7 @@ }, "node_modules/@sap/cds-dk/node_modules/node-cache": { "version": "5.1.2", + "integrity": "sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==", "dev": true, "license": "MIT", "dependencies": { @@ -1942,16 +1342,9 @@ "node": ">= 8.0.0" } }, - "node_modules/@sap/cds-dk/node_modules/node-watch": { - "version": "0.7.4", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/@sap/cds-dk/node_modules/object-inspect": { "version": "1.13.4", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "dev": true, "license": "MIT", "engines": { @@ -1963,6 +1356,7 @@ }, "node_modules/@sap/cds-dk/node_modules/on-finished": { "version": "2.4.1", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dev": true, "license": "MIT", "dependencies": { @@ -1974,110 +1368,35 @@ }, "node_modules/@sap/cds-dk/node_modules/once": { "version": "1.4.0", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, "license": "ISC", - "optional": true, "dependencies": { "wrappy": "1" } }, - "node_modules/@sap/cds-dk/node_modules/optionator": { - "version": "0.9.4", - "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/@sap/cds-dk/node_modules/p-limit": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@sap/cds-dk/node_modules/p-locate": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@sap/cds-dk/node_modules/parent-module": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/@sap/cds-dk/node_modules/parseurl": { "version": "1.3.3", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" } }, - "node_modules/@sap/cds-dk/node_modules/path-exists": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@sap/cds-dk/node_modules/path-key": { - "version": "3.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/@sap/cds-dk/node_modules/path-to-regexp": { - "version": "0.1.12", - "dev": true, - "license": "MIT" - }, - "node_modules/@sap/cds-dk/node_modules/picomatch": { - "version": "2.3.1", + "version": "8.3.0", + "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", "dev": true, "license": "MIT", - "engines": { - "node": ">=8.6" - }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/@sap/cds-dk/node_modules/pluralize": { "version": "8.0.0", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", "dev": true, "license": "MIT", "engines": { @@ -2086,6 +1405,7 @@ }, "node_modules/@sap/cds-dk/node_modules/prebuild-install": { "version": "7.1.3", + "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", "dev": true, "license": "MIT", "optional": true, @@ -2110,16 +1430,9 @@ "node": ">=10" } }, - "node_modules/@sap/cds-dk/node_modules/prelude-ls": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/@sap/cds-dk/node_modules/proxy-addr": { "version": "2.0.7", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "dev": true, "license": "MIT", "dependencies": { @@ -2132,11 +1445,13 @@ }, "node_modules/@sap/cds-dk/node_modules/proxy-from-env": { "version": "1.1.0", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", "dev": true, "license": "MIT" }, "node_modules/@sap/cds-dk/node_modules/pump": { - "version": "3.0.2", + "version": "3.0.3", + "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", "dev": true, "license": "MIT", "optional": true, @@ -2145,20 +1460,13 @@ "once": "^1.3.1" } }, - "node_modules/@sap/cds-dk/node_modules/punycode": { - "version": "2.3.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/@sap/cds-dk/node_modules/qs": { - "version": "6.13.0", + "version": "6.14.1", + "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.6" + "side-channel": "^1.1.0" }, "engines": { "node": ">=0.6" @@ -2169,6 +1477,7 @@ }, "node_modules/@sap/cds-dk/node_modules/range-parser": { "version": "1.2.1", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "dev": true, "license": "MIT", "engines": { @@ -2176,21 +1485,23 @@ } }, "node_modules/@sap/cds-dk/node_modules/raw-body": { - "version": "2.5.2", + "version": "3.0.2", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", "dev": true, "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">= 0.10" } }, "node_modules/@sap/cds-dk/node_modules/rc": { "version": "1.2.8", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dev": true, "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", "optional": true, @@ -2204,17 +1515,9 @@ "rc": "cli.js" } }, - "node_modules/@sap/cds-dk/node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@sap/cds-dk/node_modules/readable-stream": { "version": "3.6.2", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, "license": "MIT", "optional": true, @@ -2227,16 +1530,25 @@ "node": ">= 6" } }, - "node_modules/@sap/cds-dk/node_modules/resolve-from": { - "version": "4.0.0", + "node_modules/@sap/cds-dk/node_modules/router": { + "version": "2.2.0", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", "dev": true, "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, "engines": { - "node": ">=4" + "node": ">= 18" } }, "node_modules/@sap/cds-dk/node_modules/safe-buffer": { "version": "5.2.1", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true, "funding": [ { @@ -2252,22 +1564,30 @@ "url": "https://feross.org/support" } ], - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/@sap/cds-dk/node_modules/safer-buffer": { "version": "2.1.2", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true, "license": "MIT" }, "node_modules/@sap/cds-dk/node_modules/sax": { - "version": "1.4.1", + "version": "1.4.4", + "integrity": "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==", "dev": true, - "license": "ISC" + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } }, "node_modules/@sap/cds-dk/node_modules/semver": { - "version": "7.7.1", + "version": "7.7.3", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "dev": true, "license": "ISC", + "optional": true, "bin": { "semver": "bin/semver.js" }, @@ -2276,89 +1596,59 @@ } }, "node_modules/@sap/cds-dk/node_modules/send": { - "version": "0.19.0", + "version": "1.2.1", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", "dev": true, "license": "MIT", "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" }, "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/@sap/cds-dk/node_modules/send/node_modules/debug": { - "version": "2.6.9", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/@sap/cds-dk/node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/@sap/cds-dk/node_modules/send/node_modules/encodeurl": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/@sap/cds-dk/node_modules/serve-static": { - "version": "1.16.2", + "version": "2.2.1", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", "dev": true, "license": "MIT", "dependencies": { - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.19.0" + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/@sap/cds-dk/node_modules/setprototypeof": { "version": "1.2.0", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "dev": true, "license": "ISC" }, - "node_modules/@sap/cds-dk/node_modules/shebang-command": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@sap/cds-dk/node_modules/shebang-regex": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/@sap/cds-dk/node_modules/side-channel": { "version": "1.1.0", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "dev": true, "license": "MIT", "dependencies": { @@ -2377,6 +1667,7 @@ }, "node_modules/@sap/cds-dk/node_modules/side-channel-list": { "version": "1.0.0", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", "dev": true, "license": "MIT", "dependencies": { @@ -2392,6 +1683,7 @@ }, "node_modules/@sap/cds-dk/node_modules/side-channel-map": { "version": "1.0.1", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", "dev": true, "license": "MIT", "dependencies": { @@ -2409,6 +1701,7 @@ }, "node_modules/@sap/cds-dk/node_modules/side-channel-weakmap": { "version": "1.0.2", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", "dev": true, "license": "MIT", "dependencies": { @@ -2427,6 +1720,7 @@ }, "node_modules/@sap/cds-dk/node_modules/simple-concat": { "version": "1.0.1", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", "dev": true, "funding": [ { @@ -2447,6 +1741,7 @@ }, "node_modules/@sap/cds-dk/node_modules/simple-get": { "version": "4.0.1", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", "dev": true, "funding": [ { @@ -2472,6 +1767,7 @@ }, "node_modules/@sap/cds-dk/node_modules/source-map": { "version": "0.6.1", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -2479,7 +1775,8 @@ } }, "node_modules/@sap/cds-dk/node_modules/statuses": { - "version": "2.0.1", + "version": "2.0.2", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "dev": true, "license": "MIT", "engines": { @@ -2488,6 +1785,7 @@ }, "node_modules/@sap/cds-dk/node_modules/string_decoder": { "version": "1.3.0", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, "license": "MIT", "optional": true, @@ -2496,29 +1794,18 @@ } }, "node_modules/@sap/cds-dk/node_modules/strip-json-comments": { - "version": "3.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@sap/cds-dk/node_modules/supports-color": { - "version": "7.2.0", + "version": "2.0.1", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", "dev": true, "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, + "optional": true, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, "node_modules/@sap/cds-dk/node_modules/tar-fs": { - "version": "2.1.2", + "version": "2.1.4", + "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", "dev": true, "license": "MIT", "optional": true, @@ -2531,6 +1818,7 @@ }, "node_modules/@sap/cds-dk/node_modules/tar-stream": { "version": "2.2.0", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "dev": true, "license": "MIT", "optional": true, @@ -2547,6 +1835,7 @@ }, "node_modules/@sap/cds-dk/node_modules/to-regex-range": { "version": "5.0.1", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2558,6 +1847,7 @@ }, "node_modules/@sap/cds-dk/node_modules/toidentifier": { "version": "1.0.1", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "dev": true, "license": "MIT", "engines": { @@ -2566,6 +1856,7 @@ }, "node_modules/@sap/cds-dk/node_modules/tunnel-agent": { "version": "0.6.0", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "dev": true, "license": "Apache-2.0", "optional": true, @@ -2576,24 +1867,15 @@ "node": "*" } }, - "node_modules/@sap/cds-dk/node_modules/type-check": { - "version": "0.4.0", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/@sap/cds-dk/node_modules/type-is": { - "version": "1.6.18", + "version": "2.0.1", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", "dev": true, "license": "MIT", "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" }, "engines": { "node": ">= 0.6" @@ -2601,6 +1883,7 @@ }, "node_modules/@sap/cds-dk/node_modules/uglify-js": { "version": "3.19.3", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", "dev": true, "license": "BSD-2-Clause", "optional": true, @@ -2613,36 +1896,23 @@ }, "node_modules/@sap/cds-dk/node_modules/unpipe": { "version": "1.0.0", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" } }, - "node_modules/@sap/cds-dk/node_modules/uri-js": { - "version": "4.4.1", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, "node_modules/@sap/cds-dk/node_modules/util-deprecate": { "version": "1.0.2", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true, "license": "MIT", "optional": true }, - "node_modules/@sap/cds-dk/node_modules/utils-merge": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/@sap/cds-dk/node_modules/vary": { "version": "1.1.2", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "dev": true, "license": "MIT", "engines": { @@ -2651,6 +1921,7 @@ }, "node_modules/@sap/cds-dk/node_modules/verror": { "version": "1.10.1", + "integrity": "sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==", "dev": true, "license": "MIT", "dependencies": { @@ -2662,41 +1933,21 @@ "node": ">=0.6.0" } }, - "node_modules/@sap/cds-dk/node_modules/which": { - "version": "2.0.2", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@sap/cds-dk/node_modules/word-wrap": { - "version": "1.2.5", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@sap/cds-dk/node_modules/wordwrap": { "version": "1.0.0", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", "dev": true, "license": "MIT" }, "node_modules/@sap/cds-dk/node_modules/wrappy": { "version": "1.0.2", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true, - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/@sap/cds-dk/node_modules/ws": { - "version": "8.18.1", + "version": "8.19.0", + "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", "dev": true, "license": "MIT", "engines": { @@ -2717,6 +1968,7 @@ }, "node_modules/@sap/cds-dk/node_modules/xml-js": { "version": "1.6.11", + "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", "dev": true, "license": "MIT", "dependencies": { @@ -2726,34 +1978,19 @@ "xml-js": "bin/cli.js" } }, - "node_modules/@sap/cds-dk/node_modules/xmlbuilder": { - "version": "15.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.0" - } - }, "node_modules/@sap/cds-dk/node_modules/yaml": { - "version": "2.7.1", + "version": "2.8.2", + "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", "dev": true, "license": "ISC", "bin": { "yaml": "bin.mjs" }, "engines": { - "node": ">= 14" - } - }, - "node_modules/@sap/cds-dk/node_modules/yocto-queue": { - "version": "0.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" + "node": ">= 14.6" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/eemeli" } } } diff --git a/package.json b/package.json index 535d182..6183b12 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,6 @@ "app/incidents" ], "devDependencies": { - "@sap/cds-dk": "^8.6.1" + "@sap/cds-dk": "^9" } } diff --git a/pom.xml b/pom.xml index 3cf4285..ef0b6b7 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ 1.0.0-SNAPSHOT 21 - 4.4.0 + 4.8.0-SNAPSHOT 3.5.6 1.0.7 https://nodejs.org/dist/ From 7ad302ae5656316039384d5f9be53bc439a46947 Mon Sep 17 00:00:00 2001 From: Robin de Silva Jayasinghe Date: Fri, 13 Feb 2026 09:03:04 +0100 Subject: [PATCH 03/10] release instead of snapshot --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ef0b6b7..1e2c803 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ 1.0.0-SNAPSHOT 21 - 4.8.0-SNAPSHOT + 4.7.0 3.5.6 1.0.7 https://nodejs.org/dist/ From fceb26edd285b674168ed2e0d4166a8625bef8c3 Mon Sep 17 00:00:00 2001 From: Robin de Silva Jayasinghe Date: Fri, 13 Feb 2026 09:56:29 +0100 Subject: [PATCH 04/10] snapshot --- pom.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1e2c803..d1d19da 100644 --- a/pom.xml +++ b/pom.xml @@ -11,13 +11,15 @@ 1.0.0-SNAPSHOT 21 - 4.7.0 + 4.8.0-SNAPSHOT 3.5.6 1.0.7 https://nodejs.org/dist/ UTF-8 + reuse-models + apis srv From ca38caf7b5d6d1b264d08ff29d96fb252be18fbb Mon Sep 17 00:00:00 2001 From: Robin de Silva Jayasinghe Date: Fri, 13 Feb 2026 13:09:02 +0100 Subject: [PATCH 05/10] fix pom --- pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/pom.xml b/pom.xml index d1d19da..ea521ea 100644 --- a/pom.xml +++ b/pom.xml @@ -18,7 +18,6 @@ UTF-8 - reuse-models apis srv From 72eeab5aa156db4d6eb64616282c5870fc925987 Mon Sep 17 00:00:00 2001 From: Robin de Silva Jayasinghe Date: Mon, 2 Mar 2026 15:05:38 +0100 Subject: [PATCH 06/10] add documentation for CAP Java OData request/response cycle Documents the complete request processing flow from HTTP entry point through OData adapter, CQN conversion, event handlers, and persistence layer. Includes code references to actual CAP runtime classes and this app's handler implementations. --- requests.md | 876 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 876 insertions(+) create mode 100644 requests.md diff --git a/requests.md b/requests.md new file mode 100644 index 0000000..3bbce89 --- /dev/null +++ b/requests.md @@ -0,0 +1,876 @@ +# CAP Java: OData Request/Response Cycle + +## Overview + +This application demonstrates SAP Cloud Application Programming Model (CAP) for Java. CAP provides an opinionated framework that handles OData protocol, database persistence, and business logic orchestration through a well-defined event-driven architecture. + +--- + +## 1. High-Level Architecture + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ CAP Java Runtime β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ OData V4 β”‚ β”‚ Service β”‚ β”‚ Persistence Layer β”‚ β”‚ +β”‚ β”‚ Adapter │───▢│ Layer │───▢│ (PersistenceService) β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ - Parse β”‚ β”‚ - Processor β”‚ β”‚ - CQN to SQL translation β”‚ β”‚ +β”‚ β”‚ - Serialize β”‚ β”‚ Service β”‚ β”‚ - Transaction management β”‚ β”‚ +β”‚ β”‚ - $metadata β”‚ β”‚ - Admin β”‚ β”‚ - Database execution β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ Service β”‚ β”‚ β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ β–Ό β”‚ β”‚ +β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ +β”‚ β”‚ β”‚ Event β”‚ β”‚ β”‚ +β”‚ β”‚ β”‚ Handlers β”‚ β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ β”‚ @Before β”‚ β”‚ β”‚ +β”‚ β”‚ β”‚ @On β”‚ β”‚ β”‚ +β”‚ β”‚ β”‚ @After β”‚ β”‚ β”‚ +β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ β”‚ + β–Ό β–Ό + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ HTTP β”‚ β”‚ Database β”‚ + β”‚ Client β”‚ β”‚ (H2/HANA) β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +### Runtime Components (Maven Dependencies) + +| Component | Maven Artifact | Purpose | +|-----------|----------------|---------| +| OData V4 Adapter | `cds-adapter-odata-v4` | HTTP/OData protocol handling | +| Spring Boot Integration | `cds-starter-spring-boot` | Auto-configuration, DI | +| Core Runtime | `cds4j-runtime` | Event handling, persistence | + +--- + +## 2. The CDS Model Layer + +CAP uses **CDS (Core Data Services)** to define both the domain model and service exposure: + +### Domain Model + +**File:** [`db/schema.cds`](db/schema.cds) + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Domain Model β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ Incidents │────────▢│ Customers β”‚ β”‚ +β”‚ β”‚ β”‚ N:1 β”‚ β”‚ β”‚ +β”‚ β”‚ - title β”‚ β”‚ - name β”‚ β”‚ +β”‚ β”‚ - urgency ─┼────┐ β”‚ - email β”‚ β”‚ +β”‚ β”‚ - status ──┼──┐ β”‚ β”‚ - phone β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ 1:N β”‚ β”‚ β”‚ 1:N β”‚ +β”‚ β–Ό β”‚ β”‚ β–Ό β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚Conversation β”‚ β”‚ β”‚ β”‚ Addresses β”‚ β”‚ +β”‚ β”‚ - author β”‚ β”‚ β”‚ β”‚ - city β”‚ β”‚ +β”‚ β”‚ - message β”‚ β”‚ β”‚ β”‚ - postCode β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ └─────────┐ β”‚ +β”‚ β–Ό β–Ό β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ Status β”‚ β”‚ Urgency β”‚ (CodeList entities) β”‚ +β”‚ β”‚ N,A,I,H, β”‚ β”‚ H, M, L β”‚ β”‚ +β”‚ β”‚ R,C β”‚ β”‚ β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +**Code Reference:** [`db/schema.cds:7-18`](db/schema.cds) - Incidents entity definition + +```cds +entity Incidents : cuid, managed { + customer : Association to Customers; + title : String @title : 'Title'; + urgency : Association to Urgency default 'M'; + status : Association to Status default 'N'; + conversation : Composition of many { ... }; +} +``` + +### Service Projections + +**File:** [`srv/services.cds`](srv/services.cds) + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ ProcessorService β”‚ β”‚ AdminService β”‚ +β”‚ @requires: 'support' β”‚ β”‚ @requires: 'admin' β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ β”‚ β”‚ β”‚ +β”‚ Incidents β”‚ β”‚ Incidents β”‚ +β”‚ β”œβ”€β”€ @odata.draft.enabled β”‚ β”‚ └── full CRUD β”‚ +β”‚ └── full CRUD β”‚ β”‚ β”‚ +β”‚ β”‚ β”‚ Customers β”‚ +β”‚ Customers β”‚ β”‚ └── full CRUD β”‚ +β”‚ └── @readonly β”‚ β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ β”‚ + β”‚ OData Endpoint β”‚ OData Endpoint + β–Ό β–Ό + /odata/v4/ProcessorService /odata/v4/AdminService +``` + +**Code Reference:** [`srv/services.cds:6-9`](srv/services.cds) - ProcessorService definition + +```cds +service ProcessorService { + entity Incidents as projection on my.Incidents; + entity Customers @readonly as projection on my.Customers; +} +``` + +**Code Reference:** [`srv/services.cds:19-21`](srv/services.cds) - Annotations + +```cds +annotate ProcessorService.Incidents with @odata.draft.enabled; +annotate ProcessorService with @(requires: 'support'); +annotate AdminService with @(requires: 'admin'); +``` + +--- + +## 3. Request/Response Flow: CREATE Example + +Let's trace a `POST /odata/v4/ProcessorService/Incidents` request through the actual code: + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ CREATE Incident Flow β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + + Client Database + β”‚ β”‚ + β”‚ POST /odata/v4/ProcessorService/Incidents β”‚ + β”‚ { "title": "Urgent: Server down", "customer_ID": "1001" } β”‚ + β”‚ β”‚ + β–Ό β”‚ +``` + +### Step 1: HTTP Entry Point (OData Servlet) + +**Class:** `com.sap.cds.adapter.odata.v4.AbstractCdsODataServlet` +**Artifact:** `cds-adapter-odata-v4` + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ 1. OData V4 Adapter Entry Point β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ AbstractCdsODataServlet.service(HttpServletRequest, HttpServletResponse)β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ β€’ Establishes request context with runtime.requestContext() β”‚ β”‚ +β”‚ β”‚ β€’ Extracts service name from URL: "ProcessorService" β”‚ β”‚ +β”‚ β”‚ β€’ Validates service definition exists β”‚ β”‚ +β”‚ β”‚ β€’ Initializes Olingo OData infrastructure (EDM, metadata) β”‚ β”‚ +β”‚ β”‚ β€’ Registers OlingoProcessor as the request processor β”‚ β”‚ +β”‚ β”‚ β€’ Calls odataHandler.process(req, resp) β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +``` + +### Step 2: Olingo Processing Bridge + +**Class:** `com.sap.cds.adapter.odata.v4.processors.OlingoProcessor` +**Implements:** `EntityProcessor`, `ActionEntityProcessor`, `BatchProcessor`, etc. + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ 2. Olingo Processor Bridge β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ OlingoProcessor implements all Olingo processor interfaces β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ β€’ Receives parsed OData request from Olingo β”‚ β”‚ +β”‚ β”‚ β€’ Delegates to CdsProcessor for CAP-specific handling β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +``` + +### Step 3: CQN Conversion & Service Dispatch + +**Class:** `com.sap.cds.adapter.odata.v4.processors.CdsProcessor` +**Key Methods:** +- `processRequest()` - Main entry point +- `post()` - Handles POST/CREATE requests +- `delegateRequest()` - Routes by HTTP method + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ 3. CQN Conversion (CdsProcessor) β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ CdsProcessor.post(CdsODataRequest request) β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ // Get the target service β”‚ β”‚ +β”‚ β”‚ ApplicationService applicationService = globals.getApplicationService();β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ // Convert OData payload to CQN Insert statement β”‚ β”‚ +β”‚ β”‚ Insert insert = Insert.into(ref).entry(entityData); β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ // Dispatch to service layer (triggers event handlers) β”‚ β”‚ +β”‚ β”‚ result = applicationService.run(insert); // ◄── SERVICE DISPATCH β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ return new CdsODataResponse(SC_CREATED, remapResult(...)); β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β”‚ applicationService.run(insert) + β–Ό +``` + +### Step 4: Event Handler Chain + +**Interface:** `com.sap.cds.services.cds.ApplicationService` +**Interface:** `com.sap.cds.services.handler.EventHandler` + +The `applicationService.run()` call triggers the event handler chain: + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ 4. Service Layer - Event Dispatch β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ ApplicationService.run(CqnInsert) β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ β€’ Authorization check: user has 'support' role? (from @requires) β”‚ β”‚ +β”‚ β”‚ β€’ Emit event: CqnService.EVENT_CREATE ("CREATE") β”‚ β”‚ +β”‚ β”‚ β€’ Find registered handlers via @ServiceName annotation β”‚ β”‚ +β”‚ β”‚ β€’ Execute handler chain: @Before β†’ @On β†’ @After β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +``` + +### Step 5: @Before Handler Execution + +**File:** [`srv/src/main/java/customer/incident_management/handler/ProcessorServiceHandler.java`](srv/src/main/java/customer/incident_management/handler/ProcessorServiceHandler.java) + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ 5. @Before Handler Phase β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ ProcessorServiceHandler.java:35-45 β”‚ β”‚ +β”‚ β”‚ ───────────────────────────────────────────────────────────────────── β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ @Before(event = CqnService.EVENT_CREATE) β”‚ β”‚ +β”‚ β”‚ public void ensureHighUrgencyForIncidentsWithUrgentInTitle( β”‚ β”‚ +β”‚ β”‚ List incidents) { β”‚ β”‚ +β”‚ β”‚ for (Incidents incident : incidents) { β”‚ β”‚ +β”‚ β”‚ if (incident.getTitle() β”‚ β”‚ +β”‚ β”‚ .toLowerCase(Locale.ENGLISH) β”‚ β”‚ +β”‚ β”‚ .contains("urgent") && β”‚ β”‚ +β”‚ β”‚ incident.getUrgencyCode() == null || β”‚ β”‚ +β”‚ β”‚ !incident.getUrgencyCode().equals("H")) { β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ incident.setUrgencyCode("H"); // ◄── MUTATE INPUT β”‚ β”‚ +β”‚ β”‚ logger.info("Adjusted Urgency..."); β”‚ β”‚ +β”‚ β”‚ } β”‚ β”‚ +β”‚ β”‚ } β”‚ β”‚ +β”‚ β”‚ } β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ Input: { title: "Urgent: Server down", urgency_code: null } β”‚ β”‚ +β”‚ β”‚ Output: { title: "Urgent: Server down", urgency_code: "H" } β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +``` + +### Step 6: @On Handler (Default Persistence) + +**Interface:** `com.sap.cds.services.persistence.PersistenceService` + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ 6. @On Handler Phase (Default: GenericHandler β†’ PersistenceService) β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ No custom @On handler in this app β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ CAP's built-in GenericHandler delegates to: β”‚ β”‚ +β”‚ β”‚ PersistenceService.run(CqnInsert) β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ The PersistenceService: β”‚ β”‚ +β”‚ β”‚ β€’ Translates CQN to SQL (database-specific) β”‚ β”‚ +β”‚ β”‚ β€’ Manages transaction boundaries β”‚ β”‚ +β”‚ β”‚ β€’ Executes the SQL statement β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +``` + +### Step 7: SQL Generation & Execution + +**Package:** `com.sap.cds.impl.sql.*` (in `cds4j-runtime`) +**Generated Schema:** [`srv/src/main/resources/schema-h2.sql`](srv/src/main/resources/schema-h2.sql) (generated at build time) + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ 7. Persistence Layer - SQL Execution β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ CQN to SQL Translation (com.sap.cds.impl.sql.*) β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ INSERT INTO sap_capire_incidents_Incidents β”‚ β”‚ +β”‚ β”‚ (ID, title, urgency_code, status_code, customer_ID, β”‚ β”‚ +β”‚ β”‚ createdAt, createdBy, modifiedAt, modifiedBy) β”‚ β”‚ +β”‚ β”‚ VALUES β”‚ β”‚ +β”‚ β”‚ (UUID, 'Urgent: Server down', 'H', 'N', '1001', β”‚ β”‚ +β”‚ β”‚ NOW(), 'alice', NOW(), 'alice') β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ Target table defined in: schema-h2.sql (generated from schema.cds) β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ H2 β”‚ + β”‚ Database β”‚ + β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ + β”‚ + β”‚ (Result: 1 row inserted) + β–Ό +``` + +### Step 8: @After Handler & Response + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ 8. @After Handler Phase β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ No custom @After handler in this app β”‚ β”‚ +β”‚ β”‚ Could be used for: audit logging, notifications, enrichment β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ 9. Response Serialization β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ CdsProcessor.post() returns: β”‚ β”‚ +β”‚ β”‚ new CdsODataResponse(SC_CREATED, remapResult(result, entity, null)) β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ OlingoProcessor serializes to OData JSON format β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό + Client receives: + HTTP/1.1 201 Created + { + "ID": "...", + "title": "Urgent: Server down", + "urgency_code": "H", + "status_code": "N", + ... + } +``` + +--- + +## 4. Event Handler Phases + +CAP Java uses three handler phases, executed in order: + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Event Handler Lifecycle β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ @Before Phase β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ Annotation: com.sap.cds.services.handler.annotations.Before β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ Purpose: Validation, input mutation, authorization checks β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ β€’ Runs BEFORE the main operation β”‚ β”‚ +β”‚ β”‚ β€’ Can modify input data β”‚ β”‚ +β”‚ β”‚ β€’ Can reject request by throwing ServiceException β”‚ β”‚ +β”‚ β”‚ β€’ Multiple @Before handlers execute in registration order β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ This app's handlers: β”‚ β”‚ +β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ +β”‚ β”‚ β”‚ ProcessorServiceHandler.java:35-45 β”‚ β”‚ β”‚ +β”‚ β”‚ β”‚ @Before(event = CqnService.EVENT_CREATE) β”‚ β”‚ β”‚ +β”‚ β”‚ β”‚ ensureHighUrgencyForIncidentsWithUrgentInTitle(List) β”‚ β”‚ β”‚ +β”‚ β”‚ β”‚ β†’ Mutates urgency_code if title contains "urgent" β”‚ β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ β”‚ ProcessorServiceHandler.java:50-57 β”‚ β”‚ β”‚ +β”‚ β”‚ β”‚ @Before(event = CqnService.EVENT_UPDATE) β”‚ β”‚ β”‚ +β”‚ β”‚ β”‚ ensureNoUpdateOnClosedIncidents(Incidents) β”‚ β”‚ β”‚ +β”‚ β”‚ β”‚ β†’ Throws ServiceException(CONFLICT) if status = 'C' β”‚ β”‚ β”‚ +β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ β”‚ +β”‚ β–Ό β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ @On Phase β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ Annotation: com.sap.cds.services.handler.annotations.On β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ Purpose: Main operation execution β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ β€’ The actual CRUD operation happens here β”‚ β”‚ +β”‚ β”‚ β€’ Default: CAP's GenericHandler delegates to PersistenceService β”‚ β”‚ +β”‚ β”‚ β€’ Custom @On handler REPLACES default behavior β”‚ β”‚ +β”‚ β”‚ β€’ Only ONE @On handler executes (first registered wins) β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ Use cases for custom @On: β”‚ β”‚ +β”‚ β”‚ β€’ Call external APIs instead of/alongside database β”‚ β”‚ +β”‚ β”‚ β€’ Complex multi-step operations β”‚ β”‚ +β”‚ β”‚ β€’ Custom actions/functions β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ β”‚ +β”‚ β–Ό β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ @After Phase β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ Annotation: com.sap.cds.services.handler.annotations.After β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ Purpose: Post-processing, side effects β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ β€’ Runs AFTER the main operation completes successfully β”‚ β”‚ +β”‚ β”‚ β€’ Can modify response data β”‚ β”‚ +β”‚ β”‚ β€’ Can trigger side effects (notifications, audit logs, etc.) β”‚ β”‚ +β”‚ β”‚ β€’ Multiple @After handlers execute in registration order β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ Common uses: β”‚ β”‚ +β”‚ β”‚ β€’ Enrich response with computed fields β”‚ β”‚ +β”‚ β”‚ β€’ Send notifications β”‚ β”‚ +β”‚ β”‚ β€’ Log audit trails β”‚ β”‚ +β”‚ β”‚ β€’ Trigger downstream workflows β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +--- + +## 5. UPDATE Flow with Validation Rejection + +The `@Before(EVENT_UPDATE)` handler demonstrates request rejection. + +**File:** [`srv/src/main/java/customer/incident_management/handler/ProcessorServiceHandler.java:50-57`](srv/src/main/java/customer/incident_management/handler/ProcessorServiceHandler.java) + +``` + Client Database + β”‚ β”‚ + β”‚ PATCH /odata/v4/ProcessorService/Incidents(ID='...') β”‚ + β”‚ { "title": "Updated title" } β”‚ + β”‚ β”‚ + β–Ό β”‚ +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ @Before(EVENT_UPDATE) - ProcessorServiceHandler.java:50-57 β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚ +β”‚ β”‚ β”‚β”‚ +β”‚ β”‚ @Before(event = CqnService.EVENT_UPDATE) β”‚β”‚ +β”‚ β”‚ public void ensureNoUpdateOnClosedIncidents(Incidents incident) { β”‚β”‚ +β”‚ β”‚ β”‚β”‚ +β”‚ β”‚ // Line 52: Query current state using PersistenceService β”‚β”‚ +β”‚ β”‚ Incidents in = db.run( β”‚β”‚ +β”‚ β”‚ Select.from(Incidents_.class) β”‚β”‚ +β”‚ β”‚ .where(i -> i.ID().eq(incident.getId())) β”‚β”‚ +β”‚ β”‚ ).single(Incidents.class); β”‚β”‚ +β”‚ β”‚ β”‚β”‚ +β”‚ β”‚ // Line 53-55: Check status and reject if closed β”‚β”‚ +β”‚ β”‚ if (in.getStatusCode().equals("C")) { β”‚β”‚ +β”‚ β”‚ throw new ServiceException( β”‚β”‚ +β”‚ β”‚ ErrorStatuses.CONFLICT, ◄─── HTTP 409 β”‚β”‚ +β”‚ β”‚ "Can't modify a closed incident" β”‚β”‚ +β”‚ β”‚ ); β”‚β”‚ +β”‚ β”‚ } β”‚β”‚ +β”‚ β”‚ } β”‚β”‚ +β”‚ β”‚ β”‚β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ β”‚ + β–Ό β–Ό + Status = 'C' (Closed) Status != 'C' + β”‚ β”‚ + β–Ό β–Ό + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ ServiceException β”‚ β”‚ Continue to @On β”‚ + β”‚ thrown β”‚ β”‚ phase (UPDATE β”‚ + β”‚ β”‚ β”‚ proceeds) β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό + Client receives: + HTTP/1.1 409 Conflict + { + "error": { + "code": "409", + "message": "Can't modify a closed incident" + } + } +``` + +**Key Classes Used:** + +| Import | Purpose | +|--------|---------| +| `com.sap.cds.services.ErrorStatuses` | HTTP status code mappings | +| `com.sap.cds.services.ServiceException` | Exception that maps to HTTP error response | +| `com.sap.cds.services.persistence.PersistenceService` | Direct database access | +| `com.sap.cds.ql.Select` | CQN query builder | + +--- + +## 6. CQN (CDS Query Notation) + +CQN is CAP's internal query representation, independent of the database. + +**Package:** `com.sap.cds.ql.*` + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ CQN: Abstraction Layer for Queries β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ β”‚ +β”‚ OData Request CQN Representation β”‚ +β”‚ ───────────── ────────────────── β”‚ +β”‚ β”‚ +β”‚ GET /Incidents?$filter=urgency_code eq 'H' β”‚ +β”‚ ──────────────────────────────────────────── β”‚ +β”‚ β”‚ +β”‚ // com.sap.cds.ql.Select β”‚ +β”‚ Select.from(Incidents_.class) β”‚ +β”‚ .where(i -> i.urgency().code().eq("H")) β”‚ +β”‚ β”‚ +β”‚ CdsProcessor.get() builds this from OData $filter β”‚ +β”‚ β”‚ +β”‚ ═══════════════════════════════════════════════════════════════════════════ β”‚ +β”‚ β”‚ +β”‚ POST /Incidents { "title": "New issue" } β”‚ +β”‚ ──────────────────────────────────────── β”‚ +β”‚ β”‚ +β”‚ // com.sap.cds.ql.Insert β”‚ +β”‚ Insert.into(Incidents_.class) β”‚ +β”‚ .entry(incident) β”‚ +β”‚ β”‚ +β”‚ CdsProcessor.post(): Insert insert = Insert.into(ref).entry(entityData); β”‚ +β”‚ β”‚ +β”‚ ═══════════════════════════════════════════════════════════════════════════ β”‚ +β”‚ β”‚ +β”‚ PATCH /Incidents(ID='xxx') { "status_code": "R" } β”‚ +β”‚ ───────────────────────────────────────────────── β”‚ +β”‚ β”‚ +β”‚ // com.sap.cds.ql.Update β”‚ +β”‚ Update.entity(Incidents_.class) β”‚ +β”‚ .data(incident) β”‚ +β”‚ .where(i -> i.ID().eq("xxx")) β”‚ +β”‚ β”‚ +β”‚ CdsProcessor.patch(): CqnUpdate update = Update.entity(ref).data(entityData);β”‚ +β”‚ β”‚ +β”‚ ═══════════════════════════════════════════════════════════════════════════ β”‚ +β”‚ β”‚ +β”‚ DELETE /Incidents(ID='xxx') β”‚ +β”‚ ─────────────────────────── β”‚ +β”‚ β”‚ +β”‚ // com.sap.cds.ql.Delete β”‚ +β”‚ Delete.from(Incidents_.class) β”‚ +β”‚ .where(i -> i.ID().eq("xxx")) β”‚ +β”‚ β”‚ +β”‚ CdsProcessor.delete(): CqnDelete delete = Delete.from(toPathExpression(...));β”‚ +β”‚ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + + β”‚ + β”‚ PersistenceService.run() translates + β”‚ via com.sap.cds.impl.sql.* + β–Ό + +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Generated SQL β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ β”‚ +β”‚ SELECT * FROM sap_capire_incidents_Incidents WHERE urgency_code = 'H' β”‚ +β”‚ β”‚ +β”‚ INSERT INTO sap_capire_incidents_Incidents (...) VALUES (...) β”‚ +β”‚ β”‚ +β”‚ UPDATE sap_capire_incidents_Incidents SET status_code = 'R' WHERE ID = ... β”‚ +β”‚ β”‚ +β”‚ DELETE FROM sap_capire_incidents_Incidents WHERE ID = ... β”‚ +β”‚ β”‚ +β”‚ Table names from: srv/src/main/resources/schema-h2.sql (generated) β”‚ +β”‚ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +--- + +## 7. Handler Registration & Spring Integration + +**File:** [`srv/src/main/java/customer/incident_management/handler/ProcessorServiceHandler.java`](srv/src/main/java/customer/incident_management/handler/ProcessorServiceHandler.java) + +```java +// Line 16: Spring component annotation +@Component // Spring-managed bean + +// Line 21: Binds this handler to ProcessorService +@ServiceName(ProcessorService_.CDS_NAME) // "ProcessorService" + +// Line 22: Implements CAP's EventHandler marker interface +public class ProcessorServiceHandler implements EventHandler { + + // Line 26: PersistenceService for direct DB access + private final PersistenceService db; // Injected by Spring + + // Line 28-30: Constructor injection + public ProcessorServiceHandler(PersistenceService db) { + this.db = db; + } + + // Line 35: Register for CREATE events on Incidents + @Before(event = CqnService.EVENT_CREATE) + public void ensureHighUrgencyForIncidentsWithUrgentInTitle( + List incidents) { // CAP deserializes request body + // Handler logic... + } +} +``` + +### Key Annotations & Interfaces + +| Annotation/Interface | Package | Purpose | +|---------------------|---------|---------| +| `@Component` | `org.springframework.stereotype` | Spring bean registration | +| `@ServiceName` | `com.sap.cds.services.handler.annotations` | Binds handler to CDS service | +| `EventHandler` | `com.sap.cds.services.handler` | Marker interface for CAP handlers | +| `@Before` | `com.sap.cds.services.handler.annotations` | Pre-operation handler | +| `@On` | `com.sap.cds.services.handler.annotations` | Main operation handler | +| `@After` | `com.sap.cds.services.handler.annotations` | Post-operation handler | + +### Event Constants + +**Class:** `com.sap.cds.services.cds.CqnService` + +| Constant | Value | Triggered By | +|----------|-------|--------------| +| `EVENT_CREATE` | `"CREATE"` | POST (new entity) | +| `EVENT_READ` | `"READ"` | GET | +| `EVENT_UPDATE` | `"UPDATE"` | PATCH/PUT | +| `EVENT_DELETE` | `"DELETE"` | DELETE | + +### Generated POJOs + +**Location:** `srv/src/gen/java/cds/gen/` +**Generated By:** `cds-maven-plugin` during build + +| Generated Class | Source | +|-----------------|--------| +| `cds.gen.processorservice.Incidents` | `srv/services.cds` projection | +| `cds.gen.processorservice.ProcessorService_` | Service metadata | +| `cds.gen.sap.capire.incidents.Incidents_` | Entity metadata (for CQN queries) | + +--- + +## 8. Draft-Enabled Entities + +**Annotation:** [`srv/services.cds:19`](srv/services.cds) + +```cds +annotate ProcessorService.Incidents with @odata.draft.enabled; +``` + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Draft Entity Lifecycle β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ β”‚ +β”‚ 1. CREATE (New Draft) β”‚ +β”‚ POST /ProcessorService/Incidents β”‚ +β”‚ ───────────────────────────────────────────────────────────────────── β”‚ +β”‚ β†’ Creates draft record (IsActiveEntity = false) β”‚ +β”‚ β†’ Stored in: ProcessorService_Incidents_drafts table β”‚ +β”‚ β”‚ +β”‚ 2. EDIT (Modify Draft) β”‚ +β”‚ PATCH /ProcessorService/Incidents(ID='...',IsActiveEntity=false) β”‚ +β”‚ ───────────────────────────────────────────────────────────────────── β”‚ +β”‚ β†’ Updates draft without touching active entity β”‚ +β”‚ β†’ Multiple users can see draft state β”‚ +β”‚ β”‚ +β”‚ 3. ACTIVATE (Promote to Active) β”‚ +β”‚ POST .../Incidents(...,IsActiveEntity=false)/ProcessorService.draftActivateβ”‚ +β”‚ ───────────────────────────────────────────────────────────────────── β”‚ +β”‚ β†’ Validates draft β”‚ +β”‚ β†’ Moves to active table (IsActiveEntity = true) β”‚ +β”‚ β†’ Deletes draft record β”‚ +β”‚ β”‚ +β”‚ 4. DISCARD β”‚ +β”‚ DELETE /ProcessorService/Incidents(ID='...',IsActiveEntity=false) β”‚ +β”‚ ───────────────────────────────────────────────────────────────────── β”‚ +β”‚ β†’ Removes draft without affecting active entity β”‚ +β”‚ β”‚ +β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ Draft Tables β”‚ draftActivate β”‚ Active Tables β”‚ β”‚ +β”‚ β”‚ ─────────────── β”‚ ─────────────► β”‚ ───────────── β”‚ β”‚ +β”‚ β”‚ IsActiveEntity β”‚ β”‚ IsActiveEntity β”‚ β”‚ +β”‚ β”‚ = false β”‚ β”‚ = true β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +--- + +## 9. Complete Request Flow Summary + +``` +HTTP Request (POST /odata/v4/ProcessorService/Incidents) + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ AbstractCdsODataServlet.service() β”‚ +β”‚ Package: com.sap.cds.adapter.odata.v4 β”‚ +β”‚ β€’ Establishes request context β”‚ +β”‚ β€’ Extracts service name from URL β”‚ +β”‚ β€’ Initializes Olingo OData infrastructure β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ OlingoProcessor β”‚ +β”‚ Package: com.sap.cds.adapter.odata.v4.processors β”‚ +β”‚ β€’ Implements Olingo processor interfaces β”‚ +β”‚ β€’ Delegates to CdsProcessor β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ CdsProcessor.post() β”‚ +β”‚ Package: com.sap.cds.adapter.odata.v4.processors β”‚ +β”‚ β€’ Converts OData request to CQN: Insert.into(ref).entry(entityData) β”‚ +β”‚ β€’ Calls applicationService.run(insert) β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ ApplicationService.run(CqnInsert) β”‚ +β”‚ Interface: com.sap.cds.services.cds.ApplicationService β”‚ +β”‚ β€’ Authorization check (@requires annotation) β”‚ +β”‚ β€’ Emits EVENT_CREATE event β”‚ +β”‚ β€’ Triggers handler chain β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ @Before Handler β”‚ +β”‚ File: ProcessorServiceHandler.java:35-45 β”‚ +β”‚ Method: ensureHighUrgencyForIncidentsWithUrgentInTitle() β”‚ +β”‚ β€’ Validates/mutates input data β”‚ +β”‚ β€’ Can throw ServiceException to reject request β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ @On Handler (Default: GenericHandler) β”‚ +β”‚ β€’ Delegates to PersistenceService.run(CqnInsert) β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ PersistenceService.run() β”‚ +β”‚ Interface: com.sap.cds.services.persistence.PersistenceService β”‚ +β”‚ Implementation: com.sap.cds.impl.sql.* (in cds4j-runtime) β”‚ +β”‚ β€’ Translates CQN to SQL β”‚ +β”‚ β€’ Executes within transaction β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Database (H2) β”‚ +β”‚ Schema: srv/src/main/resources/schema-h2.sql β”‚ +β”‚ Table: sap_capire_incidents_Incidents β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ @After Handler (none in this app) β”‚ +β”‚ β€’ Post-processing, side effects β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Response Serialization β”‚ +β”‚ CdsProcessor: return new CdsODataResponse(SC_CREATED, remapResult(...)) β”‚ +β”‚ OlingoProcessor: Serializes to OData JSON β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +HTTP Response (201 Created + JSON body) +``` + +--- + +## 10. Key Files Reference + +| File | Purpose | +|------|---------| +| [`db/schema.cds`](db/schema.cds) | Domain model (entities, associations) | +| [`srv/services.cds`](srv/services.cds) | Service definitions, projections, annotations | +| [`srv/src/main/java/customer/incident_management/handler/ProcessorServiceHandler.java`](srv/src/main/java/customer/incident_management/handler/ProcessorServiceHandler.java) | Custom event handlers | +| [`srv/src/main/java/customer/incident_management/Application.java`](srv/src/main/java/customer/incident_management/Application.java) | Spring Boot entry point | +| [`srv/src/main/resources/application.yaml`](srv/src/main/resources/application.yaml) | Runtime configuration | +| `srv/src/main/resources/schema-h2.sql` | Generated database schema | +| `srv/src/gen/java/cds/gen/` | Generated POJOs from CDS | + +--- + +## 11. Key Takeaways + +| Concept | Description | +|---------|-------------| +| **CDS-First** | Define models in CDS; CAP generates SQL, POJOs, and OData metadata | +| **Event-Driven** | All operations emit events; handlers intercept at `@Before`/`@On`/`@After` | +| **CQN** | Database-agnostic query notation; same code works on H2, HANA, PostgreSQL | +| **Service Projections** | Multiple services can expose different views of the same entities | +| **Type-Safe POJOs** | Generated from CDS; handlers receive/return typed objects | +| **Spring Integration** | Handlers are Spring beans with full DI support | +| **Draft Support** | Built-in collaborative editing via `@odata.draft.enabled` | +| **Declarative Security** | `@requires` annotation on services enforces role-based access | + +The beauty of CAP Java is that most of the boilerplate (OData parsing, SQL generation, transaction management) is handled automatically, allowing developers to focus on business logic in event handlers. From 8b500f658153ab1240f57ebd54ad4378390ab155 Mon Sep 17 00:00:00 2001 From: Robin de Silva Jayasinghe Date: Wed, 11 Mar 2026 11:31:41 +0100 Subject: [PATCH 07/10] manually aligned vertical lines --- requests.md | 196 ++++++++++++++++++++++++++-------------------------- 1 file changed, 98 insertions(+), 98 deletions(-) diff --git a/requests.md b/requests.md index 3bbce89..9093298 100644 --- a/requests.md +++ b/requests.md @@ -10,7 +10,7 @@ This application demonstrates SAP Cloud Application Programming Model (CAP) for ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ CAP Java Runtime β”‚ +β”‚ CAP Java Runtime β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ @@ -62,33 +62,33 @@ CAP uses **CDS (Core Data Services)** to define both the domain model and servic ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Domain Model β”‚ +β”‚ Domain Model β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Incidents │────────▢│ Customers β”‚ β”‚ -β”‚ β”‚ β”‚ N:1 β”‚ β”‚ β”‚ -β”‚ β”‚ - title β”‚ β”‚ - name β”‚ β”‚ -β”‚ β”‚ - urgency ─┼────┐ β”‚ - email β”‚ β”‚ -β”‚ β”‚ - status ──┼──┐ β”‚ β”‚ - phone β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ Incidents │────────▢│ Customers β”‚ β”‚ +β”‚ β”‚ β”‚ N:1 β”‚ β”‚ β”‚ +β”‚ β”‚ - title β”‚ β”‚ - name β”‚ β”‚ +β”‚ β”‚ - urgency ─┼────┐ β”‚ - email β”‚ β”‚ +β”‚ β”‚ - status ──┼──┐ β”‚ β”‚ - phone β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ 1:N β”‚ β”‚ β”‚ 1:N β”‚ β”‚ β–Ό β”‚ β”‚ β–Ό β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚Conversation β”‚ β”‚ β”‚ β”‚ Addresses β”‚ β”‚ -β”‚ β”‚ - author β”‚ β”‚ β”‚ β”‚ - city β”‚ β”‚ -β”‚ β”‚ - message β”‚ β”‚ β”‚ β”‚ - postCode β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚Conversation β”‚ β”‚ β”‚ β”‚ Addresses β”‚ β”‚ +β”‚ β”‚ - author β”‚ β”‚ β”‚ β”‚ - city β”‚ β”‚ +β”‚ β”‚ - message β”‚ β”‚ β”‚ β”‚ - postCode β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ └─────────┐ β”‚ -β”‚ β–Ό β–Ό β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ Status β”‚ β”‚ Urgency β”‚ (CodeList entities) β”‚ -β”‚ β”‚ N,A,I,H, β”‚ β”‚ H, M, L β”‚ β”‚ -β”‚ β”‚ R,C β”‚ β”‚ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ └─────────┐ β”‚ +β”‚ β–Ό β–Ό β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ Status β”‚ β”‚ Urgency β”‚ (CodeList entities) β”‚ +β”‚ β”‚ N,A,I,H, β”‚ β”‚ H, M, L β”‚ β”‚ +β”‚ β”‚ R,C β”‚ β”‚ β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` @@ -154,7 +154,7 @@ Let's trace a `POST /odata/v4/ProcessorService/Incidents` request through the ac ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ CREATE Incident Flow β”‚ +β”‚ CREATE Incident Flow β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ Client Database @@ -175,7 +175,7 @@ Let's trace a `POST /odata/v4/ProcessorService/Incidents` request through the ac β”‚ 1. OData V4 Adapter Entry Point β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ AbstractCdsODataServlet.service(HttpServletRequest, HttpServletResponse)β”‚ β”‚ +β”‚ β”‚ AbstractCdsODataServlet.service(HttpServletRequest, HttpServletResponse)β”‚β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β€’ Establishes request context with runtime.requestContext() β”‚ β”‚ β”‚ β”‚ β€’ Extracts service name from URL: "ProcessorService" β”‚ β”‚ @@ -227,7 +227,7 @@ Let's trace a `POST /odata/v4/ProcessorService/Incidents` request through the ac β”‚ β”‚ CdsProcessor.post(CdsODataRequest request) β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ // Get the target service β”‚ β”‚ -β”‚ β”‚ ApplicationService applicationService = globals.getApplicationService();β”‚ β”‚ +β”‚ β”‚ ApplicationService applicationService = globals.getApplicationService();β”‚β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ // Convert OData payload to CQN Insert statement β”‚ β”‚ β”‚ β”‚ Insert insert = Insert.into(ref).entry(entityData); β”‚ β”‚ @@ -297,8 +297,8 @@ The `applicationService.run()` call triggers the event handler chain: β”‚ β”‚ } β”‚ β”‚ β”‚ β”‚ } β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ Input: { title: "Urgent: Server down", urgency_code: null } β”‚ β”‚ -β”‚ β”‚ Output: { title: "Urgent: Server down", urgency_code: "H" } β”‚ β”‚ +β”‚ β”‚ Input: { title: "Urgent: Server down", urgency_code: null } β”‚ β”‚ +β”‚ β”‚ Output: { title: "Urgent: Server down", urgency_code: "H" } β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ @@ -343,17 +343,17 @@ The `applicationService.run()` call triggers the event handler chain: β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ CQN to SQL Translation (com.sap.cds.impl.sql.*) β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ INSERT INTO sap_capire_incidents_Incidents β”‚ β”‚ -β”‚ β”‚ (ID, title, urgency_code, status_code, customer_ID, β”‚ β”‚ -β”‚ β”‚ createdAt, createdBy, modifiedAt, modifiedBy) β”‚ β”‚ +β”‚ β”‚ INSERT INTO sap_capire_incidents_Incidents β”‚ β”‚ +β”‚ β”‚ (ID, title, urgency_code, status_code, customer_ID, β”‚ β”‚ +β”‚ β”‚ createdAt, createdBy, modifiedAt, modifiedBy) β”‚ β”‚ β”‚ β”‚ VALUES β”‚ β”‚ -β”‚ β”‚ (UUID, 'Urgent: Server down', 'H', 'N', '1001', β”‚ β”‚ -β”‚ β”‚ NOW(), 'alice', NOW(), 'alice') β”‚ β”‚ +β”‚ β”‚ (UUID, 'Urgent: Server down', 'H', 'N', '1001', β”‚ β”‚ +β”‚ β”‚ NOW(), 'alice', NOW(), 'alice') β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ Target table defined in: schema-h2.sql (generated from schema.cds) β”‚ β”‚ +β”‚ β”‚ Target table defined in: schema-h2.sql (generated from schema.cds) β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” @@ -376,7 +376,7 @@ The `applicationService.run()` call triggers the event handler chain: β”‚ β”‚ Could be used for: audit logging, notifications, enrichment β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” @@ -384,12 +384,12 @@ The `applicationService.run()` call triggers the event handler chain: β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ CdsProcessor.post() returns: β”‚ β”‚ -β”‚ β”‚ new CdsODataResponse(SC_CREATED, remapResult(result, entity, null)) β”‚ β”‚ +β”‚ β”‚ new CdsODataResponse(SC_CREATED, remapResult(result, entity, null)) β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ OlingoProcessor serializes to OData JSON format β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β–Ό Client receives: @@ -411,7 +411,7 @@ CAP Java uses three handler phases, executed in order: ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Event Handler Lifecycle β”‚ +β”‚ Event Handler Lifecycle β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ @@ -493,8 +493,8 @@ The `@Before(EVENT_UPDATE)` handler demonstrates request rejection. ``` Client Database β”‚ β”‚ - β”‚ PATCH /odata/v4/ProcessorService/Incidents(ID='...') β”‚ - β”‚ { "title": "Updated title" } β”‚ + β”‚ PATCH /odata/v4/ProcessorService/Incidents(ID='...') β”‚ + β”‚ { "title": "Updated title" } β”‚ β”‚ β”‚ β–Ό β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” @@ -512,15 +512,15 @@ The `@Before(EVENT_UPDATE)` handler demonstrates request rejection. β”‚ β”‚ β”‚β”‚ β”‚ β”‚ // Line 53-55: Check status and reject if closed β”‚β”‚ β”‚ β”‚ if (in.getStatusCode().equals("C")) { β”‚β”‚ -β”‚ β”‚ throw new ServiceException( β”‚β”‚ -β”‚ β”‚ ErrorStatuses.CONFLICT, ◄─── HTTP 409 β”‚β”‚ -β”‚ β”‚ "Can't modify a closed incident" β”‚β”‚ -β”‚ β”‚ ); β”‚β”‚ -β”‚ β”‚ } β”‚β”‚ +β”‚ β”‚ throw new ServiceException( |β”‚ +β”‚ β”‚ ErrorStatuses.CONFLICT, ◄─── HTTP 409 |β”‚ +β”‚ β”‚ "Can't modify a closed incident" |β”‚ +β”‚ β”‚ ); |β”‚ +β”‚ β”‚ } |β”‚ β”‚ β”‚ } β”‚β”‚ β”‚ β”‚ β”‚β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ @@ -564,7 +564,7 @@ CQN is CAP's internal query representation, independent of the database. ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ CQN: Abstraction Layer for Queries β”‚ +β”‚ CQN: Abstraction Layer for Queries β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ OData Request CQN Representation β”‚ @@ -575,7 +575,7 @@ CQN is CAP's internal query representation, independent of the database. β”‚ β”‚ β”‚ // com.sap.cds.ql.Select β”‚ β”‚ Select.from(Incidents_.class) β”‚ -β”‚ .where(i -> i.urgency().code().eq("H")) β”‚ +β”‚ .where(i -> i.urgency().code().eq("H")) β”‚ β”‚ β”‚ β”‚ CdsProcessor.get() builds this from OData $filter β”‚ β”‚ β”‚ @@ -588,17 +588,17 @@ CQN is CAP's internal query representation, independent of the database. β”‚ Insert.into(Incidents_.class) β”‚ β”‚ .entry(incident) β”‚ β”‚ β”‚ -β”‚ CdsProcessor.post(): Insert insert = Insert.into(ref).entry(entityData); β”‚ +β”‚ CdsProcessor.post(): Insert insert = Insert.into(ref).entry(entityData); β”‚ β”‚ β”‚ β”‚ ═══════════════════════════════════════════════════════════════════════════ β”‚ β”‚ β”‚ -β”‚ PATCH /Incidents(ID='xxx') { "status_code": "R" } β”‚ -β”‚ ───────────────────────────────────────────────── β”‚ +β”‚ PATCH /Incidents(ID='xxx') { "status_code": "R" } β”‚ +β”‚ ───────────────────────────────────────────────── β”‚ β”‚ β”‚ β”‚ // com.sap.cds.ql.Update β”‚ β”‚ Update.entity(Incidents_.class) β”‚ β”‚ .data(incident) β”‚ -β”‚ .where(i -> i.ID().eq("xxx")) β”‚ +β”‚ .where(i -> i.ID().eq("xxx")) β”‚ β”‚ β”‚ β”‚ CdsProcessor.patch(): CqnUpdate update = Update.entity(ref).data(entityData);β”‚ β”‚ β”‚ @@ -609,7 +609,7 @@ CQN is CAP's internal query representation, independent of the database. β”‚ β”‚ β”‚ // com.sap.cds.ql.Delete β”‚ β”‚ Delete.from(Incidents_.class) β”‚ -β”‚ .where(i -> i.ID().eq("xxx")) β”‚ +β”‚ .where(i -> i.ID().eq("xxx")) β”‚ β”‚ β”‚ β”‚ CdsProcessor.delete(): CqnDelete delete = Delete.from(toPathExpression(...));β”‚ β”‚ β”‚ @@ -621,18 +621,18 @@ CQN is CAP's internal query representation, independent of the database. β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Generated SQL β”‚ +β”‚ Generated SQL β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ -β”‚ SELECT * FROM sap_capire_incidents_Incidents WHERE urgency_code = 'H' β”‚ +β”‚ SELECT * FROM sap_capire_incidents_Incidents WHERE urgency_code = 'H' β”‚ β”‚ β”‚ -β”‚ INSERT INTO sap_capire_incidents_Incidents (...) VALUES (...) β”‚ +β”‚ INSERT INTO sap_capire_incidents_Incidents (...) VALUES (...) β”‚ β”‚ β”‚ -β”‚ UPDATE sap_capire_incidents_Incidents SET status_code = 'R' WHERE ID = ... β”‚ +β”‚ UPDATE sap_capire_incidents_Incidents SET status_code = 'R' WHERE ID = ... β”‚ β”‚ β”‚ -β”‚ DELETE FROM sap_capire_incidents_Incidents WHERE ID = ... β”‚ +β”‚ DELETE FROM sap_capire_incidents_Incidents WHERE ID = ... β”‚ β”‚ β”‚ -β”‚ Table names from: srv/src/main/resources/schema-h2.sql (generated) β”‚ +β”‚ Table names from: srv/src/main/resources/schema-h2.sql (generated) β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` @@ -714,45 +714,45 @@ annotate ProcessorService.Incidents with @odata.draft.enabled; ``` ``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Draft Entity Lifecycle β”‚ -β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ -β”‚ β”‚ -β”‚ 1. CREATE (New Draft) β”‚ -β”‚ POST /ProcessorService/Incidents β”‚ -β”‚ ───────────────────────────────────────────────────────────────────── β”‚ -β”‚ β†’ Creates draft record (IsActiveEntity = false) β”‚ -β”‚ β†’ Stored in: ProcessorService_Incidents_drafts table β”‚ -β”‚ β”‚ -β”‚ 2. EDIT (Modify Draft) β”‚ -β”‚ PATCH /ProcessorService/Incidents(ID='...',IsActiveEntity=false) β”‚ -β”‚ ───────────────────────────────────────────────────────────────────── β”‚ -β”‚ β†’ Updates draft without touching active entity β”‚ -β”‚ β†’ Multiple users can see draft state β”‚ -β”‚ β”‚ -β”‚ 3. ACTIVATE (Promote to Active) β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ β”‚ +β”‚ 1. CREATE (New Draft) β”‚ +β”‚ POST /ProcessorService/Incidents β”‚ +β”‚ ───────────────────────────────────────────────────────────────────── β”‚ +β”‚ β†’ Creates draft record (IsActiveEntity = false) β”‚ +β”‚ β†’ Stored in: ProcessorService_Incidents_drafts table β”‚ +β”‚ β”‚ +β”‚ 2. EDIT (Modify Draft) β”‚ +β”‚ PATCH /ProcessorService/Incidents(ID='...',IsActiveEntity=false) β”‚ +β”‚ ───────────────────────────────────────────────────────────────────── β”‚ +β”‚ β†’ Updates draft without touching active entity β”‚ +β”‚ β†’ Multiple users can see draft state β”‚ +β”‚ β”‚ +β”‚ 3. ACTIVATE (Promote to Active) β”‚ β”‚ POST .../Incidents(...,IsActiveEntity=false)/ProcessorService.draftActivateβ”‚ -β”‚ ───────────────────────────────────────────────────────────────────── β”‚ -β”‚ β†’ Validates draft β”‚ -β”‚ β†’ Moves to active table (IsActiveEntity = true) β”‚ -β”‚ β†’ Deletes draft record β”‚ -β”‚ β”‚ -β”‚ 4. DISCARD β”‚ -β”‚ DELETE /ProcessorService/Incidents(ID='...',IsActiveEntity=false) β”‚ -β”‚ ───────────────────────────────────────────────────────────────────── β”‚ -β”‚ β†’ Removes draft without affecting active entity β”‚ -β”‚ β”‚ -β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ Draft Tables β”‚ draftActivate β”‚ Active Tables β”‚ β”‚ -β”‚ β”‚ ─────────────── β”‚ ─────────────► β”‚ ───────────── β”‚ β”‚ -β”‚ β”‚ IsActiveEntity β”‚ β”‚ IsActiveEntity β”‚ β”‚ -β”‚ β”‚ = false β”‚ β”‚ = true β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β”‚ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +β”‚ ───────────────────────────────────────────────────────────────────── β”‚ +β”‚ β†’ Validates draft β”‚ +β”‚ β†’ Moves to active table (IsActiveEntity = true) β”‚ +β”‚ β†’ Deletes draft record β”‚ +β”‚ β”‚ +β”‚ 4. DISCARD β”‚ +β”‚ DELETE /ProcessorService/Incidents(ID='...',IsActiveEntity=false) β”‚ +β”‚ ───────────────────────────────────────────────────────────────────── β”‚ +β”‚ β†’ Removes draft without affecting active entity β”‚ +β”‚ β”‚ +β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ Draft Tables β”‚ draftActivate β”‚ Active Tables β”‚ β”‚ +β”‚ β”‚ ─────────────── β”‚ ─────────────► β”‚ ───────────── β”‚ β”‚ +β”‚ β”‚ IsActiveEntity β”‚ β”‚ IsActiveEntity β”‚ β”‚ +β”‚ β”‚ = false β”‚ β”‚ = true β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` --- @@ -783,7 +783,7 @@ HTTP Request (POST /odata/v4/ProcessorService/Incidents) β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ CdsProcessor.post() β”‚ β”‚ Package: com.sap.cds.adapter.odata.v4.processors β”‚ -β”‚ β€’ Converts OData request to CQN: Insert.into(ref).entry(entityData) β”‚ +β”‚ β€’ Converts OData request to CQN: Insert.into(ref).entry(entityData) β”‚ β”‚ β€’ Calls applicationService.run(insert) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ @@ -836,7 +836,7 @@ HTTP Request (POST /odata/v4/ProcessorService/Incidents) β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Response Serialization β”‚ -β”‚ CdsProcessor: return new CdsODataResponse(SC_CREATED, remapResult(...)) β”‚ +β”‚ CdsProcessor: return new CdsODataResponse(SC_CREATED, remapResult(...)) β”‚ β”‚ OlingoProcessor: Serializes to OData JSON β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ From c429dcd6dfcfe0d80ae62e5352134b2a40f1e8b6 Mon Sep 17 00:00:00 2001 From: Robin de Silva Jayasinghe Date: Wed, 11 Mar 2026 11:32:27 +0100 Subject: [PATCH 08/10] remove apis module --- pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/pom.xml b/pom.xml index ea521ea..ef0b6b7 100644 --- a/pom.xml +++ b/pom.xml @@ -18,7 +18,6 @@ UTF-8 - apis srv From a4b6a044ea615cc9206ebbcf6918f7771af9753d Mon Sep 17 00:00:00 2001 From: Robin de Silva Jayasinghe Date: Wed, 11 Mar 2026 11:47:28 +0100 Subject: [PATCH 09/10] small correction in the document --- requests.md | 70 +++++++++++++++++++++++------------------------------ 1 file changed, 30 insertions(+), 40 deletions(-) diff --git a/requests.md b/requests.md index 9093298..2afbac4 100644 --- a/requests.md +++ b/requests.md @@ -13,15 +13,15 @@ This application demonstrates SAP Cloud Application Programming Model (CAP) for β”‚ CAP Java Runtime β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ OData V4 β”‚ β”‚ Service β”‚ β”‚ Persistence Layer β”‚ β”‚ -β”‚ β”‚ Adapter │───▢│ Layer │───▢│ (PersistenceService) β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ - Parse β”‚ β”‚ - Processor β”‚ β”‚ - CQN to SQL translation β”‚ β”‚ -β”‚ β”‚ - Serialize β”‚ β”‚ Service β”‚ β”‚ - Transaction management β”‚ β”‚ -β”‚ β”‚ - $metadata β”‚ β”‚ - Admin β”‚ β”‚ - Database execution β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ Service β”‚ β”‚ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ OData V4 β”‚ β”‚ Service β”‚ β”‚ Persistence Layer β”‚ β”‚ +β”‚ β”‚ Adapter │───▢│ Layer │───▢│ (PersistenceService) β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ - Parse β”‚ β”‚ - Processor β”‚ β”‚ - CQN to SQL translation β”‚ β”‚ +β”‚ β”‚ - Serialize β”‚ β”‚ Service β”‚ β”‚ - Transaction management β”‚ β”‚ +β”‚ β”‚ - $metadata β”‚ β”‚ - Admin β”‚ β”‚ - Database execution β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ Service β”‚ β”‚ β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β–Ό β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ @@ -42,16 +42,6 @@ This application demonstrates SAP Cloud Application Programming Model (CAP) for β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` -### Runtime Components (Maven Dependencies) - -| Component | Maven Artifact | Purpose | -|-----------|----------------|---------| -| OData V4 Adapter | `cds-adapter-odata-v4` | HTTP/OData protocol handling | -| Spring Boot Integration | `cds-starter-spring-boot` | Auto-configuration, DI | -| Core Runtime | `cds4j-runtime` | Event handling, persistence | - ---- - ## 2. The CDS Model Layer CAP uses **CDS (Core Data Services)** to define both the domain model and service exposure: @@ -159,8 +149,8 @@ Let's trace a `POST /odata/v4/ProcessorService/Incidents` request through the ac Client Database β”‚ β”‚ - β”‚ POST /odata/v4/ProcessorService/Incidents β”‚ - β”‚ { "title": "Urgent: Server down", "customer_ID": "1001" } β”‚ + β”‚ POST /odata/v4/ProcessorService/Incidents β”‚ + β”‚ { "title": "Urgent: Server down", "customer_ID": "1001" } β”‚ β”‚ β”‚ β–Ό β”‚ ``` @@ -173,19 +163,19 @@ Let's trace a `POST /odata/v4/ProcessorService/Incidents` request through the ac ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ 1. OData V4 Adapter Entry Point β”‚ -β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -β”‚ β”‚ β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚ +β”‚ β”‚ β”‚β”‚ β”‚ β”‚ AbstractCdsODataServlet.service(HttpServletRequest, HttpServletResponse)β”‚β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ β€’ Establishes request context with runtime.requestContext() β”‚ β”‚ -β”‚ β”‚ β€’ Extracts service name from URL: "ProcessorService" β”‚ β”‚ -β”‚ β”‚ β€’ Validates service definition exists β”‚ β”‚ -β”‚ β”‚ β€’ Initializes Olingo OData infrastructure (EDM, metadata) β”‚ β”‚ -β”‚ β”‚ β€’ Registers OlingoProcessor as the request processor β”‚ β”‚ -β”‚ β”‚ β€’ Calls odataHandler.process(req, resp) β”‚ β”‚ -β”‚ β”‚ β”‚ β”‚ -β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +β”‚ β”‚ β”‚β”‚ +β”‚ β”‚ β€’ Establishes request context with runtime.requestContext() β”‚β”‚ +β”‚ β”‚ β€’ Extracts service name from URL: "ProcessorService" β”‚β”‚ +β”‚ β”‚ β€’ Validates service definition exists β”‚β”‚ +β”‚ β”‚ β€’ Initializes Olingo OData infrastructure (EDM, metadata) β”‚β”‚ +β”‚ β”‚ β€’ Registers OlingoProcessor as the request processor β”‚β”‚ +β”‚ β”‚ β€’ Calls odataHandler.process(req, resp) β”‚β”‚ +β”‚ β”‚ β”‚β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β–Ό ``` @@ -206,7 +196,7 @@ Let's trace a `POST /odata/v4/ProcessorService/Incidents` request through the ac β”‚ β”‚ β€’ Delegates to CdsProcessor for CAP-specific handling β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β–Ό ``` @@ -238,7 +228,7 @@ Let's trace a `POST /odata/v4/ProcessorService/Incidents` request through the ac β”‚ β”‚ return new CdsODataResponse(SC_CREATED, remapResult(...)); β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ applicationService.run(insert) β–Ό @@ -264,7 +254,7 @@ The `applicationService.run()` call triggers the event handler chain: β”‚ β”‚ β€’ Execute handler chain: @Before β†’ @On β†’ @After β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β–Ό ``` @@ -297,11 +287,11 @@ The `applicationService.run()` call triggers the event handler chain: β”‚ β”‚ } β”‚ β”‚ β”‚ β”‚ } β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ -β”‚ β”‚ Input: { title: "Urgent: Server down", urgency_code: null } β”‚ β”‚ -β”‚ β”‚ Output: { title: "Urgent: Server down", urgency_code: "H" } β”‚ β”‚ +β”‚ β”‚ Input: { title: "Urgent: Server down", urgency_code: null } β”‚ β”‚ +β”‚ β”‚ Output: { title: "Urgent: Server down", urgency_code: "H" } β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β–Ό ``` @@ -326,7 +316,7 @@ The `applicationService.run()` call triggers the event handler chain: β”‚ β”‚ β€’ Executes the SQL statement β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β–Ό ``` From 37f80e85dda2db9ba796bed90db3504da88524c4 Mon Sep 17 00:00:00 2001 From: Robin de Silva Jayasinghe Date: Wed, 11 Mar 2026 16:02:56 +0100 Subject: [PATCH 10/10] document about batch requests --- batch-requests.md | 806 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 806 insertions(+) create mode 100644 batch-requests.md diff --git a/batch-requests.md b/batch-requests.md new file mode 100644 index 0000000..a50010f --- /dev/null +++ b/batch-requests.md @@ -0,0 +1,806 @@ +# CAP Java: OData V4 Batch Request Handling + +## Overview + +This document explains OData V4 Batch requests and how SAP Cloud Application Programming Model (CAP) for Java handles them. Batch requests enable clients to bundle multiple operations into a single HTTP request, reducing network overhead and improving performance in distributed systems. + +--- + +## 1. What are OData V4 Batch Requests? + +### 1.1 Definition + +OData V4 Batch requests allow clients to group multiple individual requests (queries, creates, updates, deletes) into a single HTTP POST request. The server processes these requests and returns all responses bundled together in a single HTTP response. + +### 1.2 Key Characteristics + +- **Single HTTP Request**: Multiple operations sent in one HTTP POST to `$batch` endpoint +- **Multipart Format**: Uses multipart/mixed content type with boundary delimiters +- **Change Sets**: Operations can be grouped into atomic transactions (changesets) +- **Independent Requests**: Queries outside changesets are processed independently +- **Reduced Latency**: Fewer HTTP roundtrips improve performance +- **Transaction Control**: Changesets provide all-or-nothing execution semantics + +### 1.3 Structure + +``` +POST /odata/v4/IncidentService/$batch HTTP/1.1 +Content-Type: multipart/mixed; boundary=batch_boundary + +--batch_boundary +Content-Type: multipart/mixed; boundary=changeset_boundary + +--changeset_boundary +Content-Type: application/http +Content-Transfer-Encoding: binary + +POST Incidents HTTP/1.1 +Content-Type: application/json + +{ + "title": "Network outage", + "urgency": "high" +} + +--changeset_boundary +Content-Type: application/http +Content-Transfer-Encoding: binary + +PATCH Incidents(ID=f60f5c43-3c6e-4c79-bb18-23cf314c55e4) HTTP/1.1 +Content-Type: application/json + +{ + "status": "closed" +} + +--changeset_boundary-- + +--batch_boundary +Content-Type: application/http +Content-Transfer-Encoding: binary + +GET Incidents HTTP/1.1 + +--batch_boundary-- +``` + +--- + +## 2. OData V4 Batch Concepts + +### 2.1 Batch Boundary + +- Separates individual requests within the batch +- Defined in the `Content-Type` header +- Format: `multipart/mixed; boundary=` +- Each part starts with `--` +- Batch ends with `----` + +### 2.2 ChangeSet + +A changeset is a group of operations that must be executed atomically: + +- **Atomic Transaction**: All operations succeed or all fail +- **Supported Operations**: CREATE, UPDATE (PUT/PATCH), DELETE +- **Not Allowed**: GET requests cannot be in changesets +- **Own Boundary**: Uses nested multipart with changeset boundary +- **Rollback**: On any failure, all changes in the changeset are rolled back + +### 2.3 Request Types + +**Within ChangeSet (Transactional)**: +- POST (Create) +- PATCH (Update) +- PUT (Replace) +- DELETE (Delete) + +**Outside ChangeSet (Independent)**: +- GET (Query) +- Can also include modification operations that should run independently + +### 2.4 Content References + +Batch requests support `Content-ID` headers to reference created entities within the same batch: + +``` +--changeset_boundary +Content-Type: application/http +Content-Transfer-Encoding: binary +Content-ID: 1 + +POST Incidents HTTP/1.1 +Content-Type: application/json + +{ + "title": "Server down" +} + +--changeset_boundary +Content-Type: application/http +Content-Transfer-Encoding: binary + +POST $1/conversations HTTP/1.1 +Content-Type: application/json + +{ + "message": "Investigating the issue" +} +``` + +Here `$1` references the Incident created in the first request. + +--- + +## 3. CAP Java Batch Request Processing + +### 3.1 Architecture Overview + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ CAP Java Batch Processing β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ OData Adapter β”‚ β”‚ Batch Executor β”‚ β”‚ Transaction Manager β”‚ β”‚ +β”‚ β”‚ │───▢│ │───▢│ β”‚ β”‚ +β”‚ β”‚ - Parse batch β”‚ β”‚ - Process each β”‚ β”‚ - Begin transaction β”‚ β”‚ +β”‚ β”‚ - Extract parts β”‚ β”‚ request β”‚ β”‚ - Commit/rollback β”‚ β”‚ +β”‚ β”‚ - Build responseβ”‚ β”‚ - Handle refs β”‚ β”‚ - Savepoint support β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ β–Ό β–Ό β”‚ +β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ β”‚ CQN Executor β”‚ β”‚ Database (HANA, β”‚ β”‚ +β”‚ β”‚ β”‚ │─────▢│ H2, PostgreSQL, β”‚ β”‚ +β”‚ β”‚ β”‚ - Build CQN β”‚ β”‚ SQLite) β”‚ β”‚ +β”‚ β”‚ β”‚ - Execute ops β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ β”‚ +β”‚ └──────────────────▢ Serialize Batch Response β”‚ +β”‚ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +### 3.2 Request Flow + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Client β”‚ +β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β”‚ POST /$batch + β”‚ (multipart/mixed) + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ 1. ODataServlet / Request Handler β”‚ +β”‚ - Receives HTTP request β”‚ +β”‚ - Routes to batch endpoint β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ 2. Batch Request Parser β”‚ +β”‚ - Parse multipart/mixed content β”‚ +β”‚ - Extract individual request parts β”‚ +β”‚ - Identify changesets vs independent requests β”‚ +β”‚ - Parse Content-ID headers β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ 3. Batch Executor β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ For each ChangeSet: β”‚ β”‚ +β”‚ β”‚ - Begin transaction β”‚ β”‚ +β”‚ β”‚ - Execute all operations in order β”‚ β”‚ +β”‚ β”‚ - Track Content-IDs for references β”‚ β”‚ +β”‚ β”‚ - If any fails: Rollback entire changeset β”‚ β”‚ +β”‚ β”‚ - If all succeed: Commit changeset β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ For each Independent Request: β”‚ β”‚ +β”‚ β”‚ - Execute immediately β”‚ β”‚ +β”‚ β”‚ - Failure doesn't affect other requests β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ 4. Individual Request Processing β”‚ +β”‚ - Parse OData request (GET, POST, PATCH, DELETE) β”‚ +β”‚ - Convert to CQN query/statement β”‚ +β”‚ - Trigger event handlers (@Before/@On/@After) β”‚ +β”‚ - Execute against persistence service β”‚ +β”‚ - Collect response β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ 5. Response Builder β”‚ +β”‚ - Collect all individual responses β”‚ +β”‚ - Build multipart/mixed response β”‚ +β”‚ - Include status codes for each operation β”‚ +β”‚ - Map Content-IDs to results β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ Client β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +### 3.3 Transaction Management + +CAP Java handles transactions for batch requests as follows: + +**ChangeSet Processing**: +```java +// Pseudo-code representation +for (ChangeSet changeSet : batch.getChangeSets()) { + try { + transaction.begin(); + + for (Request request : changeSet.getRequests()) { + Result result = processRequest(request); + results.add(result); + + // Track Content-ID for references + if (request.hasContentId()) { + contentIdMap.put(request.getContentId(), result.getEntity()); + } + } + + transaction.commit(); + } catch (Exception e) { + transaction.rollback(); + // Add error response for entire changeset + results.addChangeSetError(e); + } +} +``` + +**Independent Request Processing**: +```java +// Each request runs in its own transaction +for (Request request : batch.getIndependentRequests()) { + try { + Result result = processRequest(request); + results.add(result); + } catch (Exception e) { + // Error only affects this request + results.addError(request, e); + } +} +``` + +### 3.4 Event Handler Execution + +Event handlers are executed for each operation within the batch: + +```java +@Component +@ServiceName("IncidentService") +public class IncidentServiceHandler implements EventHandler { + + @Before(event = CqnService.EVENT_CREATE, entity = "Incidents") + public void beforeCreateIncident(List incidents) { + // Called for each CREATE in the batch + for (Incidents incident : incidents) { + incident.setCreatedAt(Instant.now()); + } + } + + @On(event = CqnService.EVENT_UPDATE, entity = "Incidents") + public void onUpdateIncident(CdsUpdateEventContext context) { + // Called for each UPDATE in the batch + // Full access to context and transaction + } + + @After(event = CqnService.EVENT_READ, entity = "Incidents") + public void afterReadIncidents(List incidents) { + // Called for each READ in the batch + // Can modify results before sending back + } +} +``` + +--- + +## 4. Batch Response Format + +### 4.1 Successful Response + +``` +HTTP/1.1 200 OK +Content-Type: multipart/mixed; boundary=batch_response_boundary + +--batch_response_boundary +Content-Type: multipart/mixed; boundary=changeset_response_boundary + +--changeset_response_boundary +Content-Type: application/http +Content-Transfer-Encoding: binary + +HTTP/1.1 201 Created +Content-Type: application/json + +{ + "ID": "f60f5c43-3c6e-4c79-bb18-23cf314c55e4", + "title": "Network outage", + "urgency": "high" +} + +--changeset_response_boundary +Content-Type: application/http +Content-Transfer-Encoding: binary + +HTTP/1.1 200 OK +Content-Type: application/json + +{ + "ID": "f60f5c43-3c6e-4c79-bb18-23cf314c55e4", + "status": "closed" +} + +--changeset_response_boundary-- + +--batch_response_boundary +Content-Type: application/http +Content-Transfer-Encoding: binary + +HTTP/1.1 200 OK +Content-Type: application/json + +{ + "value": [ + { + "ID": "f60f5c43-3c6e-4c79-bb18-23cf314c55e4", + "title": "Network outage" + } + ] +} + +--batch_response_boundary-- +``` + +### 4.2 Error Response (ChangeSet Failure) + +When any operation in a changeset fails, the entire changeset is rolled back: + +``` +--batch_response_boundary +Content-Type: multipart/mixed; boundary=changeset_response_boundary + +--changeset_response_boundary +Content-Type: application/http +Content-Transfer-Encoding: binary + +HTTP/1.1 400 Bad Request +Content-Type: application/json + +{ + "error": { + "code": "400", + "message": "Validation failed for field 'urgency'", + "target": "urgency" + } +} + +--changeset_response_boundary-- +``` + +All operations in the changeset are rolled back, and none of the changes are persisted. + +--- + +## 5. Common Use Cases + +### 5.1 Bulk Create + +Create multiple entities in a single atomic transaction: + +``` +POST /$batch + +--batch +Content-Type: multipart/mixed; boundary=changeset + +--changeset +POST Incidents +{ "title": "Issue 1" } + +--changeset +POST Incidents +{ "title": "Issue 2" } + +--changeset +POST Incidents +{ "title": "Issue 3" } + +--changeset-- +--batch-- +``` + +All incidents are created, or none if any validation fails. + +### 5.2 Create with Related Entities + +Create an entity and related entities using Content-ID references: + +``` +--changeset +Content-ID: new-incident + +POST Incidents +{ + "title": "Database performance issue", + "urgency": "high" +} + +--changeset +POST $new-incident/conversations +{ + "message": "Initial investigation started" +} + +--changeset-- +``` + +### 5.3 Mixed Operations + +Combine queries with modifications: + +``` +--batch +GET Incidents?$filter=status eq 'open' + +--batch +Content-Type: multipart/mixed; boundary=changeset + +--changeset +PATCH Incidents(ID=) +{ "status": "closed" } + +--changeset +POST Incidents +{ "title": "New incident" } + +--changeset-- + +--batch +GET Customers + +--batch-- +``` + +The GET requests execute independently, while modifications are atomic. + +--- + +## 6. CAP Java Configuration + +### 6.1 Default Behavior + +CAP Java handles OData V4 batch requests automatically with built-in defaults: + +- Batch requests are **enabled by default** on the `$batch` endpoint +- Transaction management is automatic for changesets +- No special configuration required for basic batch support + +### 6.2 Transaction Management + +CAP Java automatically manages transactions for batch requests: + +**ChangeSet Transactions**: +- Each changeset runs in a single database transaction +- Automatic commit on success, rollback on any failure +- Transaction boundaries are managed by the CAP runtime + +**Independent Requests**: +- Each request outside a changeset may run in its own transaction +- Failure of one request doesn't affect others + +### 6.3 Spring Boot Configuration + +Standard Spring Boot settings apply to batch request processing: + +```yaml +spring: + datasource: + # Connection pool settings affect batch performance + hikari: + maximum-pool-size: 10 + connection-timeout: 30000 +``` + +### 6.4 HTTP Request Limits + +Configure HTTP request size limits (applies to batch requests): + +```yaml +server: + # Maximum HTTP request body size + max-http-request-header-size: 10MB + tomcat: + max-swallow-size: 10MB +``` + +--- + +## 7. Best Practices + +### 7.1 Use ChangeSets for Related Operations + +Group related operations in changesets to ensure data consistency: + +``` +βœ“ GOOD: Create order and line items in one changeset +βœ— BAD: Create order in one changeset, line items in another +``` + +### 7.2 Optimize Request Order + +Order requests to minimize database roundtrips: + +``` +βœ“ GOOD: Create parent first, then children using Content-ID +βœ— BAD: Random order requiring multiple passes +``` + +### 7.3 Limit Batch Size + +Don't create overly large batches: + +``` +βœ“ GOOD: 10-50 operations per batch +βœ— BAD: 1000+ operations (consider pagination or background jobs) +``` + +### 7.4 Handle Partial Failures + +Independent requests outside changesets can fail without affecting others: + +``` +βœ“ GOOD: Critical operations in changesets, optional operations outside +βœ— BAD: All operations in one changeset when partial success is acceptable +``` + +### 7.5 Use Content-IDs Wisely + +Only use Content-IDs when you need to reference created entities: + +``` +βœ“ GOOD: Content-ID for parent when creating children +βœ— BAD: Content-ID on every operation (adds overhead) +``` + +--- + +## 8. Error Handling + +### 8.1 Validation Errors + +If a validation error occurs in a changeset, the entire changeset fails: + +```java +@Before(event = CqnService.EVENT_CREATE, entity = "Incidents") +public void validateIncident(List incidents) { + for (Incidents incident : incidents) { + if (incident.getUrgency() == null) { + throw new ServiceException(ErrorStatuses.BAD_REQUEST, + "Urgency is required"); + } + } +} +``` + +Response: +```json +{ + "error": { + "code": "400", + "message": "Urgency is required" + } +} +``` + +### 8.2 Database Constraint Violations + +Unique constraint violations or foreign key errors roll back the changeset: + +``` +HTTP/1.1 400 Bad Request + +{ + "error": { + "code": "400", + "message": "Entity already exists with this key" + } +} +``` + +### 8.3 Authorization Errors + +If user lacks permission for any operation in a changeset: + +``` +HTTP/1.1 403 Forbidden + +{ + "error": { + "code": "403", + "message": "User not authorized to perform this operation" + } +} +``` + +--- + +## 9. Performance Considerations + +### 9.1 Benefits + +- **Reduced Network Latency**: Single HTTP request vs multiple roundtrips +- **Connection Pooling**: Better utilization of database connections +- **Transaction Overhead**: Fewer transaction begin/commit cycles +- **Client Efficiency**: Simplified client code for bulk operations + +### 9.2 Trade-offs + +- **Memory Usage**: Large batches consume more memory +- **Response Time**: Client waits for all operations to complete +- **Error Recovery**: Partial failures require re-sending entire changeset +- **Debugging**: Harder to troubleshoot than individual requests + +### 9.3 Optimization Tips + +1. **Batch Similar Operations**: Group creates together, updates together +2. **Use Streaming**: For very large batches, process in chunks +3. **Monitor Transaction Time**: Keep changesets small enough to avoid timeouts +4. **Index Properly**: Ensure database indexes support batch operations +5. **Profile Handlers**: Ensure event handlers are efficient + +--- + +## 10. Testing Batch Requests + +### 10.1 Using cURL + +```bash +curl -X POST http://localhost:8080/odata/v4/IncidentService/$batch \ + -H "Content-Type: multipart/mixed; boundary=batch" \ + --data-binary @batch-request.txt +``` + +### 10.2 Using Postman + +1. Create a POST request to `/$batch` +2. Set Content-Type to `multipart/mixed; boundary=batch` +3. Add batch content in raw body +4. Send and inspect multipart response + +### 10.3 Integration Tests + +```java +@SpringBootTest +@AutoConfigureMockMvc +class BatchRequestTest { + + @Autowired + private MockMvc mockMvc; + + @Test + void testBatchCreateIncidents() throws Exception { + String batchContent = """ + --batch + Content-Type: multipart/mixed; boundary=changeset + + --changeset + Content-Type: application/http + Content-Transfer-Encoding: binary + + POST Incidents HTTP/1.1 + Content-Type: application/json + + {"title": "Test Incident 1"} + + --changeset + Content-Type: application/http + Content-Transfer-Encoding: binary + + POST Incidents HTTP/1.1 + Content-Type: application/json + + {"title": "Test Incident 2"} + + --changeset-- + --batch-- + """; + + mockMvc.perform(post("/odata/v4/IncidentService/$batch") + .contentType("multipart/mixed; boundary=batch") + .content(batchContent)) + .andExpect(status().isOk()) + .andExpect(content().contentTypeCompatibleWith("multipart/mixed")); + } +} +``` + +--- + +## 11. Troubleshooting + +### 11.1 Common Issues + +**Issue**: Batch request returns 400 Bad Request +**Solution**: Check boundary delimiters match exactly between Content-Type and body + +**Issue**: ChangeSet operations not atomic +**Solution**: Verify all operations are within changeset boundaries + +**Issue**: Content-ID references not working +**Solution**: Ensure Content-ID is defined before usage, check format `$` + +**Issue**: Performance degradation with large batches +**Solution**: Reduce batch size, check database connection pool settings + +### 11.2 Debugging + +Enable detailed logging in `application.yaml`: + +```yaml +logging: + level: + com.sap.cds: DEBUG + com.sap.cds.odata: TRACE + # See detailed batch processing + com.sap.cds.odata.v4.batch: TRACE +``` + +### 11.3 Monitoring + +Key metrics to monitor: + +- Batch request size distribution +- Average processing time per batch +- Changeset rollback rate +- Individual operation success/failure rates +- Memory consumption during batch processing + +--- + +## 12. Comparison with OData V2 Batch + +### 12.1 Key Differences + +| Aspect | OData V2 | OData V4 | +|--------|----------|----------| +| Content Type | `multipart/mixed` | `multipart/mixed` (same) | +| ChangeSet Format | Similar | Simplified boundaries | +| Content-ID | Limited support | Full support with `$id` | +| Error Handling | Vendor-specific | Standardized | +| Specification | Less detailed | More comprehensive | + +### 12.2 Migration Notes + +When migrating from OData V2 to V4: + +1. Update batch endpoint URLs (`/v2/` β†’ `/v4/`) +2. Review Content-ID reference syntax +3. Update error response parsing +4. Test changeset rollback behavior +5. Verify boundary delimiter handling + +--- + +## Summary + +OData V4 Batch requests provide a powerful mechanism for bundling multiple operations into a single HTTP request. CAP Java handles batch processing automatically, providing: + +- Atomic transactions via changesets +- Content-ID references for related entities +- Automatic transaction management +- Event handler integration +- Standard OData V4 compliance + +By understanding batch request structure and CAP Java's processing model, developers can build efficient applications that minimize network overhead while maintaining data consistency and leveraging CAP's full event-driven architecture.