@sap/cds 5.4.6 → 5.5.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 +208 -2
- package/apis/ql.d.ts +17 -15
- package/app/index.js +1 -1
- package/bin/build/buildTaskEngine.js +26 -42
- package/bin/build/buildTaskFactory.js +6 -10
- package/bin/build/buildTaskHandler.js +2 -4
- package/bin/build/buildTaskProvider.js +3 -1
- package/bin/build/buildTaskProviderFactory.js +9 -15
- package/bin/build/constants.js +15 -3
- package/bin/build/index.js +5 -4
- package/bin/build/mtaUtil.js +8 -11
- package/bin/build/provider/buildTaskHandlerEdmx.js +63 -6
- package/bin/build/provider/buildTaskHandlerInternal.js +2 -34
- package/bin/build/provider/buildTaskProviderInternal.js +16 -42
- package/bin/build/provider/fiori/index.js +13 -24
- package/bin/build/provider/hana/2migration.js +17 -15
- package/bin/build/provider/hana/2tabledata.js +52 -48
- package/bin/build/provider/hana/index.js +27 -25
- package/bin/build/provider/hana/migrationtable.js +91 -67
- package/bin/build/provider/java-cf/index.js +14 -24
- package/bin/build/provider/mtx/index.js +12 -14
- package/bin/build/provider/node-cf/index.js +18 -32
- package/bin/cds.js +5 -5
- package/bin/serve.js +29 -23
- package/bin/version.js +0 -1
- package/lib/compile/etc/_localized.js +4 -9
- package/lib/compile/for/sql.js +5 -2
- package/lib/compile/parse.js +25 -17
- package/lib/compile/to/srvinfo.js +2 -1
- package/lib/connect/bindings.js +2 -1
- package/lib/connect/index.js +48 -49
- package/lib/core/classes.js +1 -1
- package/lib/core/reflect.js +10 -2
- package/lib/deploy.js +26 -23
- package/lib/env/defaults.js +13 -6
- package/lib/env/index.js +73 -78
- package/lib/env/requires.js +38 -19
- package/lib/index.js +9 -10
- package/lib/lazy.js +2 -2
- package/lib/log/index.js +33 -45
- package/lib/log/service/index.js +2 -2
- package/lib/ql/CREATE.js +14 -9
- package/lib/ql/DELETE.js +6 -5
- package/lib/ql/DROP.js +12 -9
- package/lib/ql/INSERT.js +40 -16
- package/lib/ql/Query.js +67 -40
- package/lib/ql/SELECT.js +162 -127
- package/lib/ql/UPDATE.js +74 -42
- package/lib/ql/Whereable.js +77 -87
- package/lib/ql/index.js +36 -24
- package/lib/ql/parse.js +35 -0
- package/lib/req/context.js +44 -8
- package/lib/req/locale.js +7 -7
- package/lib/serve/Service-api.js +21 -14
- package/lib/serve/Service-dispatch.js +28 -12
- package/lib/serve/Transaction.js +22 -10
- package/lib/serve/index.js +16 -11
- package/lib/utils/axios.js +23 -16
- package/lib/utils/data.js +35 -0
- package/lib/utils/tests.js +27 -18
- package/libx/_runtime/audit/generic/personal/access.js +81 -0
- package/libx/_runtime/audit/generic/personal/constants.js +4 -0
- package/libx/_runtime/audit/generic/personal/index.js +50 -0
- package/libx/_runtime/audit/generic/personal/modification.js +138 -0
- package/libx/_runtime/audit/generic/personal/utils.js +186 -0
- package/libx/_runtime/audit/utils/v2.js +10 -4
- package/libx/_runtime/cds-services/adapter/odata-v4/Dispatcher.js +5 -5
- package/libx/_runtime/cds-services/adapter/odata-v4/OData.js +6 -7
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/action.js +5 -7
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/create.js +5 -7
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/delete.js +2 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/error.js +4 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +7 -4
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +59 -8
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +11 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +6 -10
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +3 -46
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/applyToCQN.js +2 -5
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/createToCQN.js +2 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/deleteToCQN.js +4 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/expandToCQN.js +1 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/index.js +0 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/selectHelper.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/updateToCQN.js +2 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/utils.js +16 -18
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/edm/EdmEntityType.js +6 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/format/RepresentationKind.js +4 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/core/OdataRequest.js +1 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/serializer/SerializerFactory.js +15 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/validator/OperationValidator.js +1 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/to.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +8 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/handlerUtils.js +6 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/omitValues.js +12 -5
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +1 -7
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/request.js +7 -7
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +14 -18
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/stream.js +13 -13
- package/libx/_runtime/cds-services/adapter/rest/handlers/create.js +0 -1
- package/libx/_runtime/cds-services/adapter/rest/handlers/operation.js +2 -1
- package/libx/_runtime/cds-services/adapter/rest/handlers/read.js +2 -2
- package/libx/_runtime/cds-services/adapter/rest/rest-to-cqn/index.js +2 -4
- package/libx/_runtime/cds-services/adapter/rest/utils/result.js +4 -2
- package/libx/_runtime/cds-services/services/Service.js +40 -5
- package/libx/_runtime/cds-services/services/utils/columns.js +13 -7
- package/libx/_runtime/cds-services/services/utils/compareJson.js +88 -4
- package/libx/_runtime/cds-services/services/utils/differ.js +24 -6
- package/libx/_runtime/cds-services/services/utils/handlerUtils.js +2 -2
- package/libx/_runtime/common/composition/data.js +44 -55
- package/libx/_runtime/common/composition/delete.js +97 -71
- package/libx/_runtime/common/composition/index.js +2 -1
- package/libx/_runtime/common/composition/insert.js +34 -11
- package/libx/_runtime/common/composition/tree.js +119 -92
- package/libx/_runtime/common/composition/update.js +4 -1
- package/libx/_runtime/common/composition/utils.js +1 -3
- package/libx/_runtime/common/constants/draft.js +12 -1
- package/libx/_runtime/common/generic/auth.js +6 -22
- package/libx/_runtime/common/generic/crud.js +14 -13
- package/libx/_runtime/common/generic/input.js +23 -26
- package/libx/_runtime/common/generic/put.js +1 -1
- package/libx/_runtime/common/generic/sorting.js +16 -16
- package/libx/_runtime/common/i18n/index.js +1 -1
- package/libx/_runtime/common/i18n/messages.properties +4 -0
- package/libx/_runtime/common/utils/backlinks.js +12 -5
- package/libx/_runtime/common/utils/cqn.js +6 -1
- package/libx/_runtime/common/utils/cqn2cqn4sql.js +102 -101
- package/libx/_runtime/common/utils/csn.js +47 -4
- package/libx/_runtime/common/utils/data.js +0 -37
- package/libx/_runtime/common/utils/enrichWithKeysFromWhere.js +1 -1
- package/libx/_runtime/common/utils/entityFromCqn.js +7 -24
- package/libx/_runtime/common/utils/foreignKeyPropagations.js +39 -7
- package/libx/_runtime/common/utils/generateOnCond.js +11 -12
- package/libx/_runtime/common/utils/onlyKeysRemain.js +10 -0
- package/libx/_runtime/common/utils/path.js +35 -0
- package/libx/_runtime/common/utils/postProcessing.js +86 -0
- package/libx/_runtime/common/utils/quotingStyles.js +37 -26
- package/libx/_runtime/common/utils/resolveView.js +223 -171
- package/libx/_runtime/common/utils/rewriteAsterisk.js +46 -26
- package/libx/_runtime/common/utils/structured.js +6 -12
- package/libx/_runtime/common/utils/template.js +10 -5
- package/libx/_runtime/common/utils/templateDelimiter.js +1 -0
- package/libx/_runtime/common/utils/templateProcessor.js +22 -30
- package/libx/_runtime/common/utils/union.js +31 -0
- package/libx/_runtime/common/utils/unionCqnTemplate.js +184 -0
- package/libx/_runtime/db/Service.js +1 -1
- package/libx/_runtime/db/data-conversion/timestamp.js +2 -9
- package/libx/_runtime/db/expand/expandCQNToJoin.js +204 -297
- package/libx/_runtime/db/expand/index.js +3 -3
- package/libx/_runtime/db/expand/rawToExpanded.js +36 -7
- package/libx/_runtime/db/generic/index.js +1 -1
- package/libx/_runtime/db/generic/input.js +5 -7
- package/libx/_runtime/db/generic/integrity.js +1 -1
- package/libx/_runtime/db/generic/rewrite.js +2 -10
- package/libx/_runtime/db/generic/update.js +13 -5
- package/libx/_runtime/db/generic/virtual.js +22 -58
- package/libx/_runtime/db/query/delete.js +7 -4
- package/libx/_runtime/db/query/insert.js +6 -4
- package/libx/_runtime/db/query/read.js +13 -20
- package/libx/_runtime/db/query/run.js +4 -1
- package/libx/_runtime/db/query/update.js +5 -4
- package/libx/_runtime/db/sql-builder/ExpressionBuilder.js +35 -2
- package/libx/_runtime/db/sql-builder/FunctionBuilder.js +17 -2
- package/libx/_runtime/db/sql-builder/InsertBuilder.js +6 -5
- package/libx/_runtime/db/sql-builder/ReferenceBuilder.js +10 -0
- package/libx/_runtime/db/sql-builder/SelectBuilder.js +35 -24
- package/libx/_runtime/db/sql-builder/UpdateBuilder.js +14 -4
- package/libx/_runtime/db/sql-builder/arrayed.js +4 -0
- package/libx/_runtime/db/utils/deep.js +8 -0
- package/libx/_runtime/db/utils/generateAliases.js +2 -1
- package/libx/_runtime/fiori/generic/activate.js +19 -15
- package/libx/_runtime/fiori/generic/before.js +3 -11
- package/libx/_runtime/fiori/generic/cancel.js +1 -1
- package/libx/_runtime/fiori/generic/delete.js +3 -1
- package/libx/_runtime/fiori/generic/edit.js +12 -2
- package/libx/_runtime/fiori/generic/new.js +5 -5
- package/libx/_runtime/fiori/generic/patch.js +0 -18
- package/libx/_runtime/fiori/generic/read.js +241 -189
- package/libx/_runtime/fiori/utils/delete.js +36 -7
- package/libx/_runtime/fiori/utils/handler.js +43 -44
- package/libx/_runtime/fiori/utils/where.js +30 -15
- package/libx/_runtime/hana/customBuilder/CustomSelectBuilder.js +4 -6
- package/libx/_runtime/hana/execute.js +2 -2
- package/libx/_runtime/hana/localized.js +4 -4
- package/libx/_runtime/hana/pool.js +29 -14
- package/libx/_runtime/hana/search2cqn4sql.js +2 -1
- package/libx/_runtime/hana/searchToContains.js +18 -14
- package/libx/_runtime/index.js +0 -5
- package/libx/_runtime/messaging/AMQPWebhookMessaging.js +13 -5
- package/libx/_runtime/messaging/common-utils/naming-conventions.js +4 -1
- package/libx/_runtime/messaging/enterprise-messaging-utils/EMManagement.js +31 -19
- package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +1 -2
- package/libx/_runtime/messaging/enterprise-messaging.js +6 -4
- package/libx/_runtime/messaging/service.js +7 -6
- package/libx/_runtime/odata/cqn2odata.js +110 -43
- package/libx/_runtime/odata/index.js +26 -48
- package/libx/_runtime/odata/odata2cqn.js +1 -6154
- package/libx/_runtime/odata/odata2cqn.pegjs +559 -0
- package/libx/_runtime/odata/readToCqn.js +94 -64
- package/libx/_runtime/remote/Service.js +74 -21
- package/libx/_runtime/remote/cqn2odata/index.js +1 -5
- package/libx/_runtime/remote/utils/client.js +24 -101
- package/libx/_runtime/remote/utils/dataConversion.js +27 -12
- package/libx/_runtime/sqlite/Service.js +3 -5
- package/libx/_runtime/sqlite/execute.js +23 -24
- package/libx/_runtime/sqlite/localized.js +12 -7
- package/libx/_runtime/types/api.js +10 -0
- package/package.json +1 -1
- package/server.js +16 -2
- package/lib/ql/grammar.pegjs +0 -208
- package/lib/ql/parser.js +0 -1
- package/lib/ql/rt/DELETE.js +0 -29
- package/lib/ql/rt/INSERT.js +0 -23
- package/lib/ql/rt/Query.js +0 -84
- package/lib/ql/rt/SELECT.js +0 -174
- package/lib/ql/rt/UPDATE.js +0 -119
- package/lib/ql/rt/_helpers.js +0 -91
- package/lib/ql/rt/index.js +0 -32
- package/libx/_runtime/audit/generic/personal.js +0 -260
- package/libx/_runtime/cds-services/statements/BaseStatement.js +0 -72
- package/libx/_runtime/cds-services/statements/Create.js +0 -57
- package/libx/_runtime/cds-services/statements/Delete.js +0 -33
- package/libx/_runtime/cds-services/statements/Drop.js +0 -42
- package/libx/_runtime/cds-services/statements/Insert.js +0 -201
- package/libx/_runtime/cds-services/statements/Select.js +0 -826
- package/libx/_runtime/cds-services/statements/Update.js +0 -181
- package/libx/_runtime/cds-services/statements/Where.js +0 -726
- package/libx/_runtime/cds-services/statements/index.js +0 -25
- package/libx/_runtime/common/generic/resolve-mock.js +0 -9
package/lib/connect/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const cds = require('..'), {one_model} = cds.env.features
|
|
1
|
+
const cds = require('..'), {one_model} = cds.env.features, LOG = cds.log('cds.connect')
|
|
2
2
|
const factory = require('../serve/factory')
|
|
3
3
|
const _pending = cds.services._pending || {} // used below to chain parallel connect.to(<same>)
|
|
4
4
|
|
|
@@ -6,12 +6,12 @@ const _pending = cds.services._pending || {} // used below to chain parallel con
|
|
|
6
6
|
* Connect to a service as primary datasource, i.e. cds.db.
|
|
7
7
|
*/
|
|
8
8
|
const connect = module.exports = async function cds_connect (options) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
if (typeof options === 'object' && cds.db) throw cds.error (
|
|
10
|
+
`You need to disconnect before creating a new primary connection with different options!`
|
|
11
|
+
)
|
|
12
|
+
if (typeof options === 'string') cds.db = await connect.to (options)
|
|
13
|
+
else await connect.to ('db',options)
|
|
14
|
+
return cds
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -21,51 +21,50 @@ const connect = module.exports = async function cds_connect (options) {
|
|
|
21
21
|
* @param {{ kind?:String, impl?:String }} [options]
|
|
22
22
|
* @returns { Promise<import('../serve/Service-api')> }
|
|
23
23
|
*/
|
|
24
|
-
connect.to = async (datasource, options) => {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
24
|
+
connect.to = async (datasource, options) => {
|
|
25
|
+
let Service = factory, _done = x=>x
|
|
26
|
+
if (typeof datasource === 'object') [options,datasource] = [datasource]
|
|
27
|
+
else if (datasource) {
|
|
28
|
+
if (datasource._is_service_class) [ Service, datasource ] = [ datasource, datasource.name ]
|
|
29
|
+
if (!options) { //> specifying ad-hoc options disallows caching
|
|
30
|
+
if (datasource in cds.services) return cds.services[datasource]
|
|
31
|
+
if (datasource in _pending) return _pending[datasource]
|
|
32
|
+
}
|
|
33
|
+
// queue parallel requests to a single promise, to avoid creating multiple services
|
|
34
|
+
_pending[datasource] = new Promise (r=>_done=r).finally(()=>{ delete _pending[datasource] })
|
|
35
|
+
}
|
|
36
|
+
const o = Service === factory ? options4 (datasource, options) : {}
|
|
37
|
+
const m = await model4 (o)
|
|
38
|
+
// check if required service definition exists
|
|
39
|
+
const required = cds.requires[datasource]
|
|
40
|
+
if (required && required.model && datasource !== 'db' && !m.definitions[required.service||datasource]) {
|
|
41
|
+
LOG.error (`No service definition found for '${required.service || datasource}', as required by 'cds.requires.${datasource}':`, required)
|
|
42
|
+
throw new Error (`No service definition found for '${required.service || datasource}'`)
|
|
43
|
+
}
|
|
44
|
+
// construct new service instance
|
|
45
|
+
const srv = new Service (datasource,m,o)
|
|
46
|
+
await srv.prepend (srv.init, srv.options.impl)
|
|
47
|
+
if (datasource === 'db') cds.db = srv
|
|
48
|
+
_done (cds.services[datasource] = srv)
|
|
49
|
+
cds.emit ('connect',srv)
|
|
50
|
+
return srv
|
|
44
51
|
}
|
|
45
52
|
|
|
46
|
-
function options4 (name, _o) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const creds = o.credentials
|
|
58
|
-
for (let p of ['url','database']) {
|
|
59
|
-
const each = creds[p]
|
|
60
|
-
if (!each || each === ':memory:') continue
|
|
61
|
-
else creds[p] = cds.utils.path.resolve(cds.root,each)
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
return o
|
|
53
|
+
function options4 (name, _o) {
|
|
54
|
+
const [, kind=_o && _o.kind, url] = /^(\w+):(.*)/.exec(name) || []
|
|
55
|
+
const conf = cds.requires[name] || cds.requires[kind]
|
|
56
|
+
const o = { kind, ...conf, ..._o }
|
|
57
|
+
if (!o.kind && !o.impl && !o.silent) throw cds.error(
|
|
58
|
+
conf ? `Configuration for 'cds.requires.${name}' lacks mandatory property 'kind' or 'impl'` :
|
|
59
|
+
name ? `Didn't find a configuration for 'cds.requires.${name}'` :
|
|
60
|
+
`Provided options object lacks mandatory property 'kind' or 'impl'`
|
|
61
|
+
)
|
|
62
|
+
if (url) o.credentials = { ...o.credentials, url }
|
|
63
|
+
return o
|
|
65
64
|
}
|
|
66
65
|
|
|
67
66
|
function model4 (o) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
67
|
+
if (o.model && o.model.definitions) return o.model
|
|
68
|
+
if (one_model && cds.model) return cds.model
|
|
69
|
+
else return o.model && cds.load(o.model)
|
|
71
70
|
}
|
package/lib/core/classes.js
CHANGED
|
@@ -6,7 +6,7 @@ class any {
|
|
|
6
6
|
set name(n) { this.set('name', n, false) }
|
|
7
7
|
set kind(k) { this.set('kind', k, true) }
|
|
8
8
|
get kind() { return this.set('kind', this.parent ? 'element' : 'type') }
|
|
9
|
-
is (kind) { return this.kind === kind }
|
|
9
|
+
is (kind) { return this.kind === kind || kind === 'any' }
|
|
10
10
|
valueOf() { return this.name }
|
|
11
11
|
|
|
12
12
|
own (property) {
|
package/lib/core/reflect.js
CHANGED
|
@@ -57,7 +57,7 @@ class LinkedCSN extends any {
|
|
|
57
57
|
if (d.includes) d.includes.forEach(i => _visit(all[i])) // Note: with delete d.includes, redirects in AFC broke
|
|
58
58
|
if (d.query) d.query._target && _visit (d.query._target)
|
|
59
59
|
if (d.type) _builtin(d.type) || _visit (d.__proto__)
|
|
60
|
-
if (d.target) _visit (d._target)
|
|
60
|
+
if (d.target) _visit (d._target) ; else if (d.targetAspect) _visit (typeof d.targetAspect === 'object' ? d.targetAspect : all[d.targetAspect])
|
|
61
61
|
if (d.returns) _visit (d.returns)
|
|
62
62
|
if (d.items) _visit (d.items)
|
|
63
63
|
if (d.parent) _visit (d.parent)
|
|
@@ -65,7 +65,15 @@ class LinkedCSN extends any {
|
|
|
65
65
|
for (let a in d.actions) _visit (d.actions[a])
|
|
66
66
|
for (let p in d.params) _visit (d.params[p])
|
|
67
67
|
}
|
|
68
|
-
for (let
|
|
68
|
+
for (let n in all) {
|
|
69
|
+
if (n.endsWith('.texts') && reached.has(all[n.slice(0,-6)])) continue
|
|
70
|
+
if (reached.has(all[n])) continue
|
|
71
|
+
else {
|
|
72
|
+
delete all[n]
|
|
73
|
+
// also delete the legacy _texts proxy (not enumerable, installed by _localized.unfold_csn)
|
|
74
|
+
if (n.endsWith('.texts')) delete all[n.replace('.texts','_texts')]
|
|
75
|
+
}
|
|
76
|
+
}
|
|
69
77
|
return csn
|
|
70
78
|
}
|
|
71
79
|
|
package/lib/deploy.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const cds = require('./index'), { local } = cds.utils
|
|
2
2
|
const DEBUG = cds.debug('deploy')
|
|
3
|
+
let LOG
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Implementation of `cds.deploy` common to all databases.
|
|
@@ -11,6 +12,7 @@ exports = module.exports = function cds_deploy (model,options) { return {
|
|
|
11
12
|
|
|
12
13
|
/** @param {cds.Service} db */
|
|
13
14
|
async to (db, o=options||{}) { // NOSONAR
|
|
15
|
+
LOG = cds.log('deploy')
|
|
14
16
|
|
|
15
17
|
if (model && !model.definitions) model = await cds.load (model)
|
|
16
18
|
if (o.mocked) exports.include_external_entities_in (model)
|
|
@@ -26,12 +28,12 @@ exports = module.exports = function cds_deploy (model,options) { return {
|
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
// fill in initial data...
|
|
29
|
-
const SILENT = o.silent ||
|
|
31
|
+
const SILENT = o.silent || !LOG._info
|
|
30
32
|
await init_from_code (db,model,SILENT)
|
|
31
33
|
await init_from_csv (db,model,SILENT)
|
|
32
34
|
await init_from_json (db,model,SILENT)
|
|
33
35
|
|
|
34
|
-
const {credentials} = db.options, file = credentials && credentials.database
|
|
36
|
+
const {credentials} = db.options, file = credentials && (credentials.database || credentials.url)
|
|
35
37
|
if (!SILENT) {
|
|
36
38
|
if (file !== ':memory:') console.log (`/> successfully deployed to ./${file}\n`)
|
|
37
39
|
else console.log (`/> successfully deployed to sqlite in-memory db\n`)
|
|
@@ -170,28 +172,29 @@ async function init_from_ (locations, filter, db, csn, SILENT, INSERT_into) { //
|
|
|
170
172
|
|
|
171
173
|
if (folders.size === 0) return
|
|
172
174
|
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
.
|
|
189
|
-
|
|
190
|
-
|
|
175
|
+
const {local} = cds.utils, inits = [], err = new Error
|
|
176
|
+
await db.tx (async tx => {
|
|
177
|
+
for (let folder of folders) {
|
|
178
|
+
const files = await readdir (folder)
|
|
179
|
+
for (let each of files.filter (filter)) {
|
|
180
|
+
let name = each.replace(/-/g,'.').slice(0, -path.extname(each).length)
|
|
181
|
+
let entity = _entity4 (name)
|
|
182
|
+
if (!entity) { DEBUG && DEBUG (`warning: ${name} not in model`); continue }
|
|
183
|
+
if (entity['@cds.persistence.skip'] === true) continue
|
|
184
|
+
const file = path.join(folder,each)
|
|
185
|
+
const src = await read (file,'utf8'); if (!src) continue
|
|
186
|
+
const q = INSERT_into (entity,src)
|
|
187
|
+
if (!q) { DEBUG && DEBUG (`skipping empty ${local(file)}`); continue }
|
|
188
|
+
SILENT || console.log (`\x1b[2m > filling ${entity.name} from ${local(file)} \x1b[0m`) // eslint-disable-line
|
|
189
|
+
inits.push (tx.run(q).catch(e=>{ const ex = new Error
|
|
190
|
+
e.stack = e.message +'\n'+ require('util').inspect(q) + err.stack.slice(5)
|
|
191
|
+
.replace (/deploy\.js:\d+:/, ex.stack.slice(5).match(/deploy\.js:\d+:/)[0])
|
|
192
|
+
throw e
|
|
193
|
+
}))
|
|
194
|
+
}
|
|
191
195
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
if (!db.context) await tx.commit()
|
|
196
|
+
await Promise.all(inits)
|
|
197
|
+
})
|
|
195
198
|
|
|
196
199
|
function _entity4 (name) {
|
|
197
200
|
let entity = csn.definitions [name]
|
package/lib/env/defaults.js
CHANGED
|
@@ -17,7 +17,10 @@ module.exports = {
|
|
|
17
17
|
// skip_unused: 'all',
|
|
18
18
|
skip_unused: true,
|
|
19
19
|
one_model: true,
|
|
20
|
-
localized: true
|
|
20
|
+
localized: true,
|
|
21
|
+
// assert_integrity: true,
|
|
22
|
+
cds_tx_protection: true,
|
|
23
|
+
cds_tx_inheritance: true,
|
|
21
24
|
},
|
|
22
25
|
|
|
23
26
|
log: {
|
|
@@ -25,6 +28,9 @@ module.exports = {
|
|
|
25
28
|
levels: {
|
|
26
29
|
compile: 'warn',
|
|
27
30
|
cli: 'warn',
|
|
31
|
+
deploy: 'info',
|
|
32
|
+
serve: 'info',
|
|
33
|
+
server: 'info',
|
|
28
34
|
},
|
|
29
35
|
service: false,
|
|
30
36
|
// adds custom fields in kibana's error rendering (unknown fields are ignored); key: index
|
|
@@ -119,16 +125,17 @@ module.exports = {
|
|
|
119
125
|
api: {
|
|
120
126
|
model: true,
|
|
121
127
|
provisioning: true,
|
|
122
|
-
metadata: true
|
|
128
|
+
metadata: true,
|
|
129
|
+
diagnose: true
|
|
123
130
|
},
|
|
124
131
|
domain: '__default__'
|
|
125
132
|
},
|
|
126
133
|
|
|
127
134
|
cdsc: {
|
|
128
|
-
cv2: {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
135
|
+
// cv2: {
|
|
136
|
+
// _localized_entries: true,
|
|
137
|
+
// _texts_entries: true,
|
|
138
|
+
// }
|
|
132
139
|
// toSql: { associations: 'joins' },
|
|
133
140
|
// newCsn: true,
|
|
134
141
|
},
|
package/lib/env/index.js
CHANGED
|
@@ -3,7 +3,6 @@ const DEFAULTS = require('./defaults'), defaults = require.resolve ('./defaults'
|
|
|
3
3
|
const user_home = require('os').homedir()
|
|
4
4
|
const compat = require('./compat')
|
|
5
5
|
const path = require('path')
|
|
6
|
-
const cache = {}
|
|
7
6
|
|
|
8
7
|
|
|
9
8
|
/**
|
|
@@ -15,20 +14,11 @@ class Config {
|
|
|
15
14
|
* This is the one and only way to construct new instances.
|
|
16
15
|
* Public API is through `cds.env.for (<context>)`
|
|
17
16
|
* @param context - the app context, like 'cds' or 'your-app'
|
|
18
|
-
* @returns {Config}
|
|
17
|
+
* @returns {Config & typeof DEFAULTS}
|
|
19
18
|
*/
|
|
20
|
-
for (context, cwd,
|
|
19
|
+
for (context, cwd, _defaults=true) {
|
|
21
20
|
if (!cwd) cwd = global.cds && global.cds.root || process.cwd()
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
if (_filter_default_values) {
|
|
25
|
-
// never update cache without default values
|
|
26
|
-
return new Config (context, cwd, false)
|
|
27
|
-
}
|
|
28
|
-
if(!cached[context] || _force_cache_update) {
|
|
29
|
-
cached[context] = new Config (context, cwd)
|
|
30
|
-
}
|
|
31
|
-
return cached[context]
|
|
21
|
+
return new Config (context, cwd, _defaults)
|
|
32
22
|
}
|
|
33
23
|
|
|
34
24
|
|
|
@@ -37,8 +27,8 @@ class Config {
|
|
|
37
27
|
*/
|
|
38
28
|
constructor (_context, _home, _defaults=true) {
|
|
39
29
|
Object.assign (this, { _context, _home, _sources:[] })
|
|
40
|
-
this.
|
|
41
|
-
this.
|
|
30
|
+
this._profiles = _determineProfilesFrom (process.env)
|
|
31
|
+
this._profiles._defined = new Set()
|
|
42
32
|
|
|
43
33
|
// compat requires default values
|
|
44
34
|
if (_context === 'cds' && _defaults) this.add (DEFAULTS, defaults)
|
|
@@ -74,6 +64,20 @@ class Config {
|
|
|
74
64
|
}
|
|
75
65
|
}
|
|
76
66
|
|
|
67
|
+
/**
|
|
68
|
+
* This is `this.requires` plus additional entries for all cds.required.<name>.service
|
|
69
|
+
*/
|
|
70
|
+
get required_services_or_defs() {
|
|
71
|
+
const dict = Object.create (this.requires)
|
|
72
|
+
for (let [name,e] of Object.entries (this.requires)) if (e.service) {
|
|
73
|
+
if (e.service in dict && e.service !== name) {
|
|
74
|
+
console.error (`Datasource name '${e.service}' conflicts with 'service' definition referred to in 'cds.requires.${name}':`, e)
|
|
75
|
+
throw new Error (`Datasource name '${e.service}' conflicts with service definition`)
|
|
76
|
+
}
|
|
77
|
+
else dict[e.service] = { ...e, name }
|
|
78
|
+
}
|
|
79
|
+
return super.required_services_or_defs = dict
|
|
80
|
+
}
|
|
77
81
|
|
|
78
82
|
set roots(v) { set (this, 'roots', v) }
|
|
79
83
|
get roots() {
|
|
@@ -118,7 +122,11 @@ class Config {
|
|
|
118
122
|
* For BAS only: get all defined profiles (could include some from the defaults)
|
|
119
123
|
*/
|
|
120
124
|
get "defined-profiles" () {
|
|
121
|
-
return Array.from (this.
|
|
125
|
+
return Array.from (this._profiles._defined)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
get profiles() {
|
|
129
|
+
return super.profiles = Array.from (this._profiles)
|
|
122
130
|
}
|
|
123
131
|
|
|
124
132
|
|
|
@@ -129,24 +137,15 @@ class Config {
|
|
|
129
137
|
//
|
|
130
138
|
|
|
131
139
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
if (json) {
|
|
136
|
-
const conf = _conf (json)
|
|
137
|
-
if (conf) {
|
|
138
|
-
this._sources.push (res)
|
|
139
|
-
_merge (this, conf, this.profiles, this._profiles_defined)
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
return this
|
|
140
|
+
_load (cwd, file, _conf=o=>o) {
|
|
141
|
+
const json = _readJson (file = path.join(cwd, file)) // only support JSON
|
|
142
|
+
if (json) this.add (_conf (json), file)
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
-
/** @returns {Config} */
|
|
146
145
|
add (conf, /*from:*/ _src) {
|
|
147
146
|
if (!conf) return this
|
|
148
147
|
if (_src) this._sources.push (_src)
|
|
149
|
-
_merge (this, conf, this.
|
|
148
|
+
_merge (this, conf, this._profiles)
|
|
150
149
|
return this
|
|
151
150
|
}
|
|
152
151
|
|
|
@@ -170,12 +169,11 @@ class Config {
|
|
|
170
169
|
const { requires } = this
|
|
171
170
|
for (let each in requires) requires[each] = _merged (each)
|
|
172
171
|
function _merged (key) {
|
|
173
|
-
|
|
174
|
-
if (entry._is_merged || entry.kind === key || !(entry.kind in requires))
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
)
|
|
172
|
+
const entry = requires[key]
|
|
173
|
+
if (entry._is_merged || entry.kind === key || !(entry.kind in requires)) return entry
|
|
174
|
+
const clone = _merge ({}, _merged (entry.kind)) // first apply inherited data
|
|
175
|
+
_merge (clone, entry, false, false, o => _merge({},o)) // then apply overridden data
|
|
176
|
+
return Object.defineProperty (clone, '_is_merged', {value:true})
|
|
179
177
|
}
|
|
180
178
|
}
|
|
181
179
|
|
|
@@ -207,12 +205,12 @@ class Config {
|
|
|
207
205
|
const env = new Config('cds')
|
|
208
206
|
this._for_tests.vcaps = (vcaps) => { _add_vcap_services_to (env, vcaps)}
|
|
209
207
|
// merge all configs, then resolve profiles (same as in 'for' function above)
|
|
210
|
-
for (let c of [...conf].reverse()) _merge(env, c, env.
|
|
208
|
+
for (let c of [...conf].reverse()) _merge(env, c, env._profiles)
|
|
211
209
|
return env
|
|
212
210
|
}
|
|
213
211
|
// FOR TESTS ONLY! --> PLEASE: tests should test public APIs (only)
|
|
214
212
|
_merge_with (src) {
|
|
215
|
-
_merge (this, src, this.
|
|
213
|
+
_merge (this, src, this._profiles)
|
|
216
214
|
return this
|
|
217
215
|
}
|
|
218
216
|
}
|
|
@@ -228,31 +226,37 @@ class Config {
|
|
|
228
226
|
/**
|
|
229
227
|
* @returns {Config} dst
|
|
230
228
|
*/
|
|
231
|
-
function _merge (dst, src, _profiles,
|
|
232
|
-
const profiled = []
|
|
233
|
-
for (let p
|
|
234
|
-
const
|
|
235
|
-
|
|
236
|
-
if (
|
|
237
|
-
|
|
238
|
-
|
|
229
|
+
function _merge (dst, src, _profiles, _cloned) {
|
|
230
|
+
const profiled = [], descr = Object.getOwnPropertyDescriptors(src)
|
|
231
|
+
for (let p in descr) {
|
|
232
|
+
const pd = descr[p]
|
|
233
|
+
|
|
234
|
+
if ('get' in pd || !pd.enumerable) {
|
|
235
|
+
Object.defineProperty(dst,p,pd)
|
|
236
|
+
continue
|
|
239
237
|
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
238
|
+
|
|
239
|
+
if (_profiles && p[0] === '[') {
|
|
240
|
+
if (_profiles._defined) _profiles._defined.add (p.slice(1,-1))
|
|
241
|
+
if (_profiles.has(p.slice(1,-1)))
|
|
242
|
+
profiled.push (()=> _merge (dst, src[p], _profiles, _cloned))
|
|
243
|
+
continue
|
|
244
244
|
}
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
245
|
+
|
|
246
|
+
const v = pd.value
|
|
247
|
+
if (typeof v === 'object' && !Array.isArray(v)) {
|
|
248
|
+
if (!dst[p]) dst[p] = {}; else if (_cloned) dst[p] = _cloned(dst[p])
|
|
249
|
+
_merge (dst[p], v, _profiles, _cloned)
|
|
250
|
+
continue
|
|
249
251
|
}
|
|
252
|
+
|
|
253
|
+
if (v !== undefined) dst[p] = v
|
|
250
254
|
}
|
|
251
255
|
for (let each of profiled) each()
|
|
252
256
|
return dst
|
|
253
257
|
}
|
|
254
258
|
|
|
255
|
-
function _process_env4 (prefix) {
|
|
259
|
+
function _process_env4 (prefix) {
|
|
256
260
|
const {env} = process
|
|
257
261
|
const PREF = prefix.toUpperCase(), my = { CONFIG: PREF+'_CONFIG', ENV: PREF+'_ENV' }
|
|
258
262
|
const out = JSON.parse (env[my.CONFIG] || '{}')
|
|
@@ -280,7 +284,7 @@ function _value4 (val) {
|
|
|
280
284
|
}
|
|
281
285
|
|
|
282
286
|
|
|
283
|
-
function _add_vcap_services_to (env, vcaps={}) {
|
|
287
|
+
function _add_vcap_services_to (env, vcaps={}) {
|
|
284
288
|
let any
|
|
285
289
|
for (let service in env.requires) {
|
|
286
290
|
const conf = env.requires [service]
|
|
@@ -288,40 +292,31 @@ function _add_vcap_services_to (env, vcaps={}) { //NOSONAR
|
|
|
288
292
|
conf.vcap && _fetch (conf.vcap) || //> alternatives, e.g. { name:'foo', tag:'foo' }
|
|
289
293
|
_fetch ({ name: service }) ||
|
|
290
294
|
_fetch ({ tag: env._context+':'+service }) ||
|
|
291
|
-
_fetch ({ tag: conf.
|
|
292
|
-
_fetch ({ label: conf.
|
|
295
|
+
_fetch ({ tag: conf.dialect || conf.kind }) || // important for hanatrial, labeled 'hanatrial', tagged 'hana'
|
|
296
|
+
_fetch ({ label: conf.dialect || conf.kind }) ||
|
|
293
297
|
{/* not found */}
|
|
294
298
|
)
|
|
295
|
-
// `credentials.database` is used as indicator for sqlite, so must not appear for other DBs
|
|
296
|
-
if (conf.credentials && conf.use !== 'sqlite') delete conf.credentials.database
|
|
297
299
|
// Merge `credentials`. Needed because some app-defined things like `credentials.destination` must survive.
|
|
298
300
|
if (credentials) any = conf.credentials = Object.assign ({}, conf.credentials, credentials)
|
|
299
301
|
}
|
|
300
302
|
return any
|
|
301
303
|
|
|
302
|
-
function _fetch (predicate) {
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
const
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
function _filter4 (predicate) {
|
|
311
|
-
let filter; for (let key in predicate) {
|
|
312
|
-
const val = predicate[key], prev=filter, next=(
|
|
313
|
-
key === 'tag' ? e => _array(e,'tags').includes (val)
|
|
314
|
-
: e => val !== undefined ? e[key] === val : false
|
|
315
|
-
)
|
|
316
|
-
filter = prev ? e => prev(e) || next(e) : next
|
|
304
|
+
function _fetch (predicate) {
|
|
305
|
+
for (let k of Object.keys(predicate).reverse()) {
|
|
306
|
+
const v = predicate[k]; if (!v) continue
|
|
307
|
+
const filter = k === 'tag' ? e => _array(e,'tags').includes(v) : e => e[k] === v
|
|
308
|
+
for (let stype in vcaps) {
|
|
309
|
+
const found = _array(vcaps,stype) .find (filter)
|
|
310
|
+
if (found) return found
|
|
311
|
+
}
|
|
317
312
|
}
|
|
318
|
-
return filter
|
|
319
313
|
}
|
|
320
314
|
|
|
321
315
|
function _array(o,p) {
|
|
322
316
|
const v = o[p]
|
|
323
|
-
if (!v
|
|
324
|
-
|
|
317
|
+
if (!v) return []
|
|
318
|
+
if (Array.isArray(v)) return v
|
|
319
|
+
throw new Error(`Expected VCAP entry '${p}' to be an array, but was: ${require('util').inspect(vcaps)}`)
|
|
325
320
|
}
|
|
326
321
|
|
|
327
322
|
}
|
|
@@ -343,7 +338,7 @@ function _determineProfilesFrom (env = process.env) {
|
|
|
343
338
|
}
|
|
344
339
|
const split = (x) => env[x] ? env[x].split (/\s*,\s*/) : []
|
|
345
340
|
const profiles = [ ...split ('NODE_ENV'), ...split ('CDS_ENV') ]
|
|
346
|
-
return
|
|
341
|
+
return new Set (profiles)
|
|
347
342
|
}
|
|
348
343
|
|
|
349
344
|
|
package/lib/env/requires.js
CHANGED
|
@@ -30,20 +30,17 @@ module.exports = {
|
|
|
30
30
|
logging: undefined,
|
|
31
31
|
audit: undefined,
|
|
32
32
|
"sql": {
|
|
33
|
-
'[development]': { kind: 'sqlite', credentials: {
|
|
33
|
+
'[development]': { kind: 'sqlite', credentials: { url: ':memory:' } },
|
|
34
34
|
'[production]': { kind: 'hana' },
|
|
35
35
|
},
|
|
36
|
-
"sqlite": {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
use: 'hana', // enforce using hana when accessed through <sql>
|
|
45
|
-
impl: `${_runtime}/hana/Service.js`
|
|
46
|
-
},
|
|
36
|
+
"sqlite": _compat_to_use({
|
|
37
|
+
dialect: 'sqlite', credentials: { url: 'sqlite.db' },
|
|
38
|
+
impl: `${_runtime}/sqlite/Service.js`,
|
|
39
|
+
}),
|
|
40
|
+
"hana": _compat_to_use ({
|
|
41
|
+
dialect: 'hana',
|
|
42
|
+
impl: `${_runtime}/hana/Service.js`,
|
|
43
|
+
}),
|
|
47
44
|
"rest": {
|
|
48
45
|
impl: `${_runtime}/remote/Service.js`
|
|
49
46
|
},
|
|
@@ -57,21 +54,37 @@ module.exports = {
|
|
|
57
54
|
kind: 'odata'
|
|
58
55
|
},
|
|
59
56
|
"local-messaging": {
|
|
60
|
-
impl: `${_runtime}/messaging/service.js
|
|
57
|
+
impl: `${_runtime}/messaging/service.js`,
|
|
58
|
+
local: true
|
|
61
59
|
},
|
|
62
60
|
"file-based-messaging": {
|
|
63
61
|
outbox: true,
|
|
64
62
|
impl: `${_runtime}/messaging/file-based.js`,
|
|
65
63
|
credentials: { file:'~/.cds-msg-box' }
|
|
66
64
|
},
|
|
67
|
-
"
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
65
|
+
"default-messaging": {
|
|
66
|
+
"[development]": { "kind": "local-messaging" },
|
|
67
|
+
"[hybrid]": { "kind": "enterprise-messaging-amqp" },
|
|
68
|
+
"[production]": {
|
|
69
|
+
"kind": "enterprise-messaging-amqp",
|
|
70
|
+
"[multitenant]": { "kind": "enterprise-messaging-http" }
|
|
71
|
+
}
|
|
71
72
|
},
|
|
72
73
|
"enterprise-messaging": {
|
|
74
|
+
kind: "enterprise-messaging-http",
|
|
75
|
+
},
|
|
76
|
+
"enterprise-messaging-shared": { // for temporary compat only
|
|
77
|
+
kind: "enterprise-messaging-amqp",
|
|
78
|
+
},
|
|
79
|
+
"enterprise-messaging-http": {
|
|
80
|
+
outbox: true,
|
|
81
|
+
impl: `${_runtime}/messaging/enterprise-messaging.js`,
|
|
82
|
+
vcap: { label: "enterprise-messaging" },
|
|
83
|
+
},
|
|
84
|
+
"enterprise-messaging-amqp": {
|
|
73
85
|
outbox: true,
|
|
74
|
-
impl: `${_runtime}/messaging/enterprise-messaging.js
|
|
86
|
+
impl: `${_runtime}/messaging/enterprise-messaging-shared.js`,
|
|
87
|
+
vcap: { label: "enterprise-messaging" },
|
|
75
88
|
},
|
|
76
89
|
'message-queuing': {
|
|
77
90
|
outbox: true,
|
|
@@ -85,6 +98,12 @@ module.exports = {
|
|
|
85
98
|
// REVISIT: how to load model?
|
|
86
99
|
// model: 'AuditLogService.cds',
|
|
87
100
|
outbox: true,
|
|
88
|
-
|
|
101
|
+
vcap: { label: "auditlog" },
|
|
89
102
|
}
|
|
90
103
|
}
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
function _compat_to_use(o) { return Object.defineProperties (o,{
|
|
107
|
+
// NOTE: Property .use is for compatibility only -> use .dialect instead!
|
|
108
|
+
use: { get(){ return this.dialect }, enumerable:true },
|
|
109
|
+
})}
|