@sap/cds 5.6.4 → 5.7.1
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 +102 -0
- package/_i18n/i18n_fr.properties +4 -4
- package/apis/cds.d.ts +7 -10
- package/apis/connect.d.ts +3 -3
- package/apis/core.d.ts +2 -4
- package/apis/models.d.ts +2 -3
- package/apis/ql.d.ts +0 -1
- package/apis/services.d.ts +3 -3
- package/bin/build/buildTaskFactory.js +16 -10
- package/bin/build/buildTaskProviderFactory.js +3 -3
- package/bin/build/constants.js +2 -1
- package/bin/build/provider/buildTaskProviderInternal.js +14 -14
- package/bin/build/provider/hana/2migration.js +2 -3
- package/bin/build/provider/hana/index.js +34 -0
- package/bin/build/provider/hana/migrationtable.js +90 -22
- package/bin/build/provider/hana/template/undeploy.json +5 -0
- package/bin/build/provider/node-cf/index.js +9 -2
- package/bin/serve.js +16 -18
- package/lib/compile/cdsc.js +15 -5
- package/lib/compile/etc/_localized.js +4 -4
- package/lib/compile/extend.js +8 -0
- package/lib/compile/index.js +3 -1
- package/lib/compile/minify.js +61 -0
- package/lib/compile/resolve.js +4 -1
- package/lib/compile/to/gql.js +9 -0
- package/lib/compile/to/sql.js +26 -30
- package/lib/connect/index.js +1 -1
- package/lib/core/entities.js +0 -3
- package/lib/core/infer.js +1 -0
- package/lib/core/reflect.js +0 -34
- package/lib/deploy.js +25 -17
- package/lib/env/defaults.js +3 -1
- package/lib/env/index.js +8 -3
- package/lib/env/presets.js +38 -0
- package/lib/env/requires.js +16 -11
- package/lib/index.js +13 -11
- package/lib/log/format/kibana.js +3 -1
- package/lib/log/index.js +2 -2
- package/lib/req/cds-context.js +79 -0
- package/lib/req/context.js +5 -77
- package/lib/req/request.js +1 -1
- package/lib/serve/Service-api.js +8 -4
- package/lib/serve/Service-dispatch.js +0 -7
- package/lib/serve/Service-methods.js +6 -8
- package/lib/serve/Transaction.js +35 -30
- package/lib/serve/adapters.js +1 -4
- package/lib/utils/axios.js +1 -1
- package/libx/_runtime/audit/Service.js +44 -20
- package/libx/_runtime/audit/generic/personal/access.js +16 -11
- package/libx/_runtime/audit/generic/personal/modification.js +5 -5
- package/libx/_runtime/audit/generic/personal/utils.js +46 -37
- package/libx/_runtime/{common/auth → auth}/index.js +21 -7
- package/libx/_runtime/{common/auth → auth}/strategies/JWT.js +2 -2
- package/libx/_runtime/{common/auth → auth}/strategies/basic.js +2 -2
- package/libx/_runtime/{common/auth → auth}/strategies/dummy.js +1 -1
- package/libx/_runtime/{common/auth → auth}/strategies/mock.js +2 -2
- package/libx/_runtime/{common/auth → auth}/strategies/utils/uaa.js +1 -1
- package/libx/_runtime/{common/auth → auth}/strategies/utils/xssec.js +0 -0
- package/libx/_runtime/{common/auth → auth}/strategies/xsuaa.js +2 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/Dispatcher.js +7 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/OData.js +0 -7
- package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +0 -8
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/action.js +3 -4
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/create.js +6 -7
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/delete.js +3 -4
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/error.js +2 -11
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +16 -6
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +26 -65
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +0 -7
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +3 -66
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +24 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/utils.js +2 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/UriParser.js +13 -10
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/invocation/ConditionalRequestControlCommand.js +0 -7
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/validator/ConditionalRequestValidator.js +0 -8
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/stream.js +54 -76
- package/libx/_runtime/cds-services/adapter/rest/RestRequest.js +0 -7
- package/libx/_runtime/cds-services/adapter/rest/handlers/create.js +3 -6
- package/libx/_runtime/cds-services/adapter/rest/handlers/delete.js +3 -6
- package/libx/_runtime/cds-services/adapter/rest/handlers/operation.js +3 -6
- package/libx/_runtime/cds-services/adapter/rest/handlers/read.js +3 -6
- package/libx/_runtime/cds-services/adapter/rest/handlers/update.js +3 -6
- package/libx/_runtime/cds-services/adapter/rest/utils/parse-url.js +8 -4
- package/libx/_runtime/cds-services/services/Service.js +0 -6
- package/libx/_runtime/cds-services/services/utils/columns.js +10 -3
- package/libx/_runtime/cds-services/services/utils/compareJson.js +3 -6
- package/libx/_runtime/cds-services/services/utils/differ.js +4 -1
- package/libx/_runtime/cds-services/services/utils/handlerUtils.js +1 -41
- package/libx/_runtime/cds-services/util/assert.js +1 -262
- package/libx/_runtime/cds.js +6 -9
- package/libx/_runtime/common/aspects/entity.js +1 -1
- package/libx/_runtime/common/composition/delete.js +4 -2
- package/libx/_runtime/common/composition/update.js +22 -38
- package/libx/_runtime/common/composition/utils.js +3 -7
- package/libx/_runtime/common/error/standardError.js +11 -0
- package/libx/_runtime/common/generic/auth.js +61 -30
- package/libx/_runtime/common/generic/crud.js +11 -23
- package/libx/_runtime/common/generic/input.js +20 -0
- package/libx/_runtime/common/generic/put.js +4 -10
- package/libx/_runtime/common/generic/sorting.js +12 -30
- package/libx/_runtime/common/perf/index.js +24 -0
- package/libx/_runtime/common/utils/cqn.js +58 -1
- package/libx/_runtime/common/utils/cqn2cqn4sql.js +289 -114
- package/libx/_runtime/common/utils/csn.js +38 -56
- package/libx/_runtime/common/utils/entityFromCqn.js +6 -6
- package/libx/_runtime/common/utils/resolveView.js +4 -5
- package/libx/_runtime/common/utils/rewriteAsterisks.js +46 -5
- package/libx/_runtime/common/utils/search2cqn4sql.js +21 -9
- package/libx/_runtime/common/utils/structured.js +35 -25
- package/libx/_runtime/db/Service.js +0 -6
- package/libx/_runtime/db/expand/expand-v2.js +130 -0
- package/libx/_runtime/db/expand/expandCQNToJoin.js +38 -52
- package/libx/_runtime/db/expand/index.js +3 -1
- package/libx/_runtime/db/generic/input.js +52 -10
- package/libx/_runtime/db/generic/integrity.js +367 -26
- package/libx/_runtime/db/generic/virtual.js +51 -13
- package/libx/_runtime/db/query/update.js +9 -3
- package/libx/_runtime/db/sql-builder/ExpressionBuilder.js +8 -9
- package/libx/_runtime/{common → db}/utils/propagateForeignKeys.js +11 -14
- package/libx/_runtime/fiori/generic/activate.js +1 -0
- package/libx/_runtime/fiori/generic/before.js +2 -1
- package/libx/_runtime/fiori/generic/edit.js +1 -0
- package/libx/_runtime/fiori/generic/patch.js +1 -1
- package/libx/_runtime/fiori/generic/read.js +123 -57
- package/libx/_runtime/fiori/uiflex/index.js +1 -1
- package/libx/_runtime/fiori/uiflex/{extensibility/index.js → service.js} +3 -3
- package/libx/_runtime/fiori/utils/delete.js +7 -1
- package/libx/_runtime/hana/Service.js +1 -8
- package/libx/_runtime/hana/customBuilder/CustomSelectBuilder.js +5 -14
- package/libx/_runtime/hana/execute.js +10 -4
- package/libx/_runtime/hana/pool.js +55 -45
- package/libx/_runtime/hana/search.js +7 -6
- package/libx/_runtime/hana/search2cqn4sql.js +8 -5
- package/libx/_runtime/hana/searchToContains.js +3 -1
- package/libx/_runtime/index.js +5 -5
- package/libx/_runtime/messaging/AMQPWebhookMessaging.js +3 -3
- package/libx/_runtime/messaging/Outbox.js +53 -0
- package/libx/_runtime/messaging/common-utils/AMQPClient.js +17 -10
- package/libx/_runtime/messaging/common-utils/connections.js +14 -9
- package/libx/_runtime/messaging/common-utils/waitingTime.js +2 -0
- package/libx/_runtime/messaging/enterprise-messaging-shared.js +2 -3
- package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +2 -2
- package/libx/_runtime/messaging/enterprise-messaging.js +21 -15
- package/libx/_runtime/messaging/file-based.js +5 -5
- package/libx/_runtime/messaging/message-queuing.js +2 -3
- package/libx/_runtime/messaging/outbox/OutboxRunner.js +75 -0
- package/libx/_runtime/messaging/outbox/utils.js +192 -0
- package/libx/_runtime/messaging/service.js +16 -30
- package/libx/_runtime/remote/Service.js +15 -0
- package/libx/_runtime/remote/utils/client.js +15 -3
- package/libx/_runtime/remote/utils/{dataConversion.js → data.js} +12 -2
- package/libx/_runtime/sqlite/Service.js +7 -10
- package/libx/_runtime/sqlite/customBuilder/CustomExpressionBuilder.js +19 -0
- package/libx/_runtime/sqlite/execute.js +18 -12
- package/libx/_runtime/types/api.js +2 -1
- package/libx/odata/{odata2cqn/afterburner.js → afterburner.js} +19 -15
- package/libx/odata/{cqn2odata/index.js → cqn2odata.js} +1 -1
- package/libx/odata/{odata2cqn/grammar.pegjs → grammar.pegjs} +171 -130
- package/libx/odata/index.js +16 -14
- package/libx/odata/parser.js +1 -0
- package/libx/odata/utils.js +57 -0
- package/libx/rest/RestAdapter.js +2 -6
- package/libx/rest/utils/data.js +1 -6
- package/package.json +4 -3
- package/server.js +4 -5
- package/srv/audit-log.cds +87 -0
- package/{libx/_runtime/fiori/uiflex/extensibility/index.cds → srv/flex.cds} +0 -0
- package/srv/flex.js +1 -0
- package/srv/outbox.cds +11 -0
- package/srv/outbox.js +0 -0
- package/libx/_runtime/cds-services/adapter/perf/performance.js +0 -104
- package/libx/_runtime/cds-services/adapter/perf/performanceMeasurement.js +0 -33
- package/libx/odata/odata2cqn/index.js +0 -3
- package/libx/odata/odata2cqn/parser.js +0 -1
- package/libx/odata/readme.md +0 -1
- package/libx/odata/utils/index.js +0 -64
package/lib/core/reflect.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
const { types, classes:{ service, entity, action, event, any, struct, array, context, annotation } } = require('.')
|
|
2
2
|
const _kinds = { annotation, context, service, action, event, entity, view:entity }
|
|
3
|
-
const _minified = Symbol('minified')
|
|
4
3
|
|
|
5
4
|
class LinkedCSN extends any {
|
|
6
5
|
|
|
@@ -48,38 +47,6 @@ class LinkedCSN extends any {
|
|
|
48
47
|
return Object.setPrototypeOf (x, new.target.prototype)
|
|
49
48
|
}
|
|
50
49
|
|
|
51
|
-
minified (skip = global.cds.env.features.skip_unused) {
|
|
52
|
-
if (!skip) return this
|
|
53
|
-
if (this[_minified]) return this; else _set (this,_minified,true)
|
|
54
|
-
const csn = this, all = csn.definitions, reached = new Set
|
|
55
|
-
const roots = skip === 'all' ? this.services : this.each(_root)
|
|
56
|
-
for (let each of roots) _visit (each)
|
|
57
|
-
function _visit (d) {
|
|
58
|
-
if (reached.has(d)) return; else reached.add(d)
|
|
59
|
-
if (d.kind === 'service') for (let e of csn.childrenOf(d)) _visit(e)
|
|
60
|
-
if (d.includes) d.includes.forEach(i => _visit(all[i])) // Note: with delete d.includes, redirects in AFC broke
|
|
61
|
-
if (d.query) d.query._target && _visit (d.query._target)
|
|
62
|
-
if (d.type) _builtin(d.type) || _visit (d.__proto__)
|
|
63
|
-
if (d.target) _visit (d._target) ; else if (d.targetAspect) _visit (typeof d.targetAspect === 'object' ? d.targetAspect : all[d.targetAspect])
|
|
64
|
-
if (d.returns) _visit (d.returns)
|
|
65
|
-
if (d.items) _visit (d.items)
|
|
66
|
-
if (d.parent) _visit (d.parent)
|
|
67
|
-
for (let e in d.elements) _visit (d.elements[e])
|
|
68
|
-
for (let a in d.actions) _visit (d.actions[a])
|
|
69
|
-
for (let p in d.params) _visit (d.params[p])
|
|
70
|
-
}
|
|
71
|
-
for (let n in all) {
|
|
72
|
-
if (n.endsWith('.texts') && reached.has(all[n.slice(0,-6)])) continue
|
|
73
|
-
if (reached.has(all[n])) continue
|
|
74
|
-
else {
|
|
75
|
-
delete all[n]
|
|
76
|
-
// also delete the legacy _texts proxy (not enumerable, installed by _localized.unfold_csn)
|
|
77
|
-
if (n.endsWith('.texts')) delete all[n.replace('.texts','_texts')]
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
return this
|
|
81
|
-
}
|
|
82
|
-
|
|
83
50
|
*each (x, defs=this.definitions) {
|
|
84
51
|
const pick=_is(x); for (let d in defs) if (pick(defs[d])) yield defs[d]
|
|
85
52
|
}
|
|
@@ -131,7 +98,6 @@ class LinkedCSN extends any {
|
|
|
131
98
|
const _unresolved = (x,unknown=any) => ({name:x, __proto__:unknown.prototype, _unresolved:true})
|
|
132
99
|
const _builtin = x => types[x] || typeof x === 'string' && x.startsWith('cds.hana.') && any.prototype
|
|
133
100
|
const _infer = require('./infer'), _not_inferred = _unresolved('<query>',entity)
|
|
134
|
-
const _root = d => d instanceof service || d instanceof entity && !d.name.endsWith('.texts') && d['@cds.persistence.skip'] !== 'if-unused'
|
|
135
101
|
const _set = (o,p,v) => Object.defineProperty (o,p,{value:v,enumerable:false,configurable:1,writable:1})
|
|
136
102
|
const _own = (o,p) => { const pd = Reflect.getOwnPropertyDescriptor(o,p); return pd && pd.value }
|
|
137
103
|
const _is = x => {
|
package/lib/deploy.js
CHANGED
|
@@ -14,7 +14,16 @@ exports = module.exports = function cds_deploy (model,options) { return {
|
|
|
14
14
|
async to (db, o=options||{}) { // NOSONAR
|
|
15
15
|
LOG = cds.log('deploy')
|
|
16
16
|
|
|
17
|
-
if (model && !model.definitions)
|
|
17
|
+
if (model && !model.definitions) {
|
|
18
|
+
model = await cds.load (model) .then (cds.minify)
|
|
19
|
+
if (DEBUG) try {
|
|
20
|
+
DEBUG (`model loaded from ${model.$sources.length} file(s):\n\x1b[2m`)
|
|
21
|
+
for (let each of model.$sources) console.log (' ', local(each))
|
|
22
|
+
} finally {
|
|
23
|
+
console.log ('\x1b[0m')
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
18
27
|
if (o.mocked) exports.include_external_entities_in (model)
|
|
19
28
|
else exports.exclude_external_entities_in (model)
|
|
20
29
|
|
|
@@ -120,37 +129,36 @@ function init_from_csv (db, csn, SILENT) {
|
|
|
120
129
|
|
|
121
130
|
function _csvs (filename,_,allFiles) {
|
|
122
131
|
if (filename[0] === '-' || !filename.endsWith ('.csv')) return false
|
|
123
|
-
if (
|
|
124
|
-
return false
|
|
125
|
-
}
|
|
132
|
+
if (prefer_translated_texts(filename, allFiles)) return false
|
|
126
133
|
return true
|
|
127
134
|
}
|
|
128
135
|
}
|
|
129
136
|
|
|
130
137
|
function init_from_json (db, csn, SILENT) {
|
|
131
138
|
return init_from_ (['data'], _jsons, db, csn, SILENT, (entity, src) => {
|
|
132
|
-
|
|
133
|
-
|
|
139
|
+
let json = JSON.parse (src)
|
|
140
|
+
return json[0] && INSERT.into (entity) .entries (json)
|
|
134
141
|
});
|
|
135
142
|
|
|
136
143
|
function _jsons (filename,_,allFiles) {
|
|
137
144
|
if (filename[0] === '-' || !filename.endsWith ('.json')) return false
|
|
138
|
-
if (
|
|
139
|
-
return false
|
|
140
|
-
}
|
|
145
|
+
if (prefer_translated_texts(filename, allFiles)) return false
|
|
141
146
|
return true
|
|
142
147
|
}
|
|
143
148
|
}
|
|
144
149
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
if (
|
|
150
|
-
|
|
151
|
-
|
|
150
|
+
/**
|
|
151
|
+
* ignores 'Books_texts.csv/json' if there is any 'Books_texts_LANG.csv/json'
|
|
152
|
+
*/
|
|
153
|
+
function prefer_translated_texts (file, all) {
|
|
154
|
+
if (/[._]texts\.(json|csv)$/.test (file)) {
|
|
155
|
+
const pattern = new RegExp('^'+ path.basename(file) +'_')
|
|
156
|
+
const translated = all.filter (f => pattern.test(f))
|
|
157
|
+
if (translated.length > 0) {
|
|
158
|
+
DEBUG && DEBUG (`ignoring '${file}' in favor of [${translated}]`) // eslint-disable-line
|
|
159
|
+
return true
|
|
160
|
+
}
|
|
152
161
|
}
|
|
153
|
-
return false
|
|
154
162
|
}
|
|
155
163
|
|
|
156
164
|
async function init_from_ (locations, filter, db, csn, SILENT, INSERT_into) { // NOSONAR
|
package/lib/env/defaults.js
CHANGED
|
@@ -13,12 +13,14 @@ module.exports = {
|
|
|
13
13
|
in_memory_db: !production,
|
|
14
14
|
test_data: !production,
|
|
15
15
|
test_mocks: !production,
|
|
16
|
+
with_mocks: !production,
|
|
16
17
|
mocked_bindings: !production,
|
|
17
18
|
// skip_unused: 'all',
|
|
18
19
|
skip_unused: true,
|
|
19
20
|
one_model: true,
|
|
20
21
|
localized: true,
|
|
21
|
-
|
|
22
|
+
assert_integrity: true,
|
|
23
|
+
assert_integrity_type: 'RT',
|
|
22
24
|
cds_tx_protection: true,
|
|
23
25
|
cds_tx_inheritance: true,
|
|
24
26
|
},
|
package/lib/env/index.js
CHANGED
|
@@ -2,6 +2,7 @@ const { isfile, fs } = require('../utils')
|
|
|
2
2
|
const DEFAULTS = require('./defaults'), defaults = require.resolve ('./defaults')
|
|
3
3
|
const os_user_home = require('os').homedir()
|
|
4
4
|
const compat = require('./compat')
|
|
5
|
+
const presets = require('./presets')
|
|
5
6
|
const path = require('path')
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -73,6 +74,9 @@ class Config {
|
|
|
73
74
|
else if (this.requires.db.multiTenant !== undefined) this.requires.multitenancy = this.requires.db.multiTenant
|
|
74
75
|
}
|
|
75
76
|
|
|
77
|
+
// 9. apply presets
|
|
78
|
+
presets (this)
|
|
79
|
+
|
|
76
80
|
// Only if feature is enabled
|
|
77
81
|
this._emulate_vcap_services()
|
|
78
82
|
}
|
|
@@ -214,14 +218,15 @@ _loadFromPath (_path, _basePath) {
|
|
|
214
218
|
_add_process_env (prefix, basePath) {
|
|
215
219
|
const {env} = process
|
|
216
220
|
const PREF = prefix.toUpperCase(), my = { CONFIG: PREF+'_CONFIG', ENV: PREF+'_ENV' }
|
|
217
|
-
const configEnvValue = env[my.CONFIG]
|
|
218
221
|
let config
|
|
219
|
-
|
|
222
|
+
|
|
223
|
+
const configEnvValue = env[my.CONFIG]
|
|
224
|
+
if (configEnvValue) try {
|
|
220
225
|
// CDS_CONFIG={ /* json */}
|
|
221
226
|
config = JSON.parse (configEnvValue)
|
|
222
227
|
} catch (e) {
|
|
223
228
|
// CDS_CONFIG=/path/to/config.json *OR* CDS_CONFIG=/path/to/config/dir
|
|
224
|
-
if (
|
|
229
|
+
if (typeof configEnvValue === "string") this._loadFromPath (configEnvValue, basePath)
|
|
225
230
|
}
|
|
226
231
|
|
|
227
232
|
if (!config) config = {}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
module.exports = function (conf) {
|
|
2
|
+
const { features } = conf
|
|
3
|
+
if (!features) return
|
|
4
|
+
|
|
5
|
+
// integrity checks
|
|
6
|
+
if (typeof features.assert_integrity === 'string') {
|
|
7
|
+
switch (features.assert_integrity) {
|
|
8
|
+
case 'individual':
|
|
9
|
+
// > keep as is
|
|
10
|
+
break
|
|
11
|
+
case 'off':
|
|
12
|
+
features.assert_integrity = false
|
|
13
|
+
break
|
|
14
|
+
case 'app':
|
|
15
|
+
features.assert_integrity = true
|
|
16
|
+
features.assert_integrity_type = 'RT'
|
|
17
|
+
break
|
|
18
|
+
case 'db':
|
|
19
|
+
features.assert_integrity = true
|
|
20
|
+
features.assert_integrity_type = 'DB'
|
|
21
|
+
break
|
|
22
|
+
// *-opt-in options not officially documented!
|
|
23
|
+
case 'app-opt-in':
|
|
24
|
+
features.assert_integrity = 'individual'
|
|
25
|
+
features.assert_integrity_type = 'RT'
|
|
26
|
+
break
|
|
27
|
+
case 'db-opt-in':
|
|
28
|
+
features.assert_integrity = 'individual'
|
|
29
|
+
features.assert_integrity_type = 'DB'
|
|
30
|
+
break
|
|
31
|
+
default:
|
|
32
|
+
// > invalid -> set to default
|
|
33
|
+
features.assert_integrity = true
|
|
34
|
+
features.assert_integrity_type = 'RT'
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
}
|
package/lib/env/requires.js
CHANGED
|
@@ -73,16 +73,16 @@ module.exports = {
|
|
|
73
73
|
local: true
|
|
74
74
|
},
|
|
75
75
|
"file-based-messaging": {
|
|
76
|
-
outbox:
|
|
76
|
+
outbox: {},
|
|
77
77
|
impl: `${_runtime}/messaging/file-based.js`,
|
|
78
78
|
credentials: { file:'~/.cds-msg-box' }
|
|
79
79
|
},
|
|
80
80
|
"default-messaging": {
|
|
81
|
-
"[development]": {
|
|
82
|
-
"[hybrid]": {
|
|
81
|
+
"[development]": { kind: "local-messaging" },
|
|
82
|
+
"[hybrid]": { kind: "enterprise-messaging-amqp" },
|
|
83
83
|
"[production]": {
|
|
84
|
-
|
|
85
|
-
"[multitenant]": {
|
|
84
|
+
kind: "enterprise-messaging-amqp",
|
|
85
|
+
"[multitenant]": { kind: "enterprise-messaging-http" }
|
|
86
86
|
}
|
|
87
87
|
},
|
|
88
88
|
"enterprise-messaging": {
|
|
@@ -92,17 +92,17 @@ module.exports = {
|
|
|
92
92
|
kind: "enterprise-messaging-amqp",
|
|
93
93
|
},
|
|
94
94
|
"enterprise-messaging-http": {
|
|
95
|
-
outbox:
|
|
95
|
+
outbox: {},
|
|
96
96
|
impl: `${_runtime}/messaging/enterprise-messaging.js`,
|
|
97
97
|
vcap: { label: "enterprise-messaging" },
|
|
98
98
|
},
|
|
99
99
|
"enterprise-messaging-amqp": {
|
|
100
|
-
outbox:
|
|
100
|
+
outbox: {},
|
|
101
101
|
impl: `${_runtime}/messaging/enterprise-messaging-shared.js`,
|
|
102
102
|
vcap: { label: "enterprise-messaging" },
|
|
103
103
|
},
|
|
104
104
|
'message-queuing': {
|
|
105
|
-
outbox:
|
|
105
|
+
outbox: {},
|
|
106
106
|
impl: `${_runtime}/messaging/message-queuing.js`
|
|
107
107
|
},
|
|
108
108
|
"composite-messaging": {
|
|
@@ -110,15 +110,20 @@ module.exports = {
|
|
|
110
110
|
},
|
|
111
111
|
"audit-log": {
|
|
112
112
|
impl: `${_runtime}/audit/Service.js`,
|
|
113
|
-
// REVISIT: how to load model?
|
|
113
|
+
// REVISIT: how to load model? -> see _prototypes below
|
|
114
114
|
// model: 'AuditLogService.cds',
|
|
115
|
-
outbox:
|
|
115
|
+
outbox: {},
|
|
116
116
|
vcap: { label: "auditlog" },
|
|
117
117
|
},
|
|
118
118
|
|
|
119
119
|
_prototypes: {
|
|
120
120
|
"uiflex": {
|
|
121
|
-
|
|
121
|
+
model: "@sap/cds/srv/flex"
|
|
122
|
+
},
|
|
123
|
+
"persistent-outbox": {
|
|
124
|
+
model: "@sap/cds/srv/outbox",
|
|
125
|
+
maxAttempts: 20,
|
|
126
|
+
chunkSize: 100
|
|
122
127
|
},
|
|
123
128
|
}
|
|
124
129
|
}
|
package/lib/index.js
CHANGED
|
@@ -3,19 +3,20 @@ if (global.cds) Object.assign(module,{exports:global.cds}) ; else {
|
|
|
3
3
|
|
|
4
4
|
const facade = class cds extends require('events') {
|
|
5
5
|
|
|
6
|
-
get
|
|
7
|
-
get env() { return super.env = require('./env') }
|
|
6
|
+
get env() { return super.env = require('./env') }
|
|
8
7
|
get requires() { return super.requires = this.env.required_services_or_defs }
|
|
9
|
-
get
|
|
10
|
-
get
|
|
8
|
+
get version() { return super.version = require('../package.json').version }
|
|
9
|
+
get builtin() { return super.builtin = require ('./core') }
|
|
10
|
+
get service() { return super.service = extend (this.builtin.classes.service) .with ({
|
|
11
11
|
/** @param x {(this:Service, srv:Service) => any} */ impl: x=>x,
|
|
12
12
|
/** @type Service[] */ providers: [],
|
|
13
13
|
factory: require ('./serve/factory'),
|
|
14
14
|
bindings: require ('./connect/bindings'),
|
|
15
15
|
})}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
/** @type {import './req/context'} */
|
|
17
|
+
get context() { return require('./req/cds-context').for(this) }
|
|
18
|
+
set context(_){ require('./req/cds-context').for(this,_) }
|
|
19
|
+
get spawn() { return super.spawn = require('./req/cds-context').spawn }
|
|
19
20
|
|
|
20
21
|
emit (eve, ...args) {
|
|
21
22
|
if (eve === 'served') return Promise.all (this.listeners(eve).map (l => l.call(this,...args)))
|
|
@@ -46,11 +47,13 @@ if (global.cds) Object.assign(module,{exports:global.cds}) ; else {
|
|
|
46
47
|
|
|
47
48
|
// Loading and Compiling Models
|
|
48
49
|
model: undefined,
|
|
50
|
+
compiler: require ('./compile/cdsc'),
|
|
51
|
+
compile: require ('./compile'),
|
|
49
52
|
resolve: require ('./compile/resolve'),
|
|
50
53
|
load: require ('./compile/load'), get: lazy => cds.load.parsed,
|
|
51
54
|
parse: require ('./compile/parse'),
|
|
52
|
-
|
|
53
|
-
|
|
55
|
+
minify: require ('./compile/minify'),
|
|
56
|
+
extend: require ('./compile/extend'),
|
|
54
57
|
deploy: require ('./deploy'),
|
|
55
58
|
|
|
56
59
|
// Providing and Consuming Services
|
|
@@ -87,7 +90,7 @@ if (global.cds) Object.assign(module,{exports:global.cds}) ; else {
|
|
|
87
90
|
log: require ('./log'), debug: lazy => cds.log.debug,
|
|
88
91
|
exec: require ('../bin/cds'),
|
|
89
92
|
clone: m => JSON.parse (JSON.stringify(m)),
|
|
90
|
-
lazified, lazify,
|
|
93
|
+
lazified, lazify,
|
|
91
94
|
|
|
92
95
|
// Configuration & Information
|
|
93
96
|
home: __dirname.slice(0,-4),
|
|
@@ -117,7 +120,6 @@ if (global.cds) Object.assign(module,{exports:global.cds}) ; else {
|
|
|
117
120
|
// legacy and to be moved stuff -> hidden for tools in cds.__proto__
|
|
118
121
|
extend (cds.__proto__) .with (lazified ({
|
|
119
122
|
/** @deprecated */ in: (cwd) => !cwd ? cds : {__proto__:cds, cwd, env: cds.env.for('cds',cwd) },
|
|
120
|
-
alpha_localized: lazy => require('./compile/etc/_localized'),
|
|
121
123
|
mtx: lazy => require('../bin/mtx/in-cds'),
|
|
122
124
|
build: lazy => require('../bin/build'),
|
|
123
125
|
}))
|
package/lib/log/format/kibana.js
CHANGED
|
@@ -26,7 +26,9 @@ module.exports = (module, level, ...args) => {
|
|
|
26
26
|
if (user && log_user) toLog.remote_user = user.id
|
|
27
27
|
// add headers, if available, with _ instead of -
|
|
28
28
|
const req = cds.context._ && cds.context._.req
|
|
29
|
-
if (req && req.headers)
|
|
29
|
+
if (req && req.headers)
|
|
30
|
+
for (const k in req.headers)
|
|
31
|
+
toLog[k.replace(/-/g, '_')] = k.match(/authorization/i) ? `${req.headers[k].split(' ')[0]} ***` : req.headers[k]
|
|
30
32
|
}
|
|
31
33
|
toLog.timestamp = new Date()
|
|
32
34
|
|
package/lib/log/index.js
CHANGED
|
@@ -4,8 +4,8 @@ const cds = require ('../index'), { log } = cds.env
|
|
|
4
4
|
if (log.Logger || log.service) {
|
|
5
5
|
if (log.Logger) exports.Logger = require (log.Logger)
|
|
6
6
|
if (log.service) {
|
|
7
|
-
const {app} = cds,
|
|
8
|
-
app ? setImmediate(()=>
|
|
7
|
+
const {app} = cds, serveIn = app => require('./service').serveIn(app)
|
|
8
|
+
app ? setImmediate(() => serveIn(app)) : cds.on('bootstrap', app => serveIn(app))
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
11
|
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
const cds = require('../index'), { EventContext } = cds
|
|
2
|
+
const { EventEmitter } = require('events')
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Continuation Local Storage for cds.context
|
|
7
|
+
*/
|
|
8
|
+
exports.for = (cds,v) => {
|
|
9
|
+
|
|
10
|
+
if (cds.env.features.cls) {
|
|
11
|
+
|
|
12
|
+
const { executionAsyncResource:current, createHook } = module.require ('async_hooks')
|
|
13
|
+
const _context = Symbol('cds.context')
|
|
14
|
+
|
|
15
|
+
createHook ({ init(id,t,tid, res) {
|
|
16
|
+
const cr = current(); if (!cr) return
|
|
17
|
+
const ctx = cr[_context]
|
|
18
|
+
if (ctx) res[_context] = ctx
|
|
19
|
+
}}).enable()
|
|
20
|
+
|
|
21
|
+
Reflect.defineProperty (cds,'context',{ enumerable:1,
|
|
22
|
+
set(v) {
|
|
23
|
+
const cr = current(); if (!cr) return
|
|
24
|
+
const ctx = typeof v !== 'object' ? v : v.context || (v instanceof EventContext ? v : EventContext.for(v,false))
|
|
25
|
+
cr[_context] = ctx
|
|
26
|
+
},
|
|
27
|
+
get() {
|
|
28
|
+
const cr = current(); if (!cr) return undefined
|
|
29
|
+
return cr[_context]
|
|
30
|
+
},
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
} else {
|
|
34
|
+
|
|
35
|
+
Reflect.defineProperty (cds,'context',{ enumerable:1,
|
|
36
|
+
get:()=> undefined,
|
|
37
|
+
set:()=> {},
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return v ? cds.context = v : cds.context
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
exports.spawn = function cds_spawn (o,fn) {
|
|
48
|
+
|
|
49
|
+
if (typeof o === 'function') [fn,o] = [o,fn] //> for compatibility
|
|
50
|
+
if (o instanceof cds.EventContext) throw new Error('The passed options must not be an instance of cds.EventContext.')
|
|
51
|
+
else if (!o) o = {}
|
|
52
|
+
|
|
53
|
+
const em = new EventEmitter()
|
|
54
|
+
const fx = () => {
|
|
55
|
+
// create a new transaction for each run of the background job
|
|
56
|
+
// which inherits from the current event context by default
|
|
57
|
+
const o2 = { ...o }; delete o2.timestamp //> spawned txes set their own timestamps
|
|
58
|
+
const tx = cds.context = cds.tx(o2)
|
|
59
|
+
const commit = async (res) => {
|
|
60
|
+
await tx.commit()
|
|
61
|
+
for (const handler of em.listeners('succeeded')) await handler(res)
|
|
62
|
+
for (const handler of em.listeners('done')) await handler()
|
|
63
|
+
}
|
|
64
|
+
fn(tx).then(commit, tx.rollback) .catch (async e => {
|
|
65
|
+
// tx.rollback throws passed error -> we will arrive here for any error
|
|
66
|
+
cds.log().error(`ERROR occured in background job:`, e)
|
|
67
|
+
for (const handler of em.listeners('failed')) await handler(e)
|
|
68
|
+
for (const handler of em.listeners('done')) await handler()
|
|
69
|
+
})
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const timer = (
|
|
73
|
+
(o && o.after) ? setTimeout(fx, o.after) :
|
|
74
|
+
(o && o.every) ? setInterval(fx, o.every) :
|
|
75
|
+
setImmediate(fx)
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
return Object.assign (em, { timer })
|
|
79
|
+
}
|
package/lib/req/context.js
CHANGED
|
@@ -12,8 +12,9 @@ class EventContext {
|
|
|
12
12
|
|
|
13
13
|
toString() { return `${this.event} ${this.path}` }
|
|
14
14
|
|
|
15
|
-
static
|
|
16
|
-
if (data
|
|
15
|
+
static for (data={}, base = cds.context) {
|
|
16
|
+
if (data instanceof EventContext) return data
|
|
17
|
+
if (base && features.cds_tx_inheritance) {
|
|
17
18
|
let u = _inherit('user', u => typeof u === 'object' ? Object.create(u) : u)
|
|
18
19
|
if (!u || !u.tenant) _inherit('tenant')
|
|
19
20
|
if (!u || !u.locale) _inherit('locale')
|
|
@@ -156,78 +157,5 @@ class EventContext {
|
|
|
156
157
|
}
|
|
157
158
|
}
|
|
158
159
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
* Continuation Local Storage for cds.context
|
|
162
|
-
*/
|
|
163
|
-
const cls = (cds,v) => {
|
|
164
|
-
|
|
165
|
-
if (cds.env.features.cls) {
|
|
166
|
-
|
|
167
|
-
const { executionAsyncResource:current, createHook } = module.require ('async_hooks')
|
|
168
|
-
const _context = Symbol('cds.context')
|
|
169
|
-
|
|
170
|
-
createHook ({ init(id,t,tid, res) {
|
|
171
|
-
const cr = current(); if (!cr) return
|
|
172
|
-
const ctx = cr[_context]
|
|
173
|
-
if (ctx) res[_context] = ctx
|
|
174
|
-
}}).enable()
|
|
175
|
-
|
|
176
|
-
Reflect.defineProperty (cds,'context',{ enumerable:1,
|
|
177
|
-
set(v) {
|
|
178
|
-
const cr = current(); if (!cr) return
|
|
179
|
-
const ctx = typeof v !== 'object' ? v : v.context || (v instanceof EventContext ? v : EventContext.new(v,false))
|
|
180
|
-
cr[_context] = ctx
|
|
181
|
-
},
|
|
182
|
-
get() {
|
|
183
|
-
const cr = current(); if (!cr) return undefined
|
|
184
|
-
return cr[_context]
|
|
185
|
-
},
|
|
186
|
-
})
|
|
187
|
-
|
|
188
|
-
} else {
|
|
189
|
-
|
|
190
|
-
Reflect.defineProperty (cds,'context',{ enumerable:1,
|
|
191
|
-
get:()=> undefined,
|
|
192
|
-
set:()=> {},
|
|
193
|
-
})
|
|
194
|
-
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
return v ? cds.context = v : cds.context
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
function cds_spawn (o,fn) {
|
|
202
|
-
if (typeof o === 'function') [ fn, o ] = [ o, fn ]
|
|
203
|
-
if (!o) o = {}
|
|
204
|
-
const em = new EventEmitter()
|
|
205
|
-
const fx = async ()=> {
|
|
206
|
-
// create a new transaction for each run of the background job
|
|
207
|
-
// which inherits from the current event context by default
|
|
208
|
-
const tx = cds.context = cds.tx({...o})
|
|
209
|
-
try {
|
|
210
|
-
const res = await fn(tx)
|
|
211
|
-
await tx.commit()
|
|
212
|
-
for (const handler of em.listeners('succeeded')) await handler(res)
|
|
213
|
-
for (const handler of em.listeners('done')) await handler()
|
|
214
|
-
} catch(e) {
|
|
215
|
-
console.trace (`ERROR occured in background job:`, e) // eslint-disable-line no-console
|
|
216
|
-
await tx.rollback()
|
|
217
|
-
for (const handler of em.listeners('failed')) await handler(e)
|
|
218
|
-
for (const handler of em.listeners('done')) await handler()
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
const timer = (
|
|
222
|
-
(o && o.after) ? setTimeout (fx, o.after) :
|
|
223
|
-
(o && o.every) ? setInterval (fx, o.every) :
|
|
224
|
-
setImmediate (fx) )
|
|
225
|
-
return Object.assign(em, { timer })
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
module.exports = Object.assign (EventContext,{
|
|
230
|
-
/** @type {(cds,v)=>EventContext} */ for: cls,
|
|
231
|
-
spawn: cds_spawn,
|
|
232
|
-
propagateHeaders: [ 'x-correlation-id' ]
|
|
233
|
-
})
|
|
160
|
+
EventContext.propagateHeaders = [ 'x-correlation-id' ]
|
|
161
|
+
module.exports = EventContext
|
package/lib/req/request.js
CHANGED
|
@@ -112,7 +112,7 @@ const SQL2Crud = {
|
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
const Query2Crud = (q) => {
|
|
115
|
-
if (typeof q === 'string') return SQL2Crud[q] || /^\s*(\w+)
|
|
115
|
+
if (typeof q === 'string') return SQL2Crud[q] || /^\s*(\w+)/i.test(q) && SQL2Crud[RegExp.$1.toUpperCase()] || q
|
|
116
116
|
else for (let each in q) if (each in SQL2Crud) return SQL2Crud[each]
|
|
117
117
|
}
|
|
118
118
|
|
package/lib/serve/Service-api.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const add_methods_to = require ('./Service-methods')
|
|
2
|
-
const cds = require('..')
|
|
2
|
+
const cds = require('..'), { unfold_csn: cds_localized } = cds.compile._localized
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
class Service extends require('./Service-handlers') {
|
|
@@ -13,9 +13,13 @@ class Service extends require('./Service-handlers') {
|
|
|
13
13
|
/**
|
|
14
14
|
* Subclasses may override this to prepare the given model appropriately
|
|
15
15
|
*/
|
|
16
|
-
set model(
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
set model (csn) {
|
|
17
|
+
if (csn) {
|
|
18
|
+
super.model = cds_localized(cds.linked(cds.compile.for.odata(csn)))
|
|
19
|
+
add_methods_to (this)
|
|
20
|
+
} else {
|
|
21
|
+
super.model = undefined
|
|
22
|
+
}
|
|
19
23
|
}
|
|
20
24
|
|
|
21
25
|
/**
|
|
@@ -37,13 +37,6 @@ exports.dispatch = async function dispatch (req) { //NOSONAR
|
|
|
37
37
|
if (!req.query._srv) Object.defineProperty (req.query,'_srv',{ value:this, configurable:true, writable:true })
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
// REVISIT: Ensure req._.req and req._.res in case of srv.run(query)?!
|
|
41
|
-
/*
|
|
42
|
-
if (this instanceof cds.ApplicationService && !req._.req) {
|
|
43
|
-
// TODO: add req and res to req._ from tx
|
|
44
|
-
}
|
|
45
|
-
*/
|
|
46
|
-
|
|
47
40
|
return this.handle(req)
|
|
48
41
|
}
|
|
49
42
|
|
|
@@ -47,14 +47,12 @@ const add_handler_for = (srv, def) => {
|
|
|
47
47
|
|
|
48
48
|
// object variant of params, ensure at least one param is present in args[0]
|
|
49
49
|
// REVISIT: still not bullet proof, but parameters might be optional
|
|
50
|
-
if (
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
data[p] = params[p]
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
for (let p in def.params) {
|
|
57
|
-
data[p] = args.shift()
|
|
50
|
+
if (def.params) {
|
|
51
|
+
if (args[0] !== null && typeof args[0] === 'object' && args.length === 1 && Object.keys(def.params).some(p => p in args[0])) {
|
|
52
|
+
const params = args.shift()
|
|
53
|
+
for (const p in def.params) data[p] = params[p]
|
|
54
|
+
} else { // positional
|
|
55
|
+
for (let p in def.params) data[p] = args.shift()
|
|
58
56
|
}
|
|
59
57
|
}
|
|
60
58
|
|