@sap/cds-dk 10.1.0 → 10.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/bin/bind.js +4 -0
- package/bin/build.js +1 -0
- package/bin/compile/index.js +12 -11
- package/bin/completion/index.js +21 -10
- package/bin/completion/scripts/cds.fish +179 -127
- package/bin/completion/scripts/cds.ps1 +88 -14
- package/bin/completion/scripts/cds.sh +71 -5
- package/bin/completion/scripts/cds.zsh +81 -15
- package/bin/completion/templates/cds-tmpl.ps1 +15 -6
- package/bin/deploy/index.js +7 -3
- package/bin/env.js +4 -1
- package/bin/export.js +9 -1
- package/bin/import.js +4 -1
- package/bin/init.js +1 -0
- package/bin/inspect.js +3 -1
- package/bin/lint.js +5 -3
- package/bin/minify.js +6 -1
- package/bin/repl.js +11 -2
- package/bin/run.js +12 -1
- package/bin/serve.js +13 -2
- package/bin/up.js +4 -1
- package/bin/util/containerize.js +2 -0
- package/bin/watch/index.js +8 -1
- package/lib/build/plugins/internal.js +0 -26
- package/lib/build/plugins/nodejs/index.js +8 -3
- package/lib/build/util.js +2 -4
- package/lib/cds.js +8 -2
- package/lib/init/constants.js +1 -1
- package/lib/init/merge.js +21 -17
- package/lib/init/template/cloud-logging/index.js +3 -3
- package/lib/init/template/data/as-json.js +3 -0
- package/lib/init/template/destination/index.js +3 -3
- package/lib/init/template/enterprise-messaging/index.js +4 -1
- package/lib/init/template/event-mesh/index.js +3 -0
- package/lib/init/template/multitenancy/index.js +2 -2
- package/lib/init/template/workzone-standard/index.js +1 -1
- package/node_modules/@cap-js/db-service/CHANGELOG.md +30 -0
- package/node_modules/@cap-js/db-service/lib/common/generic-pool.js +4 -7
- package/node_modules/@cap-js/db-service/lib/cqn2pql.js +1 -1
- package/node_modules/@cap-js/db-service/lib/cqn2sql.js +15 -11
- package/node_modules/@cap-js/db-service/lib/cqn4sql.js +125 -21
- package/node_modules/@cap-js/db-service/lib/infer/index.js +27 -16
- package/node_modules/@cap-js/db-service/lib/recursion-guard.js +40 -0
- package/node_modules/@cap-js/db-service/lib/search.js +1 -1
- package/node_modules/@cap-js/db-service/package.json +1 -1
- package/node_modules/@cap-js/sqlite/CHANGELOG.md +28 -0
- package/node_modules/@cap-js/sqlite/lib/SQLiteService.js +110 -14
- package/node_modules/@cap-js/sqlite/package.json +3 -3
- package/node_modules/@sap/cds/CHANGELOG.md +19 -0
- package/node_modules/@sap/cds/common.cds +3 -3
- package/node_modules/@sap/cds/lib/compile/minify.js +3 -1
- package/node_modules/@sap/cds/lib/env/cds-env.js +1 -1
- package/node_modules/@sap/cds/lib/env/cds-requires.js +1 -0
- package/node_modules/@sap/cds/libx/_runtime/common/generic/crud.js +7 -1
- package/node_modules/@sap/cds/libx/_runtime/common/utils/cqn.js +1 -1
- package/node_modules/@sap/cds/libx/_runtime/fiori/lean-draft.js +1 -1
- package/node_modules/@sap/cds/libx/_runtime/messaging/common-utils/normalizeIncomingMessage.js +1 -1
- package/node_modules/@sap/cds/libx/_runtime/messaging/kafka.js +1 -1
- package/node_modules/@sap/cds/libx/http/location.js +10 -11
- package/node_modules/@sap/cds/libx/odata/middleware/read.js +1 -1
- package/node_modules/@sap/cds/libx/queue/SchedulingService.js +4 -0
- package/node_modules/@sap/cds/libx/queue/index.js +44 -10
- package/node_modules/@sap/cds/libx/queue/processing.js +47 -16
- package/node_modules/@sap/cds/libx/queue/utils.js +3 -0
- package/node_modules/@sap/cds/package.json +1 -1
- package/node_modules/@sap/cds/tasks/enterprise-messaging-deploy.js +13 -5
- package/node_modules/@sap/cds-compiler/CHANGELOG.md +15 -0
- package/node_modules/@sap/cds-compiler/lib/compiler/resolve.js +7 -3
- package/node_modules/@sap/cds-compiler/lib/model/csnUtils.js +2 -0
- package/node_modules/@sap/cds-compiler/lib/transform/db/applyTransformations.js +12 -0
- package/node_modules/@sap/cds-compiler/lib/transform/db/associations.js +5 -3
- package/node_modules/@sap/cds-compiler/lib/transform/db/flattening.js +4 -3
- package/node_modules/@sap/cds-compiler/lib/transform/effective/flattening.js +17 -1
- package/node_modules/@sap/cds-compiler/lib/transform/effective/main.js +19 -0
- package/node_modules/@sap/cds-compiler/lib/transform/fioriTreeViews.js +12 -1
- package/node_modules/@sap/cds-compiler/lib/transform/forRelationalDB.js +1 -1
- package/node_modules/@sap/cds-compiler/lib/transform/odata/adaptAnnotationRefs.js +11 -5
- package/node_modules/@sap/cds-compiler/lib/transform/translateAssocsToJoins.js +29 -2
- package/node_modules/@sap/cds-compiler/package.json +1 -1
- package/node_modules/@sap/cds-mtxs/CHANGELOG.md +34 -0
- package/node_modules/@sap/cds-mtxs/bin/cds-mtx-migrate.js +26 -5
- package/node_modules/@sap/cds-mtxs/bin/cds-mtx.js +3 -0
- package/node_modules/@sap/cds-mtxs/lib/utils.js +5 -4
- package/node_modules/@sap/cds-mtxs/package.json +1 -1
- package/node_modules/@sap/cds-mtxs/srv/cf/abstract-provisioning-service.js +62 -7
- package/node_modules/@sap/cds-mtxs/srv/cf/saas-provisioning-service.js +1 -1
- package/node_modules/@sap/cds-mtxs/srv/cf/sms-provisioning-service.js +23 -3
- package/node_modules/@sap/cds-mtxs/srv/extensibility/compat/update.js +15 -0
- package/node_modules/@sap/cds-mtxs/srv/extensibility/linter/annotations.js +2 -2
- package/node_modules/@sap/cds-mtxs/srv/extensibility/linter/config.js +2 -0
- package/node_modules/@sap/cds-mtxs/srv/extensibility/linter/index.js +2 -0
- package/node_modules/@sap/cds-mtxs/srv/extensibility/linter/protected-namespace.js +45 -0
- package/node_modules/@sap/cds-mtxs/srv/extensibility-service.js +8 -3
- package/node_modules/@sap/cds-mtxs/srv/jobs-service.js +49 -10
- package/node_modules/@sap/cds-mtxs/srv/model-provider.js +11 -2
- package/node_modules/@sap/cds-mtxs/srv/plugins/common.js +19 -12
- package/node_modules/@sap/cds-mtxs/srv/plugins/hana/hdi-ctnr-mgr.js +6 -3
- package/node_modules/@sap/cds-mtxs/srv/plugins/hana/serverless.js +271 -0
- package/node_modules/@sap/cds-mtxs/srv/plugins/hana.js +3 -2
- package/node_modules/@sap/cds-mtxs/srv/worker/job-worker-pool.js +212 -0
- package/node_modules/@sap/cds-mtxs/srv/worker/job-worker.js +61 -0
- package/node_modules/proxy-addr/HISTORY.md +60 -54
- package/node_modules/proxy-addr/README.md +1 -1
- package/node_modules/proxy-addr/index.js +32 -0
- package/node_modules/proxy-addr/package.json +8 -4
- package/node_modules/yaml/browser/dist/compose/resolve-flow-scalar.js +19 -18
- package/node_modules/yaml/browser/dist/nodes/Alias.js +25 -23
- package/node_modules/yaml/dist/compose/resolve-flow-scalar.js +19 -18
- package/node_modules/yaml/dist/nodes/Alias.js +25 -23
- package/node_modules/yaml/package.json +1 -1
- package/package.json +2 -2
- /package/node_modules/@sap/cds-mtxs/srv/worker/{pool.js → model-worker-pool.js} +0 -0
- /package/node_modules/@sap/cds-mtxs/srv/worker/{load.js → model-worker.js} +0 -0
package/bin/import.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
const { FILE, DIR } = require('./completion')
|
|
1
2
|
module.exports = Object.assign(_import, {
|
|
2
3
|
_name: 'import',
|
|
3
4
|
staticCompletions: () => ({
|
|
4
5
|
'--from': ['asyncapi', 'edmx', 'openapi'],
|
|
5
6
|
'--as': ['cds', 'csn', 'json'],
|
|
6
|
-
'
|
|
7
|
+
'--out': DIR(),
|
|
8
|
+
'-o': DIR(),
|
|
9
|
+
'_': FILE('json,xml,edmx'),
|
|
7
10
|
}),
|
|
8
11
|
options: [ '--services', '--for', '--out', '--as', '--name', '--include-namespaces', '--dependencies', '--from', '--config', '--destination', '--group', '--into-namespace' ],
|
|
9
12
|
shortcuts: [ '-s', '-4', '-o', '-as', '-n', '-ns', '-d',undefined, '-c', undefined, undefined, '-2', '-', '-f', '-b'],
|
package/bin/init.js
CHANGED
|
@@ -10,6 +10,7 @@ module.exports = Object.assign(init, {
|
|
|
10
10
|
staticCompletions: () => ({
|
|
11
11
|
'--add': COMMA(require('../bin/completion/completionFs').readTemplates([])),
|
|
12
12
|
'--java:package': DIR(),
|
|
13
|
+
'--base': DIR(),
|
|
13
14
|
}),
|
|
14
15
|
options: ['--add', '--java:mvn', '--java:package', '--lint:custom', '--lint:custom:example', '--no-db', '--base'],
|
|
15
16
|
shortcuts: ['-a'],
|
package/bin/inspect.js
CHANGED
|
@@ -9,7 +9,9 @@ const { FILE } = require('./completion');
|
|
|
9
9
|
module.exports = Object.assign (inspect, {
|
|
10
10
|
staticCompletions: () => ({
|
|
11
11
|
'--kind': ['entity', 'aspect', 'type', 'service'],
|
|
12
|
-
'
|
|
12
|
+
'--list': ['names', 'elements', 'keys', 'associations', 'compositions', 'ids', 'sources', 'all'],
|
|
13
|
+
'-l': ['names', 'elements', 'keys', 'associations', 'compositions', 'ids', 'sources', 'all'],
|
|
14
|
+
'_': FILE('cds,json', { dirs: true }),
|
|
13
15
|
}),
|
|
14
16
|
options: [ '--stats', '--list', '--kind' ],
|
|
15
17
|
shortcuts: [ '-s', '-l', '-k' ],
|
package/bin/lint.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
+
const { FILE } = require('./completion')
|
|
1
2
|
const Linter = require('../lib/lint/Linter');
|
|
2
3
|
const linter = new Linter();
|
|
3
4
|
|
|
4
|
-
// cds cli exec expects an executable object with various additional properties.
|
|
5
|
-
// As most of the linting functionality is bound to a class instance, we need to wrap the instance
|
|
6
|
-
// to not lose the this-context and attach the additional properties to the function.
|
|
7
5
|
const lint = (...args) => linter.lint(...args)
|
|
8
6
|
const additionalProperties = Object.entries(linter.init())
|
|
9
7
|
.map(([key, value]) => [key, { value }])
|
|
10
8
|
|
|
11
9
|
Object.defineProperties(lint, Object.fromEntries(additionalProperties))
|
|
12
10
|
|
|
11
|
+
lint.staticCompletions = () => ({
|
|
12
|
+
'_': FILE('js,ts,cds', { dirs: true }),
|
|
13
|
+
})
|
|
14
|
+
|
|
13
15
|
module.exports = lint
|
package/bin/minify.js
CHANGED
|
@@ -119,4 +119,9 @@ class Dryifier extends Minifier {
|
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
|
|
122
|
+
const { FILE } = require('./completion')
|
|
123
|
+
module.exports = Object.assign (Minify._for_cds_dk(), { Minify,
|
|
124
|
+
staticCompletions: () => ({
|
|
125
|
+
'_': FILE('cds,json', { dirs: true }),
|
|
126
|
+
})
|
|
127
|
+
})
|
package/bin/repl.js
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
|
+
const { DIR } = require('./completion');
|
|
1
2
|
module.exports = Object.assign (repl, {
|
|
2
|
-
options: [ '--run', '--use'
|
|
3
|
-
|
|
3
|
+
options: [ '--run', '--use' ],
|
|
4
|
+
flags: [ '--ql' ],
|
|
5
|
+
shortcuts: ['-r', '-u'],
|
|
6
|
+
staticCompletions: () => ({
|
|
7
|
+
'_': DIR(),
|
|
8
|
+
'--run': DIR(),
|
|
9
|
+
'-r': DIR(),
|
|
10
|
+
'--use': ['xl', 'ql', 'entities', 'services'],
|
|
11
|
+
'-u': ['xl', 'ql', 'entities', 'services'],
|
|
12
|
+
}),
|
|
4
13
|
help: `
|
|
5
14
|
# SYNOPSIS
|
|
6
15
|
|
package/bin/run.js
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
|
+
const { DIR } = require('./completion');
|
|
1
2
|
const serve = require ('./serve')
|
|
2
3
|
module.exports = Object.assign (
|
|
3
|
-
cds_run, serve, {
|
|
4
|
+
cds_run, serve, {
|
|
5
|
+
staticCompletions: () => ({
|
|
6
|
+
'_': DIR(),
|
|
7
|
+
'--from': DIR(),
|
|
8
|
+
'-f': DIR(),
|
|
9
|
+
'--with': DIR(),
|
|
10
|
+
'-w': DIR(),
|
|
11
|
+
'--to': ['odata', 'fiori', 'rest'],
|
|
12
|
+
'-2': ['odata', 'fiori', 'rest'],
|
|
13
|
+
}),
|
|
14
|
+
help: `
|
|
4
15
|
# SYNOPSIS
|
|
5
16
|
|
|
6
17
|
*cds run* [<project>] [<options>]
|
package/bin/serve.js
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
// allows executing `cds serve` even when `cds` executable is removed from `@sap/cds`
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
const { DIR } = require('./completion');
|
|
3
|
+
const serve = require(_local('@sap/cds/bin/serve'))
|
|
4
|
+
module.exports = Object.assign(serve, {
|
|
5
|
+
staticCompletions: () => ({
|
|
6
|
+
'_': DIR(),
|
|
7
|
+
'--from': DIR(),
|
|
8
|
+
'-f': DIR(),
|
|
9
|
+
'--with': DIR(),
|
|
10
|
+
'-w': DIR(),
|
|
11
|
+
'--to': ['odata', 'fiori', 'rest'],
|
|
12
|
+
'-2': ['odata', 'fiori', 'rest'],
|
|
13
|
+
}),
|
|
14
|
+
})
|
|
4
15
|
|
|
5
16
|
function _local (id) {
|
|
6
17
|
return require.resolve (id, { paths: [ process.cwd(), __dirname ] })
|
package/bin/up.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
const { FILE } = require('./completion');
|
|
2
|
+
|
|
1
3
|
module.exports = Object.assign(up, {
|
|
2
4
|
staticCompletions: () => ({
|
|
3
|
-
'--to':
|
|
5
|
+
'--to': ['cf', 'k8s'],
|
|
6
|
+
'--overlay': FILE('mtaext')
|
|
4
7
|
}),
|
|
5
8
|
options: ['--to', '--namespace', '--overlay'],
|
|
6
9
|
shortcuts: ['-2', '-n'],
|
package/bin/util/containerize.js
CHANGED
|
@@ -59,6 +59,7 @@ function processCommands(bp) {
|
|
|
59
59
|
}
|
|
60
60
|
function processBuildpack(bp, name, tag, clearCache = false, image, publish = false) {
|
|
61
61
|
let { type, path, env, builder } = bp.buildpack
|
|
62
|
+
const dependencyMirrors = Object.keys(process.env).filter(key => key.startsWith('BP_DEPENDENCY_MIRROR_') && process.env[key])
|
|
62
63
|
type = type ? type.split(',').map(t => buildpacks.has(t.trim()) ? `paketo-buildpacks/${t.trim()}` : t.trim()) : []
|
|
63
64
|
if (builders.has(builder)) builder = `paketobuildpacks/${builder}`
|
|
64
65
|
const cacheArgs = clearCache ? ['--clear-cache'] : []
|
|
@@ -69,6 +70,7 @@ function processBuildpack(bp, name, tag, clearCache = false, image, publish = fa
|
|
|
69
70
|
...type.flatMap(t => appendSubcommand(t, '--buildpack')),
|
|
70
71
|
...appendSubcommand(builder, '--builder'),
|
|
71
72
|
...appendSubcommand(env, '--env'),
|
|
73
|
+
...dependencyMirrors.flatMap(key => ['--env', key]),
|
|
72
74
|
...(publish ? ['--publish'] : []),
|
|
73
75
|
...cacheArgs
|
|
74
76
|
]]
|
package/bin/watch/index.js
CHANGED
|
@@ -3,10 +3,17 @@ const { DIR } = require('../completion')
|
|
|
3
3
|
|
|
4
4
|
module.exports = Object.assign ( watch, {
|
|
5
5
|
staticCompletions: () => ({
|
|
6
|
+
'_': DIR(),
|
|
7
|
+
'--from': DIR(),
|
|
8
|
+
'-f': DIR(),
|
|
9
|
+
'--with': DIR(),
|
|
10
|
+
'-w': DIR(),
|
|
11
|
+
'--to': ['odata', 'fiori', 'rest'],
|
|
12
|
+
'-2': ['odata', 'fiori', 'rest'],
|
|
6
13
|
'--experimental-hot-reload': ['true', 'false'],
|
|
7
14
|
'--livereload': ['false'],
|
|
8
15
|
'--include': DIR(),
|
|
9
|
-
'--exclude': DIR()
|
|
16
|
+
'--exclude': DIR()
|
|
10
17
|
}),
|
|
11
18
|
flags: [ '--in-memory', '--in-memory?', '--with-mocks', '--with-mtx' ],
|
|
12
19
|
options: [ '--port', ...watchOnlyOptions ],
|
|
@@ -132,36 +132,10 @@ module.exports = class InternalBuildPlugin extends require('./plugin') {
|
|
|
132
132
|
// bundleDest might be null
|
|
133
133
|
if (bundleDest && Object.keys(bundles).length > 0) {
|
|
134
134
|
await this.write(bundles).to(file)
|
|
135
|
-
// also collect and write messages from plugins
|
|
136
|
-
await this.collectMessageBundles(bundleDest, model)
|
|
137
135
|
return { file, bundles }
|
|
138
136
|
}
|
|
139
137
|
return null
|
|
140
138
|
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Collect and write message bundles from CAP plugins into messages.properties files.
|
|
144
|
-
* @param {string} bundleDest
|
|
145
|
-
* @param {Object} model - passed for signature consistency with subclass overrides; not used here
|
|
146
|
-
* as Java does not require neighborhood resolution of plugin i18n files.
|
|
147
|
-
*/
|
|
148
|
-
// eslint-disable-next-line no-unused-vars
|
|
149
|
-
async collectMessageBundles(bundleDest, model) {
|
|
150
|
-
const messageBundle = cds.i18n.bundle4('messages')
|
|
151
|
-
const messagesData = messageBundle.translations4?.(cds.env.i18n.languages) ?? {}
|
|
152
|
-
|
|
153
|
-
// Write messages.properties files for each locale
|
|
154
|
-
for (const [locale, messages] of Object.entries(messagesData)) {
|
|
155
|
-
if (Object.keys(messages).length > 0) {
|
|
156
|
-
const fileName = locale ? `messages_${locale}.properties` : 'messages.properties'
|
|
157
|
-
const filePath = path.join(bundleDest, fileName)
|
|
158
|
-
const content = Object.entries(messages)
|
|
159
|
-
.map(([key, value]) => `${key}=${value}`)
|
|
160
|
-
.join('\n') + '\n'
|
|
161
|
-
await this.write(content).to(filePath)
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
139
|
}
|
|
166
140
|
|
|
167
141
|
// Emits the 'compile.for.runtime' event, as the produced CSN is for runtime usage.
|
|
@@ -10,6 +10,7 @@ const DEBUG = cds.debug('cli|build')
|
|
|
10
10
|
const NODE_ENGINE_VERSION = '^24'
|
|
11
11
|
const { exec } = require('node:child_process')
|
|
12
12
|
const pexec = require('node:util').promisify(exec)
|
|
13
|
+
const escapeLineBreaks = value => value.replace(/\r/g, '\\u000D').replace(/\n/g, '\\u000A')
|
|
13
14
|
|
|
14
15
|
module.exports = class NodejsBuildPlugin extends require('../edmx') {
|
|
15
16
|
|
|
@@ -353,15 +354,19 @@ module.exports = class NodejsBuildPlugin extends require('../edmx') {
|
|
|
353
354
|
return Array.isArray(parsed) ? parsed : Object.values(parsed)
|
|
354
355
|
}
|
|
355
356
|
|
|
356
|
-
|
|
357
|
-
|
|
357
|
+
async collectLanguageBundles(model, bundleDest) {
|
|
358
|
+
const result = await super.collectLanguageBundles(model, bundleDest)
|
|
359
|
+
if (result) await this.collectMessageBundles(bundleDest, model)
|
|
360
|
+
return result
|
|
361
|
+
}
|
|
362
|
+
|
|
358
363
|
async collectMessageBundles(bundleDest, model) {
|
|
359
364
|
const messageBundle = cds.i18n.bundle4('messages', { model })
|
|
360
365
|
const messagesData = messageBundle.translations4?.(cds.env.i18n.languages) ?? {}
|
|
361
366
|
for (const [locale, messages] of Object.entries(messagesData)) {
|
|
362
367
|
if (Object.keys(messages).length > 0) {
|
|
363
368
|
const fileName = locale ? `messages_${locale}.properties` : 'messages.properties'
|
|
364
|
-
const content = Object.entries(messages).map(([k, v]) => `${k}=${v}`).join('\n') + '\n'
|
|
369
|
+
const content = Object.entries(messages).map(([k, v]) => `${k}=${escapeLineBreaks(v)}`).join('\n') + '\n'
|
|
365
370
|
await this.write(content).to(path.join(bundleDest, fileName))
|
|
366
371
|
}
|
|
367
372
|
}
|
package/lib/build/util.js
CHANGED
|
@@ -8,7 +8,6 @@ const { exists } = cds.utils
|
|
|
8
8
|
const execAsync = require('node:util').promisify(cp.exec)
|
|
9
9
|
const { isRoot } = require('../util/fs')
|
|
10
10
|
|
|
11
|
-
const IS_WIN = require('node:os').platform() === 'win32'
|
|
12
11
|
const { SEVERITY_ERROR, FILE_EXT_CDS, NODEJS_MODEL_EXCLUDE_LIST } = require('./constants');
|
|
13
12
|
const DEBUG = cds.debug('cli|build')
|
|
14
13
|
|
|
@@ -288,7 +287,7 @@ const _cachedWsRoots = new Map()
|
|
|
288
287
|
* could contain globs. Glob resolution will be supported.
|
|
289
288
|
* The result is cached by workspace root!
|
|
290
289
|
* natively in the future (fs.glob is in experimental state as of Node23).
|
|
291
|
-
* @param {
|
|
290
|
+
* @param {string} wsRoot - the root directory of the workspace
|
|
292
291
|
* @returns {Promise<string[]>} list of package paths, or an empty array if either
|
|
293
292
|
* no workspaces are defined or have not been installed.
|
|
294
293
|
*/
|
|
@@ -302,8 +301,7 @@ async function _execNpmWs(wsRoot) {
|
|
|
302
301
|
try {
|
|
303
302
|
const cmdLine = 'npm ls --ws --json'
|
|
304
303
|
DEBUG?.(`execute ${cmdLine}`)
|
|
305
|
-
|
|
306
|
-
const { stdout } = await execAsync(cmdLine, { shell: IS_WIN, stdio: ['inherit', 'pipe', 'inherit'], cwd: wsRoot })
|
|
304
|
+
const { stdout } = await execAsync(cmdLine, { cwd: wsRoot })
|
|
307
305
|
const jsonResult = JSON.parse(stdout)
|
|
308
306
|
if (jsonResult.dependencies) {
|
|
309
307
|
result = Object.keys(jsonResult.dependencies)
|
package/lib/cds.js
CHANGED
|
@@ -11,10 +11,16 @@ module.exports = Object.defineProperties (cds, {
|
|
|
11
11
|
|
|
12
12
|
function _local (id, ...morePaths) {
|
|
13
13
|
return require(require.resolve (id, {paths:[
|
|
14
|
-
|
|
14
|
+
_cwd(), // project-local module is preferred
|
|
15
15
|
__dirname, // otherwise from our own dependencies
|
|
16
16
|
...morePaths
|
|
17
|
-
]}))
|
|
17
|
+
].filter(Boolean)})) // drop empty paths (e.g. _cwd()/_npmRoot() fallbacks); require.resolve expects real paths
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function _cwd() {
|
|
21
|
+
// process.cwd() throws ENOENT (uv_cwd) when the cwd was deleted
|
|
22
|
+
try { return process.cwd() }
|
|
23
|
+
catch (e) { if (e.code === 'ENOENT') return '' }
|
|
18
24
|
}
|
|
19
25
|
|
|
20
26
|
function _npmRoot() {
|
package/lib/init/constants.js
CHANGED
package/lib/init/merge.js
CHANGED
|
@@ -165,8 +165,28 @@ async function _mergeYAML(into, from, project, semantics = {}) {
|
|
|
165
165
|
t.value = s.value
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
|
+
const deleteEntries = entries => {
|
|
169
|
+
for (const { item, key, relationships: refs } of entries) {
|
|
170
|
+
const seq = locate(target, item.in)
|
|
171
|
+
const node = locate(target, item)
|
|
172
|
+
if (!YAML.isSeq(seq) || !node) continue
|
|
173
|
+
const removed = node.toJSON()
|
|
174
|
+
key ? node.deleteIn(path(key)) : seq.delete(seq.items.indexOf(node))
|
|
175
|
+
for (const { removeProperty, allWithin } of refs ?? []) {
|
|
176
|
+
const [parentPath, childPath, prop] = allWithin
|
|
177
|
+
for (const parent of locate(target, parentPath)?.items ?? []) {
|
|
178
|
+
const list = parent.getIn(path(childPath))
|
|
179
|
+
const i = list?.items?.findIndex(n => n.get?.(prop) === removed[removeProperty]) ?? -1
|
|
180
|
+
if (i > -1) list.delete(i)
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
168
185
|
mergeNode(target.contents, source.contents)
|
|
169
186
|
|
|
187
|
+
// Deletions: remove the matched node (or a sub-key), then cascade-remove references to it.
|
|
188
|
+
deleteEntries(deletions.filter(({ key }) => !key))
|
|
189
|
+
|
|
170
190
|
// Placement: add matched (and relationship-referenced) template entries not already present.
|
|
171
191
|
const isEntry = e => e && typeof e === 'object' && !Array.isArray(e) && e.in !== undefined
|
|
172
192
|
const insertNode = ins => Array.isArray(ins) ? (ins.length === 1 ? ins[0] : undefined) : ins
|
|
@@ -208,22 +228,7 @@ async function _mergeYAML(into, from, project, semantics = {}) {
|
|
|
208
228
|
}
|
|
209
229
|
}
|
|
210
230
|
|
|
211
|
-
|
|
212
|
-
for (const { item, key, relationships: refs } of deletions) {
|
|
213
|
-
const seq = locate(target, item.in)
|
|
214
|
-
const node = locate(target, item)
|
|
215
|
-
if (!YAML.isSeq(seq) || !node) continue
|
|
216
|
-
const removed = node.toJSON()
|
|
217
|
-
key ? node.deleteIn(path(key)) : seq.delete(seq.items.indexOf(node))
|
|
218
|
-
for (const { removeProperty, allWithin } of refs ?? []) {
|
|
219
|
-
const [parentPath, childPath, prop] = allWithin
|
|
220
|
-
for (const parent of locate(target, parentPath)?.items ?? []) {
|
|
221
|
-
const list = parent.getIn(path(childPath))
|
|
222
|
-
const i = list?.items?.findIndex(n => n.get?.(prop) === removed[removeProperty]) ?? -1
|
|
223
|
-
if (i > -1) list.delete(i)
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}
|
|
231
|
+
deleteEntries(deletions.filter(({ key }) => key))
|
|
227
232
|
|
|
228
233
|
typeof into === 'string' && await writeYAML(into, target)
|
|
229
234
|
return target
|
|
@@ -349,4 +354,3 @@ module.exports.merge = (...src) => {
|
|
|
349
354
|
* @property {Deletion[]} [deletions] - matched nodes (or sub-keys) to delete
|
|
350
355
|
* @property {Relationship[]} [relationships] - relationships to wire into target sequences
|
|
351
356
|
*/
|
|
352
|
-
|
|
@@ -40,7 +40,7 @@ module.exports = class extends require('../../plugin') {
|
|
|
40
40
|
|
|
41
41
|
async combine(facet) {
|
|
42
42
|
const project = readProject(facet)
|
|
43
|
-
const { hasMta, addMta, addKyma, addApprouter, isJava, addMultitenancy, srv } = project
|
|
43
|
+
const { hasMta, addMta, addKyma, addApprouter, hasApprouter, isJava, addMultitenancy, hasMultitenancy, srv } = project
|
|
44
44
|
|
|
45
45
|
if (addMta || (addMultitenancy || addApprouter) && hasMta) {
|
|
46
46
|
const cloudLogging = {
|
|
@@ -58,14 +58,14 @@ module.exports = class extends require('../../plugin') {
|
|
|
58
58
|
into: [srvModule, 'requires', 'name']
|
|
59
59
|
})
|
|
60
60
|
}
|
|
61
|
-
if (
|
|
61
|
+
if (hasMultitenancy) {
|
|
62
62
|
const mtxSidecar = mtxSidecar4(isJava ? 'mtx/sidecar' : 'gen/mtx/sidecar')
|
|
63
63
|
relationships.push({
|
|
64
64
|
insert: [cloudLogging, 'name'],
|
|
65
65
|
into: [mtxSidecar, 'requires', 'name']
|
|
66
66
|
})
|
|
67
67
|
}
|
|
68
|
-
if (
|
|
68
|
+
if (hasApprouter) {
|
|
69
69
|
relationships.push({
|
|
70
70
|
insert: [cloudLogging, 'name'],
|
|
71
71
|
into: [approuter, 'requires', 'name']
|
|
@@ -247,6 +247,9 @@ function dataForField(element, artifact, csn, record, data, parent, depth, refer
|
|
|
247
247
|
const range = { from: 0, to: prec }
|
|
248
248
|
annotatedIntRange(element, range)
|
|
249
249
|
if (scale === 0) return randomIntInRange(range)
|
|
250
|
+
const factor = Math.pow(10, scale)
|
|
251
|
+
range.from = Math.ceil(range.from * factor) / factor
|
|
252
|
+
range.to = Math.floor(range.to * factor) / factor
|
|
250
253
|
// draw uniformly across the range and round to scale, so annotated bounds are never exceeded
|
|
251
254
|
const val = +randomDecimalInRange(range).toFixed(scale)
|
|
252
255
|
return +Math.min(Math.max(val, range.from), range.to).toFixed(scale)
|
|
@@ -25,7 +25,7 @@ module.exports = class DestinationTemplate extends require('../../plugin') {
|
|
|
25
25
|
|
|
26
26
|
async combine(facet) {
|
|
27
27
|
const project = readProject(facet)
|
|
28
|
-
const { addApprouter, addMultitenancy, addKyma, addMta, hasMta, srv, isJava } = project
|
|
28
|
+
const { addApprouter, hasApprouter, addMultitenancy, hasMultitenancy, addKyma, addMta, hasMta, srv, isJava } = project
|
|
29
29
|
|
|
30
30
|
if (addMta || (addApprouter || addMultitenancy) && hasMta) {
|
|
31
31
|
const srvModule = srv4(srv.path)
|
|
@@ -34,13 +34,13 @@ module.exports = class DestinationTemplate extends require('../../plugin') {
|
|
|
34
34
|
insert: [destination, 'name'],
|
|
35
35
|
into: [srvModule, 'requires', 'name']
|
|
36
36
|
}]
|
|
37
|
-
if (
|
|
37
|
+
if (hasApprouter) {
|
|
38
38
|
relationships.push({
|
|
39
39
|
insert: [destination, 'name'],
|
|
40
40
|
into: [approuter, 'requires', 'name']
|
|
41
41
|
})
|
|
42
42
|
}
|
|
43
|
-
if (
|
|
43
|
+
if (hasMultitenancy) {
|
|
44
44
|
relationships.push({
|
|
45
45
|
insert: [destination, 'name'],
|
|
46
46
|
into: [mtxSidecar4(isJava ? 'mtx/sidecar' : 'gen/mtx/sidecar'), 'requires', 'name']
|
|
@@ -6,6 +6,9 @@ const { srv4, enterpriseMessaging, xsuaa } = require('../../registries/mta')
|
|
|
6
6
|
const KymaTemplate = require('../kyma')
|
|
7
7
|
|
|
8
8
|
module.exports = class EnterpriseMessagingTemplate extends require('../../plugin') {
|
|
9
|
+
static get kind() { return 'enterprise-messaging-http' }
|
|
10
|
+
static get vcap() { return 'enterprise-messaging' }
|
|
11
|
+
|
|
9
12
|
constructor(...args) {
|
|
10
13
|
super(...args)
|
|
11
14
|
this._name = 'enterprise-messaging'
|
|
@@ -37,7 +40,7 @@ module.exports = class EnterpriseMessagingTemplate extends require('../../plugin
|
|
|
37
40
|
|
|
38
41
|
static hasInProduction(env) {
|
|
39
42
|
const { kind = 'dummy', vcap } = env.requires?.messaging ?? {}
|
|
40
|
-
return kind === this.
|
|
43
|
+
return kind === this.kind && vcap?.label === this.vcap
|
|
41
44
|
}
|
|
42
45
|
|
|
43
46
|
async run() {
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
const { eventMesh } = require('../../registries/mta')
|
|
2
2
|
|
|
3
3
|
module.exports = class EventMeshTemplate extends require('../enterprise-messaging') {
|
|
4
|
+
static get kind() { return 'enterprise-messaging-http' }
|
|
5
|
+
static get vcap() { return 'event-mesh-message-client' }
|
|
6
|
+
|
|
4
7
|
constructor(...args) {
|
|
5
8
|
super(...args)
|
|
6
9
|
this._name = 'event-mesh'
|
|
@@ -44,11 +44,11 @@ module.exports = class MultitenancyTemplate extends require('../../plugin') {
|
|
|
44
44
|
const project = readProject(facet)
|
|
45
45
|
const {
|
|
46
46
|
isNodejs, isJava, addMta, hasMta,
|
|
47
|
-
addXsuaa, hasXsuaa, addIas, hasIas, hasHana, hasHanaServerless, addKyma, hasApprouter,
|
|
47
|
+
addXsuaa, hasXsuaa, addIas, hasIas, addMultitenancy, hasHana, hasHanaServerless, addKyma, hasApprouter,
|
|
48
48
|
srv, appName
|
|
49
49
|
} = project
|
|
50
50
|
|
|
51
|
-
if (addMta || (addIas || addXsuaa) && hasMta) {
|
|
51
|
+
if (addMta || (addMultitenancy || addIas || addXsuaa) && hasMta) {
|
|
52
52
|
const srvModule = srv4(srv.path)
|
|
53
53
|
const mtxSidecar = mtxSidecar4(isJava ? 'mtx/sidecar' : 'gen/mtx/sidecar')
|
|
54
54
|
const modules = [srvModule, mtxSidecar]
|
|
@@ -4,6 +4,36 @@
|
|
|
4
4
|
- The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
|
5
5
|
- This project adheres to [Semantic Versioning](http://semver.org/).
|
|
6
6
|
|
|
7
|
+
## [3.1.1](https://github.com/cap-js/cds-dbs/compare/db-service-v3.1.0...db-service-v3.1.1) (2026-09-15)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
* **cqn4sql:** correctly expand `not exists <assoc>` alongside a null-check branch ([#1736](https://github.com/cap-js/cds-dbs/issues/1736)) ([bfb0a01](https://github.com/cap-js/cds-dbs/commit/bfb0a010cce2cea089f4fabf92a3ecea43486a09))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Performance Improvements
|
|
16
|
+
|
|
17
|
+
* do not use ranked search for static values ([#1727](https://github.com/cap-js/cds-dbs/issues/1727)) ([33fb36b](https://github.com/cap-js/cds-dbs/commit/33fb36bbf0f86291e5fc0b9e2ff5b7244b49d19e))
|
|
18
|
+
* if explicit order by is specified, do not add ranked search as a secondary clause ([33fb36b](https://github.com/cap-js/cds-dbs/commit/33fb36bbf0f86291e5fc0b9e2ff5b7244b49d19e))
|
|
19
|
+
|
|
20
|
+
## [3.1.0](https://github.com/cap-js/cds-dbs/compare/db-service-v3.0.1...db-service-v3.1.0) (2026-09-07)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
* rank $search results by relevance ([#1725](https://github.com/cap-js/cds-dbs/issues/1725)) ([bc93160](https://github.com/cap-js/cds-dbs/commit/bc931601a721f7c9e00b89e6844ba064352b541d))
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
* **cqn4sql:** reject overly nested query expressions instead of crashing ([#1712](https://github.com/cap-js/cds-dbs/issues/1712)) ([29a45b7](https://github.com/cap-js/cds-dbs/commit/29a45b7daadbc77433b882148700d73c00efae62))
|
|
31
|
+
* don't throw when releasing/destroying a resource that's no longer in the pool ([#1696](https://github.com/cap-js/cds-dbs/issues/1696)) ([5d3b277](https://github.com/cap-js/cds-dbs/commit/5d3b277a1cf7cac02e41f2f24975a8e9473e5b5e))
|
|
32
|
+
* exclude cds.Vector from wildcard select expansion ([#1716](https://github.com/cap-js/cds-dbs/issues/1716)) ([398bacc](https://github.com/cap-js/cds-dbs/commit/398bacc2a74883dcd93acba288deae362570a4c1))
|
|
33
|
+
* INSERT.from(SELECT) used non-existent `value` ([#1565](https://github.com/cap-js/cds-dbs/issues/1565)) ([fd98844](https://github.com/cap-js/cds-dbs/commit/fd98844c83a78d6cf2b0b71344d3ee1d88528106))
|
|
34
|
+
* **pool:** recover lost connection after stale acquire timeout ([#1724](https://github.com/cap-js/cds-dbs/issues/1724)) ([cf6af99](https://github.com/cap-js/cds-dbs/commit/cf6af991d02be7cf5f861e2a424d4d733b8f9238))
|
|
35
|
+
* pql groupby path expression ([#1700](https://github.com/cap-js/cds-dbs/issues/1700)) ([82b5e03](https://github.com/cap-js/cds-dbs/commit/82b5e0385e680321f30c352f0f78ade6d25259a6))
|
|
36
|
+
|
|
7
37
|
## [3.0.1](https://github.com/cap-js/cds-dbs/compare/db-service-v3.0.0...db-service-v3.0.1) (2026-06-29)
|
|
8
38
|
|
|
9
39
|
|
|
@@ -150,7 +150,7 @@ constructor (factory, options = {}) {
|
|
|
150
150
|
return
|
|
151
151
|
}
|
|
152
152
|
const loan = this._loans.get(resource)
|
|
153
|
-
if (!loan)
|
|
153
|
+
if (!loan) return
|
|
154
154
|
this._loans.delete(resource)
|
|
155
155
|
const pooledResource = loan.pooledResource
|
|
156
156
|
pooledResource.idle()
|
|
@@ -164,7 +164,7 @@ constructor (factory, options = {}) {
|
|
|
164
164
|
return
|
|
165
165
|
}
|
|
166
166
|
const loan = this._loans.get(resource)
|
|
167
|
-
if (!loan)
|
|
167
|
+
if (!loan) return
|
|
168
168
|
this._loans.delete(resource)
|
|
169
169
|
const pooledResource = loan.pooledResource
|
|
170
170
|
await this.#destroy(pooledResource)
|
|
@@ -212,16 +212,13 @@ constructor (factory, options = {}) {
|
|
|
212
212
|
for (let i = 0; i < needed; i++) this.#createResource()
|
|
213
213
|
}
|
|
214
214
|
const dispense = async resource => {
|
|
215
|
-
|
|
215
|
+
let request = this._queue.shift()
|
|
216
|
+
while (request && request.state !== RequestState.PENDING) request = this._queue.shift()
|
|
216
217
|
if (!request) {
|
|
217
218
|
resource.idle()
|
|
218
219
|
this._available.add(resource)
|
|
219
220
|
return false
|
|
220
221
|
}
|
|
221
|
-
if (request.state !== RequestState.PENDING) {
|
|
222
|
-
this.#dispense()
|
|
223
|
-
return false
|
|
224
|
-
}
|
|
225
222
|
this._loans.set(resource.obj, { pooledResource: resource })
|
|
226
223
|
resource.update(ResourceState.ALLOCATED)
|
|
227
224
|
request.resolve(resource.obj)
|
|
@@ -18,7 +18,7 @@ class CQN2PQLRenderer extends CQN2SQL {
|
|
|
18
18
|
|
|
19
19
|
column_expr(x, q) {
|
|
20
20
|
// omit alias when target is a single source
|
|
21
|
-
if (q.SELECT.from
|
|
21
|
+
if (q.SELECT.from?.ref && x?.ref) x.ref = x.ref.slice(-1)
|
|
22
22
|
return super.column_expr(x, q)
|
|
23
23
|
}
|
|
24
24
|
|
|
@@ -1088,7 +1088,7 @@ class CQN2SQLRenderer {
|
|
|
1088
1088
|
|
|
1089
1089
|
const extractions = this._managed = this.managed(columns.map(c => ({ name: c, sql: `NEW.${this.quote(c)}` })), elements)
|
|
1090
1090
|
const sql = extractions.length > columns.length
|
|
1091
|
-
? `SELECT ${extractions.map(c => `${c.insert} AS ${this.quote(c.name)}`)} FROM (${this.SELECT(src)}) AS NEW`
|
|
1091
|
+
? `SELECT ${extractions.map((c, i) => `${i < columns.length ? c.insert : c.onInsert} AS ${this.quote(c.name)}`)} FROM (${this.SELECT(src)}) AS NEW`
|
|
1092
1092
|
: this.SELECT(src)
|
|
1093
1093
|
if (extractions.length > columns.length) columns = this.columns = extractions.map(c => c.name)
|
|
1094
1094
|
this.sql = `INSERT INTO ${this.quote(entity)}${alias ? ' as ' + this.quote(alias) : ''} (${columns.map(c => this.quote(transitions.mapping.get(c)?.ref?.[0] || c))}) ${sql}`
|
|
@@ -1161,12 +1161,12 @@ class CQN2SQLRenderer {
|
|
|
1161
1161
|
const extractions = this._managed
|
|
1162
1162
|
if (this.values) this.values = [] // Clear previously computed values
|
|
1163
1163
|
const src = this.cqn4sql(UPSERT.from || UPSERT.as)
|
|
1164
|
-
const aliasedQuery =
|
|
1165
|
-
.columns(
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
sql = `SELECT ${extractions.map(c =>
|
|
1164
|
+
const aliasedQuery = `SELECT ${[
|
|
1165
|
+
...src.SELECT.columns.map((c, i) => this.column_expr({ ref: [this.column_name(c)], as: this.columns[i] })),
|
|
1166
|
+
...extractions.slice(src.SELECT.columns.length).map(c => `${elements[c.name].key ? c.onInsert : 'NULL'} AS ${this.quote(c.name)}`), // fill in missing default values
|
|
1167
|
+
]} FROM (${this.SELECT(src)})`
|
|
1168
|
+
|
|
1169
|
+
sql = `SELECT ${extractions.map(c => elements[c.name].key ? `NEW.${this.quote(c.name)}` : c.upsert)} FROM(${aliasedQuery}) AS NEW LEFT JOIN ${this.quote(entity)} AS OLD ON ${keyCompare} `
|
|
1170
1170
|
if (extractions.length > columns.length) columns = this.columns = extractions.map(c => c.name)
|
|
1171
1171
|
this.entries = [this.values]
|
|
1172
1172
|
}
|
|
@@ -1574,9 +1574,11 @@ class CQN2SQLRenderer {
|
|
|
1574
1574
|
|
|
1575
1575
|
managed_extract(name, element, converter) {
|
|
1576
1576
|
const { UPSERT, INSERT } = this.cqn
|
|
1577
|
-
const extract =
|
|
1578
|
-
? `value->>${this.string(
|
|
1579
|
-
:
|
|
1577
|
+
const extract = (INSERT?.entries || UPSERT?.entries)
|
|
1578
|
+
? `value->>${this.string(`$.${JSON.stringify(name)}`)}`
|
|
1579
|
+
: (INSERT?.rows || UPSERT?.rows)
|
|
1580
|
+
? `value->>${this.string(`$[${this.columns.indexOf(name)}]`)}`
|
|
1581
|
+
: `NEW.${this.quote(name)}` // in case of (INSERT?.from || UPSERT?.from)
|
|
1580
1582
|
const sql = converter?.(extract) || extract
|
|
1581
1583
|
return { extract, sql }
|
|
1582
1584
|
}
|
|
@@ -1587,7 +1589,9 @@ class CQN2SQLRenderer {
|
|
|
1587
1589
|
}
|
|
1588
1590
|
|
|
1589
1591
|
managed_default(name, managed, src) {
|
|
1590
|
-
|
|
1592
|
+
const { UPSERT, INSERT } = this.cqn
|
|
1593
|
+
const isJson = INSERT?.entries || UPSERT?.entries || INSERT?.rows || UPSERT?.rows
|
|
1594
|
+
return `(CASE WHEN ${isJson ? `json_type(value,${this.managed_extract(name).extract.slice(8)})` : `NEW.${this.quote(name)}`} IS NULL THEN ${managed} ELSE ${src} END)`
|
|
1591
1595
|
}
|
|
1592
1596
|
}
|
|
1593
1597
|
|