@sap/cds 6.1.3 → 6.2.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 +77 -8
- package/apis/cds.d.ts +18 -6
- package/apis/connect.d.ts +1 -1
- package/apis/cqn.d.ts +1 -1
- package/apis/log.d.ts +23 -5
- package/apis/ql.d.ts +128 -61
- package/apis/services.d.ts +11 -0
- package/apis/test.d.ts +61 -0
- package/apis/utils.d.ts +15 -0
- package/app/fiori/preview.js +1 -0
- package/bin/build/buildTaskEngine.js +70 -22
- package/bin/build/buildTaskFactory.js +18 -11
- package/bin/build/buildTaskHandler.js +1 -1
- package/bin/build/buildTaskProviderFactory.js +3 -13
- package/bin/build/constants.js +0 -1
- package/bin/build/index.js +14 -6
- package/bin/build/provider/buildTaskHandlerEdmx.js +2 -3
- package/bin/build/provider/buildTaskHandlerFeatureToggles.js +2 -2
- package/bin/build/provider/buildTaskHandlerInternal.js +3 -6
- package/bin/build/provider/buildTaskProviderInternal.js +51 -39
- package/bin/build/provider/fiori/index.js +3 -3
- package/bin/build/provider/hana/2migration.js +1 -1
- package/bin/build/provider/hana/index.js +34 -27
- package/bin/build/provider/java/index.js +6 -7
- package/bin/build/provider/mtx/index.js +20 -18
- package/bin/build/provider/mtx/resourcesTarBuilder.js +8 -11
- package/bin/build/provider/mtx-sidecar/index.js +13 -17
- package/bin/build/provider/nodejs/index.js +8 -7
- package/bin/build/util.js +22 -4
- package/bin/cds.js +8 -4
- package/bin/deploy/to-hana/cfUtil.js +53 -18
- package/bin/mtx/in-cds.js +1 -0
- package/bin/serve.js +37 -30
- package/lib/auth/basic-auth.js +33 -0
- package/lib/auth/dummy-auth.js +7 -0
- package/lib/auth/ias-auth.js +2 -0
- package/lib/auth/index.js +31 -0
- package/lib/auth/jwt-auth.js +3 -0
- package/lib/auth/mocked-users.js +72 -0
- package/lib/auth/passport-basic.js +12 -0
- package/lib/auth/passport-digest.js +14 -0
- package/lib/auth/xsuaa-auth.js +3 -0
- package/lib/compile/cds-compile.js +3 -3
- package/lib/compile/to/cdl.js +5 -1
- package/lib/compile/to/edm.js +8 -0
- package/lib/compile/to/gql.js +1 -0
- package/lib/compile/to/json.js +30 -5
- package/lib/compile/to/sql.js +3 -1
- package/lib/core/index.js +5 -1
- package/lib/dbs/cds-deploy.js +36 -6
- package/lib/env/cds-env.js +15 -5
- package/lib/env/cds-requires.js +51 -58
- package/lib/env/defaults.js +1 -0
- package/lib/env/schemas/cds-package.json +4 -0
- package/lib/env/schemas/cds-rc.json +63 -77
- package/lib/i18n/localize.js +16 -5
- package/lib/index.js +9 -4
- package/lib/log/cds-error.js +4 -6
- package/lib/log/cds-log.js +89 -53
- package/lib/log/service/index.js +1 -0
- package/lib/ql/CREATE.js +2 -5
- package/lib/ql/DELETE.js +1 -1
- package/lib/ql/DROP.js +1 -3
- package/lib/ql/INSERT.js +3 -3
- package/lib/ql/Query.js +10 -23
- package/lib/ql/SELECT.js +1 -2
- package/lib/ql/UPDATE.js +2 -2
- package/lib/ql/Whereable.js +7 -15
- package/lib/ql/cds-ql.js +9 -3
- package/lib/req/cds-context.js +11 -3
- package/lib/req/context.js +29 -23
- package/lib/req/locale.js +9 -5
- package/lib/req/request.js +1 -0
- package/lib/req/user.js +2 -1
- package/lib/srv/cds-connect.js +1 -1
- package/lib/srv/cds-serve.js +21 -14
- package/lib/srv/middlewares/cds-context.js +29 -0
- package/lib/srv/middlewares/ctx-model.js +24 -0
- package/lib/srv/middlewares/errors.js +9 -0
- package/lib/srv/middlewares/index.js +22 -0
- package/lib/srv/middlewares/sap-statistics.js +13 -0
- package/lib/srv/middlewares/trace.js +102 -0
- package/lib/srv/protocols/_legacy.js +42 -0
- package/lib/srv/protocols/graphql.js +39 -0
- package/lib/srv/protocols/hcql.js +37 -0
- package/lib/srv/protocols/index.js +86 -0
- package/lib/srv/protocols/odata-v2-proxy.js +3767 -0
- package/lib/srv/protocols/odata-v2.js +26 -0
- package/lib/srv/protocols/odata-v4.js +16 -0
- package/lib/srv/protocols/rest.js +13 -0
- package/lib/srv/srv-api.js +5 -0
- package/lib/srv/srv-models.js +4 -6
- package/lib/utils/axios.js +3 -2
- package/lib/utils/cds-test.js +27 -21
- package/lib/utils/cds-utils.js +19 -20
- package/lib/utils/tar.js +175 -0
- package/libx/_runtime/audit/generic/personal/utils.js +18 -7
- package/libx/_runtime/audit/utils/v2.js +1 -0
- package/libx/_runtime/auth/index.js +4 -0
- package/libx/_runtime/auth/strategies/ias-auth.js +76 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/error.js +8 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +15 -4
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/expandToCQN.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/orderByToCQN.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/utils.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/ResourcePathParser.js +9 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/UriInfo.js +5 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/UriParser.js +12 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/utils/BufferedWriter.js +6 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/validator/RequestValidator.js +47 -7
- package/libx/_runtime/cds-services/adapter/odata-v4/to.js +1 -1
- package/libx/_runtime/cds-services/util/assert.js +4 -0
- package/libx/_runtime/common/aspects/relation.js +1 -1
- package/libx/_runtime/common/composition/data.js +61 -15
- package/libx/_runtime/common/composition/delete.js +0 -1
- package/libx/_runtime/common/composition/insert.js +0 -1
- package/libx/_runtime/common/composition/tree.js +4 -10
- package/libx/_runtime/common/composition/update.js +44 -21
- package/libx/_runtime/common/generic/auth/capabilities.js +8 -10
- package/libx/_runtime/common/generic/crud.js +1 -2
- package/libx/_runtime/common/generic/etag.js +4 -4
- package/libx/_runtime/common/generic/input.js +4 -4
- package/libx/_runtime/common/generic/paging.js +3 -3
- package/libx/_runtime/common/generic/put.js +3 -3
- package/libx/_runtime/common/generic/sorting.js +4 -4
- package/libx/_runtime/common/generic/temporal.js +3 -3
- package/libx/_runtime/common/i18n/messages.properties +0 -7
- package/libx/_runtime/common/utils/cqn2cqn4sql.js +11 -6
- package/libx/_runtime/common/utils/csn.js +0 -28
- package/libx/_runtime/common/utils/draft.js +8 -1
- package/libx/_runtime/common/utils/path.js +7 -1
- package/libx/_runtime/common/utils/resolveView.js +2 -3
- package/libx/_runtime/db/data-conversion/post-processing.js +3 -44
- package/libx/_runtime/db/generic/input.js +3 -3
- package/libx/_runtime/db/sql-builder/dataTypes.js +4 -0
- package/libx/_runtime/fiori/generic/activate.js +2 -2
- package/libx/_runtime/fiori/generic/before.js +40 -72
- package/libx/_runtime/fiori/generic/cancel.js +2 -2
- package/libx/_runtime/fiori/generic/delete.js +2 -2
- package/libx/_runtime/fiori/generic/edit.js +2 -2
- package/libx/_runtime/fiori/generic/new.js +2 -2
- package/libx/_runtime/fiori/generic/patch.js +49 -37
- package/libx/_runtime/fiori/generic/prepare.js +2 -2
- package/libx/_runtime/fiori/generic/read.js +27 -37
- package/libx/_runtime/fiori/utils/where.js +4 -2
- package/libx/_runtime/hana/Service.js +1 -3
- package/libx/_runtime/hana/conversion.js +3 -0
- package/libx/_runtime/hana/driver.js +33 -3
- package/libx/_runtime/hana/dynatrace.js +1 -0
- package/libx/_runtime/hana/search2Contains.js +12 -1
- package/libx/_runtime/hana/search2cqn4sql.js +10 -27
- package/libx/_runtime/hana/streaming.js +1 -0
- package/libx/_runtime/messaging/AMQPWebhookMessaging.js +4 -2
- package/libx/_runtime/messaging/common-utils/AMQPClient.js +1 -0
- package/libx/_runtime/messaging/enterprise-messaging-utils/getTenantInfo.js +5 -2
- package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +2 -0
- package/libx/_runtime/messaging/enterprise-messaging.js +62 -3
- package/libx/_runtime/messaging/outbox/utils.js +1 -1
- package/libx/_runtime/messaging/redis-messaging.js +1 -0
- package/libx/_runtime/remote/Service.js +2 -2
- package/libx/_runtime/remote/utils/client.js +8 -3
- package/libx/_runtime/remote/utils/data.js +7 -2
- package/libx/_runtime/sqlite/Service.js +18 -7
- package/libx/_runtime/sqlite/conversion.js +3 -0
- package/libx/_runtime/sqlite/convertAssocToOneManaged.js +3 -3
- package/libx/_runtime/sqlite/localized.js +8 -8
- package/libx/odata/afterburner.js +39 -7
- package/libx/odata/cqn2odata.js +6 -3
- package/libx/odata/grammar.pegjs +66 -18
- package/libx/odata/index.js +3 -2
- package/libx/odata/parser.js +1 -1
- package/libx/odata/utils.js +2 -0
- package/libx/rest/RestAdapter.js +62 -43
- package/libx/rest/middleware/parse.js +2 -1
- package/libx/rest/middleware/update.js +1 -1
- package/package.json +2 -2
- package/server.js +5 -4
- package/srv/mtx.cds +1 -1
- package/srv/mtx.js +4 -33
- package/lib/srv/adapters.js +0 -85
- package/lib/utils/resources/index.js +0 -48
- package/lib/utils/resources/tar.js +0 -49
- package/lib/utils/resources/utils.js +0 -11
- package/libx/_runtime/extensibility/activate.js +0 -69
- package/libx/_runtime/extensibility/add.js +0 -50
- package/libx/_runtime/extensibility/addExtension.js +0 -72
- package/libx/_runtime/extensibility/defaults.js +0 -34
- package/libx/_runtime/extensibility/handler/transformREAD.js +0 -121
- package/libx/_runtime/extensibility/handler/transformRESULT.js +0 -51
- package/libx/_runtime/extensibility/handler/transformWRITE.js +0 -64
- package/libx/_runtime/extensibility/linter/allowlist_checker.js +0 -373
- package/libx/_runtime/extensibility/linter/annotations_checker.js +0 -113
- package/libx/_runtime/extensibility/linter/checker_base.js +0 -20
- package/libx/_runtime/extensibility/linter/namespace_checker.js +0 -180
- package/libx/_runtime/extensibility/linter.js +0 -32
- package/libx/_runtime/extensibility/push.js +0 -118
- package/libx/_runtime/extensibility/service.js +0 -38
- package/libx/_runtime/extensibility/token.js +0 -57
- package/libx/_runtime/extensibility/utils.js +0 -131
- package/libx/_runtime/extensibility/validation.js +0 -50
- package/libx/_runtime/extensibility/views.js +0 -12
- package/srv/extensibility-service.cds +0 -60
- package/srv/extensibility-service.js +0 -1
- package/srv/extensions.cds +0 -8
- package/srv/model-provider.cds +0 -61
- package/srv/model-provider.js +0 -143
|
@@ -1,40 +1,25 @@
|
|
|
1
1
|
const cds = require('../../cds')
|
|
2
2
|
const { UPDATE, SELECT } = cds.ql
|
|
3
3
|
|
|
4
|
-
const { getUpdateDraftAdminCQN, ensureDraftsSuffix
|
|
5
|
-
const {
|
|
6
|
-
const {
|
|
7
|
-
const {
|
|
8
|
-
|
|
9
|
-
const _getSelectCQN = (
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
getColumns(model.definitions[activeName], { removeIgnore: true, filterVirtual: true }).map(obj => obj.name),
|
|
16
|
-
draftName
|
|
17
|
-
),
|
|
18
|
-
...DRAFT_COLUMNS_CQN
|
|
19
|
-
]
|
|
20
|
-
|
|
21
|
-
if (checkUser) {
|
|
22
|
-
columns.push({ ref: ['DRAFT.DraftAdministrativeData', 'inProcessByUser'], as: 'draftAdmin_inProcessByUser' })
|
|
4
|
+
const { getUpdateDraftAdminCQN, ensureDraftsSuffix } = require('../utils/handler')
|
|
5
|
+
const { removeIsActiveEntityRecursively } = require('../utils/where')
|
|
6
|
+
const { deepCopyArray } = require('../../common/utils/copy')
|
|
7
|
+
const { cqn2cqn4sql } = require('../../common/utils/cqn2cqn4sql')
|
|
8
|
+
|
|
9
|
+
const _getSelectCQN = ({ query }) => {
|
|
10
|
+
const fromRef = deepCopyArray(query.UPDATE.entity.ref)
|
|
11
|
+
for (const item of fromRef) {
|
|
12
|
+
if (item.where) {
|
|
13
|
+
item.where = removeIsActiveEntityRecursively(item.where)
|
|
14
|
+
}
|
|
23
15
|
}
|
|
16
|
+
fromRef[0].id = ensureDraftsSuffix(fromRef[0].id)
|
|
17
|
+
const from = { ref: fromRef }
|
|
24
18
|
|
|
25
|
-
|
|
26
|
-
return SELECT.one(draftName)
|
|
27
|
-
.columns(columns)
|
|
28
|
-
.join('DRAFT.DraftAdministrativeData')
|
|
29
|
-
.on([
|
|
30
|
-
{ ref: [draftName, 'DraftAdministrativeData_DraftUUID'] },
|
|
31
|
-
'=',
|
|
32
|
-
{ ref: ['DRAFT.DraftAdministrativeData', 'DraftUUID'] }
|
|
33
|
-
])
|
|
34
|
-
.where(keysCondition)
|
|
19
|
+
return SELECT.from(from)
|
|
35
20
|
}
|
|
36
21
|
|
|
37
|
-
const _getUpdateDraftCQN = ({ query
|
|
22
|
+
const _getUpdateDraftCQN = ({ query }, where, targetRef) => {
|
|
38
23
|
const set = {}
|
|
39
24
|
|
|
40
25
|
for (const entry in query.UPDATE.data) {
|
|
@@ -46,7 +31,23 @@ const _getUpdateDraftCQN = ({ query, target: { name } }, keysCondition) => {
|
|
|
46
31
|
}
|
|
47
32
|
|
|
48
33
|
if (set.IsActiveEntity) set.IsActiveEntity = false
|
|
49
|
-
|
|
34
|
+
|
|
35
|
+
return UPDATE(targetRef).data(set).where(where)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const _joinDraftAdministrativeData = (selectResolved, target) => {
|
|
39
|
+
const columns = []
|
|
40
|
+
columns.push({ ref: ['DRAFT.DraftAdministrativeData', 'inProcessByUser'], as: 'draftAdmin_inProcessByUser' })
|
|
41
|
+
columns.push({ ref: [target, 'DraftAdministrativeData_DraftUUID'] })
|
|
42
|
+
|
|
43
|
+
return selectResolved
|
|
44
|
+
.columns(columns)
|
|
45
|
+
.join('DRAFT.DraftAdministrativeData')
|
|
46
|
+
.on([
|
|
47
|
+
{ ref: [target, 'DraftAdministrativeData_DraftUUID'] },
|
|
48
|
+
'=',
|
|
49
|
+
{ ref: ['DRAFT.DraftAdministrativeData', 'DraftUUID'] }
|
|
50
|
+
])
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
/**
|
|
@@ -57,20 +58,31 @@ const _getUpdateDraftCQN = ({ query, target: { name } }, keysCondition) => {
|
|
|
57
58
|
*
|
|
58
59
|
* @param req
|
|
59
60
|
*/
|
|
60
|
-
const
|
|
61
|
+
const fioriGenericPatch = async function (req) {
|
|
61
62
|
if (req.data.IsActiveEntity === true) req.reject(400, 'Patch can only be applied to a draft entity')
|
|
62
63
|
|
|
63
|
-
const keysCondition = getKeysCondition(req.target, req.data)
|
|
64
64
|
const dbtx = cds.tx(req)
|
|
65
|
-
|
|
65
|
+
|
|
66
|
+
const selectResolved = cqn2cqn4sql(_getSelectCQN(req), this.model)
|
|
67
|
+
|
|
68
|
+
const targetName = selectResolved.SELECT.from.ref[selectResolved.SELECT.from.ref.length - 1]
|
|
69
|
+
const alias = selectResolved.SELECT.from.as
|
|
70
|
+
const selectWithAdmin = _joinDraftAdministrativeData(selectResolved, alias || targetName)
|
|
71
|
+
const results = await dbtx.run(selectWithAdmin)
|
|
72
|
+
|
|
73
|
+
if (results.length === 0) req.reject(404)
|
|
74
|
+
|
|
75
|
+
const result = results[0]
|
|
66
76
|
|
|
67
77
|
// Potential timeout scenario supported
|
|
68
78
|
if (result.draftAdmin_inProcessByUser && result.draftAdmin_inProcessByUser !== req.user.id) {
|
|
69
79
|
// REVISIT: security log?
|
|
70
80
|
req.reject(403)
|
|
71
81
|
}
|
|
72
|
-
|
|
73
|
-
|
|
82
|
+
const updateDraftCQN = _getUpdateDraftCQN(req, selectResolved.SELECT.where, {
|
|
83
|
+
ref: [targetName],
|
|
84
|
+
as: alias || targetName
|
|
85
|
+
})
|
|
74
86
|
const updateDraftAdminCQN = getUpdateDraftAdminCQN(req, result.DraftAdministrativeData_DraftUUID)
|
|
75
87
|
|
|
76
88
|
await Promise.all([dbtx.run(updateDraftCQN), dbtx.run(updateDraftAdminCQN)])
|
|
@@ -80,5 +92,5 @@ const _handler = async function (req) {
|
|
|
80
92
|
}
|
|
81
93
|
|
|
82
94
|
module.exports = cds.service.impl(function (srv, entity) {
|
|
83
|
-
srv.on('PATCH', entity,
|
|
95
|
+
srv.on('PATCH', entity, fioriGenericPatch)
|
|
84
96
|
})
|
|
@@ -11,7 +11,7 @@ const { getColumns } = require('../../cds-services/services/utils/columns')
|
|
|
11
11
|
*
|
|
12
12
|
* @param req
|
|
13
13
|
*/
|
|
14
|
-
const
|
|
14
|
+
const fioriGenericPrepare = async function (req) {
|
|
15
15
|
if (req.query.SELECT.from.ref.length > 1 || isActiveEntityRequested(req.query.SELECT.from.ref[0].where || [])) {
|
|
16
16
|
req.reject(400, 'Action "draftPrepare" can only be called on a draft entity')
|
|
17
17
|
}
|
|
@@ -44,5 +44,5 @@ const _handler = async function (req) {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
module.exports = cds.service.impl(function (srv, entity) {
|
|
47
|
-
srv.on('draftPrepare', entity,
|
|
47
|
+
srv.on('draftPrepare', entity, fioriGenericPrepare)
|
|
48
48
|
})
|
|
@@ -4,6 +4,7 @@ const { SELECT } = cds.ql
|
|
|
4
4
|
const { cqn2cqn4sql, convertWhereExists } = require('../../common/utils/cqn2cqn4sql')
|
|
5
5
|
const { getElementDeep } = require('../../common/utils/csn')
|
|
6
6
|
const { DRAFT_COLUMNS_MAP, SCENARIO } = require('../../common/constants/draft')
|
|
7
|
+
const { filterNonDraftColumns } = require('../../common/utils/draft')
|
|
7
8
|
const {
|
|
8
9
|
addColumnAlias,
|
|
9
10
|
draftIsLocked,
|
|
@@ -16,15 +17,11 @@ const {
|
|
|
16
17
|
filterKeys
|
|
17
18
|
} = require('../utils/handler')
|
|
18
19
|
const { deleteCondition, readAndDeleteKeywords, removeIsActiveEntityRecursively } = require('../utils/where')
|
|
19
|
-
const { getColumns } = require('../../cds-services/services/utils/columns')
|
|
20
20
|
const { adaptStreamCQN } = require('../../cds-services/adapter/odata-v4/utils/stream')
|
|
21
21
|
|
|
22
22
|
const _findSubselect = where => {
|
|
23
23
|
return where.find((e, i) => {
|
|
24
|
-
if (e.xpr)
|
|
25
|
-
return _findSubselect(e.xpr)
|
|
26
|
-
}
|
|
27
|
-
|
|
24
|
+
if (e.xpr) return _findSubselect(e.xpr)
|
|
28
25
|
return e.SELECT && where[i - 1] === 'exists'
|
|
29
26
|
})
|
|
30
27
|
}
|
|
@@ -626,6 +623,9 @@ const _siblingEntity = (
|
|
|
626
623
|
|
|
627
624
|
if (siblingIndex === 0) {
|
|
628
625
|
const columnCqnPartial = columns.map(col => {
|
|
626
|
+
if (col.val) {
|
|
627
|
+
return Object.assign({}, col)
|
|
628
|
+
}
|
|
629
629
|
const colName = col.ref ? col.ref[col.ref.length - 1] : col
|
|
630
630
|
const ref = col.ref ? [table.as, ...col.ref] : [table.as, colName]
|
|
631
631
|
return Object.assign({}, col, { ref })
|
|
@@ -694,7 +694,7 @@ function _siblingSubScenario(nav, siblingIndex, siblingQuery, target, params, mo
|
|
|
694
694
|
const existsIdx = siblingQuery.SELECT.where.indexOf('exists')
|
|
695
695
|
if (existsIdx > -1) subReq.query.where(siblingQuery.SELECT.where.slice(existsIdx, existsIdx + 2))
|
|
696
696
|
const subOrigFrom = { ref: [...subNav].reverse() }
|
|
697
|
-
subScenario = _generateCQN(
|
|
697
|
+
subScenario = _generateCQN(subReq, [{ val: 1 }], subOrigFrom, model)
|
|
698
698
|
subScenario.cqn.where(onCond)
|
|
699
699
|
}
|
|
700
700
|
|
|
@@ -757,9 +757,8 @@ const _replaceWhereExists = (query, _siblingIndex, siblingCQN) => {
|
|
|
757
757
|
}
|
|
758
758
|
}
|
|
759
759
|
|
|
760
|
-
const _mergeSiblingIntoCQN = (cqn, { cqn: siblingCQN }, siblingIndex) =>
|
|
761
|
-
|
|
762
|
-
}
|
|
760
|
+
const _mergeSiblingIntoCQN = (cqn, { cqn: siblingCQN }, siblingIndex) =>
|
|
761
|
+
_replaceWhereExists(cqn, siblingIndex, siblingCQN)
|
|
763
762
|
|
|
764
763
|
const _getDraftDoc = (req, draftName, draftWhere) => {
|
|
765
764
|
const refDraft = req.query.SELECT.from.as ? { ref: [draftName], as: req.query.SELECT.from.as } : draftName
|
|
@@ -784,8 +783,10 @@ const _getDraftDoc = (req, draftName, draftWhere) => {
|
|
|
784
783
|
|
|
785
784
|
const _getOrderByEnrichedColumns = (orderBy, columns, entity) => {
|
|
786
785
|
const enrichedCol = []
|
|
786
|
+
|
|
787
787
|
if (orderBy && orderBy.length > 1) {
|
|
788
788
|
const colNames = columns.map(el => el.ref[el.ref.length - 1])
|
|
789
|
+
|
|
789
790
|
// REVISIT: GET Books?$select=title&$expand=NotBooks($select=pages)&$orderby=NotBooks/title - what's then?
|
|
790
791
|
for (const el of orderBy) {
|
|
791
792
|
// For associations we need to 'materialise' the resulting field, otherwise we cannot access it in an outer SELECT.
|
|
@@ -906,11 +907,11 @@ const _getUnionCQN = (req, draftName, columns, subSelect, draftWhere, model, ent
|
|
|
906
907
|
}
|
|
907
908
|
|
|
908
909
|
return union
|
|
909
|
-
.columns(...columns)
|
|
910
|
+
.columns(...columns.map(ref => (ref.as ? { ref: [ref.as], as: ref.as } : ref))) // needed for aliased stream property ref@odata.mediaContentType
|
|
910
911
|
.columns(..._filterDraftColumnsBySelected(DRAFT_COLUMNS_CASTED, req.query.SELECT.columns))
|
|
911
912
|
}
|
|
912
913
|
|
|
913
|
-
const _excludeActiveDraftExists = (req,
|
|
914
|
+
const _excludeActiveDraftExists = (req, columns, draftWhere, model) => {
|
|
914
915
|
const { table, name } = _getTableName(req, true)
|
|
915
916
|
const draftName = table.ref[0]
|
|
916
917
|
|
|
@@ -964,8 +965,9 @@ const _validatedWithSiblingInProcess = (req, draftWhere, draftParameters, column
|
|
|
964
965
|
if (
|
|
965
966
|
!draftInProcessByUser &&
|
|
966
967
|
_isValidExcludeActiveDraftExists(draftParameters.isActiveEntity, draftParameters.siblingIsActive)
|
|
967
|
-
)
|
|
968
|
-
return _excludeActiveDraftExists(req,
|
|
968
|
+
) {
|
|
969
|
+
return _excludeActiveDraftExists(req, columns, draftWhere, model)
|
|
970
|
+
}
|
|
969
971
|
|
|
970
972
|
if (
|
|
971
973
|
draftInProcessByUser &&
|
|
@@ -1005,8 +1007,8 @@ const _draftInSubSelect = (where, req) => {
|
|
|
1005
1007
|
const _isDraftAdminScenario = req =>
|
|
1006
1008
|
req.target.query && req.target.query._target && req.target.query._target.name === 'DRAFT.DraftAdministrativeData'
|
|
1007
1009
|
|
|
1008
|
-
const _generateCQN = (
|
|
1009
|
-
const nav = [...
|
|
1010
|
+
const _generateCQN = (req, columns, from, model) => {
|
|
1011
|
+
const nav = [...from.ref].reverse() || []
|
|
1010
1012
|
let siblingIndex = nav.indexOf('SiblingEntity')
|
|
1011
1013
|
|
|
1012
1014
|
// it can also be a property access (new parser), then we must shift it
|
|
@@ -1018,20 +1020,12 @@ const _generateCQN = (originalFrom, req, columns, model) => {
|
|
|
1018
1020
|
let siblingScenario
|
|
1019
1021
|
if (siblingIndex > -1) {
|
|
1020
1022
|
siblingScenario = _getSiblingScenario(req, columns, model, siblingIndex, nav)
|
|
1021
|
-
if (siblingIndex === 0)
|
|
1022
|
-
return siblingScenario
|
|
1023
|
-
}
|
|
1024
|
-
|
|
1023
|
+
if (siblingIndex === 0) return siblingScenario
|
|
1025
1024
|
_mergeSiblingIntoCQN(req.query, siblingScenario, siblingIndex - 1)
|
|
1026
1025
|
}
|
|
1027
1026
|
|
|
1028
|
-
if (_isDraftAdminScenario(req))
|
|
1029
|
-
|
|
1030
|
-
}
|
|
1031
|
-
|
|
1032
|
-
if (!req.query.SELECT.where) {
|
|
1033
|
-
return _allActive(req, columns)
|
|
1034
|
-
}
|
|
1027
|
+
if (_isDraftAdminScenario(req)) return _draftAdminTable(req)
|
|
1028
|
+
if (!req.query.SELECT.where) return _allActive(req, columns)
|
|
1035
1029
|
|
|
1036
1030
|
// REVISIT this function does not only read, but modifies where!
|
|
1037
1031
|
const draftParameters = _readDraftParameters(req.query.SELECT.where)
|
|
@@ -1065,11 +1059,6 @@ const _generateCQN = (originalFrom, req, columns, model) => {
|
|
|
1065
1059
|
return _validatedDraftOfWhichIAmOwner(req, req.query.SELECT.where, draftParameters, columns)
|
|
1066
1060
|
}
|
|
1067
1061
|
|
|
1068
|
-
const _getColumns = ({ query: { SELECT } }) =>
|
|
1069
|
-
SELECT.columns.filter(
|
|
1070
|
-
col => (col.ref && !(col.ref[col.ref.length - 1] in DRAFT_COLUMNS_MAP)) || (!col.ref && !(col in DRAFT_COLUMNS_MAP))
|
|
1071
|
-
)
|
|
1072
|
-
|
|
1073
1062
|
const _isIsActiveEntity = element => element.ref && element.ref[element.ref.length - 1] === 'IsActiveEntity'
|
|
1074
1063
|
|
|
1075
1064
|
const _adaptSubSelects = ({ SELECT: { from, where } }, scenario) => {
|
|
@@ -1182,6 +1171,7 @@ const _setLastSubQuery = (query, last, prev = query) => {
|
|
|
1182
1171
|
const _adaptDraftAdminExpand = cqn => {
|
|
1183
1172
|
const draftAdminExpand =
|
|
1184
1173
|
cqn.SELECT.columns && cqn.SELECT.columns.find(c => c.expand && c.ref[0] === 'DraftAdministrativeData')
|
|
1174
|
+
|
|
1185
1175
|
if (draftAdminExpand) {
|
|
1186
1176
|
_ensureDraftAdminColumnsForCalculation(draftAdminExpand.expand)
|
|
1187
1177
|
}
|
|
@@ -1274,7 +1264,7 @@ const _adaptColumns4readAfterWrite = (req, cqnScenario, query4sql) => {
|
|
|
1274
1264
|
*
|
|
1275
1265
|
* @param req
|
|
1276
1266
|
*/
|
|
1277
|
-
const
|
|
1267
|
+
const fioriGenericRead = async function (req) {
|
|
1278
1268
|
const query = req.query
|
|
1279
1269
|
const originalFrom = _copyCQNPartial(query.SELECT.from)
|
|
1280
1270
|
|
|
@@ -1299,12 +1289,12 @@ const _handler = async function (req) {
|
|
|
1299
1289
|
// just to make existing tests working with new parser. not really tested, not needed to be supported
|
|
1300
1290
|
if (reqClone.query.SELECT.from.SELECT) {
|
|
1301
1291
|
const subQueryReq = { __proto__: req, query: _copyCQNPartial(_getLastSubQuery(reqClone.query)) }
|
|
1302
|
-
const
|
|
1303
|
-
cqnScenario = _generateCQN(originalFrom.SELECT.from,
|
|
1292
|
+
const nonDraftColumns = filterNonDraftColumns(subQueryReq.query.SELECT.columns)
|
|
1293
|
+
cqnScenario = _generateCQN(subQueryReq, nonDraftColumns, originalFrom.SELECT.from, this.model)
|
|
1304
1294
|
cqnScenario.cqn = _setLastSubQuery(reqClone.query, cqnScenario.cqn)
|
|
1305
1295
|
} else {
|
|
1306
|
-
const
|
|
1307
|
-
cqnScenario = _generateCQN(
|
|
1296
|
+
const nonDraftColumns = filterNonDraftColumns(reqClone.query.SELECT.columns)
|
|
1297
|
+
cqnScenario = _generateCQN(reqClone, nonDraftColumns, originalFrom, this.model)
|
|
1308
1298
|
}
|
|
1309
1299
|
|
|
1310
1300
|
if (!cqnScenario) req.reject(400)
|
|
@@ -1334,5 +1324,5 @@ const _handler = async function (req) {
|
|
|
1334
1324
|
}
|
|
1335
1325
|
|
|
1336
1326
|
module.exports = cds.service.impl(function (srv, entity) {
|
|
1337
|
-
srv.on('READ', entity,
|
|
1327
|
+
srv.on('READ', entity, fioriGenericRead)
|
|
1338
1328
|
})
|
|
@@ -210,11 +210,13 @@ const extractKeyConditions = whereCondition => {
|
|
|
210
210
|
return result
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
-
const getKeysCondition =
|
|
213
|
+
const getKeysCondition = req => {
|
|
214
|
+
const data = req.data
|
|
215
|
+
const target = req.target
|
|
214
216
|
const where = []
|
|
215
217
|
for (const k in target.keys) {
|
|
216
218
|
const key = target.keys[k]
|
|
217
|
-
if (!key.isAssociation && key.name !== 'IsActiveEntity') {
|
|
219
|
+
if (!key.isAssociation && key.name !== 'IsActiveEntity' && data[key.name] != undefined) {
|
|
218
220
|
if (where.length) where.push('and')
|
|
219
221
|
where.push({ ref: [key.name] }, '=', { val: data[key.name] })
|
|
220
222
|
}
|
|
@@ -163,10 +163,8 @@ class HanaDatabase extends DatabaseService {
|
|
|
163
163
|
}
|
|
164
164
|
|
|
165
165
|
// REVISIT: should happen automatically after a configurable time
|
|
166
|
-
|
|
167
|
-
async disconnect(tenant, poolOnly) {
|
|
166
|
+
async disconnect(tenant) {
|
|
168
167
|
await pool.drain(tenant)
|
|
169
|
-
if (!poolOnly) super.disconnect(tenant)
|
|
170
168
|
}
|
|
171
169
|
}
|
|
172
170
|
|
|
@@ -55,6 +55,7 @@ const convertToString = element => {
|
|
|
55
55
|
const HANA_TYPE_CONVERSION_MAP = new Map([
|
|
56
56
|
['cds.Boolean', convertToBoolean],
|
|
57
57
|
['cds.Integer64', convertInt64ToString],
|
|
58
|
+
['cds.Int64', convertInt64ToString],
|
|
58
59
|
['cds.DateTime', convertToISONoMillis],
|
|
59
60
|
['cds.Timestamp', convertToISO],
|
|
60
61
|
['cds.LargeString', convertToString],
|
|
@@ -62,10 +63,12 @@ const HANA_TYPE_CONVERSION_MAP = new Map([
|
|
|
62
63
|
])
|
|
63
64
|
|
|
64
65
|
if (cds.env.features.bigjs) {
|
|
66
|
+
// eslint-disable-next-line cds/no-missing-dependencies -- needs to be added by app dev
|
|
65
67
|
const Big = require('big.js')
|
|
66
68
|
const convertToBig = value => new Big(value)
|
|
67
69
|
|
|
68
70
|
HANA_TYPE_CONVERSION_MAP.set('cds.Integer64', convertToBig)
|
|
71
|
+
HANA_TYPE_CONVERSION_MAP.set('cds.Int64', convertToBig)
|
|
69
72
|
HANA_TYPE_CONVERSION_MAP.set('cds.Decimal', convertToBig)
|
|
70
73
|
}
|
|
71
74
|
|
|
@@ -129,9 +129,37 @@ function _connectHanaClient(creds, tenant) {
|
|
|
129
129
|
|
|
130
130
|
let driver
|
|
131
131
|
|
|
132
|
-
const _getHanaDriver =
|
|
132
|
+
const _getHanaDriver = name => {
|
|
133
133
|
if (driver) return driver
|
|
134
134
|
|
|
135
|
+
let isConfigured = false
|
|
136
|
+
if (!name) {
|
|
137
|
+
let packageJson
|
|
138
|
+
try {
|
|
139
|
+
packageJson = require(cds.root + '/package.json')
|
|
140
|
+
} catch (e) {
|
|
141
|
+
LOG._debug && LOG.debug(`Could not find package.json. Trying to lookup hana driver automatically.`)
|
|
142
|
+
name = 'hdb'
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (packageJson?.dependencies?.hdb) {
|
|
146
|
+
LOG._debug && LOG.debug(`"hdb" found in dependencies of "${cds.root}".`)
|
|
147
|
+
name = 'hdb'
|
|
148
|
+
isConfigured = true
|
|
149
|
+
} else if (packageJson?.dependencies?.['@sap/hana-client']) {
|
|
150
|
+
LOG._debug && LOG.debug(`"@sap/hana-client" found in dependencies of "${cds.root}".`)
|
|
151
|
+
name = '@sap/hana-client'
|
|
152
|
+
isConfigured = true
|
|
153
|
+
} else if (!name) {
|
|
154
|
+
LOG._debug &&
|
|
155
|
+
LOG.debug(
|
|
156
|
+
`Neither "hdb" nor "@sap/hana-client" found in dependencies of "${cds.root}". Trying to lookup hana driver automatically.`
|
|
157
|
+
)
|
|
158
|
+
// fallback to hdb in case both are not provided, which will fallback to @sap/hana-client if hdb is not installed
|
|
159
|
+
name = 'hdb'
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
135
163
|
try {
|
|
136
164
|
driver = Object.assign({ name }, require(name))
|
|
137
165
|
|
|
@@ -161,9 +189,11 @@ const _getHanaDriver = (name = 'hdb') => {
|
|
|
161
189
|
|
|
162
190
|
return driver
|
|
163
191
|
} catch (e) {
|
|
164
|
-
if (name === 'hdb') {
|
|
192
|
+
if (name === 'hdb' && !isConfigured) {
|
|
165
193
|
LOG._debug && LOG.debug(`Failed to require "hdb" with error "${e.message}". Trying "@sap/hana-client" next.`)
|
|
166
194
|
return _getHanaDriver('@sap/hana-client')
|
|
195
|
+
} else if (isConfigured) {
|
|
196
|
+
throw new Error(`"${name}" could not be required. Please make sure it is installed.`)
|
|
167
197
|
} else {
|
|
168
198
|
throw new Error(
|
|
169
199
|
'Neither "hdb" nor "@sap/hana-client" could be required. Please make sure one of them is installed.'
|
|
@@ -172,4 +202,4 @@ const _getHanaDriver = (name = 'hdb') => {
|
|
|
172
202
|
}
|
|
173
203
|
}
|
|
174
204
|
|
|
175
|
-
module.exports = _getHanaDriver(
|
|
205
|
+
module.exports = _getHanaDriver()
|
|
@@ -59,7 +59,7 @@ const search2Contains = (cqnSearchPhrase, columns) => {
|
|
|
59
59
|
return expression
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
const isContainsPredicateSupported = query => {
|
|
62
|
+
const isContainsPredicateSupported = (query, entity, columns2Search) => {
|
|
63
63
|
const cqnSearchPhrase = query.SELECT.search
|
|
64
64
|
|
|
65
65
|
if (cqnSearchPhrase && cqnSearchPhrase[0] && cqnSearchPhrase[0].val === ' ') return false
|
|
@@ -84,9 +84,20 @@ const isContainsPredicateSupported = query => {
|
|
|
84
84
|
// brackets are not supported as search operators in SAP HANA
|
|
85
85
|
if (cqnSearchPhrase.some(searchXpr => searchXpr.xpr)) return false
|
|
86
86
|
|
|
87
|
+
// join not optimized
|
|
88
|
+
if (entity.query?.SELECT.from.join) return false
|
|
89
|
+
|
|
90
|
+
// the CONTAINS function does not interoperate with columns that use the CONCAT function
|
|
91
|
+
if (_isColumnFunc(columns2Search, entity.query?.SELECT.columns)) return false
|
|
87
92
|
return true
|
|
88
93
|
}
|
|
89
94
|
|
|
95
|
+
const _isColumnFunc = (columns2Search, columnsDefs) =>
|
|
96
|
+
columns2Search.some(column2Search => {
|
|
97
|
+
if (column2Search.func) return true
|
|
98
|
+
return columnsDefs?.some(columnDef => columnDef.func && columnDef.as === column2Search.ref[0])
|
|
99
|
+
})
|
|
100
|
+
|
|
90
101
|
module.exports = {
|
|
91
102
|
isContainsPredicateSupported,
|
|
92
103
|
search2Contains
|
|
@@ -25,35 +25,29 @@ const search2cqn4sql = (query, entity, options) => {
|
|
|
25
25
|
if (!cqnSearchPhrase) return query
|
|
26
26
|
|
|
27
27
|
let { columns: columns2Search = computeColumnsToBeSearched(query, entity), locale } = options
|
|
28
|
-
const localizedAssociation =
|
|
28
|
+
const localizedAssociation = entity.associations?.localized
|
|
29
29
|
|
|
30
|
-
//
|
|
31
|
-
// there should be at least one localized element.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
// suppress the localize handler from redirecting the query's target to the localized view
|
|
35
|
-
Object.defineProperty(query, '_suppressLocalization', { value: true })
|
|
36
|
-
|
|
37
|
-
const columnsDefs = entity.query && entity.query.SELECT.columns
|
|
38
|
-
const isSomeColumn2SearchUseFunction = _isSomeColumn2SearchAFunction(columns2Search, columnsDefs)
|
|
39
|
-
|
|
40
|
-
if (resolveLocalizedDataAtRuntime) {
|
|
30
|
+
// Resolve localized data at runtime if the localized association is defined for the target entity.
|
|
31
|
+
// Notice that if the localized association is defined, there should be at least one localized element.
|
|
32
|
+
if (localizedAssociation) {
|
|
41
33
|
const onCondition = entity._relations[localizedAssociation.name].join(localizedAssociation.target, entity.name)
|
|
42
34
|
|
|
43
35
|
// REVISIT this is dirty but works for now
|
|
44
36
|
// replace $user_locale placeholder with the user locale or the HANA session context
|
|
45
37
|
onCondition[0].xpr[onCondition[0].xpr.length - 1] = { val: locale || "SESSION_CONTEXT('LOCALE')" }
|
|
46
38
|
|
|
47
|
-
// inner join the target table with the _texts table (the _texts table contains
|
|
48
|
-
// the translated texts)
|
|
39
|
+
// inner join the target table with the _texts table (the _texts table contains the translated texts)
|
|
49
40
|
const localizedEntityName = localizedAssociation.target
|
|
50
41
|
query.join(localizedEntityName).on(onCondition)
|
|
51
42
|
|
|
52
43
|
// prevent SQL ambiguity error for columns with the same name
|
|
53
44
|
columns2Search = _addAliasToQuery(query, entity, columns2Search)
|
|
45
|
+
|
|
46
|
+
// suppress the localize handler from redirecting the query's target to the localized view
|
|
47
|
+
Object.defineProperty(query, '_suppressLocalization', { value: true })
|
|
54
48
|
} // else --> resolve localized texts via localized view (default)
|
|
55
49
|
|
|
56
|
-
const useContains =
|
|
50
|
+
const useContains = !!localizedAssociation && isContainsPredicateSupported(query, entity, columns2Search)
|
|
57
51
|
let expression
|
|
58
52
|
|
|
59
53
|
if (useContains) {
|
|
@@ -70,23 +64,12 @@ const search2cqn4sql = (query, entity, options) => {
|
|
|
70
64
|
return query
|
|
71
65
|
}
|
|
72
66
|
|
|
73
|
-
const _isSomeColumn2SearchAFunction = (columns2Search, columnsDefs) =>
|
|
74
|
-
columns2Search.some(column2Search => {
|
|
75
|
-
if (column2Search.func) return true
|
|
76
|
-
return columnsDefs && columnsDefs.some(columnDef => columnDef.func && columnDef.as === column2Search.ref[0])
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
const _getLocalizedAssociation = entity => {
|
|
80
|
-
const associations = entity.associations
|
|
81
|
-
return associations && associations.localized
|
|
82
|
-
}
|
|
83
|
-
|
|
84
67
|
// The inner join modifies the original SELECT ... FROM query and adds ambiguity,
|
|
85
68
|
// therefore add the table/entity name (as a preceding element) to the columns ref
|
|
86
69
|
// to prevent a SQL ambiguity error.
|
|
87
70
|
const _addAliasToQuery = (query, entity, columnsToBeSearched) => {
|
|
88
71
|
const SELECT = query.SELECT
|
|
89
|
-
const localizedEntityName =
|
|
72
|
+
const localizedEntityName = entity.associations?.localized.target
|
|
90
73
|
const elements = entity.elements
|
|
91
74
|
const entityName = entity.name
|
|
92
75
|
const getEntityName = columnRef => {
|
|
@@ -9,6 +9,7 @@ const STREAM_PLACEHOLDER = '[<stream>]'
|
|
|
9
9
|
const _loadStreamExtensionIfNeeded = () => {
|
|
10
10
|
const hana = require('./driver')
|
|
11
11
|
if (hana.name !== 'hdb') {
|
|
12
|
+
// eslint-disable-next-line cds/no-missing-dependencies -- needs to be added by app dev
|
|
12
13
|
const extension = require('@sap/hana-client/extension/Stream.js')
|
|
13
14
|
return isDynatraceEnabled() ? dynatraceStreamingExtension(extension) : extension
|
|
14
15
|
}
|
|
@@ -39,8 +39,10 @@ class AMQPWebhookMessaging extends MessagingService {
|
|
|
39
39
|
|
|
40
40
|
startListening(opt = {}) {
|
|
41
41
|
if (!this.subscribedTopics.size) return
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
if (!opt.doNotDeploy) {
|
|
43
|
+
const management = this.getManagement()
|
|
44
|
+
this.queued(management.createQueueAndSubscriptions.bind(management))()
|
|
45
|
+
}
|
|
44
46
|
this.queued(this.listenToClient.bind(this))(async (_topic, _payload, _other, { done, failed }) => {
|
|
45
47
|
const msg = Object.assign(normalizeIncomingMessage(_payload), _other || {})
|
|
46
48
|
msg.event = _topic
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const cds = require('../../cds.js')
|
|
2
|
+
// eslint-disable-next-line cds/no-missing-dependencies -- needs to be added by app dev
|
|
2
3
|
const ClientAmqp = require('@sap/xb-msg-amqp-v100').Client
|
|
3
4
|
const { connect, disconnect } = require('./connections')
|
|
4
5
|
const { hasPersistentOutbox } = require('../outbox/utils')
|
|
@@ -2,11 +2,14 @@ const cds = require('../../cds')
|
|
|
2
2
|
const _transform = o => ({ subdomain: o.subscribedSubdomain, tenant: o.subscribedTenantId })
|
|
3
3
|
|
|
4
4
|
const getTenantInfo = async tenant => {
|
|
5
|
-
const
|
|
5
|
+
const provisioningServiceName = cds.mtx ? 'ProvisioningService' : 'cds.xt.SaasProvisioningService'
|
|
6
|
+
const primaryKey = cds.mtx ? 'ID' : 'subscribedTenantId'
|
|
7
|
+
|
|
8
|
+
const provisioning = await cds.connect.to(provisioningServiceName)
|
|
6
9
|
const tx = provisioning.tx({ user: new cds.User.Privileged() })
|
|
7
10
|
try {
|
|
8
11
|
const result = tenant
|
|
9
|
-
? _transform(await tx.get(`tenant`, {
|
|
12
|
+
? _transform(await tx.get(`tenant`, { [primaryKey]: tenant }))
|
|
10
13
|
: (await tx.read('tenant')).map(o => _transform(o))
|
|
11
14
|
await tx.commit()
|
|
12
15
|
return result
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const cds = require('../../cds.js')
|
|
2
|
+
// eslint-disable-next-line cds/no-missing-dependencies -- needs to be added by app dev
|
|
2
3
|
const express = require('express')
|
|
3
4
|
const getTenantInfo = require('./getTenantInfo.js')
|
|
4
5
|
const isSecured = () => cds.requires.auth && cds.requires.auth.credentials
|
|
@@ -14,6 +15,7 @@ class EndpointRegistry {
|
|
|
14
15
|
this.deployCallbacks = new Map()
|
|
15
16
|
if (isSecured()) {
|
|
16
17
|
const JWTStrategy = require('../../auth/strategies/JWT.js')
|
|
18
|
+
// eslint-disable-next-line cds/no-missing-dependencies -- needs to be added by app dev
|
|
17
19
|
const passport = require('passport')
|
|
18
20
|
// REVISIT: It's unclear if the credentials from cds.requires.auth need to be used here.
|
|
19
21
|
// In principle, user-facing endpoints might differ from messaging ones.
|