@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
|
@@ -2,9 +2,14 @@ const cds = require('../../cds')
|
|
|
2
2
|
const { SELECT, DELETE } = cds.ql
|
|
3
3
|
|
|
4
4
|
const { isDraftRootEntity } = require('./csn')
|
|
5
|
-
const {
|
|
5
|
+
const {
|
|
6
|
+
getUpdateDraftAdminCQN,
|
|
7
|
+
ensureDraftsSuffix,
|
|
8
|
+
ensureNoDraftsSuffix,
|
|
9
|
+
getDeleteDraftAdminCqn,
|
|
10
|
+
getCompositionTargets
|
|
11
|
+
} = require('./handler')
|
|
6
12
|
const { extractKeyConditions } = require('./where')
|
|
7
|
-
const { getTargetData } = require('../../common/utils/data')
|
|
8
13
|
|
|
9
14
|
const _getSelectCQN = (req, keys) => {
|
|
10
15
|
return SELECT.from(ensureNoDraftsSuffix(req.target.name), [1]).where(keys.keyList)
|
|
@@ -28,23 +33,49 @@ const _validate = (activeResult, draftResult, req, IsActiveEntity) => {
|
|
|
28
33
|
}
|
|
29
34
|
}
|
|
30
35
|
|
|
31
|
-
const deleteDraft = async (req,
|
|
36
|
+
const deleteDraft = async (req, srv, includingActive = false) => {
|
|
32
37
|
const dbtx = cds.tx(req)
|
|
38
|
+
const definitions = srv.model.definitions
|
|
33
39
|
|
|
34
40
|
// REVISIT: how to handle delete of to 1 assoc
|
|
35
41
|
const keys = extractKeyConditions(req.query.DELETE.from.ref[req.query.DELETE.from.ref.length - 1].where)
|
|
42
|
+
|
|
43
|
+
// IsActiveEntity is deleted from where clause in auth.js, hence keys.IsActiveEntity is undefined here.
|
|
44
|
+
// Intentional?
|
|
45
|
+
const deleteActive = keys.IsActiveEntity !== false
|
|
46
|
+
|
|
36
47
|
const [activeResult, draftResult] = await Promise.all([
|
|
37
48
|
dbtx.run(_getSelectCQN(req, keys)),
|
|
38
49
|
dbtx.run(_getDraftSelectCQN(req, keys))
|
|
39
50
|
])
|
|
40
51
|
|
|
41
|
-
_validate(activeResult, draftResult, req,
|
|
52
|
+
_validate(activeResult, draftResult, req, deleteActive)
|
|
53
|
+
|
|
54
|
+
if (isDraftRootEntity(definitions, ensureNoDraftsSuffix(req.target.name)) && !deleteActive) {
|
|
55
|
+
const draftUUID = draftResult[0].DraftUUID
|
|
56
|
+
|
|
57
|
+
const draftTablesToDeleteFrom = [req.target.name + '_drafts']
|
|
58
|
+
for (const [entity] of getCompositionTargets(req.target, srv).entries()) {
|
|
59
|
+
if (!draftTablesToDeleteFrom.includes(entity + '_drafts')) draftTablesToDeleteFrom.push(entity + '_drafts')
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const deleteDraftAdminCqn = getDeleteDraftAdminCqn(draftUUID)
|
|
63
|
+
|
|
64
|
+
return dbtx.run([
|
|
65
|
+
deleteDraftAdminCqn,
|
|
66
|
+
...draftTablesToDeleteFrom.map(dt => {
|
|
67
|
+
const d = DELETE.from(dt).where({ DraftAdministrativeData_DraftUUID: draftUUID })
|
|
68
|
+
d._suppressDeepDelete = true // hidden flag to tell db layer that no deep delete is required
|
|
69
|
+
return d
|
|
70
|
+
})
|
|
71
|
+
])
|
|
72
|
+
}
|
|
42
73
|
|
|
43
74
|
const source = definitions[ensureNoDraftsSuffix(req.target.name)]
|
|
44
75
|
const delCQNs = []
|
|
45
76
|
|
|
46
77
|
if (includingActive) {
|
|
47
|
-
delCQNs.push(DELETE.from(ensureNoDraftsSuffix(
|
|
78
|
+
delCQNs.push(DELETE.from(ensureNoDraftsSuffix(req.target.name)).where(keys.keyList))
|
|
48
79
|
}
|
|
49
80
|
|
|
50
81
|
if (draftResult.length !== 0) {
|
|
@@ -58,8 +89,6 @@ const deleteDraft = async (req, definitions, includingActive = false) => {
|
|
|
58
89
|
}
|
|
59
90
|
}
|
|
60
91
|
|
|
61
|
-
req._oldData = keys.IsActiveEntity ? activeResult[0] : draftResult[0]
|
|
62
|
-
|
|
63
92
|
return Promise.all(delCQNs.map(cqn => dbtx.run(cqn)))
|
|
64
93
|
}
|
|
65
94
|
|
|
@@ -3,11 +3,12 @@ const { UPDATE, SELECT } = cds.ql
|
|
|
3
3
|
const { removeIsActiveEntityRecursively, isActiveEntityRequested } = require('./where')
|
|
4
4
|
const { getColumns } = require('../../cds-services/services/utils/columns')
|
|
5
5
|
const { ensureNoDraftsSuffix, ensureDraftsSuffix, ensureUnlocalized } = require('../../common/utils/draft')
|
|
6
|
+
const getTemplate = require('../../common/utils/template')
|
|
6
7
|
|
|
7
8
|
const { DRAFT_COLUMNS } = require('../../common/constants/draft')
|
|
8
9
|
|
|
9
|
-
//
|
|
10
|
-
const
|
|
10
|
+
// unofficial config!
|
|
11
|
+
const MAX_RECURSION_DEPTH = (cds.env.features.recursion_depth && Number(cds.env.features.recursion_depth)) || 2
|
|
11
12
|
|
|
12
13
|
const _getParentCQNWithKeyColumn = (parentCQN, parentKeyName) => {
|
|
13
14
|
const parentCQNWithKeyColumn = Object.assign({}, parentCQN)
|
|
@@ -23,33 +24,32 @@ const _getSubSelectFromCQN = (element, columns, selectFromDraft) => {
|
|
|
23
24
|
)
|
|
24
25
|
}
|
|
25
26
|
|
|
26
|
-
const getSubCQNs = ({ definitions,
|
|
27
|
+
const getSubCQNs = ({ definitions, rootCQN, compositionTree, selectFromDraft = false }) => {
|
|
27
28
|
const subCQNs = []
|
|
28
29
|
// only one backLink
|
|
29
|
-
const _generateSubCQNs = (
|
|
30
|
+
const _generateSubCQNs = (parentCQN, compositionElements, elementMap = new Map()) => {
|
|
30
31
|
for (const element of compositionElements) {
|
|
31
32
|
const backLink = element.backLinks[0] || element.customBackLinks[0]
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
33
|
+
if (backLink) {
|
|
34
|
+
const fqn = element.source + ':' + element.name
|
|
35
|
+
const seen = elementMap.get(fqn)
|
|
36
|
+
if (seen && seen >= MAX_RECURSION_DEPTH) {
|
|
37
|
+
// recursion -> abort
|
|
38
|
+
continue
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const columns = getColumns(definitions[element.source], { onlyNames: true, filterVirtual: true })
|
|
39
42
|
const subCQN = _getSubSelectFromCQN(element, columns, selectFromDraft)
|
|
40
|
-
subCQN.where([
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
subCQNs.push({ cqn: subCQN, level })
|
|
47
|
-
_generateSubCQNs(definitions[element.source], subCQN, element.compositionElements, level + 1)
|
|
43
|
+
subCQN.where([{ ref: [backLink.entityKey] }, 'in', _getParentCQNWithKeyColumn(parentCQN, backLink.targetKey)])
|
|
44
|
+
subCQNs.push({ cqn: subCQN })
|
|
45
|
+
const newElementMap = new Map(elementMap)
|
|
46
|
+
newElementMap.set(fqn, (seen && seen + 1) || 1)
|
|
47
|
+
_generateSubCQNs(subCQN, element.compositionElements, newElementMap)
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
_generateSubCQNs(
|
|
52
|
+
_generateSubCQNs(rootCQN, compositionTree.compositionElements)
|
|
53
53
|
|
|
54
54
|
return subCQNs
|
|
55
55
|
}
|
|
@@ -96,13 +96,8 @@ const _addAlias = (where, tableName) => {
|
|
|
96
96
|
return where.map(element => {
|
|
97
97
|
if (element.ref && element.ref.length === 1) {
|
|
98
98
|
// and copy ref
|
|
99
|
-
|
|
100
|
-
if (element[SYMBOL_FROM_ANNOTATION] === true) {
|
|
101
|
-
ref[SYMBOL_FROM_ANNOTATION] = true
|
|
102
|
-
}
|
|
103
|
-
return ref
|
|
99
|
+
return { ref: [tableName, element.ref[0]] }
|
|
104
100
|
}
|
|
105
|
-
|
|
106
101
|
return element
|
|
107
102
|
})
|
|
108
103
|
}
|
|
@@ -169,6 +164,9 @@ const _aliasRef = (ref, alias) => {
|
|
|
169
164
|
return newRef
|
|
170
165
|
}
|
|
171
166
|
|
|
167
|
+
const getDeleteDraftAdminCqn = draftUUID =>
|
|
168
|
+
DELETE.from('DRAFT.DraftAdministrativeData').where([{ ref: ['DraftUUID'] }, '=', { val: draftUUID }])
|
|
169
|
+
|
|
172
170
|
const _aliased = (arr, alias) =>
|
|
173
171
|
arr.map(item => {
|
|
174
172
|
if (alias && item.ref && item.ref[0] !== alias) {
|
|
@@ -230,23 +228,24 @@ const addColumnAlias = (columns, alias) => {
|
|
|
230
228
|
})
|
|
231
229
|
}
|
|
232
230
|
|
|
233
|
-
const
|
|
234
|
-
if (!
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
231
|
+
const getCompositionTargets = (entity, srv) => {
|
|
232
|
+
if (!entity.own('_deepCompositionTargets')) {
|
|
233
|
+
const _deepCompositionTargets = []
|
|
234
|
+
getTemplate('delete-drafts', srv, entity, {
|
|
235
|
+
pick: element => {
|
|
236
|
+
if (element.isAssociation && !element._isAssociationStrict && srv.model.definitions[element.target].drafts)
|
|
237
|
+
_deepCompositionTargets.push(element.target)
|
|
238
|
+
}
|
|
239
|
+
})
|
|
240
|
+
entity.set('_deepCompositionTargets', new Set(_deepCompositionTargets))
|
|
241
|
+
}
|
|
242
242
|
|
|
243
|
-
|
|
244
|
-
|
|
243
|
+
return entity.own('_deepCompositionTargets')
|
|
244
|
+
}
|
|
245
245
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
return where
|
|
246
|
+
const replaceRefWithDraft = ref => {
|
|
247
|
+
if (!ref || !ref[0]) return
|
|
248
|
+
ref[0] = ensureDraftsSuffix(ref[0])
|
|
250
249
|
}
|
|
251
250
|
|
|
252
251
|
const adaptStreamCQN = cqn => {
|
|
@@ -254,7 +253,6 @@ const adaptStreamCQN = cqn => {
|
|
|
254
253
|
cqn.SELECT.where = removeIsActiveEntityRecursively(cqn.SELECT.where)
|
|
255
254
|
} else {
|
|
256
255
|
replaceRefWithDraft(cqn.SELECT.from.ref)
|
|
257
|
-
removeAnnotationWhere(cqn.SELECT.where)
|
|
258
256
|
}
|
|
259
257
|
}
|
|
260
258
|
|
|
@@ -302,8 +300,9 @@ module.exports = {
|
|
|
302
300
|
addColumnAlias,
|
|
303
301
|
adaptStreamCQN,
|
|
304
302
|
replaceRefWithDraft,
|
|
305
|
-
removeAnnotationWhere,
|
|
306
303
|
getKeyProperty,
|
|
307
304
|
hasKeyInWhere,
|
|
308
|
-
filterKeys
|
|
305
|
+
filterKeys,
|
|
306
|
+
getDeleteDraftAdminCqn,
|
|
307
|
+
getCompositionTargets
|
|
309
308
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
const _removeMultipleBrackets = (index, whereCondition) => {
|
|
1
|
+
const _removeMultipleBrackets = (index, whereCondition, isXpr) => {
|
|
2
|
+
if (isXpr) return index
|
|
3
|
+
|
|
2
4
|
let resIndex = index
|
|
3
5
|
if (whereCondition[index - 1] === '(') {
|
|
4
6
|
while (resIndex - 2 >= 0 && whereCondition[resIndex - 2] === '(') {
|
|
@@ -17,25 +19,26 @@ const _removeMultipleBrackets = (index, whereCondition) => {
|
|
|
17
19
|
return resIndex
|
|
18
20
|
}
|
|
19
21
|
|
|
20
|
-
const _calculateSpliceArgs = (index, whereCondition) => {
|
|
22
|
+
const _calculateSpliceArgs = (index, whereCondition, isXpr = false) => {
|
|
21
23
|
const AND_OR = ['and', 'or']
|
|
24
|
+
const len = isXpr ? 1 : 3
|
|
22
25
|
if (AND_OR.includes(whereCondition[index - 1])) {
|
|
23
|
-
return { index: index - 1, count:
|
|
26
|
+
return { index: index - 1, count: 1 + len }
|
|
24
27
|
}
|
|
25
|
-
if (AND_OR.includes(whereCondition[index +
|
|
26
|
-
return { index: index, count:
|
|
28
|
+
if (AND_OR.includes(whereCondition[index + len])) {
|
|
29
|
+
return { index: index, count: len + 1 }
|
|
27
30
|
}
|
|
28
|
-
if (whereCondition[index - 1] === '(' && whereCondition[index +
|
|
31
|
+
if (whereCondition[index - 1] === '(' && whereCondition[index + len] === ')') {
|
|
29
32
|
if (AND_OR.includes(whereCondition[index - 2])) {
|
|
30
|
-
return { index: index - 2, count:
|
|
33
|
+
return { index: index - 2, count: len + 3 }
|
|
31
34
|
}
|
|
32
|
-
if (AND_OR.includes(whereCondition[index +
|
|
33
|
-
return { index: index - 1, count:
|
|
35
|
+
if (AND_OR.includes(whereCondition[index + len + 1])) {
|
|
36
|
+
return { index: index - 1, count: len + 3 }
|
|
34
37
|
}
|
|
35
38
|
|
|
36
|
-
return { index: index - 1, count:
|
|
39
|
+
return { index: index - 1, count: len + 2 }
|
|
37
40
|
}
|
|
38
|
-
return { index: index, count:
|
|
41
|
+
return { index: index, count: len }
|
|
39
42
|
}
|
|
40
43
|
|
|
41
44
|
const _isActiveEntity = entry => entry.ref && entry.ref[entry.ref.length - 1] === 'IsActiveEntity'
|
|
@@ -75,14 +78,26 @@ const _isKeyValue = (i, keys, where) => {
|
|
|
75
78
|
return where[i + 1] === '=' && 'val' in where[i + 2]
|
|
76
79
|
}
|
|
77
80
|
|
|
78
|
-
const deleteCondition = (index, whereCondition) => {
|
|
79
|
-
index = _removeMultipleBrackets(index, whereCondition)
|
|
80
|
-
const spliceArgs = _calculateSpliceArgs(index, whereCondition)
|
|
81
|
+
const deleteCondition = (index, whereCondition, isXpr = false) => {
|
|
82
|
+
index = _removeMultipleBrackets(index, whereCondition, isXpr)
|
|
83
|
+
const spliceArgs = _calculateSpliceArgs(index, whereCondition, isXpr)
|
|
81
84
|
whereCondition.splice(spliceArgs.index, spliceArgs.count)
|
|
85
|
+
return spliceArgs.index
|
|
82
86
|
}
|
|
83
87
|
|
|
84
88
|
const readAndDeleteKeywords = (keywords, whereCondition, toDelete = true) => {
|
|
85
|
-
|
|
89
|
+
let index = whereCondition.findIndex(({ xpr }) => xpr)
|
|
90
|
+
if (index !== -1) {
|
|
91
|
+
const result = readAndDeleteKeywords(keywords, whereCondition[index].xpr, toDelete)
|
|
92
|
+
if (result) {
|
|
93
|
+
if (whereCondition[index].xpr.length === 0) {
|
|
94
|
+
deleteCondition(index, whereCondition, true)
|
|
95
|
+
}
|
|
96
|
+
return result
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
index = whereCondition.findIndex(({ ref }) => {
|
|
86
101
|
if (!ref) {
|
|
87
102
|
return false
|
|
88
103
|
}
|
|
@@ -29,11 +29,8 @@ class CustomSelectBuilder extends SelectBuilder {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
_val(obj) {
|
|
32
|
-
if (typeof obj.val === 'boolean') {
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return obj.val
|
|
32
|
+
if (typeof obj.val === 'boolean') return { sql: obj.val ? 'true' : 'false', values: [] }
|
|
33
|
+
return super._val(obj)
|
|
37
34
|
}
|
|
38
35
|
|
|
39
36
|
getParameters() {
|
|
@@ -91,9 +88,10 @@ if (cds.env.sql.names === 'plain') {
|
|
|
91
88
|
CustomSelectBuilder.prototype._buildRefElement = function (col, res, noQuoting) {
|
|
92
89
|
res = new this.ReferenceBuilder(col, this._options, this._csn).build()
|
|
93
90
|
|
|
94
|
-
if (!noQuoting && !col.as && res.sql && !res.sql.
|
|
91
|
+
if (!noQuoting && !col.as && res.sql && !res.sql.match(/\sas\s/i)) {
|
|
95
92
|
res.sql += ` AS ${this._options.delimiter}${col.ref[col.ref.length - 1]}${this._options.delimiter}`
|
|
96
93
|
}
|
|
94
|
+
|
|
97
95
|
return res
|
|
98
96
|
}
|
|
99
97
|
}
|
|
@@ -132,7 +132,7 @@ function _executeSelectSQL(dbc, sql, values, isOne, postMapper, propertyMapper,
|
|
|
132
132
|
|
|
133
133
|
function _processExpand(model, dbc, cqn, user, locale, txTimestamp) {
|
|
134
134
|
const queries = []
|
|
135
|
-
const expandQueries = createJoinCQNFromExpanded(cqn, model
|
|
135
|
+
const expandQueries = createJoinCQNFromExpanded(cqn, model)
|
|
136
136
|
|
|
137
137
|
for (const cqn of expandQueries.queries) {
|
|
138
138
|
cqn._conversionMapper = getPostProcessMapper(HANA_TYPE_CONVERSION_MAP, model, cqn)
|
|
@@ -144,7 +144,7 @@ function _processExpand(model, dbc, cqn, user, locale, txTimestamp) {
|
|
|
144
144
|
queries.push(_executeSelectSQL(dbc, sql, values, false))
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
-
return rawToExpanded(expandQueries, queries, cqn.SELECT.one)
|
|
147
|
+
return rawToExpanded(expandQueries, queries, cqn.SELECT.one, cqn._rootEntity)
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
function executeSelectCQN(model, dbc, query, user, locale, txTimestamp) {
|
|
@@ -13,15 +13,15 @@ const getLocalize = (locale, model) => name => {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
const localizedHandler = function (req) {
|
|
16
|
-
const query = req
|
|
16
|
+
const { query } = req
|
|
17
17
|
|
|
18
18
|
// do simple checks upfront and exit early
|
|
19
19
|
if (!query || typeof query === 'string') return
|
|
20
20
|
if (!query.SELECT) return
|
|
21
|
-
if (!req.user || !req.user.locale) return
|
|
22
21
|
if (!this.model) return
|
|
22
|
+
if (!req.locale) return
|
|
23
23
|
|
|
24
|
-
// suppress localization
|
|
24
|
+
// suppress localization by instruction
|
|
25
25
|
if (query._suppressLocalization) return
|
|
26
26
|
|
|
27
27
|
// suppress localization for pure counts
|
|
@@ -31,7 +31,7 @@ const localizedHandler = function (req) {
|
|
|
31
31
|
// suppress localization in "select for update"
|
|
32
32
|
if (query.SELECT.forUpdate) return
|
|
33
33
|
|
|
34
|
-
redirect(
|
|
34
|
+
redirect(query.SELECT, getLocalize(req.locale, this.model))
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
localizedHandler._initial = true
|
|
@@ -192,22 +192,37 @@ async function pool4(tenant, credentials) {
|
|
|
192
192
|
return pools.get(tenant)
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
-
|
|
196
|
-
|
|
195
|
+
async function resilientAcquire(pool, attempts = 1) {
|
|
196
|
+
// max 3 attempts
|
|
197
|
+
attempts = Math.min(attempts, 3)
|
|
198
|
+
let client
|
|
199
|
+
let err
|
|
200
|
+
let attempt = 0
|
|
201
|
+
while (!client && attempt < attempts) {
|
|
197
202
|
try {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
if (err.name === 'TimeoutError') {
|
|
204
|
-
err.statusCode = 503
|
|
205
|
-
err.message =
|
|
206
|
-
'Acquiring client from pool timed out. Please review your system setup, transaction handling, and pool configuration.'
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
throw err
|
|
203
|
+
client = await pool.acquire()
|
|
204
|
+
} catch (e) {
|
|
205
|
+
if (e.name !== 'TimeoutError') throw e
|
|
206
|
+
err = e
|
|
207
|
+
attempt++
|
|
210
208
|
}
|
|
209
|
+
}
|
|
210
|
+
if (client) return client
|
|
211
|
+
err.statusCode = 503
|
|
212
|
+
err.message =
|
|
213
|
+
'Acquiring client from pool timed out. Please review your system setup, transaction handling, and pool configuration.'
|
|
214
|
+
err._attempts = attempt
|
|
215
|
+
throw err
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
module.exports = {
|
|
219
|
+
acquire: async (tenant, credentials) => {
|
|
220
|
+
const pool = await pool4(tenant, credentials)
|
|
221
|
+
const _attempts = cds.env.requires.db.connection_attempts
|
|
222
|
+
const attempts = _attempts && !isNaN(_attempts) && parseInt(_attempts)
|
|
223
|
+
const client = await resilientAcquire(pool, attempts)
|
|
224
|
+
client._pool = pool
|
|
225
|
+
return client
|
|
211
226
|
},
|
|
212
227
|
release: client => {
|
|
213
228
|
return client._pool.release(client)
|
|
@@ -41,7 +41,7 @@ const search2cqn4sql = (cqn, entity, options) => {
|
|
|
41
41
|
const onCondition = getOnCond(localizedAssociation, onConditionOptions)
|
|
42
42
|
|
|
43
43
|
// replace $user_locale placeholder with the user locale or the HANA session context
|
|
44
|
-
onCondition[onCondition.length - 2]
|
|
44
|
+
onCondition[onCondition.length - 2] = { val: locale || "SESSION_CONTEXT('LOCALE')" }
|
|
45
45
|
|
|
46
46
|
// inner join the target table with the _texts table (the _texts table contains
|
|
47
47
|
// the translated texts)
|
|
@@ -54,6 +54,7 @@ const search2cqn4sql = (cqn, entity, options) => {
|
|
|
54
54
|
// defined.
|
|
55
55
|
cqn.SELECT.columns = _unshiftEntityNameToColumnRef(entity, cqn.SELECT.columns)
|
|
56
56
|
columns = _unshiftEntityNameToColumnRef(entity, columns)
|
|
57
|
+
if (cqn.SELECT.groupBy) cqn.SELECT.groupBy = _unshiftEntityNameToColumnRef(entity, cqn.SELECT.groupBy)
|
|
57
58
|
} // else --> resolve localized texts via localized view (default)
|
|
58
59
|
|
|
59
60
|
const useContains = resolveLocalizedTextsAtRuntime && isContainsPredicateSupported(cqn)
|
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
*
|
|
4
4
|
* OData search string | `CONTAINS` search string
|
|
5
5
|
* ----------------------------- | ------------------------
|
|
6
|
-
* `foo` |
|
|
7
|
-
* `NOT foo` |
|
|
8
|
-
* `foo AND bar` |
|
|
9
|
-
* `foo OR bar` |
|
|
10
|
-
* `foo or bar` |
|
|
11
|
-
* `" foo" OR " bar"` |
|
|
12
|
-
* ` foo` |
|
|
13
|
-
* `foo bar` |
|
|
6
|
+
* `foo` | `"%foo%"`
|
|
7
|
+
* `NOT foo` | `-"%foo%"` (Currently disabled -> BCP 2180256508)
|
|
8
|
+
* `foo AND bar` | `"%foo%" "%bar%"`
|
|
9
|
+
* `foo OR bar` | `"%foo%" OR "%bar%"`
|
|
10
|
+
* `foo or bar` | `"%foo%" OR "%bar%"`
|
|
11
|
+
* `" foo" OR " bar"` | `"% foo%" OR "% bar%"`
|
|
12
|
+
* ` foo` | `"% foo%"`
|
|
13
|
+
* `foo bar` | `"%foo%" "%bar%"`
|
|
14
14
|
*
|
|
15
15
|
* **Some limitations of the `CONTAINS` predicate in SAP HANA:**
|
|
16
16
|
* - The `-` (minus sign) search operator can not be placed directly after `OR`.
|
|
@@ -38,15 +38,15 @@ const searchToContains = (cqnSearchPhrase, columns) => {
|
|
|
38
38
|
// the - (minus sign) is used to exclude terms from the search
|
|
39
39
|
if (currentValue === 'not') return (searchStringAccumulator += '-')
|
|
40
40
|
|
|
41
|
-
//
|
|
42
|
-
const searchTermEscaped = currentValue.val.replace(/
|
|
41
|
+
// escape double quotation mark(s) with \\
|
|
42
|
+
const searchTermEscaped = currentValue.val.replace(/"/g, '\\$&')
|
|
43
43
|
|
|
44
44
|
// A search term enclosed with the wildcard character % (percentage sign)
|
|
45
45
|
// is used to match zero or more characters. In SAP HANA, the % sign is
|
|
46
46
|
// replaced with an asterisk (*), and a wildcard search is run.
|
|
47
47
|
// The % sign also prevents ambiguity, as a search input might contain
|
|
48
48
|
// an 'OR' (uppercase characters), causing semantics issues.
|
|
49
|
-
return (searchStringAccumulator +=
|
|
49
|
+
return (searchStringAccumulator += `"%${searchTermEscaped}%"`)
|
|
50
50
|
}, '')
|
|
51
51
|
|
|
52
52
|
const expressionArgs = [{ list: columns }, { val: searchString }]
|
|
@@ -71,9 +71,13 @@ const isContainsPredicateSupported = cqn => {
|
|
|
71
71
|
// want to remove the following condition(s).
|
|
72
72
|
if (cqn._aggregated) return false
|
|
73
73
|
|
|
74
|
-
// search terms starting with
|
|
75
|
-
//
|
|
76
|
-
|
|
74
|
+
// REVISIT: search terms starting with whitespace after a `NOT` operator does not
|
|
75
|
+
// return the expected result on SAP HANA (BCP 2180256508). In addition, double
|
|
76
|
+
// quotation marks after a `NOT` operator do not return the desired result.
|
|
77
|
+
// if (cqnSearchPhrase[0] === 'not' && cqnSearchPhrase[1].val[0] === ' ') return false
|
|
78
|
+
|
|
79
|
+
// so for now do not optimize for the `NOT` operator
|
|
80
|
+
if (cqnSearchPhrase[0] === 'not') return false
|
|
77
81
|
|
|
78
82
|
// The `AND` operator in combination with the `OR` operator does not
|
|
79
83
|
// return the expected result
|
package/libx/_runtime/index.js
CHANGED
|
@@ -16,11 +16,6 @@ module.exports = {
|
|
|
16
16
|
return this._auth || (this._auth = require('./common/auth'))
|
|
17
17
|
},
|
|
18
18
|
|
|
19
|
-
/** @type {import('./cds-services/statements')} */
|
|
20
|
-
get statements() {
|
|
21
|
-
return this._statements || (this._statements = require('./cds-services/statements'))
|
|
22
|
-
},
|
|
23
|
-
|
|
24
19
|
// REVISIT: remove once not needed anymore
|
|
25
20
|
get performanceMeasurement() {
|
|
26
21
|
return this._perf || (this._perf = require('./cds-services/adapter/perf/performanceMeasurement'))
|
|
@@ -28,15 +28,23 @@ class AMQPWebhookMessaging extends MessagingService {
|
|
|
28
28
|
return client.emit(msg)
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
startListening() {
|
|
31
|
+
startListening(opt = {}) {
|
|
32
32
|
if (this.subscribedTopics.size) {
|
|
33
33
|
const management = this.getManagement()
|
|
34
|
-
this.queued(management.createQueueAndSubscriptions.bind(management))()
|
|
34
|
+
if (!opt.doNotDeploy) this.queued(management.createQueueAndSubscriptions.bind(management))()
|
|
35
35
|
this.queued(this.listenToClient.bind(this))(async (_topic, _payload, _other, { done, failed }) => {
|
|
36
36
|
const event = _topic
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
// Some messaging systems don't adhere to the standard that the payload has a `data` property.
|
|
38
|
+
// For these cases, we interpret the whole payload as `data`.
|
|
39
|
+
let data, headers
|
|
40
|
+
if ('data' in _payload) {
|
|
41
|
+
data = _payload.data
|
|
42
|
+
headers = { ..._payload }
|
|
43
|
+
delete headers.data
|
|
44
|
+
} else {
|
|
45
|
+
data = _payload
|
|
46
|
+
headers = {}
|
|
47
|
+
}
|
|
40
48
|
const msg = {
|
|
41
49
|
event,
|
|
42
50
|
data,
|
|
@@ -5,7 +5,10 @@ const _queueName = ({ appName, appID, ownNamespace }) => {
|
|
|
5
5
|
|
|
6
6
|
const queueName = (options, optionsApp = {}) => {
|
|
7
7
|
const namespace = options.credentials && options.credentials.namespace
|
|
8
|
-
if (options.queue && options.queue.name)
|
|
8
|
+
if (options.queue && options.queue.name) {
|
|
9
|
+
if (options.credentials.namespace) return options.queue.name.replace(/\$namespace/g, options.credentials.namespace)
|
|
10
|
+
return options.queue.name
|
|
11
|
+
}
|
|
9
12
|
const ownNamespace = namespace
|
|
10
13
|
return _queueName({
|
|
11
14
|
appName: optionsApp.appName || 'CAP',
|
|
@@ -4,7 +4,6 @@ const LOG = cds.log('messaging')
|
|
|
4
4
|
const sleep = require('util').promisify(setTimeout)
|
|
5
5
|
|
|
6
6
|
const _getWebhookName = queueName => queueName
|
|
7
|
-
const isSecured = () => cds.requires.uaa && cds.requires.uaa.credentials
|
|
8
7
|
|
|
9
8
|
// REVISIT: Maybe use `error` definitions as in req.error?
|
|
10
9
|
|
|
@@ -52,6 +51,20 @@ class EMManagement {
|
|
|
52
51
|
return res.body
|
|
53
52
|
}
|
|
54
53
|
|
|
54
|
+
async getQueues() {
|
|
55
|
+
const res = await authorizedRequest({
|
|
56
|
+
method: 'GET',
|
|
57
|
+
uri: this.options.uri,
|
|
58
|
+
path: `/hub/rest/api/v1/management/messaging/queues`,
|
|
59
|
+
oa2: this.options.oa2,
|
|
60
|
+
attemptInfo: () => LOG._info && LOG.info('Get queues', this.subdomain ? { subdomain: this.subdomain } : {}),
|
|
61
|
+
errMsg: `Queues could not be retrieved ${this.subdomainInfo}`,
|
|
62
|
+
target: { kind: 'QUEUE' },
|
|
63
|
+
tokenStore: this
|
|
64
|
+
})
|
|
65
|
+
return res.body
|
|
66
|
+
}
|
|
67
|
+
|
|
55
68
|
createQueue(queueName = this.queueName) {
|
|
56
69
|
return authorizedRequest({
|
|
57
70
|
method: 'PUT',
|
|
@@ -196,26 +209,25 @@ class EMManagement {
|
|
|
196
209
|
const pushConfig = {
|
|
197
210
|
type: 'webhook',
|
|
198
211
|
endpoint: this.optionsApp.appURL + this.path,
|
|
199
|
-
exemptHandshake: false
|
|
212
|
+
exemptHandshake: false,
|
|
213
|
+
defaultContentType: 'application/json'
|
|
200
214
|
}
|
|
201
|
-
if (isSecured()) {
|
|
202
|
-
// Use credentials from Enterprise Messaging.
|
|
203
|
-
// For it to work, you'll need to add scopes in your
|
|
204
|
-
// xs-security.json:
|
|
205
|
-
//
|
|
206
|
-
// scopes: [{
|
|
207
|
-
// "name": "$XSAPPNAME.em",
|
|
208
|
-
// "description": "EM Callback Access",
|
|
209
|
-
// "grant-as-authority-to-apps": ["$XSSERVICENAME(messaging-name)"]
|
|
210
|
-
// }]
|
|
211
215
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
216
|
+
// Use credentials from Enterprise Messaging.
|
|
217
|
+
// For it to work, you'll need to add scopes in your
|
|
218
|
+
// xs-security.json:
|
|
219
|
+
//
|
|
220
|
+
// scopes: [{
|
|
221
|
+
// "name": "$XSAPPNAME.em",
|
|
222
|
+
// "description": "EM Callback Access",
|
|
223
|
+
// "grant-as-authority-to-apps": ["$XSSERVICENAME(messaging-name)"]
|
|
224
|
+
// }]
|
|
225
|
+
pushConfig.securitySchema = {
|
|
226
|
+
type: 'oauth2',
|
|
227
|
+
grantType: 'client_credentials',
|
|
228
|
+
clientId: this.optionsMessagingREST.oa2.client,
|
|
229
|
+
clientSecret: this.optionsMessagingREST.oa2.secret,
|
|
230
|
+
tokenUrl: this.optionsMessagingREST.oa2.endpoint
|
|
219
231
|
}
|
|
220
232
|
|
|
221
233
|
const dataObj = {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
const cds = require('../../cds.js')
|
|
2
|
-
const bodyParser = require('body-parser')
|
|
3
2
|
const LOG = cds.log('messaging')
|
|
4
3
|
const express = require('express')
|
|
5
4
|
const getTenantInfo = require('./getTenantInfo.js')
|
|
@@ -28,7 +27,7 @@ class EndpointRegistry {
|
|
|
28
27
|
paths.forEach(path => {
|
|
29
28
|
cds.app.use(path, express.json({ type: 'application/*+json' }))
|
|
30
29
|
cds.app.use(path, express.json())
|
|
31
|
-
cds.app.use(path,
|
|
30
|
+
cds.app.use(path, express.urlencoded({ extended: true }))
|
|
32
31
|
})
|
|
33
32
|
LOG._debug && LOG.debug('Register inbound endpoint', { basePath, method: 'OPTIONS' })
|
|
34
33
|
|