@sap/cds 5.5.3 → 5.6.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 +134 -1
- package/apis/services.d.ts +27 -1
- package/app/index.js +22 -11
- package/bin/build/buildTaskFactory.js +1 -1
- package/bin/build/provider/buildTaskProviderInternal.js +1 -1
- package/bin/build/provider/fiori/index.js +1 -1
- package/bin/build/provider/hana/2migration.js +8 -7
- package/bin/build/provider/java-cf/index.js +1 -1
- package/bin/deploy/to-hana/hana.js +1 -17
- package/common.cds +8 -0
- package/lib/compile/index.js +1 -1
- package/lib/compile/to/sql.js +22 -2
- package/lib/connect/bindings.js +2 -1
- package/lib/connect/index.js +1 -1
- package/lib/core/infer.js +1 -1
- package/lib/core/reflect.js +3 -1
- package/lib/env/index.js +175 -41
- package/lib/env/requires.js +24 -3
- package/lib/i18n/localize.js +33 -5
- package/lib/index.js +7 -6
- package/lib/log/format/kibana.js +6 -2
- package/lib/ql/DELETE.js +1 -1
- package/lib/ql/INSERT.js +1 -1
- package/lib/ql/Query.js +13 -10
- package/lib/ql/SELECT.js +15 -8
- package/lib/ql/UPDATE.js +1 -1
- package/lib/ql/Whereable.js +5 -0
- package/lib/req/context.js +87 -37
- package/lib/req/{impl.js → request.js} +1 -1
- package/lib/req/{res.js → response.js} +0 -0
- package/lib/serve/Service-api.js +1 -1
- package/lib/serve/Service-dispatch.js +12 -2
- package/lib/serve/Service-handlers.js +21 -7
- package/lib/serve/Service-methods.js +1 -1
- package/lib/serve/Transaction.js +7 -6
- package/lib/serve/index.js +1 -1
- package/lib/utils/axios.js +7 -0
- package/lib/utils/data.js +1 -1
- package/libx/_runtime/audit/Service.js +18 -18
- package/libx/_runtime/audit/generic/personal/access.js +1 -1
- package/libx/_runtime/audit/generic/personal/modification.js +3 -2
- package/libx/_runtime/audit/generic/personal/utils.js +23 -63
- package/libx/_runtime/cds-services/adapter/odata-v4/Dispatcher.js +6 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/OData.js +37 -35
- package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/create.js +3 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/error.js +5 -5
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +13 -7
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +84 -34
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +10 -4
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/applyToCQN.js +9 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/expandToCQN.js +8 -6
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/index.js +1 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/readToCQN.js +13 -11
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/selectHelper.js +11 -95
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/ResourcePathParser.js +17 -11
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/UriParser.js +2 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/to.js +6 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +3 -34
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/handlerUtils.js +3 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +48 -18
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/stream.js +10 -5
- package/libx/_runtime/cds-services/adapter/rest/handlers/operation.js +1 -1
- package/libx/_runtime/cds-services/adapter/rest/handlers/update.js +1 -1
- package/libx/_runtime/cds-services/adapter/rest/rest-to-cqn/index.js +1 -3
- package/libx/_runtime/cds-services/adapter/rest/utils/parse-url.js +9 -2
- package/libx/_runtime/cds-services/adapter/rest/utils/validation-checks.js +20 -21
- package/libx/_runtime/cds-services/services/utils/columns.js +6 -1
- package/libx/_runtime/cds-services/services/utils/compareJson.js +1 -8
- package/libx/_runtime/cds-services/services/utils/differ.js +7 -26
- package/libx/_runtime/cds-services/services/utils/handlerUtils.js +2 -4
- package/libx/_runtime/cds-services/util/assert.js +29 -13
- package/libx/_runtime/cds.js +2 -1
- package/libx/_runtime/common/aspects/Association.js +72 -0
- package/libx/_runtime/common/aspects/any.js +8 -45
- package/libx/_runtime/common/aspects/entity.js +0 -1
- package/libx/_runtime/common/aspects/relation.js +40 -0
- package/libx/_runtime/common/aspects/utils.js +73 -1
- package/libx/_runtime/common/auth/strategies/utils/uaa.js +10 -14
- package/libx/_runtime/common/composition/data.js +3 -2
- package/libx/_runtime/common/composition/delete.js +3 -1
- package/libx/_runtime/common/composition/tree.js +23 -18
- package/libx/_runtime/common/composition/utils.js +34 -8
- package/libx/_runtime/common/error/frontend.js +6 -1
- package/libx/_runtime/common/generic/auth.js +15 -13
- package/libx/_runtime/common/generic/crud.js +2 -2
- package/libx/_runtime/common/generic/etag.js +11 -8
- package/libx/_runtime/common/generic/input.js +3 -3
- package/libx/_runtime/common/generic/paging.js +9 -5
- package/libx/_runtime/common/generic/put.js +3 -2
- package/libx/_runtime/common/generic/sorting.js +3 -3
- package/libx/_runtime/common/generic/temporal.js +3 -3
- package/libx/_runtime/common/toggles/alpha.js +1 -1
- package/libx/_runtime/common/utils/cqn.js +20 -1
- package/libx/_runtime/common/utils/cqn2cqn4sql.js +125 -139
- package/libx/_runtime/common/utils/csn.js +50 -52
- package/libx/_runtime/common/utils/foreignKeyPropagations.js +41 -176
- package/libx/_runtime/common/utils/generateOnCond.js +40 -70
- package/libx/_runtime/common/utils/{enrichWithKeysFromWhere.js → keys.js} +29 -28
- package/libx/_runtime/common/utils/postProcessing.js +3 -0
- package/libx/_runtime/common/utils/propagateForeignKeys.js +84 -0
- package/libx/_runtime/common/utils/resolveStructured.js +1 -1
- package/libx/_runtime/common/utils/resolveView.js +19 -9
- package/libx/_runtime/common/utils/rewriteAsterisks.js +94 -0
- package/libx/_runtime/common/utils/search2cqn4sql.js +9 -8
- package/libx/_runtime/common/utils/template.js +54 -46
- package/libx/_runtime/db/Service.js +9 -2
- package/libx/_runtime/db/expand/expandCQNToJoin.js +10 -24
- package/libx/_runtime/db/expand/rawToExpanded.js +2 -1
- package/libx/_runtime/db/generic/create.js +1 -0
- package/libx/_runtime/db/generic/input.js +7 -11
- package/libx/_runtime/db/generic/integrity.js +2 -2
- package/libx/_runtime/db/generic/rewrite.js +2 -5
- package/libx/_runtime/db/generic/update.js +1 -0
- package/libx/_runtime/db/query/read.js +10 -5
- package/libx/_runtime/db/sql-builder/ExpressionBuilder.js +6 -0
- package/libx/_runtime/db/sql-builder/SelectBuilder.js +7 -2
- package/libx/_runtime/db/sql-builder/annotations.js +1 -0
- package/libx/_runtime/db/utils/columns.js +14 -43
- package/libx/_runtime/db/utils/deep.js +5 -7
- package/libx/_runtime/fiori/generic/activate.js +3 -2
- package/libx/_runtime/fiori/generic/before.js +2 -2
- package/libx/_runtime/fiori/generic/cancel.js +3 -2
- package/libx/_runtime/fiori/generic/delete.js +3 -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 +2 -2
- package/libx/_runtime/fiori/generic/prepare.js +2 -2
- package/libx/_runtime/fiori/generic/read.js +17 -63
- package/libx/_runtime/fiori/generic/readOverDraft.js +4 -4
- package/libx/_runtime/fiori/uiflex/extensibility/index.cds +15 -0
- package/libx/_runtime/fiori/uiflex/extensibility/index.js +148 -0
- package/libx/_runtime/fiori/uiflex/handler/transformREAD.js +119 -0
- package/libx/_runtime/fiori/uiflex/handler/transformRESULT.js +43 -0
- package/libx/_runtime/fiori/uiflex/handler/transformWRITE.js +62 -0
- package/libx/_runtime/fiori/uiflex/index.js +35 -0
- package/libx/_runtime/fiori/uiflex/utils.js +78 -0
- package/libx/_runtime/fiori/utils/handler.js +3 -13
- package/libx/_runtime/fiori/utils/where.js +6 -1
- package/libx/_runtime/hana/Service.js +5 -2
- package/libx/_runtime/hana/execute.js +1 -1
- package/libx/_runtime/hana/pool.js +12 -11
- package/libx/_runtime/hana/search2cqn4sql.js +34 -43
- package/libx/_runtime/hana/searchToContains.js +3 -3
- package/libx/_runtime/index.js +5 -2
- package/libx/_runtime/messaging/AMQPWebhookMessaging.js +1 -1
- package/libx/_runtime/messaging/common-utils/AMQPClient.js +16 -3
- package/libx/_runtime/messaging/common-utils/connections.js +11 -14
- package/libx/_runtime/messaging/common-utils/naming-conventions.js +1 -1
- package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +2 -1
- package/libx/_runtime/messaging/enterprise-messaging.js +1 -1
- package/libx/_runtime/messaging/message-queuing.js +18 -0
- package/libx/_runtime/remote/Service.js +14 -2
- package/libx/_runtime/remote/utils/client-types.d.ts +7 -0
- package/libx/_runtime/remote/utils/client.js +117 -23
- package/libx/_runtime/sqlite/Service.js +4 -3
- package/libx/_runtime/sqlite/convertAssocToOneManaged.js +1 -3
- package/libx/_runtime/sqlite/execute.js +1 -1
- package/libx/gql/GraphQLAdapter.js +33 -0
- package/libx/gql/constants/adapter.js +69 -0
- package/libx/gql/constants/cds.js +18 -0
- package/libx/gql/constants/graphql.js +33 -0
- package/libx/gql/resolvers/crud/create.js +15 -0
- package/libx/gql/resolvers/crud/delete.js +24 -0
- package/libx/gql/resolvers/crud/index.js +6 -0
- package/libx/gql/resolvers/crud/read.js +25 -0
- package/libx/gql/resolvers/crud/update.js +31 -0
- package/libx/gql/resolvers/crud/utils/index.js +36 -0
- package/libx/gql/resolvers/field.js +5 -0
- package/libx/gql/resolvers/index.js +7 -0
- package/libx/gql/resolvers/mutation.js +23 -0
- package/libx/gql/resolvers/parse/ast/enrich.js +51 -0
- package/libx/gql/resolvers/parse/ast/fragment.js +11 -0
- package/libx/gql/resolvers/parse/ast/fromObject.js +39 -0
- package/libx/gql/resolvers/parse/ast/index.js +3 -0
- package/libx/gql/resolvers/parse/ast/meta.js +4 -0
- package/libx/gql/resolvers/parse/ast/variable.js +7 -0
- package/libx/gql/resolvers/parse/ast2cqn/columns.js +42 -0
- package/libx/gql/resolvers/parse/ast2cqn/entries.js +31 -0
- package/libx/gql/resolvers/parse/ast2cqn/index.js +8 -0
- package/libx/gql/resolvers/parse/ast2cqn/limit.js +6 -0
- package/libx/gql/resolvers/parse/ast2cqn/orderBy.js +24 -0
- package/libx/gql/resolvers/parse/ast2cqn/utils/index.js +3 -0
- package/libx/gql/resolvers/parse/ast2cqn/where.js +70 -0
- package/libx/gql/resolvers/parse/utils/index.js +8 -0
- package/libx/gql/resolvers/query.js +13 -0
- package/libx/gql/resolvers/root.js +34 -0
- package/libx/gql/schema/generate.js +18 -0
- package/libx/gql/schema/index.js +5 -0
- package/libx/gql/schema/mutation.js +76 -0
- package/libx/gql/schema/query.js +108 -0
- package/libx/gql/schema/typeDefMap.js +45 -0
- package/libx/gql/schema/utils/index.js +54 -0
- package/libx/gql/utils/index.js +12 -0
- package/libx/{_runtime/odata/cqn2odata.js → odata/cqn2odata/index.js} +39 -100
- package/libx/odata/index.js +80 -0
- package/libx/odata/odata2cqn/afterburner.js +170 -0
- package/libx/{_runtime/odata/odata2cqn.pegjs → odata/odata2cqn/grammar.pegjs} +102 -123
- package/libx/odata/odata2cqn/index.js +3 -0
- package/libx/odata/odata2cqn/parser.js +1 -0
- package/libx/odata/utils/index.js +64 -0
- package/libx/rest/RestAdapter.js +101 -0
- package/libx/rest/RestRequest.js +30 -0
- package/libx/rest/index.js +3 -0
- package/libx/rest/middleware/auth.js +22 -0
- package/libx/rest/middleware/content.js +15 -0
- package/libx/rest/middleware/create.js +40 -0
- package/libx/rest/middleware/delete.js +20 -0
- package/libx/rest/middleware/error.js +56 -0
- package/libx/rest/middleware/operation.js +39 -0
- package/libx/rest/middleware/parse.js +90 -0
- package/libx/rest/middleware/read.js +29 -0
- package/libx/rest/middleware/update.js +42 -0
- package/libx/rest/utils/data.js +65 -0
- package/package.json +4 -1
- package/server.js +42 -29
- package/lib/req/cls.js +0 -39
- package/libx/_runtime/cds-services/services/utils/diff.js +0 -53
- package/libx/_runtime/cds-services/util/auditlog.js +0 -247
- package/libx/_runtime/cds-services/util/xsenv.js +0 -51
- package/libx/_runtime/common/utils/backlinks.js +0 -83
- package/libx/_runtime/common/utils/rewriteAsterisk.js +0 -72
- package/libx/_runtime/odata/index.js +0 -55
- package/libx/_runtime/odata/odata2cqn.js +0 -1
- package/libx/_runtime/odata/readToCqn.js +0 -129
- package/libx/_runtime/remote/cqn2odata/index.js +0 -2
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
const cds = require('../../cds')
|
|
2
2
|
|
|
3
|
-
const { isSelfManaged, isBacklink } = require('../utils/backlinks')
|
|
4
|
-
|
|
5
3
|
const { ensureNoDraftsSuffix } = require('../utils/draft')
|
|
6
4
|
const { isRootEntity } = require('../utils/csn')
|
|
7
5
|
const { getTransition, getDBTable } = require('../utils/resolveView')
|
|
8
6
|
|
|
9
|
-
const { foreignKeyPropagations } = require('../utils/foreignKeyPropagations')
|
|
10
|
-
|
|
11
7
|
const getError = require('../../common/error')
|
|
12
8
|
|
|
13
9
|
/*
|
|
@@ -15,21 +11,25 @@ const getError = require('../../common/error')
|
|
|
15
11
|
*/
|
|
16
12
|
|
|
17
13
|
const _foreignKeysToLinks = (element, inverse) =>
|
|
18
|
-
|
|
14
|
+
element._foreignKeys.map(e => {
|
|
19
15
|
e = inverse
|
|
20
16
|
? {
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
childElement: e.parentElement,
|
|
18
|
+
parentElement: e.childElement,
|
|
23
19
|
childFieldValue: e.parentFieldValue,
|
|
24
20
|
parentFieldValue: e.childFieldValue,
|
|
25
21
|
prefix: e.prefix
|
|
26
22
|
}
|
|
27
23
|
: e
|
|
28
|
-
const link = {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
24
|
+
const link = {}
|
|
25
|
+
if (e.parentElement)
|
|
26
|
+
link.entityKey =
|
|
27
|
+
e.prefix && !e.parentElement.name.includes(e.prefix)
|
|
28
|
+
? `${e.prefix}_${e.parentElement.name}`
|
|
29
|
+
: e.parentElement.name
|
|
30
|
+
if (e.childElement)
|
|
31
|
+
link.targetKey =
|
|
32
|
+
e.prefix && !e.childElement.name.includes(e.prefix) ? `${e.prefix}_${e.childElement.name}` : e.childElement.name
|
|
33
33
|
if (e.parentFieldValue !== undefined) link.entityVal = e.parentFieldValue
|
|
34
34
|
if (e.childFieldValue !== undefined) link.targetVal = e.childFieldValue
|
|
35
35
|
return link
|
|
@@ -57,7 +57,7 @@ const _resolvedElement = (element, service) => {
|
|
|
57
57
|
const _navigationExistsInCompositionMap = (element, compositionMap) =>
|
|
58
58
|
compositionMap.has(element.target) && element._isCompositionEffective
|
|
59
59
|
|
|
60
|
-
const _isUnManaged = element => element.on && !
|
|
60
|
+
const _isUnManaged = element => element.on && !element._isSelfManaged
|
|
61
61
|
|
|
62
62
|
const _isNonRecursiveNavigation = (element, rootEntityName) =>
|
|
63
63
|
rootEntityName !== element.target && element._isCompositionEffective
|
|
@@ -106,7 +106,7 @@ const _getCompositionTreeRec = ({
|
|
|
106
106
|
backLinks: [],
|
|
107
107
|
customBackLinks: []
|
|
108
108
|
})
|
|
109
|
-
if (!
|
|
109
|
+
if (!element._isSelfManaged) {
|
|
110
110
|
const backLinks = _foreignKeysToLinks(element, true) || []
|
|
111
111
|
if (element.is2many) {
|
|
112
112
|
compositionElement.customBackLinks.push(...backLinks)
|
|
@@ -118,7 +118,11 @@ const _getCompositionTreeRec = ({
|
|
|
118
118
|
for (const backLinkName in targetEntity.elements) {
|
|
119
119
|
const _backLink = targetEntity.elements[backLinkName]
|
|
120
120
|
if (!_backLink._isAssociationEffective) continue
|
|
121
|
-
if (
|
|
121
|
+
if (
|
|
122
|
+
_backLink._isCompositionBacklink &&
|
|
123
|
+
_backLink.target === compositionElement.target &&
|
|
124
|
+
_backLink._anchor.name === element.name
|
|
125
|
+
) {
|
|
122
126
|
const backLinks = _foreignKeysToLinks(_backLink) || []
|
|
123
127
|
if (_isUnManaged(element)) {
|
|
124
128
|
compositionElement.customBackLinks.push(...backLinks)
|
|
@@ -131,7 +135,7 @@ const _getCompositionTreeRec = ({
|
|
|
131
135
|
compositionTree.compositionElements.push(compositionElement)
|
|
132
136
|
} else if (_isNonRecursiveNavigation(element, rootEntityName)) {
|
|
133
137
|
const subObject = _createSubElement(element, definitions)
|
|
134
|
-
if (!
|
|
138
|
+
if (!element._isSelfManaged) {
|
|
135
139
|
const backLinks = _foreignKeysToLinks(element, true) || []
|
|
136
140
|
if (element.is2many) {
|
|
137
141
|
subObject.customBackLinks.push(...backLinks)
|
|
@@ -151,7 +155,8 @@ const _getCompositionTreeRec = ({
|
|
|
151
155
|
})
|
|
152
156
|
} else if (
|
|
153
157
|
element._isAssociationEffective &&
|
|
154
|
-
|
|
158
|
+
element._isCompositionBacklink &&
|
|
159
|
+
element.target === compositionTree.target &&
|
|
155
160
|
compositionMap.has(element.target)
|
|
156
161
|
) {
|
|
157
162
|
const backLinks = _foreignKeysToLinks(element) || []
|
|
@@ -218,7 +223,7 @@ const _cacheCompositionParentsOfOne = ({ definitions }) => {
|
|
|
218
223
|
if (!parent.kind === 'entity' || !parent.elements) continue
|
|
219
224
|
for (const elementName in parent.elements) {
|
|
220
225
|
const element = parent.elements[elementName]
|
|
221
|
-
if (element._isCompositionEffective && element.is2one && !
|
|
226
|
+
if (element._isCompositionEffective && element.is2one && !element._isSelfManaged) {
|
|
222
227
|
const targetName = element.target
|
|
223
228
|
const target = definitions[targetName]
|
|
224
229
|
if (!target) continue
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
const { isSelfManaged } = require('../utils/backlinks')
|
|
2
|
-
|
|
3
1
|
const { ensureNoDraftsSuffix, ensureDraftsSuffix } = require('../utils/draft')
|
|
4
2
|
|
|
5
3
|
const addDraftSuffix = (draft, name) => {
|
|
@@ -24,6 +22,7 @@ const keyElements = entity => {
|
|
|
24
22
|
|
|
25
23
|
const key = (entity, data) => {
|
|
26
24
|
return keyElements(entity).reduce((result, element) => {
|
|
25
|
+
if (element.name === 'IsActiveEntity' && !Object.prototype.hasOwnProperty.call(data, element.name)) return result
|
|
27
26
|
result[element.name] = data[element.name]
|
|
28
27
|
return result
|
|
29
28
|
}, {})
|
|
@@ -33,10 +32,6 @@ const val = element => (element && element.val) || element
|
|
|
33
32
|
|
|
34
33
|
const array = x => (Array.isArray(x) ? x : [x])
|
|
35
34
|
|
|
36
|
-
const isManaged = element => {
|
|
37
|
-
return isSelfManaged(element) || !element.on
|
|
38
|
-
}
|
|
39
|
-
|
|
40
35
|
const isCompOrAssoc = (entity, k, onlyToOne) => {
|
|
41
36
|
return (
|
|
42
37
|
entity.elements &&
|
|
@@ -60,6 +55,37 @@ const cleanDeepData = (entity, data, onlyToOne = false) => {
|
|
|
60
55
|
})
|
|
61
56
|
}
|
|
62
57
|
|
|
58
|
+
const _getBacklinkNameFromOnCond = element => {
|
|
59
|
+
if (element.on && element.on.length === 3 && element.on[0].ref && element.on[2].ref) {
|
|
60
|
+
if (element.on[0].ref[0] === '$self') {
|
|
61
|
+
return element.on[2].ref[element.on[2].ref.length - 1]
|
|
62
|
+
} else if (element.on[2].ref[0] === '$self') {
|
|
63
|
+
return element.on[0].ref[element.on[0].ref.length - 1]
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const isBacklink = (element, parent, checkContained, backLinkName) => {
|
|
69
|
+
if (!element._isAssociationStrict) return false
|
|
70
|
+
if (!parent || !(element.keys || element.on)) return false
|
|
71
|
+
if (element.target !== parent.name) return false
|
|
72
|
+
|
|
73
|
+
const _isBackLink = parentElement =>
|
|
74
|
+
(!checkContained || parentElement._isContained) && _getBacklinkNameFromOnCond(parentElement) === element.name
|
|
75
|
+
|
|
76
|
+
if (backLinkName) {
|
|
77
|
+
const parentElement = parent.elements[backLinkName]
|
|
78
|
+
return parentElement.isAssociation && _isBackLink(parentElement)
|
|
79
|
+
}
|
|
80
|
+
for (const parentElementName in parent.elements) {
|
|
81
|
+
const parentElement = parent.elements[parentElementName]
|
|
82
|
+
if (!parentElement.isAssociation) continue
|
|
83
|
+
if (_isBackLink(parentElement)) return true
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return false
|
|
87
|
+
}
|
|
88
|
+
|
|
63
89
|
module.exports = {
|
|
64
90
|
addDraftSuffix,
|
|
65
91
|
whereKey,
|
|
@@ -67,7 +93,7 @@ module.exports = {
|
|
|
67
93
|
key,
|
|
68
94
|
val,
|
|
69
95
|
array,
|
|
70
|
-
isManaged,
|
|
71
96
|
isCompOrAssoc,
|
|
72
|
-
cleanDeepData
|
|
97
|
+
cleanDeepData,
|
|
98
|
+
isBacklink
|
|
73
99
|
}
|
|
@@ -22,6 +22,8 @@ const {
|
|
|
22
22
|
MAX_SEVERITY
|
|
23
23
|
} = require('./constants')
|
|
24
24
|
|
|
25
|
+
const SKIP_SANITIZATION = '@cds.skip_sanitization'
|
|
26
|
+
|
|
25
27
|
const _getFiltered = err => {
|
|
26
28
|
const error = {}
|
|
27
29
|
|
|
@@ -103,10 +105,13 @@ const normalizeError = (err, req) => {
|
|
|
103
105
|
// make sure it's a number
|
|
104
106
|
statusCode = statusCode ? Number(statusCode) : 500
|
|
105
107
|
|
|
106
|
-
|
|
108
|
+
// REVISIT: make === 500 in cds^6
|
|
109
|
+
// error[SKIP_SANITIZATION] is not an official API!!!
|
|
110
|
+
if (statusCode >= 500 && process.env.NODE_ENV === 'production' && !error[SKIP_SANITIZATION]) {
|
|
107
111
|
// > return sanitized error to client
|
|
108
112
|
return { error: { code: `${statusCode}`, message: i18n(statusCode, locale) }, statusCode }
|
|
109
113
|
}
|
|
114
|
+
delete error[SKIP_SANITIZATION]
|
|
110
115
|
|
|
111
116
|
// no top level null codes
|
|
112
117
|
if (error.code === 'null') {
|
|
@@ -6,7 +6,7 @@ const cds = require('../../cds')
|
|
|
6
6
|
const { SELECT } = cds.ql
|
|
7
7
|
|
|
8
8
|
const { getRequiresAsArray } = require('../utils/auth')
|
|
9
|
-
const cqn2cqn4sql = require('../utils/cqn2cqn4sql')
|
|
9
|
+
const { cqn2cqn4sql } = require('../utils/cqn2cqn4sql')
|
|
10
10
|
const { isActiveEntityRequested, removeIsActiveEntityRecursively } = require('../../fiori/utils/where')
|
|
11
11
|
const { ensureDraftsSuffix } = require('../../fiori/utils/handler')
|
|
12
12
|
|
|
@@ -204,9 +204,10 @@ const _findTableName = (ref, aliases) => {
|
|
|
204
204
|
|
|
205
205
|
const _getTableForColumn = (col, aliases, model) => {
|
|
206
206
|
for (let i = 0; i < aliases.length; i++) {
|
|
207
|
-
const
|
|
207
|
+
const index = aliases.length - i - 1
|
|
208
|
+
const alias = aliases[index]
|
|
208
209
|
if (Object.keys(model.definitions[alias].elements).includes(col)) {
|
|
209
|
-
return { index
|
|
210
|
+
return { index, table: alias.replace(/\./g, '_') }
|
|
210
211
|
}
|
|
211
212
|
}
|
|
212
213
|
|
|
@@ -549,13 +550,18 @@ const _addNormalizedRestrict = (restrict, restricts, definition, definitions) =>
|
|
|
549
550
|
if (where) {
|
|
550
551
|
// operate on a copy
|
|
551
552
|
let _where = where
|
|
552
|
-
|
|
553
|
+
// find all path expressions in order to normalize shorthand (i.e., inject "[exists ...]")
|
|
554
|
+
const paths = (where.match(/ (\w\.*)*/g) || []).filter(m => m.match(/\./) && m !== ' ')
|
|
553
555
|
for (let i = 0; i < paths.length; i++) {
|
|
554
556
|
const parts = paths[i].trim().split('.')
|
|
555
557
|
let current = definition
|
|
556
558
|
while (parts.length) {
|
|
557
559
|
current = current.elements[parts.shift()]
|
|
558
|
-
if (current.
|
|
560
|
+
if (current.isAssociation && _where.includes(current.name + '.')) {
|
|
561
|
+
const matches = _where.match(new RegExp(`(${current.name}).(.*)]`))
|
|
562
|
+
_where = _where.replace(`${matches[1]}.`, `${current.name}[exists `)
|
|
563
|
+
_where = _where.replace(matches[2], `${matches[2]}]`)
|
|
564
|
+
}
|
|
559
565
|
if (current.target) current = definitions[current.target]
|
|
560
566
|
}
|
|
561
567
|
}
|
|
@@ -882,19 +888,15 @@ const _secureDependentEntities = srv => {
|
|
|
882
888
|
}
|
|
883
889
|
}
|
|
884
890
|
|
|
885
|
-
module.exports = function () {
|
|
886
|
-
|
|
887
|
-
* @restrict, @requires, @readonly, @insertonly, and @Capabilities for entities
|
|
888
|
-
*/
|
|
891
|
+
module.exports = cds.service.impl(function () {
|
|
892
|
+
// @restrict, @requires, @readonly, @insertonly, and @Capabilities for entities
|
|
889
893
|
_secureDependentEntities(this)
|
|
890
894
|
for (const k in this.entities) {
|
|
891
895
|
const entity = this.entities[k]
|
|
892
896
|
if (!_authDependsOnParents(entity)) _registerAuthHandlers(entity, this)
|
|
893
897
|
}
|
|
894
898
|
|
|
895
|
-
|
|
896
|
-
* @restrict and @requires for operations
|
|
897
|
-
*/
|
|
899
|
+
// @restrict and @requires for operations
|
|
898
900
|
for (const k in this.operations) {
|
|
899
901
|
const operation = this.operations[k]
|
|
900
902
|
|
|
@@ -904,4 +906,4 @@ module.exports = function () {
|
|
|
904
906
|
// @restrict
|
|
905
907
|
_registerOperationRestrictHandlers(operation, this)
|
|
906
908
|
}
|
|
907
|
-
}
|
|
909
|
+
})
|
|
@@ -67,7 +67,7 @@ const _updateReqData = (req, that) => {
|
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
module.exports = function () {
|
|
70
|
+
module.exports = cds.service.impl(function () {
|
|
71
71
|
this.on(['CREATE', 'READ', 'UPDATE', 'DELETE'], '*', async function (req) {
|
|
72
72
|
if (typeof req.query !== 'string' && req.target && req.target._hasPersistenceSkip) {
|
|
73
73
|
req.reject(501, 'PERSISTENCE_SKIP_NO_GENERIC_CRUD', [req.target.name])
|
|
@@ -128,4 +128,4 @@ module.exports = function () {
|
|
|
128
128
|
|
|
129
129
|
return req.data
|
|
130
130
|
})
|
|
131
|
-
}
|
|
131
|
+
})
|
|
@@ -2,9 +2,9 @@ const cds = require('../../cds')
|
|
|
2
2
|
const { SELECT } = cds.ql
|
|
3
3
|
|
|
4
4
|
// REVISIT: draft should not be handled here, e.g., target.name should be adjusted before
|
|
5
|
-
const { isActiveEntityRequested
|
|
5
|
+
const { isActiveEntityRequested } = require('../../fiori/utils/where')
|
|
6
6
|
const { ensureDraftsSuffix } = require('../../fiori/utils/handler')
|
|
7
|
-
const cqn2cqn4sql = require('../../common/utils/cqn2cqn4sql')
|
|
7
|
+
const { cqn2cqn4sql } = require('../../common/utils/cqn2cqn4sql')
|
|
8
8
|
const ODataRequest = require('../../cds-services/adapter/odata-v4/ODataRequest')
|
|
9
9
|
|
|
10
10
|
const C_U_ = {
|
|
@@ -22,10 +22,11 @@ const getSelectCQN = (query, target, model) => {
|
|
|
22
22
|
} else {
|
|
23
23
|
requestTarget = query.DELETE.from
|
|
24
24
|
}
|
|
25
|
+
|
|
26
|
+
const targetName = isActiveEntityRequested(requestTarget.ref[0].where) ? target.name : ensureDraftsSuffix(target.name)
|
|
25
27
|
const cqn = cqn2cqn4sql(SELECT.from(requestTarget), model)
|
|
26
|
-
cqn.SELECT.from.ref[0] = isActiveEntityRequested(cqn.SELECT.where) ? target.name : ensureDraftsSuffix(target.name)
|
|
27
28
|
cqn.columns([target._etag])
|
|
28
|
-
cqn.SELECT.
|
|
29
|
+
cqn.SELECT.from.ref[0] = targetName
|
|
29
30
|
|
|
30
31
|
return cqn
|
|
31
32
|
}
|
|
@@ -60,11 +61,12 @@ const _handler = async function (req) {
|
|
|
60
61
|
}
|
|
61
62
|
}
|
|
62
63
|
|
|
63
|
-
|
|
64
|
+
/**
|
|
64
65
|
* handler registration
|
|
66
|
+
*
|
|
65
67
|
*/
|
|
66
68
|
/* istanbul ignore next */
|
|
67
|
-
module.exports = function () {
|
|
69
|
+
module.exports = cds.service.impl(function () {
|
|
68
70
|
_handler._initial = true
|
|
69
71
|
|
|
70
72
|
for (const k in this.entities) {
|
|
@@ -75,8 +77,9 @@ module.exports = function () {
|
|
|
75
77
|
continue
|
|
76
78
|
}
|
|
77
79
|
|
|
78
|
-
//
|
|
80
|
+
// handler for CREATE is registered for backwards compatibility w.r.t. ETag generation
|
|
79
81
|
let events = ['CREATE', 'READ', 'UPDATE', 'DELETE']
|
|
82
|
+
|
|
80
83
|
// if odata and fiori is separated, this will not be needed in the odata version
|
|
81
84
|
if (entity._isDraftEnabled) {
|
|
82
85
|
events = ['READ', 'NEW', 'DELETE', 'PATCH', 'EDIT', 'CANCEL']
|
|
@@ -88,4 +91,4 @@ module.exports = function () {
|
|
|
88
91
|
this.before(action, entity, _handler)
|
|
89
92
|
}
|
|
90
93
|
}
|
|
91
|
-
}
|
|
94
|
+
})
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
const cds = require('../../cds')
|
|
11
|
-
const enrichDataWithKeysFromWhere = require('../utils/
|
|
11
|
+
const { enrichDataWithKeysFromWhere } = require('../utils/keys')
|
|
12
12
|
const { DRAFT_COLUMNS_MAP } = require('../../common/constants/draft')
|
|
13
13
|
const { checkInputConstraints, checkIfAssocDeep } = require('../../cds-services/util/assert')
|
|
14
14
|
const getTemplate = require('../utils/template')
|
|
@@ -295,7 +295,7 @@ function _actionFunctionHandler(req) {
|
|
|
295
295
|
_handler._initial = true
|
|
296
296
|
_actionFunctionHandler._initial = true
|
|
297
297
|
|
|
298
|
-
module.exports = function () {
|
|
298
|
+
module.exports = cds.service.impl(function () {
|
|
299
299
|
this.before(['CREATE', 'UPDATE', 'NEW', 'PATCH'], '*', _handler)
|
|
300
300
|
|
|
301
301
|
const operationNames = []
|
|
@@ -318,4 +318,4 @@ module.exports = function () {
|
|
|
318
318
|
this.before(boundOps, entity.name, _actionFunctionHandler)
|
|
319
319
|
}
|
|
320
320
|
}
|
|
321
|
-
}
|
|
321
|
+
})
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const cds = require('../../cds')
|
|
1
2
|
const { getDefaultPageSize } = require('../utils/page')
|
|
2
3
|
|
|
3
4
|
const _handler = function (req) {
|
|
@@ -5,15 +6,18 @@ const _handler = function (req) {
|
|
|
5
6
|
if (!req._.req) return
|
|
6
7
|
|
|
7
8
|
// target === null if view with parameters
|
|
8
|
-
if (!req.target || !req.query.SELECT || req.query.SELECT.
|
|
9
|
+
if (!req.target || !req.query.SELECT || req.query.SELECT.one) return
|
|
9
10
|
|
|
10
|
-
req.query.limit
|
|
11
|
+
let { rows, offset } = req.query.SELECT.limit || {}
|
|
12
|
+
rows = rows && 'val' in rows ? rows.val : getDefaultPageSize(req.target)
|
|
13
|
+
offset = offset && 'val' in offset ? offset.val : 0
|
|
14
|
+
req.query.limit(...[rows, offset])
|
|
11
15
|
}
|
|
12
16
|
|
|
13
|
-
|
|
17
|
+
/**
|
|
14
18
|
* handler registration
|
|
15
19
|
*/
|
|
16
|
-
module.exports = function () {
|
|
20
|
+
module.exports = cds.service.impl(function () {
|
|
17
21
|
_handler._initial = true
|
|
18
22
|
this.before('READ', '*', _handler)
|
|
19
|
-
}
|
|
23
|
+
})
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* and is neither key nor read-only (e.g., managed, virtual, etc.)
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
const cds = require('../../cds')
|
|
8
9
|
const getTemplate = require('../utils/template')
|
|
9
10
|
const templateProcessor = require('../utils/templateProcessor')
|
|
10
11
|
const { getDataFromCQN, setDataFromCQN } = require('../utils/data')
|
|
@@ -90,6 +91,6 @@ function _handler(req) {
|
|
|
90
91
|
|
|
91
92
|
_handler._initial = true
|
|
92
93
|
|
|
93
|
-
module.exports = function () {
|
|
94
|
+
module.exports = cds.service.impl(function () {
|
|
94
95
|
this.before(['UPDATE'], '*', _handler)
|
|
95
|
-
}
|
|
96
|
+
})
|
|
@@ -85,13 +85,13 @@ const _handler = function (req) {
|
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
|
|
88
|
+
/**
|
|
89
89
|
* handler registration
|
|
90
90
|
*/
|
|
91
|
-
module.exports = function () {
|
|
91
|
+
module.exports = cds.service.impl(function () {
|
|
92
92
|
_handler._initial = true
|
|
93
93
|
this.before('READ', '*', _handler)
|
|
94
|
-
}
|
|
94
|
+
})
|
|
95
95
|
|
|
96
96
|
// REVISIT: remove (currently needed for test)
|
|
97
97
|
module.exports.handler = _handler
|
|
@@ -71,11 +71,11 @@ const _handler = function (req) {
|
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
|
|
74
|
+
/**
|
|
75
75
|
* handler registration
|
|
76
76
|
*/
|
|
77
|
-
module.exports = function () {
|
|
77
|
+
module.exports = cds.service.impl(function () {
|
|
78
78
|
_handler._initial = true
|
|
79
79
|
// always run to allow interaction with temporal data in custom handlers
|
|
80
80
|
this.before('*', _handler)
|
|
81
|
-
}
|
|
81
|
+
})
|
|
@@ -8,7 +8,7 @@ module.exports = cds => {
|
|
|
8
8
|
// attach _getHash helper to mtx
|
|
9
9
|
if (!cds.mtx._getHash) {
|
|
10
10
|
cds.mtx._getHash = req => {
|
|
11
|
-
let hash = req.
|
|
11
|
+
let hash = req.tenant
|
|
12
12
|
if (req.features) hash += ':' + Object.keys(req.features).join(';')
|
|
13
13
|
return hash
|
|
14
14
|
}
|
|
@@ -16,7 +16,26 @@ const getEntityNameFromUpdateCQN = cqn => {
|
|
|
16
16
|
return (cqn.UPDATE.entity.ref && cqn.UPDATE.entity.ref[0]) || cqn.UPDATE.entity.name || cqn.UPDATE.entity
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
// scope: simple wheres à la "[{ ref: ['foo'] }, '=', { val: 'bar' }, 'and', ... ]"
|
|
20
|
+
function where2obj(where, target = null) {
|
|
21
|
+
const data = {}
|
|
22
|
+
for (let i = 0; i < where.length; i++) {
|
|
23
|
+
const whereEl = where[i]
|
|
24
|
+
const colName = whereEl.ref && whereEl.ref[whereEl.ref.length - 1]
|
|
25
|
+
// optional validation if target is passed
|
|
26
|
+
if (target) {
|
|
27
|
+
const colEl = target.elements[colName]
|
|
28
|
+
if (!colEl || !colEl.key) continue
|
|
29
|
+
}
|
|
30
|
+
const opWhere = where[i + 1]
|
|
31
|
+
const valWhere = where[i + 2]
|
|
32
|
+
if (opWhere === '=' && valWhere && 'val' in valWhere) data[colName] = valWhere.val
|
|
33
|
+
}
|
|
34
|
+
return data
|
|
35
|
+
}
|
|
36
|
+
|
|
19
37
|
module.exports = {
|
|
20
38
|
getEntityNameFromDeleteCQN,
|
|
21
|
-
getEntityNameFromUpdateCQN
|
|
39
|
+
getEntityNameFromUpdateCQN,
|
|
40
|
+
where2obj
|
|
22
41
|
}
|