@sap/cds 6.6.2 → 6.7.0
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 +59 -2
- package/README.md +1 -1
- package/apis/connect.d.ts +11 -4
- package/apis/core.d.ts +1 -1
- package/apis/csn.d.ts +1 -0
- package/apis/internal/inference.d.ts +15 -2
- package/apis/log.d.ts +10 -0
- package/apis/serve.d.ts +4 -9
- package/apis/services.d.ts +86 -19
- package/bin/build/buildTaskEngine.js +16 -42
- package/bin/build/constants.js +4 -2
- package/bin/build/provider/buildTaskProviderInternal.js +117 -85
- package/bin/build/provider/hana/index.js +6 -1
- package/bin/build/provider/mtx-extension/index.js +74 -34
- package/bin/build/provider/mtx-sidecar/index.js +3 -3
- package/bin/build/provider/nodejs/index.js +2 -2
- package/bin/build/util.js +63 -14
- package/bin/cds-serve.js +6 -0
- package/bin/cds.js +20 -4
- package/bin/deploy/to-hana/cfUtil.js +15 -1
- package/bin/mtx/in-cds.js +2 -9
- package/bin/plugins.js +31 -0
- package/bin/serve.js +12 -12
- package/lib/compile/etc/_localized.js +1 -1
- package/lib/compile/for/lean_drafts.js +22 -6
- package/lib/compile/for/nodejs.js +4 -1
- package/lib/compile/load.js +4 -2
- package/lib/core/index.js +35 -15
- package/lib/dbs/cds-deploy.js +129 -133
- package/lib/env/cds-env.js +25 -17
- package/lib/env/cds-requires.js +10 -40
- package/lib/env/compat.js +12 -0
- package/lib/env/defaults.js +17 -9
- package/lib/env/plugins.js +29 -0
- package/lib/env/schemas/cds-rc.json +14 -0
- package/lib/index.js +3 -0
- package/lib/log/cds-log.js +7 -4
- package/lib/ql/CREATE.js +1 -1
- package/lib/ql/DELETE.js +1 -1
- package/lib/ql/DROP.js +3 -3
- package/lib/ql/INSERT.js +1 -1
- package/lib/ql/Query.js +14 -6
- package/lib/ql/SELECT.js +8 -2
- package/lib/ql/UPDATE.js +1 -1
- package/lib/ql/Whereable.js +1 -1
- package/lib/ql/cds-ql.js +1 -9
- package/lib/req/cds-context.js +1 -4
- package/lib/req/request.js +63 -2
- package/lib/req/response.js +3 -2
- package/lib/srv/bindings.js +69 -71
- package/lib/srv/cds-connect.js +4 -1
- package/lib/srv/cds-serve.js +4 -0
- package/lib/srv/middlewares/index.js +37 -6
- package/lib/srv/protocols/_legacy.js +1 -1
- package/lib/srv/protocols/index.js +1 -1
- package/lib/srv/srv-api.js +4 -6
- package/lib/srv/srv-dispatch.js +4 -3
- package/lib/srv/srv-handlers.js +1 -1
- package/lib/srv/srv-methods.js +8 -2
- package/lib/utils/cds-test.js +4 -1
- package/libx/_runtime/audit/Service.js +8 -9
- package/libx/_runtime/audit/generic/personal/index.js +1 -1
- package/libx/_runtime/audit/generic/personal/utils.js +1 -1
- package/libx/_runtime/audit/utils/v2.js +17 -20
- package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +2 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +11 -4
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +0 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/readToCQN.js +3 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/metaInfo.js +4 -4
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/oDataConfiguration.js +2 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +1 -1
- package/libx/_runtime/cds-services/services/Service.js +1 -1
- package/libx/_runtime/cds-services/util/assert.js +41 -65
- package/libx/_runtime/common/code-ext/WorkerPool.js +90 -0
- package/libx/_runtime/common/code-ext/WorkerReq.js +0 -4
- package/libx/_runtime/common/code-ext/execute.js +28 -18
- package/libx/_runtime/common/code-ext/handlers.js +5 -4
- package/libx/_runtime/common/code-ext/worker.js +45 -3
- package/libx/_runtime/common/code-ext/workerQueryExecutor.js +8 -7
- package/libx/_runtime/common/composition/delete.js +1 -1
- package/libx/_runtime/common/composition/update.js +3 -5
- package/libx/_runtime/common/generic/auth/expand.js +1 -1
- package/libx/_runtime/common/generic/auth/readOnly.js +5 -4
- package/libx/_runtime/common/generic/auth/restrict.js +7 -2
- package/libx/_runtime/common/generic/crud.js +12 -1
- package/libx/_runtime/common/generic/etag.js +11 -3
- package/libx/_runtime/common/generic/input.js +8 -6
- package/libx/_runtime/common/generic/paging.js +25 -8
- package/libx/_runtime/common/generic/put.js +1 -1
- package/libx/_runtime/common/generic/sorting.js +0 -1
- package/libx/_runtime/common/i18n/messages.properties +1 -0
- package/libx/_runtime/common/utils/cqn.js +5 -1
- package/libx/_runtime/common/utils/cqn2cqn4sql.js +2 -2
- package/libx/_runtime/common/utils/resolveView.js +14 -10
- package/libx/_runtime/common/utils/rewriteAsterisks.js +2 -3
- package/libx/_runtime/common/utils/templateProcessor.js +15 -17
- package/libx/_runtime/common/utils/templateProcessorPathSerializer.js +18 -6
- package/libx/_runtime/db/Service.js +1 -0
- package/libx/_runtime/db/data-conversion/post-processing.js +0 -18
- package/libx/_runtime/db/expand/expand-v2.js +2 -2
- package/libx/_runtime/db/expand/rawToExpanded.js +6 -6
- package/libx/_runtime/db/generic/integrity.js +1 -1
- package/libx/_runtime/db/utils/columns.js +5 -5
- package/libx/_runtime/fiori/generic/activate.js +3 -3
- package/libx/_runtime/fiori/generic/edit.js +1 -1
- package/libx/_runtime/fiori/generic/new.js +4 -0
- package/libx/_runtime/fiori/lean-draft.js +138 -46
- package/libx/_runtime/hana/execute.js +3 -1
- package/libx/_runtime/hana/pool.js +10 -2
- package/libx/_runtime/messaging/common-utils/AMQPClient.js +6 -1
- package/libx/_runtime/messaging/enterprise-messaging.js +1 -0
- package/libx/_runtime/remote/Service.js +16 -13
- package/libx/_runtime/remote/utils/client.js +6 -1
- package/libx/_runtime/sqlite/Service.js +5 -59
- package/libx/_runtime/sqlite/convertDraftAdminPathExpression.js +1 -0
- package/libx/_runtime/sqlite/customBuilder/CustomUpsertBuilder.js +2 -2
- package/libx/_runtime/sqlite/execute.js +3 -1
- package/libx/_runtime/types/api.js +12 -3
- package/libx/odata/afterburner.js +36 -0
- package/libx/odata/cqn2odata.js +1 -1
- package/libx/odata/grammar.pegjs +5 -3
- package/libx/odata/parser.js +1 -1
- package/libx/odata/utils.js +1 -1
- package/libx/rest/RestAdapter.js +1 -1
- package/libx/rest/RestRequest.js +1 -0
- package/package.json +5 -2
- package/libx/_runtime/common/code-ext/workerQuery.js +0 -45
- package/libx/_runtime/common/constants/limit.js +0 -12
- package/libx/_runtime/common/utils/page.js +0 -39
package/lib/env/cds-env.js
CHANGED
|
@@ -32,6 +32,11 @@ class Config {
|
|
|
32
32
|
const { NODE_ENV, CDS_ENV } = process.env, profiles = []
|
|
33
33
|
if (NODE_ENV) profiles.push (NODE_ENV)
|
|
34
34
|
if (CDS_ENV) profiles.push (...CDS_ENV.split(/\s*,\s*/))
|
|
35
|
+
if (_home) try {
|
|
36
|
+
const { cds } = require(path.join(_home,'package.json'))
|
|
37
|
+
if (cds?.profiles) profiles.push(...cds.profiles)
|
|
38
|
+
if (cds?.profile) profiles.push(cds.profile)
|
|
39
|
+
} catch {/* ignore */}
|
|
35
40
|
if (!profiles.includes('production')) profiles.push('development')
|
|
36
41
|
this._profiles = new Set (profiles)
|
|
37
42
|
this._profiles._defined = new Set()
|
|
@@ -127,8 +132,9 @@ class Config {
|
|
|
127
132
|
* Retrieves the value for a config option, specified as a property path.
|
|
128
133
|
*/
|
|
129
134
|
get (option) {
|
|
130
|
-
if (!option)
|
|
131
|
-
|
|
135
|
+
if (!option) return
|
|
136
|
+
let path = option.includes('/') ? option.split('/') : option.split('.')
|
|
137
|
+
return path.reduce ((p,n)=> p && p[n], this)
|
|
132
138
|
}
|
|
133
139
|
|
|
134
140
|
get profiles() {
|
|
@@ -244,7 +250,7 @@ class Config {
|
|
|
244
250
|
}
|
|
245
251
|
|
|
246
252
|
_link_required_services () {
|
|
247
|
-
const { requires } = this; if (!requires) return
|
|
253
|
+
const { requires, _profiles } = this; if (!requires) return
|
|
248
254
|
const kinds = requires.kinds || {}
|
|
249
255
|
Object.defineProperty (requires, 'kinds', { value:kinds, enumerable:false }) // for cds env
|
|
250
256
|
// Object.setPrototypeOf (requires, kinds)
|
|
@@ -254,27 +260,28 @@ class Config {
|
|
|
254
260
|
if (!val || val._is_linked) return val
|
|
255
261
|
if (val === true) {
|
|
256
262
|
let x = kinds[key]
|
|
257
|
-
if (
|
|
258
|
-
else val = x
|
|
263
|
+
if (x) val = x; else return val
|
|
259
264
|
}
|
|
260
265
|
if (typeof val === 'string') {
|
|
261
266
|
let x = kinds[val] || kinds[val+'-'+key] || kinds[key+'-'+val]
|
|
262
|
-
if (
|
|
263
|
-
else val = { kind: val }
|
|
267
|
+
if (x) val = {kind:val}; else return val
|
|
264
268
|
}
|
|
265
|
-
|
|
266
|
-
if (
|
|
267
|
-
const
|
|
268
|
-
|
|
269
|
-
|
|
269
|
+
let k = val.kind, p, preset = kinds[p=k] || kinds[p=k+'-'+key] || kinds[p=key+'-'+k]
|
|
270
|
+
if (!preset?.$root) {
|
|
271
|
+
const preset1 = kinds[key]
|
|
272
|
+
if (typeof preset1 === 'object' && preset1 !== val) {
|
|
273
|
+
const top = val, base = _merge ({},_linked(key,preset1)), {kind} = base
|
|
274
|
+
val = _merge (base, top, false, false) // apply/override with top-level data
|
|
275
|
+
if (kind) val.kind = kind // but inherited kind wins
|
|
276
|
+
}
|
|
270
277
|
}
|
|
271
|
-
let k = val.kind, p, preset = k && kinds[p=k] || kinds[p=k+'-'+key] || kinds[p=key+'-'+k]
|
|
272
278
|
if (typeof preset === 'object' && preset !== val) {
|
|
273
|
-
const top = val, base = _merge ({},_linked(p,preset)), {kind} = base
|
|
274
|
-
val = _merge (base, top,
|
|
279
|
+
const top = val, base = _merge ({},_linked(p,preset), _profiles), {kind} = base
|
|
280
|
+
val = _merge (base, top, _profiles, false) // apply/override with top-level data
|
|
275
281
|
if (kind) val.kind = kind // but inherited kind wins
|
|
276
282
|
}
|
|
277
|
-
|
|
283
|
+
if (typeof val === 'object') Object.defineProperty (val, '_is_linked', {value:true})
|
|
284
|
+
return val
|
|
278
285
|
}
|
|
279
286
|
}
|
|
280
287
|
|
|
@@ -435,7 +442,8 @@ function _merge (dst, src, _profiles, _cloned, _profiles_only = false) {
|
|
|
435
442
|
const profile = p.slice(1,-1)
|
|
436
443
|
if (_profiles._defined) _profiles._defined.add (profile)
|
|
437
444
|
if (_profiles.has(profile)) {
|
|
438
|
-
|
|
445
|
+
let o = src[p]; if (typeof o === 'string') o = {kind:o}
|
|
446
|
+
profiled.push ({ profile, merge: () => _merge (dst, o, _profiles, _cloned, false)})
|
|
439
447
|
}
|
|
440
448
|
continue
|
|
441
449
|
}
|
package/lib/env/cds-requires.js
CHANGED
|
@@ -2,16 +2,8 @@ const _runtime = '@sap/cds/libx/_runtime'
|
|
|
2
2
|
|
|
3
3
|
exports = module.exports = {
|
|
4
4
|
|
|
5
|
-
middlewares:
|
|
6
|
-
"[
|
|
7
|
-
middlewares: true
|
|
8
|
-
},
|
|
9
|
-
|
|
10
|
-
"[schevo]": {
|
|
11
|
-
db: { schema_evolution: 'auto' },
|
|
12
|
-
},
|
|
13
|
-
|
|
14
|
-
db: undefined,
|
|
5
|
+
middlewares: undefined, "[middlewares]": { middlewares: true },
|
|
6
|
+
db: undefined, "[schevo]": { db: { schema_evolution: 'auto' }, },
|
|
15
7
|
messaging: undefined,
|
|
16
8
|
multitenancy: undefined,
|
|
17
9
|
extensibility: undefined,
|
|
@@ -127,19 +119,20 @@ const _databases = {
|
|
|
127
119
|
"sql": {
|
|
128
120
|
'[development]': { kind: 'sqlite', credentials: { url: ':memory:' } },
|
|
129
121
|
'[production]': { kind: 'hana' },
|
|
130
|
-
'[better-sqlite]': { kind: 'better-sqlite' },
|
|
131
122
|
},
|
|
132
|
-
"better-sqlite":
|
|
123
|
+
"better-sqlite": {
|
|
133
124
|
credentials: { url: ":memory:" },
|
|
134
125
|
impl: "@cap-js/sqlite",
|
|
135
|
-
|
|
136
|
-
|
|
126
|
+
kind: 'sqlite'
|
|
127
|
+
},
|
|
128
|
+
"sql-mt": { // For compatibility only
|
|
137
129
|
'[development]': { kind: 'sqlite' },
|
|
138
130
|
'[production]': { kind: 'hana-mt' },
|
|
139
131
|
},
|
|
140
132
|
"sqlite": _compat_to_use({
|
|
141
|
-
|
|
133
|
+
'[better-sqlite]': { impl: '@cap-js/sqlite' },
|
|
142
134
|
impl: `${_runtime}/sqlite/Service.js`,
|
|
135
|
+
credentials: { url: 'db.sqlite' },
|
|
143
136
|
}),
|
|
144
137
|
"hana": _compat_to_use ({
|
|
145
138
|
impl: `${_runtime}/hana/Service.js`,
|
|
@@ -246,37 +239,12 @@ const _platform_services = {
|
|
|
246
239
|
|
|
247
240
|
}
|
|
248
241
|
|
|
249
|
-
require = (id) => { // eslint-disable-line no-global-assign
|
|
250
|
-
try {
|
|
251
|
-
return module.require(id)
|
|
252
|
-
} catch(e) {
|
|
253
|
-
if (e.code !== 'MODULE_NOT_FOUND') throw e
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// REVISIT: we should have a real modular plugin technique for cds.env
|
|
258
|
-
const utils = require ('../utils/cds-utils')
|
|
259
|
-
const _mtxs = !utils._oldMtx()
|
|
260
|
-
// eslint-disable-next-line cds/no-missing-dependencies
|
|
261
|
-
&& require('@sap/cds-mtxs/lib/env-requires') || {
|
|
262
|
-
"toggles": {
|
|
263
|
-
model: "@sap/cds/srv/mtx"
|
|
264
|
-
},
|
|
265
|
-
"multitenancy": {
|
|
266
|
-
model: "@sap/cds/srv/mtx",
|
|
267
|
-
kind: "saas-registry",
|
|
268
|
-
},
|
|
269
|
-
"extensibility": {
|
|
270
|
-
model: "@sap/cds/srv/mtx",
|
|
271
|
-
},
|
|
272
|
-
}
|
|
273
242
|
|
|
274
243
|
exports.kinds = {
|
|
275
244
|
..._authentication_strategies,
|
|
276
245
|
..._databases,
|
|
277
246
|
..._services,
|
|
278
247
|
..._messaging,
|
|
279
|
-
..._mtxs,
|
|
280
248
|
..._platform_services,
|
|
281
249
|
}
|
|
282
250
|
|
|
@@ -285,3 +253,5 @@ function _compat_to_use(o) { return Object.defineProperties (o,{
|
|
|
285
253
|
// NOTE: Property .use is for compatibility only -> use .dialect instead!
|
|
286
254
|
use: { get(){ return this.dialect || this.kind }, configurable:true, enumerable:true },
|
|
287
255
|
})}
|
|
256
|
+
|
|
257
|
+
Object.defineProperty(exports,'_resolved',{value:exports._resolved,enumerable:false}) // hide it in outputs
|
package/lib/env/compat.js
CHANGED
|
@@ -89,4 +89,16 @@ module.exports = function (conf) {
|
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
91
|
})
|
|
92
|
+
|
|
93
|
+
Object.defineProperties (conf.features, {
|
|
94
|
+
fiori_preview: {
|
|
95
|
+
get: ()=> _.fiori.preview,
|
|
96
|
+
set: (v) => { _.fiori.preview = v },
|
|
97
|
+
},
|
|
98
|
+
fiori_routes: {
|
|
99
|
+
get: ()=> _.fiori.routes,
|
|
100
|
+
set: (v) => { _.fiori.routes = v },
|
|
101
|
+
},
|
|
102
|
+
})
|
|
103
|
+
|
|
92
104
|
}
|
package/lib/env/defaults.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
const path = require('path')
|
|
2
|
-
const [,major,minor] = /v(\d+)\.(\d+)/.exec(process.version)
|
|
3
1
|
const production = process.env.NODE_ENV === 'production'
|
|
2
|
+
const path = require('path')
|
|
4
3
|
|
|
5
|
-
module.exports = {
|
|
4
|
+
const defaults = module.exports = {
|
|
6
5
|
|
|
7
6
|
requires: require('./cds-requires'),
|
|
8
7
|
|
|
@@ -13,10 +12,7 @@ module.exports = {
|
|
|
13
12
|
|
|
14
13
|
features: {
|
|
15
14
|
folders: 'fts/*', // where to find feature toggles -> switch on by default when released
|
|
16
|
-
cls: major > 12 || major == 12 && minor >= 18,
|
|
17
15
|
live_reload: !production,
|
|
18
|
-
fiori_preview: !production,
|
|
19
|
-
fiori_routes: !production,
|
|
20
16
|
in_memory_db: !production,
|
|
21
17
|
test_data: !production,
|
|
22
18
|
test_mocks: !production,
|
|
@@ -30,10 +26,20 @@ module.exports = {
|
|
|
30
26
|
assert_integrity: false,
|
|
31
27
|
cds_tx_protection: true,
|
|
32
28
|
cds_tx_inheritance: true,
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
fiori: {
|
|
32
|
+
preview: !production,
|
|
33
|
+
routes: !production,
|
|
33
34
|
lean_draft: false,
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
35
|
+
draft_compat: false,
|
|
36
|
+
'[better-sqlite]': { lean_draft: true },
|
|
37
|
+
'[lean-draft]': { lean_draft: true },
|
|
38
|
+
'[draft-compat]': { draft_compat: true },
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
ql: {
|
|
42
|
+
quirks_mode: true, // IMPORTANT: Remove that for cds7 !!
|
|
37
43
|
},
|
|
38
44
|
|
|
39
45
|
log: {
|
|
@@ -162,3 +168,5 @@ module.exports = {
|
|
|
162
168
|
},
|
|
163
169
|
|
|
164
170
|
}
|
|
171
|
+
|
|
172
|
+
require('./plugins')(defaults)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// REVISIT: we should have a real modular plugin technique for cds.env
|
|
2
|
+
module.exports = function add_mtx_env (env) {
|
|
3
|
+
|
|
4
|
+
const mtx_env = old_mtx_env() || require('@sap/cds-mtxs/env') // eslint-disable-line cds/no-missing-dependencies
|
|
5
|
+
if (mtx_env) {
|
|
6
|
+
const {requires} = env, {kinds} = requires
|
|
7
|
+
Object.assign (env, mtx_env, {requires})
|
|
8
|
+
Object.assign (requires, mtx_env.requires, {kinds})
|
|
9
|
+
Object.assign (kinds, mtx_env.requires?.kinds)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function require (id) {
|
|
13
|
+
try { return module.require(id) }
|
|
14
|
+
catch(e) { if (e.code !== 'MODULE_NOT_FOUND') throw e }
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function old_mtx_env() {
|
|
18
|
+
const {_oldMtx} = require('../utils/cds-utils')
|
|
19
|
+
if (_oldMtx()) return {
|
|
20
|
+
requires: { kinds: {
|
|
21
|
+
"multitenancy": { model: "@sap/cds/srv/mtx", kind: "saas-registry" },
|
|
22
|
+
"extensibility": { model: "@sap/cds/srv/mtx" },
|
|
23
|
+
// "toggles": { model: "@sap/cds/srv/mtx" },
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}}
|
|
27
|
+
|
|
28
|
+
return env
|
|
29
|
+
}
|
|
@@ -5,6 +5,20 @@
|
|
|
5
5
|
"type": "object",
|
|
6
6
|
"additionalProperties": true,
|
|
7
7
|
"properties": {
|
|
8
|
+
"[development]": { "type": "object" },
|
|
9
|
+
"[production]": { "type": "object" },
|
|
10
|
+
"[hybrid]": { "type": "object" },
|
|
11
|
+
"profile": {
|
|
12
|
+
"description": "A single static profile",
|
|
13
|
+
"anyOf": [
|
|
14
|
+
{ "enum": [ "mtx-sidecar", "with-mtx-sidecar" ] },
|
|
15
|
+
{ "type": "string" }
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
"profiles": {
|
|
19
|
+
"description": "An array of profiles",
|
|
20
|
+
"type": "array", "items": { "$ref": "#/properties/profile" }
|
|
21
|
+
},
|
|
8
22
|
"folders": {
|
|
9
23
|
"type": "object",
|
|
10
24
|
"description": "Only set folders if you don't want to use the defaults 'app/', 'db/', 'srv/'.",
|
package/lib/index.js
CHANGED
|
@@ -77,6 +77,9 @@ const cds = module.exports = extend (new facade) .with ({
|
|
|
77
77
|
User: require ('./req/user'),
|
|
78
78
|
ql: lazy => require ('./ql/cds-ql'),
|
|
79
79
|
tx: (..._) => (cds.db || cds.Service.prototype) .tx (..._),
|
|
80
|
+
inferred: lazy => require('@cap-js/sqlite/lib/ql/cds.infer'), // eslint-disable-line cds/no-missing-dependencies
|
|
81
|
+
cqn2sql: lazy => require('@cap-js/sqlite/lib/db/sql/cqn2sql'), // eslint-disable-line cds/no-missing-dependencies
|
|
82
|
+
cqn4sql: lazy => require('@cap-js/sqlite/lib/db/sql/cqn4sql'), // eslint-disable-line cds/no-missing-dependencies
|
|
80
83
|
/** @type Service */ db: undefined,
|
|
81
84
|
|
|
82
85
|
// Protocols and Periphery
|
package/lib/log/cds-log.js
CHANGED
|
@@ -65,9 +65,12 @@ function cds_log (module, options) { // NOSONAR
|
|
|
65
65
|
* Shortcut to `cds.log(...).debug`, returning undefined if `cds.log(...)._debug` is false.
|
|
66
66
|
* @param {string} [module] the module for which a logger is requested
|
|
67
67
|
*/
|
|
68
|
-
exports.debug = function cds_debug (
|
|
69
|
-
const L =
|
|
70
|
-
if (L._debug) return L.debug
|
|
68
|
+
exports.debug = function cds_debug (id, options) {
|
|
69
|
+
const L = cds_log (id, options)
|
|
70
|
+
if (L._debug) return Object.assign(L.debug, {
|
|
71
|
+
time: label => console.time (`[${id}] - ${label}`),
|
|
72
|
+
timeEnd: label => console.timeEnd (`[${id}] - ${label}`),
|
|
73
|
+
})
|
|
71
74
|
}
|
|
72
75
|
|
|
73
76
|
|
|
@@ -87,7 +90,7 @@ exports.Logger = (label, level) => {
|
|
|
87
90
|
const fmt = (level,args) => logger.format (label,level,...args)
|
|
88
91
|
const logger = {
|
|
89
92
|
format: exports.format, // use logger.format as this could be changed dynamically
|
|
90
|
-
trace: level <
|
|
93
|
+
trace: level < DEBUG ? ()=>{} : (...args) => console.trace (...fmt(TRACE,args)),
|
|
91
94
|
debug: level < DEBUG ? ()=>{} : (...args) => console.debug (...fmt(DEBUG,args)),
|
|
92
95
|
log: level < INFO ? ()=>{} : (...args) => console.log (...fmt(INFO,args)),
|
|
93
96
|
info: level < INFO ? ()=>{} : (...args) => console.info (...fmt(INFO,args)),
|
package/lib/ql/CREATE.js
CHANGED
|
@@ -10,7 +10,7 @@ module.exports = class Query extends require('./Query') {
|
|
|
10
10
|
if (elements)
|
|
11
11
|
this.CREATE.entity = { elements: elements, kind: 'entity', name:e }
|
|
12
12
|
else
|
|
13
|
-
this.CREATE.entity = e && e.elements ? e : this.
|
|
13
|
+
this.CREATE.entity = e && e.elements ? e : this._target4(e)
|
|
14
14
|
return this
|
|
15
15
|
}
|
|
16
16
|
|
package/lib/ql/DELETE.js
CHANGED
|
@@ -9,7 +9,7 @@ module.exports = class Query extends Whereable {
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
from(entity, key) {
|
|
12
|
-
this.DELETE.from = this.
|
|
12
|
+
this.DELETE.from = this._target4 (...arguments) // supporting tts
|
|
13
13
|
if (key) this.byKey(key)
|
|
14
14
|
return this
|
|
15
15
|
}
|
package/lib/ql/DROP.js
CHANGED
|
@@ -7,17 +7,17 @@ module.exports = class Query extends require('./Query') {
|
|
|
7
7
|
})
|
|
8
8
|
}
|
|
9
9
|
entity(e) {
|
|
10
|
-
this.DROP.entity = this.
|
|
10
|
+
this.DROP.entity = this._target4 (e)
|
|
11
11
|
return this
|
|
12
12
|
}
|
|
13
13
|
table(e) {
|
|
14
14
|
const {DROP} = this
|
|
15
|
-
DROP.entity = DROP.table = this.
|
|
15
|
+
DROP.entity = DROP.table = this._target4 (e)
|
|
16
16
|
return this
|
|
17
17
|
}
|
|
18
18
|
view(e) {
|
|
19
19
|
const {DROP} = this
|
|
20
|
-
DROP.entity = DROP.view = this.
|
|
20
|
+
DROP.entity = DROP.view = this._target4 (e)
|
|
21
21
|
return this
|
|
22
22
|
}
|
|
23
23
|
}
|
package/lib/ql/INSERT.js
CHANGED
|
@@ -7,7 +7,7 @@ module.exports = class Query extends require('./Query') {
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
into (entity, ...data) {
|
|
10
|
-
this[this.cmd].into = this.
|
|
10
|
+
this[this.cmd].into = this._target4 (...arguments) // supporting tts
|
|
11
11
|
if (data.length) this.entries(...data)
|
|
12
12
|
return this
|
|
13
13
|
}
|
package/lib/ql/Query.js
CHANGED
|
@@ -52,12 +52,6 @@ class Query {
|
|
|
52
52
|
|| this._expected `${{target}} to be an entity path string, a CSN definition, a {ref}, a {SELECT}, or a {SET}`
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
//> REVISIT: should we rather have consistent .from/.entity/.into in CQN?
|
|
56
|
-
_target_name4 (...args) {
|
|
57
|
-
const {ref, as} = this._target_ref4 (...args)
|
|
58
|
-
return ref.length === 1 && typeof ref[0] === 'string' && !as ? ref[0] : as ? {ref, as} : {ref}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
55
|
_expected (...args) {
|
|
62
56
|
return cds.error.expected (...args)
|
|
63
57
|
}
|
|
@@ -72,8 +66,15 @@ class Query {
|
|
|
72
66
|
return `${cmd} ${_name(this._target.name)} `
|
|
73
67
|
}
|
|
74
68
|
|
|
69
|
+
forSQL (db = cds.db || cds) { return _flat(db.cqn4sql(this)) }
|
|
70
|
+
toSQL (db = cds.db || cds) { return _2sql(db.cqn2sql(this)) }
|
|
71
|
+
toSql (db = cds.db || cds) { return this.toSQL(db).sql }
|
|
72
|
+
|
|
75
73
|
}
|
|
76
74
|
|
|
75
|
+
// skip .cqn property when in repl
|
|
76
|
+
const _2sql = cds.repl ? ({sql,values}) => ({sql,values}) : (x => x)
|
|
77
|
+
const _flat = Query.prototype.flat
|
|
77
78
|
|
|
78
79
|
const _target4 = (target, arg2) => target && (
|
|
79
80
|
typeof target === 'string' ? { name: target } :
|
|
@@ -85,5 +86,12 @@ const _target4 = (target, arg2) => target && (
|
|
|
85
86
|
|
|
86
87
|
const _name = cds.env.sql.names === 'quoted' ? n =>`"${n}"` : n => n.replace(/[.:]/g,'_')
|
|
87
88
|
|
|
89
|
+
Object.defineProperty (Query.prototype, '_target4', { value: (
|
|
90
|
+
cds.env.ql.quirks_mode === false ? Query.prototype._target_ref4
|
|
91
|
+
: function (...args) {
|
|
92
|
+
const {ref, as} = this._target_ref4 (...args)
|
|
93
|
+
return ref.length === 1 && typeof ref[0] === 'string' && !as ? ref[0] : as ? {ref, as} : {ref}
|
|
94
|
+
}
|
|
95
|
+
)})
|
|
88
96
|
|
|
89
97
|
module.exports = Query
|
package/lib/ql/SELECT.js
CHANGED
|
@@ -104,8 +104,14 @@ module.exports = class Query extends Whereable {
|
|
|
104
104
|
return this._where (args,'and','on')
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
-
having(...
|
|
108
|
-
return this._where (
|
|
107
|
+
having(...args) {
|
|
108
|
+
return this._where (args,'and','having')
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
search (...args) {
|
|
112
|
+
let _xpr=[]; for (let val of args) _xpr.push('or',{val})
|
|
113
|
+
this.SELECT.search = _xpr.slice(1)
|
|
114
|
+
return this
|
|
109
115
|
}
|
|
110
116
|
|
|
111
117
|
groupBy (...args) {
|
package/lib/ql/UPDATE.js
CHANGED
|
@@ -10,7 +10,7 @@ module.exports = class Query extends Whereable {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
entity (e, key) {
|
|
13
|
-
this.UPDATE.entity = this.
|
|
13
|
+
this.UPDATE.entity = this._target4 (...arguments) // supporting tts
|
|
14
14
|
if (key) this.byKey(key)
|
|
15
15
|
return this
|
|
16
16
|
}
|
package/lib/ql/Whereable.js
CHANGED
|
@@ -18,7 +18,7 @@ class Query extends require('./Query') {
|
|
|
18
18
|
error (`Invalid attempt to call '${this.cmd}.${and_or}()' before a prior call to '${this.cmd}.where()'`)
|
|
19
19
|
)
|
|
20
20
|
if (clause === 'on') _ = _.from
|
|
21
|
-
let left =
|
|
21
|
+
let left = _[clause]
|
|
22
22
|
if (!left) { //> .where() called first time
|
|
23
23
|
// SELECT.from `X` .where `x or y` .and `z` -> SELECT from X where (x or y) and z
|
|
24
24
|
if (pred.includes('or')) this._left_has_or = true
|
package/lib/ql/cds-ql.js
CHANGED
|
@@ -9,7 +9,7 @@ require = path => { // eslint-disable-line no-global-assign
|
|
|
9
9
|
}, api)
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
module.exports =
|
|
12
|
+
module.exports = {
|
|
13
13
|
Query, clone: (q,_) => Query.prototype.clone.call(q,_),
|
|
14
14
|
SELECT: require('./SELECT'),
|
|
15
15
|
INSERT: require('./INSERT'),
|
|
@@ -18,14 +18,6 @@ module.exports = Object.assign (_deprecated_srv_ql, { cdr: true,
|
|
|
18
18
|
DELETE: require('./DELETE'),
|
|
19
19
|
CREATE: require('./CREATE'),
|
|
20
20
|
DROP: require('./DROP'),
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
function _deprecated_srv_ql() { // eslint-disable-next-line no-console
|
|
24
|
-
console.trace(`
|
|
25
|
-
Method 'srv.ql(req)' is deprecated and superceded by 'cds.context'.
|
|
26
|
-
Please use global SELECT instead of 'const { SELECT } = srv.ql(req)'.
|
|
27
|
-
`)
|
|
28
|
-
return module.exports
|
|
29
21
|
}
|
|
30
22
|
|
|
31
23
|
module.exports._reset = ()=>{ // for strange tests only
|
package/lib/req/cds-context.js
CHANGED
|
@@ -15,12 +15,9 @@ module.exports = new class extends AsyncLocalStorage {
|
|
|
15
15
|
|
|
16
16
|
/** @returns {EventContext} */
|
|
17
17
|
_for (cds,v) {
|
|
18
|
-
Reflect.defineProperty (cds,'context', { enumerable:1, ...
|
|
18
|
+
Reflect.defineProperty (cds,'context', { enumerable:1, ... {
|
|
19
19
|
set:(v) => this.enterWith(v),
|
|
20
20
|
get:()=> this.getStore(),
|
|
21
|
-
} : {
|
|
22
|
-
get:()=> undefined,
|
|
23
|
-
set:()=> {},
|
|
24
21
|
}})
|
|
25
22
|
return cds.context = v // IMPORTANT: we need to set it initially, to get it all wired up correctly
|
|
26
23
|
}
|
package/lib/req/request.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const { Responses, Errors } = require('./response')
|
|
2
|
+
const cds = require('../../lib')
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Class Request represents requests received via synchronous protocols.
|
|
@@ -56,6 +57,67 @@ class Request extends require('./event') {
|
|
|
56
57
|
return this._set ('data', {})
|
|
57
58
|
}
|
|
58
59
|
|
|
60
|
+
set subject(d) { if (d) super.subject = d }
|
|
61
|
+
get subject() {
|
|
62
|
+
const q = this.query
|
|
63
|
+
let subject = (
|
|
64
|
+
q?.SELECT?.from ||
|
|
65
|
+
q?.INSERT?.into ||
|
|
66
|
+
q?.UPSERT?.into ||
|
|
67
|
+
q?.UPDATE?.entity ||
|
|
68
|
+
q?.DELETE?.from
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
const {target} = this; if (!target) return undefined
|
|
72
|
+
|
|
73
|
+
// programmatic action calls as of now only in format /Books(201)/action
|
|
74
|
+
if (!subject) {
|
|
75
|
+
let where = []
|
|
76
|
+
for (const param of this.params) {
|
|
77
|
+
if (typeof param === 'object') {
|
|
78
|
+
for (const key in param) {
|
|
79
|
+
if (key in target.keys) {
|
|
80
|
+
if (where.length > 1) where.push('and')
|
|
81
|
+
where.push({ ref: [key] }, '=', { val: param[key] })
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
} else {
|
|
85
|
+
where.push({ ref: [Object.keys(target.keys)[0]] }, '=', { val: param })
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
subject = { id: target.name, where }
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const ref = subject.ref || [ subject ]
|
|
92
|
+
|
|
93
|
+
if(!target.drafts || cds.env.fiori.lean_draft) return super.subject = { ref }
|
|
94
|
+
|
|
95
|
+
// special handling for old draft logic
|
|
96
|
+
let subjectRef = []
|
|
97
|
+
ref.forEach ((item, i) => {
|
|
98
|
+
// to one assoc & comp
|
|
99
|
+
if (typeof item === 'string') {
|
|
100
|
+
subjectRef.push(item)
|
|
101
|
+
return
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// create key value pair without IsActiveEntity & adjust root target
|
|
105
|
+
const keys = {}
|
|
106
|
+
let id = item.id
|
|
107
|
+
for (let j = 0; j < item?.where?.length; j = j + 4) {
|
|
108
|
+
const key = item.where[j].ref[0]
|
|
109
|
+
const value = item.where[j + 2].val
|
|
110
|
+
if (key !== 'IsActiveEntity') keys[key] = value
|
|
111
|
+
else if (i === 0 && key === 'IsActiveEntity' && value === false) id = item.id + '_drafts'
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// create copy
|
|
115
|
+
const {SELECT:{from:{ref}}} = SELECT.from(id,keys)
|
|
116
|
+
subjectRef.push(...ref)
|
|
117
|
+
})
|
|
118
|
+
return super.subject = {ref: subjectRef}
|
|
119
|
+
}
|
|
120
|
+
|
|
59
121
|
reply (results) { return this.results = results }
|
|
60
122
|
notify (...args) { return this._messages.add (1, ...args) }
|
|
61
123
|
info (...args) { return this._messages.add (2, ...args) }
|
|
@@ -116,8 +178,7 @@ const SQL2Crud = {
|
|
|
116
178
|
}
|
|
117
179
|
|
|
118
180
|
const Query2Crud = (q) => {
|
|
119
|
-
|
|
120
|
-
else for (let each in q) if (each in SQL2Crud) return SQL2Crud[each]
|
|
181
|
+
for (let each in q) if (each in SQL2Crud) return SQL2Crud[each]
|
|
121
182
|
}
|
|
122
183
|
|
|
123
184
|
const _path4 = (x,p) => {
|
package/lib/req/response.js
CHANGED
|
@@ -4,8 +4,9 @@ const cds = require ('../index')
|
|
|
4
4
|
* Messages Collector, used for `req.errors` and `req.messages`
|
|
5
5
|
*/
|
|
6
6
|
class Responses extends Array {
|
|
7
|
-
static get (severity, code, message, target, args) {
|
|
8
|
-
|
|
7
|
+
static get (severity, code, message, target, args, ...more) {
|
|
8
|
+
if (code?.raw) [ message, code ] = [ String.raw (code, message, target, args, ...more) ]
|
|
9
|
+
let e // be filled in below...
|
|
9
10
|
if (typeof code === 'object') e = code; else {
|
|
10
11
|
if (typeof code === 'number') e = { code }; else [ code, message, target, args, e ] = [ undefined, code, message, target, {} ]
|
|
11
12
|
if (typeof message === 'object') e = Object.assign(message,e); else {
|