@sap/cds 5.4.3 → 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 +239 -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 +66 -63
- 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 +12 -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 +53 -31
- 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 +123 -108
- package/libx/_runtime/common/utils/csn.js +56 -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 +227 -173
- package/libx/_runtime/common/utils/rewriteAsterisk.js +46 -26
- package/libx/_runtime/common/utils/structured.js +13 -13
- 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 +28 -72
- 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 +21 -8
- 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 +261 -205
- 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 +3 -3
- 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 +33 -27
- package/libx/_runtime/sqlite/localized.js +12 -7
- package/libx/_runtime/types/api.js +10 -0
- package/package.json +2 -2
- 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
|
@@ -9,11 +9,11 @@ const { foreignKeyPropagations } = require('./foreignKeyPropagations')
|
|
|
9
9
|
const search2cqn4sql = require('./search2cqn4sql')
|
|
10
10
|
const { getEntityNameFromCQN } = require('./entityFromCqn')
|
|
11
11
|
const getError = require('../../common/error')
|
|
12
|
-
|
|
13
|
-
const SYMBOL_FROM_ANNOTATION = Symbol.for('sap.cds.FROM_ANNOTATION')
|
|
12
|
+
const { getPathFromRef, getEntityFromPath } = require('../../common/utils/path')
|
|
14
13
|
|
|
15
14
|
const PARENT_ALIAS = '_parent_'
|
|
16
|
-
const
|
|
15
|
+
const PARENT_ALIAS_REGEX = new RegExp('^' + PARENT_ALIAS + '\\d*$')
|
|
16
|
+
const FOREIGN_ALIAS = '_foreign_'
|
|
17
17
|
const OPERATIONS = ['=', '>', '<', '!=', '<>', '>=', '<=', 'like', 'between', 'in', 'not in']
|
|
18
18
|
|
|
19
19
|
const _addOnCondToWhere = (cqn, entity, navigation, tableAlias, identifier, csn, prefix) => {
|
|
@@ -39,7 +39,7 @@ const _addOnCondToWhere = (cqn, entity, navigation, tableAlias, identifier, csn,
|
|
|
39
39
|
// special case in lambda functions
|
|
40
40
|
const _addParentAlias = (where, alias) => {
|
|
41
41
|
where.forEach(e => {
|
|
42
|
-
if (e.ref && e.ref[0]
|
|
42
|
+
if (e.ref && e.ref[0].match(PARENT_ALIAS_REGEX)) {
|
|
43
43
|
e.ref[0] = alias
|
|
44
44
|
}
|
|
45
45
|
})
|
|
@@ -47,9 +47,7 @@ const _addParentAlias = (where, alias) => {
|
|
|
47
47
|
|
|
48
48
|
const _addAliasToElement = (e, alias) => {
|
|
49
49
|
if (e.ref) {
|
|
50
|
-
|
|
51
|
-
if (e[SYMBOL_FROM_ANNOTATION]) aliased[SYMBOL_FROM_ANNOTATION] = true
|
|
52
|
-
return aliased
|
|
50
|
+
return { ref: [alias, ...e.ref] }
|
|
53
51
|
}
|
|
54
52
|
|
|
55
53
|
if (e.list) {
|
|
@@ -94,10 +92,10 @@ const _getTargetFromRef = ref => {
|
|
|
94
92
|
|
|
95
93
|
const _getEntityName = (fromClause, entity, i) => {
|
|
96
94
|
const targetName = _getTargetFromRef(fromClause.ref[i])
|
|
97
|
-
return i === 0 ? targetName : entity.elements[targetName].target
|
|
95
|
+
return i === 0 ? targetName : entity && entity.elements[targetName] && entity.elements[targetName].target
|
|
98
96
|
}
|
|
99
97
|
|
|
100
|
-
const convertPathExpressionToWhere = (fromClause, model) => {
|
|
98
|
+
const convertPathExpressionToWhere = (fromClause, model, options) => {
|
|
101
99
|
if (fromClause.ref.length === 1) {
|
|
102
100
|
const target = _getTargetFromRef(fromClause.ref[0])
|
|
103
101
|
const alias = fromClause.as
|
|
@@ -107,6 +105,7 @@ const convertPathExpressionToWhere = (fromClause, model) => {
|
|
|
107
105
|
|
|
108
106
|
let previousSelect, previousEntityName, previousTableAlias, structParent
|
|
109
107
|
let prefix = []
|
|
108
|
+
let columns
|
|
110
109
|
for (let i = 0; i < fromClause.ref.length; i++) {
|
|
111
110
|
const entity = structParent || model.definitions[previousEntityName]
|
|
112
111
|
const element = _elementFromRef(fromClause.ref[i], entity)
|
|
@@ -115,14 +114,16 @@ const convertPathExpressionToWhere = (fromClause, model) => {
|
|
|
115
114
|
prefix.push(element.name)
|
|
116
115
|
structParent = element
|
|
117
116
|
continue
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
if (element &&
|
|
121
|
-
|
|
122
|
-
|
|
117
|
+
} else if (element && element.isAssociation) {
|
|
118
|
+
_modifyNavigationInWhere(fromClause.ref[i].where, element._target)
|
|
119
|
+
} else if (element && previousSelect && i === fromClause.ref.length - 1) {
|
|
120
|
+
columns = [{ ref: [...prefix, element.name] }]
|
|
121
|
+
fromClause.ref.splice(-1)
|
|
122
|
+
continue
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
const currentEntityName = _getEntityName(fromClause, entity, i)
|
|
126
|
+
if (!currentEntityName) continue
|
|
126
127
|
const tableAlias = `T${i}`
|
|
127
128
|
const currentSelect = SELECT.from(`${currentEntityName} as ${tableAlias}`)
|
|
128
129
|
|
|
@@ -144,7 +145,7 @@ const convertPathExpressionToWhere = (fromClause, model) => {
|
|
|
144
145
|
model,
|
|
145
146
|
prefix
|
|
146
147
|
)
|
|
147
|
-
|
|
148
|
+
_convertSelect(previousSelect, model, options)
|
|
148
149
|
currentSelect.where('exists', previousSelect)
|
|
149
150
|
}
|
|
150
151
|
|
|
@@ -158,7 +159,8 @@ const convertPathExpressionToWhere = (fromClause, model) => {
|
|
|
158
159
|
return {
|
|
159
160
|
target: previousEntityName,
|
|
160
161
|
alias: previousTableAlias,
|
|
161
|
-
where: previousSelect && previousSelect.SELECT && previousSelect.SELECT.where
|
|
162
|
+
where: previousSelect && previousSelect.SELECT && previousSelect.SELECT.where,
|
|
163
|
+
columns
|
|
162
164
|
}
|
|
163
165
|
}
|
|
164
166
|
|
|
@@ -258,23 +260,30 @@ const _isAll = element => {
|
|
|
258
260
|
return last && last.id && last.where && last.where[0] === 'not' && last.where[1].xpr
|
|
259
261
|
}
|
|
260
262
|
|
|
261
|
-
const _getLambdaSubSelect = (cqn, index, lambdaOp, model) => {
|
|
263
|
+
const _getLambdaSubSelect = (cqn, index, lambdaOp, model, options) => {
|
|
262
264
|
const _unshiftRefsWithNavigation = nav => el => {
|
|
263
265
|
if (el.ref) return { ref: [...nav, ...el.ref] }
|
|
264
266
|
if (el.xpr) return { xpr: el.xpr.map(_unshiftRefsWithNavigation(nav)) }
|
|
265
267
|
return el
|
|
266
268
|
}
|
|
267
|
-
|
|
269
|
+
|
|
270
|
+
if (!options.lambdaIteration) options.lambdaIteration = 1
|
|
271
|
+
|
|
272
|
+
const outerAlias = cqn.SELECT.from.as || PARENT_ALIAS + options.lambdaIteration
|
|
273
|
+
const innerAlias = FOREIGN_ALIAS + options.lambdaIteration
|
|
274
|
+
cqn.SELECT.from.as = outerAlias
|
|
275
|
+
|
|
276
|
+
const queryTarget = getEntityFromPath(getPathFromRef(cqn.SELECT.from.ref), model)
|
|
277
|
+
|
|
268
278
|
const nav = cqn.SELECT.where[index].ref.map(el => (el.id ? el.id : el))
|
|
269
|
-
const navName = nav[0]
|
|
270
279
|
const last = cqn.SELECT.where[index].ref.slice(-1)[0]
|
|
271
|
-
|
|
272
|
-
const queryTarget = model.definitions[cqn._target.name] || cqn._target
|
|
280
|
+
const navName = queryTarget.elements[nav[0]] ? nav[0] : nav[nav.length - 1]
|
|
273
281
|
const navElement = queryTarget.elements[navName]
|
|
274
282
|
const lastElement = nav.reduce((csn, segment) => {
|
|
275
283
|
if (csn.items) return csn // arrayed not supported
|
|
276
284
|
if (csn.elements) {
|
|
277
285
|
const next = csn.elements[segment]
|
|
286
|
+
if (!next) return csn
|
|
278
287
|
if (next.target) return model.definitions[next.target]
|
|
279
288
|
return next
|
|
280
289
|
}
|
|
@@ -286,38 +295,54 @@ const _getLambdaSubSelect = (cqn, index, lambdaOp, model) => {
|
|
|
286
295
|
? nav.length > 1
|
|
287
296
|
? last.where.map(_unshiftRefsWithNavigation(nav.slice(1)))
|
|
288
297
|
: last.where
|
|
289
|
-
:
|
|
298
|
+
: undefined
|
|
290
299
|
const onConditionOptions = {
|
|
291
300
|
associationNames: navName,
|
|
292
301
|
csn: model,
|
|
293
302
|
aliases: {
|
|
294
|
-
select:
|
|
295
|
-
join:
|
|
303
|
+
select: innerAlias,
|
|
304
|
+
join: outerAlias
|
|
296
305
|
}
|
|
297
306
|
}
|
|
298
307
|
const onCondition = getOnCond(navElement, onConditionOptions)
|
|
299
308
|
|
|
300
|
-
const subSelect = SELECT.from({ ref: [navElement.target], as:
|
|
301
|
-
if (condition)
|
|
309
|
+
const subSelect = SELECT.from({ ref: [navElement.target], as: innerAlias })
|
|
310
|
+
if (condition) {
|
|
311
|
+
if (subSelect.SELECT.from.as) {
|
|
312
|
+
for (let i = 0; i < condition.length; i++) {
|
|
313
|
+
if (
|
|
314
|
+
condition[i].ref &&
|
|
315
|
+
condition[i].ref.length > 1 &&
|
|
316
|
+
condition[i].ref.every(r => typeof r === 'string') &&
|
|
317
|
+
condition[i].ref[0] === navName
|
|
318
|
+
) {
|
|
319
|
+
condition[i].ref[0] = subSelect.SELECT.from.as
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
subSelect.where(condition)
|
|
324
|
+
}
|
|
302
325
|
subSelect.where(onCondition)
|
|
303
326
|
if (cds.env.effective.odata.structs) {
|
|
304
327
|
flattenStructuredSelect(subSelect, model)
|
|
305
328
|
}
|
|
306
329
|
subSelect.columns([{ val: 1 }])
|
|
307
330
|
|
|
308
|
-
|
|
331
|
+
// nested where exists needs recursive conversion
|
|
332
|
+
options.lambdaIteration++
|
|
333
|
+
return _convertSelect(subSelect, model, options)
|
|
309
334
|
}
|
|
310
335
|
|
|
311
|
-
const _convertLambda = (cqn, model) => {
|
|
336
|
+
const _convertLambda = (cqn, model, options) => {
|
|
312
337
|
const where = cqn.SELECT.where
|
|
313
338
|
|
|
314
339
|
if (where) {
|
|
315
340
|
where.forEach((element, index) => {
|
|
316
341
|
if (element === 'exists' && _isAny(where[index + 1])) {
|
|
317
|
-
where[index + 1] = _getLambdaSubSelect(cqn, index + 1, 'any', model)
|
|
342
|
+
where[index + 1] = _getLambdaSubSelect(cqn, index + 1, 'any', model, options)
|
|
318
343
|
}
|
|
319
344
|
if (element === 'not' && where[index + 1] === 'exists' && _isAll(where[index + 2])) {
|
|
320
|
-
where[index + 2] = _getLambdaSubSelect(cqn, index + 2, 'all', model)
|
|
345
|
+
where[index + 2] = _getLambdaSubSelect(cqn, index + 2, 'all', model, options)
|
|
321
346
|
}
|
|
322
347
|
})
|
|
323
348
|
}
|
|
@@ -415,22 +440,24 @@ const _convertWhereIfSkip = (whereCQN, index) => {
|
|
|
415
440
|
OPERATIONS.includes(whereCQN[index + 1]) ? whereCQN.splice(index + 1, 2) : whereCQN.splice(index - 2, 2)
|
|
416
441
|
}
|
|
417
442
|
|
|
418
|
-
const _convertOrderByOrWhereCQN = (orderByOrWhereCQN,
|
|
419
|
-
const queryTarget = model.definitions[ensureNoDraftsSuffix(
|
|
443
|
+
const _convertOrderByOrWhereCQN = (orderByOrWhereCQN, target, model, processFn) => {
|
|
444
|
+
const queryTarget = model.definitions[ensureNoDraftsSuffix(target)]
|
|
445
|
+
|
|
420
446
|
orderByOrWhereCQN.forEach((el, index) => {
|
|
421
447
|
if (el.ref && _skip(queryTarget, el.ref, model)) processFn(orderByOrWhereCQN, index)
|
|
422
448
|
})
|
|
423
449
|
}
|
|
424
450
|
|
|
425
|
-
const _convertOrderByOrWhereIfSkip = (cqn, model) => {
|
|
451
|
+
const _convertOrderByOrWhereIfSkip = (cqn, target, model) => {
|
|
426
452
|
if (cqn.SELECT.orderBy && cqn.SELECT.orderBy.length > 1) {
|
|
427
|
-
_convertOrderByOrWhereCQN(cqn.SELECT.orderBy,
|
|
453
|
+
_convertOrderByOrWhereCQN(cqn.SELECT.orderBy, target, model, _convertOrderByIfSkip)
|
|
428
454
|
}
|
|
429
455
|
|
|
430
456
|
if (cqn.SELECT.where) {
|
|
431
|
-
_convertOrderByOrWhereCQN(cqn.SELECT.where,
|
|
457
|
+
_convertOrderByOrWhereCQN(cqn.SELECT.where, target, model, _convertWhereIfSkip)
|
|
432
458
|
}
|
|
433
459
|
}
|
|
460
|
+
|
|
434
461
|
const _convertExpand = expand => {
|
|
435
462
|
expand.forEach(expandElement => {
|
|
436
463
|
if (expandElement.ref && expandElement.ref[0]) {
|
|
@@ -456,12 +483,42 @@ const _convertRefWhereInExpand = columns => {
|
|
|
456
483
|
}
|
|
457
484
|
}
|
|
458
485
|
|
|
486
|
+
const _defaultColumns4 = entity => {
|
|
487
|
+
if (entity && entity.elements) {
|
|
488
|
+
const addAliasToColumns = []
|
|
489
|
+
for (const column in entity.elements) {
|
|
490
|
+
if (column === 'DraftAdministrativeData_DraftUUID') continue
|
|
491
|
+
const e = entity.elements[column]
|
|
492
|
+
if (e.isAssociation || e.virtual) continue
|
|
493
|
+
else if (entity._isDraftEnabled && column === 'IsActiveEntity') {
|
|
494
|
+
addAliasToColumns.push({ val: true, as: 'IsActiveEntity', cast: { type: 'cds.Boolean' } })
|
|
495
|
+
} else if (entity._isDraftEnabled && column === 'HasActiveEntity') {
|
|
496
|
+
addAliasToColumns.push({ val: false, as: 'HasActiveEntity', cast: { type: 'cds.Boolean' } })
|
|
497
|
+
} else if (entity._isDraftEnabled && column === 'HasDraftEntity') {
|
|
498
|
+
const draftName = `${entity.name}_drafts`
|
|
499
|
+
const subSelect = SELECT.from(draftName).columns([1])
|
|
500
|
+
for (const k in entity.keys) {
|
|
501
|
+
if (k !== 'IsActiveEntity') subSelect.where([{ ref: [entity.name, k] }, '=', { ref: [draftName, k] }])
|
|
502
|
+
}
|
|
503
|
+
addAliasToColumns.push({
|
|
504
|
+
xpr: ['case', 'when', 'exists', subSelect, 'then', 'true', 'else', 'false', 'end'],
|
|
505
|
+
as: 'HasDraftEntity',
|
|
506
|
+
cast: { type: 'cds.Boolean' }
|
|
507
|
+
})
|
|
508
|
+
} else addAliasToColumns.push({ ref: [column], as: column })
|
|
509
|
+
}
|
|
510
|
+
return addAliasToColumns
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
// eslint-disable-next-line complexity
|
|
459
515
|
const _convertSelect = (cqn, model, options) => {
|
|
460
|
-
//
|
|
461
|
-
|
|
516
|
+
// REVISIT: still needed?
|
|
517
|
+
// Moved from old SELECT.from where this done much too eager, always for all queries
|
|
518
|
+
if (!cqn.SELECT.columns && cqn._target) cqn.SELECT.columns = _defaultColumns4(cqn._target)
|
|
462
519
|
|
|
463
520
|
// lambda functions
|
|
464
|
-
_convertLambda(cqn, model)
|
|
521
|
+
_convertLambda(cqn, model, options)
|
|
465
522
|
|
|
466
523
|
// add 'or is null' in case of '!='
|
|
467
524
|
if (cqn.SELECT._4odata) _convertNotEqual(cqn.SELECT)
|
|
@@ -474,6 +531,9 @@ const _convertSelect = (cqn, model, options) => {
|
|
|
474
531
|
|
|
475
532
|
// no path expression
|
|
476
533
|
if (!cqnSelectFromRef || (cqnSelectFromRef.length === 1 && !cqnSelectFromRef[0].where)) {
|
|
534
|
+
// remove virtual and with skip annotated fields in orderby and where
|
|
535
|
+
_convertOrderByOrWhereIfSkip(cqn, getEntityNameFromCQN(cqn), model)
|
|
536
|
+
|
|
477
537
|
if (cqnSelectFromRef && cqn.SELECT.search && !options.suppressSearch) {
|
|
478
538
|
searchOptions = { ...searchOptions, ...{ targetName: cqnSelectFromRef[0] } }
|
|
479
539
|
search2cqn4sql(cqn, model, searchOptions)
|
|
@@ -492,8 +552,12 @@ const _convertSelect = (cqn, model, options) => {
|
|
|
492
552
|
}
|
|
493
553
|
|
|
494
554
|
// path expression handling
|
|
495
|
-
const { target, alias, where, cardinality } = convertPathExpressionToWhere(cqn.SELECT.from, model)
|
|
496
|
-
|
|
555
|
+
const { target, alias, where, cardinality, columns } = convertPathExpressionToWhere(cqn.SELECT.from, model, options)
|
|
556
|
+
|
|
557
|
+
// remove virtual and with skip annotated fields in orderby and where
|
|
558
|
+
_convertOrderByOrWhereIfSkip(cqn, target, model)
|
|
559
|
+
|
|
560
|
+
const select = SELECT.from(target, columns || cqn.SELECT.columns)
|
|
497
561
|
|
|
498
562
|
if (alias) {
|
|
499
563
|
select.SELECT.from.as = alias
|
|
@@ -519,7 +583,11 @@ const _convertSelect = (cqn, model, options) => {
|
|
|
519
583
|
|
|
520
584
|
// We add all previous properties ot the newly created query.
|
|
521
585
|
// Reason is to not lose the query API functionality
|
|
522
|
-
Object.assign(select.SELECT, cqn.SELECT, {
|
|
586
|
+
Object.assign(select.SELECT, cqn.SELECT, {
|
|
587
|
+
columns: select.SELECT.columns,
|
|
588
|
+
from: select.SELECT.from,
|
|
589
|
+
where: select.SELECT.where
|
|
590
|
+
})
|
|
523
591
|
|
|
524
592
|
if (select.SELECT.columns && cds.env.effective.odata.structs) {
|
|
525
593
|
flattenStructuredSelect(select, model)
|
|
@@ -528,35 +596,6 @@ const _convertSelect = (cqn, model, options) => {
|
|
|
528
596
|
return select
|
|
529
597
|
}
|
|
530
598
|
|
|
531
|
-
const _getElement = (column, columns, target) => {
|
|
532
|
-
if (!target) return
|
|
533
|
-
|
|
534
|
-
if (columns) {
|
|
535
|
-
// if columns is defined, column is index and row[column] should contain value that belongs to name in columns with same index
|
|
536
|
-
return target.elements[columns[column]]
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
return target.elements[column]
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
const _handleArrayedElements = (rows, target, columns) => {
|
|
543
|
-
for (const row of rows) {
|
|
544
|
-
for (const column in row) {
|
|
545
|
-
const element = _getElement(column, columns, target)
|
|
546
|
-
|
|
547
|
-
if (element && element.is2one) {
|
|
548
|
-
_handleArrayedElements([row[column]], element._target, columns)
|
|
549
|
-
} else if (element && element.is2many) {
|
|
550
|
-
_handleArrayedElements(row[column], element._target, columns)
|
|
551
|
-
} else if (element && element._isStructured) {
|
|
552
|
-
_handleArrayedElements([row[column]], element, columns)
|
|
553
|
-
} else if (Array.isArray(row[column])) {
|
|
554
|
-
row[column] = JSON.stringify(row[column])
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
|
|
560
599
|
const _convertInsert = (cqn, model) => {
|
|
561
600
|
// resolve path expression
|
|
562
601
|
const resolvedIntoClause = _convertPathExpressionForInsertOrDelete(cqn.INSERT.into, model)
|
|
@@ -571,22 +610,11 @@ const _convertInsert = (cqn, model) => {
|
|
|
571
610
|
Object.assign(insert.INSERT, cqn.INSERT, { into: resolvedIntoClause })
|
|
572
611
|
|
|
573
612
|
const targetName = insert.INSERT.into.name || insert.INSERT.into
|
|
574
|
-
const queryTarget = model.definitions[ensureNoDraftsSuffix(targetName)]
|
|
575
|
-
|
|
576
|
-
if (cds.env.effective.odata.version !== 'v2') {
|
|
577
|
-
if (cqn.INSERT.entries) {
|
|
578
|
-
_handleArrayedElements(cqn.INSERT.entries, queryTarget)
|
|
579
|
-
} else if (cqn.INSERT.rows) {
|
|
580
|
-
_handleArrayedElements(cqn.INSERT.rows, queryTarget, cqn.INSERT.columns)
|
|
581
|
-
} else if (cqn.INSERT.values) {
|
|
582
|
-
_handleArrayedElements([cqn.INSERT.values], queryTarget, cqn.INSERT.columns)
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
613
|
|
|
586
614
|
const target = model.definitions[targetName]
|
|
587
615
|
if (!target) return insert
|
|
588
616
|
|
|
589
|
-
const resolvedView = resolveView(insert, model,
|
|
617
|
+
const resolvedView = resolveView(insert, model, cds.db)
|
|
590
618
|
|
|
591
619
|
if (cqn.INSERT.into.ref && cqn.INSERT.into.ref.length > 1) {
|
|
592
620
|
const copyFrom = [...cqn.INSERT.into.ref]
|
|
@@ -598,6 +626,7 @@ const _convertInsert = (cqn, model) => {
|
|
|
598
626
|
}
|
|
599
627
|
|
|
600
628
|
function _modifyNavigationInWhere(whereClause, target) {
|
|
629
|
+
if (!whereClause) return
|
|
601
630
|
whereClause.forEach(e => {
|
|
602
631
|
if (e.ref && e.ref.length > 1 && target.elements[e.ref[0]]) {
|
|
603
632
|
const element = target.elements[e.ref[0]]
|
|
@@ -619,10 +648,10 @@ const _plainDelete = (cqn, model) => {
|
|
|
619
648
|
const target = model.definitions[name]
|
|
620
649
|
if (!target) return cqn
|
|
621
650
|
|
|
622
|
-
return resolveView(cqn, model,
|
|
651
|
+
return resolveView(cqn, model, cds.db)
|
|
623
652
|
}
|
|
624
653
|
|
|
625
|
-
const _convertDelete = (cqn, model) => {
|
|
654
|
+
const _convertDelete = (cqn, model, options) => {
|
|
626
655
|
// .from is plain string or csn entity
|
|
627
656
|
if (
|
|
628
657
|
typeof cqn.DELETE.from === 'string' ||
|
|
@@ -632,7 +661,7 @@ const _convertDelete = (cqn, model) => {
|
|
|
632
661
|
return _plainDelete(cqn, model)
|
|
633
662
|
}
|
|
634
663
|
|
|
635
|
-
const { target, alias, where } = convertPathExpressionToWhere(cqn.DELETE.from, model)
|
|
664
|
+
const { target, alias, where } = convertPathExpressionToWhere(cqn.DELETE.from, model, options)
|
|
636
665
|
const deleet = DELETE('x')
|
|
637
666
|
Object.assign(deleet.DELETE, cqn.DELETE, { from: target, where: undefined })
|
|
638
667
|
|
|
@@ -643,37 +672,30 @@ const _convertDelete = (cqn, model) => {
|
|
|
643
672
|
const targetEntity = model.definitions[target]
|
|
644
673
|
if (!targetEntity) return deleet
|
|
645
674
|
|
|
646
|
-
return resolveView(deleet, model,
|
|
675
|
+
return resolveView(deleet, model, cds.db)
|
|
647
676
|
}
|
|
648
677
|
|
|
649
678
|
function _plainUpdate(cqn, model) {
|
|
650
679
|
const name = cqn.UPDATE.entity.name || (cqn.UPDATE.entity.ref && cqn.UPDATE.entity.ref[0]) || cqn.UPDATE.entity
|
|
651
|
-
const queryTarget = model.definitions[ensureNoDraftsSuffix(name)]
|
|
652
|
-
|
|
653
|
-
if (cds.env.effective.odata.version !== 'v2') {
|
|
654
|
-
cqn.UPDATE.data && _handleArrayedElements([cqn.UPDATE.data], queryTarget)
|
|
655
|
-
cqn.UPDATE.with && _handleArrayedElements([cqn.UPDATE.with], queryTarget)
|
|
656
|
-
}
|
|
657
|
-
|
|
658
680
|
const target = model.definitions[name]
|
|
659
681
|
if (!target) return cqn
|
|
660
682
|
|
|
661
|
-
return resolveView(cqn, model,
|
|
683
|
+
return resolveView(cqn, model, cds.db)
|
|
662
684
|
}
|
|
663
685
|
|
|
664
|
-
const _convertUpdate = (cqn, model) => {
|
|
686
|
+
const _convertUpdate = (cqn, model, options) => {
|
|
665
687
|
// REVISIT flatten structured types, currently its done in SQL builder
|
|
666
688
|
|
|
667
689
|
// .into is plain string or csn entity
|
|
668
690
|
if (
|
|
669
691
|
typeof cqn.UPDATE.entity === 'string' ||
|
|
670
692
|
cqn.UPDATE.entity.name ||
|
|
671
|
-
(cqn.UPDATE.entity.ref && typeof cqn.UPDATE.entity.ref[0] === 'string')
|
|
693
|
+
(cqn.UPDATE.entity.ref && typeof cqn.UPDATE.entity.ref[0] === 'string' && cqn.UPDATE.entity.ref.length === 1)
|
|
672
694
|
) {
|
|
673
695
|
return _plainUpdate(cqn, model)
|
|
674
696
|
}
|
|
675
697
|
|
|
676
|
-
const { target, alias, where } = convertPathExpressionToWhere(cqn.UPDATE.entity, model)
|
|
698
|
+
const { target, alias, where } = convertPathExpressionToWhere(cqn.UPDATE.entity, model, options)
|
|
677
699
|
|
|
678
700
|
// link .with and .data and set query target and remove current where clause
|
|
679
701
|
// REVISIT: update statement does not accept cqn partial as input
|
|
@@ -684,17 +706,10 @@ const _convertUpdate = (cqn, model) => {
|
|
|
684
706
|
if (where) update.where(where)
|
|
685
707
|
if (cqn.UPDATE.where) update.where(_addAliasToExpression(cqn.UPDATE.where, alias))
|
|
686
708
|
|
|
687
|
-
const queryTarget = model.definitions[target]
|
|
688
|
-
|
|
689
|
-
if (cds.env.effective.odata.version !== 'v2') {
|
|
690
|
-
cqn.UPDATE.data && _handleArrayedElements([cqn.UPDATE.data], queryTarget)
|
|
691
|
-
cqn.UPDATE.with && _handleArrayedElements([cqn.UPDATE.with], queryTarget)
|
|
692
|
-
}
|
|
693
|
-
|
|
694
709
|
const targetEntity = model.definitions[target]
|
|
695
710
|
if (!targetEntity) return update
|
|
696
711
|
|
|
697
|
-
return resolveView(update, model,
|
|
712
|
+
return resolveView(update, model, cds.db)
|
|
698
713
|
}
|
|
699
714
|
|
|
700
715
|
/**
|
|
@@ -715,15 +730,15 @@ const cqn2cqn4sql = (cqn, model, options = { suppressSearch: false }) => {
|
|
|
715
730
|
}
|
|
716
731
|
|
|
717
732
|
if (cqn.UPDATE) {
|
|
718
|
-
return _convertUpdate(cqn, model)
|
|
733
|
+
return _convertUpdate(cqn, model, options)
|
|
719
734
|
}
|
|
720
735
|
|
|
721
736
|
if (cqn.INSERT) {
|
|
722
|
-
return _convertInsert(cqn, model)
|
|
737
|
+
return _convertInsert(cqn, model, options)
|
|
723
738
|
}
|
|
724
739
|
|
|
725
740
|
if (cqn.DELETE) {
|
|
726
|
-
return _convertDelete(cqn, model)
|
|
741
|
+
return _convertDelete(cqn, model, options)
|
|
727
742
|
}
|
|
728
743
|
|
|
729
744
|
return cqn
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const cds = require('../../cds')
|
|
2
2
|
|
|
3
3
|
const { ensureNoDraftsSuffix } = require('./draft')
|
|
4
|
+
const { getFlatArray } = require('../../db/utils/deep')
|
|
4
5
|
|
|
5
6
|
const getEtagElement = entity => {
|
|
6
7
|
return Object.values(entity.elements).find(element => element['@odata.etag'])
|
|
@@ -41,7 +42,7 @@ const _isDependent = (assoc, parent, target) => {
|
|
|
41
42
|
* doing as aspect is difficult due to no global definitons per tenant
|
|
42
43
|
*/
|
|
43
44
|
const getDependents = (entity, model) => {
|
|
44
|
-
if (entity.
|
|
45
|
+
if (entity.own('__dependents')) return entity.__dependents
|
|
45
46
|
|
|
46
47
|
/** @type {Array|boolean} */
|
|
47
48
|
let dependents = []
|
|
@@ -61,8 +62,49 @@ const getDependents = (entity, model) => {
|
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
if (dependents.length === 0) dependents = false
|
|
64
|
-
|
|
65
|
-
|
|
65
|
+
return entity.set('__dependents', dependents)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const _getUps = (entity, model, previous = []) => {
|
|
69
|
+
const ups = []
|
|
70
|
+
for (const def of Object.values(model.definitions)) {
|
|
71
|
+
if (def.kind !== 'entity') continue
|
|
72
|
+
if (!def.associations) continue
|
|
73
|
+
for (const assoc of Object.values(def.associations)) {
|
|
74
|
+
if (assoc.target !== entity.name) continue
|
|
75
|
+
ups.push({
|
|
76
|
+
entity: assoc.parent,
|
|
77
|
+
assoc: assoc,
|
|
78
|
+
previous
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return ups
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const _ifDataSubject = (entity, role) => {
|
|
86
|
+
return entity['@PersonalData.EntitySemantics'] === 'DataSubject' && entity['@PersonalData.DataSubjectRole'] === role
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const getDataSubject = (entity, model, role) => {
|
|
90
|
+
const hash = '__dataSubject4' + role
|
|
91
|
+
if (entity.own(hash)) return entity[hash]
|
|
92
|
+
|
|
93
|
+
if (_ifDataSubject(entity, role)) return entity.set(hash, { entity: entity, assoc: [], previous: [] })
|
|
94
|
+
|
|
95
|
+
let dataSubject
|
|
96
|
+
let ups = _getUps(entity, model)
|
|
97
|
+
while (!dataSubject) {
|
|
98
|
+
for (const { entity, assoc, previous } of ups) {
|
|
99
|
+
if (_ifDataSubject(entity, role)) dataSubject = { entity, assoc, previous }
|
|
100
|
+
}
|
|
101
|
+
if (dataSubject) break
|
|
102
|
+
ups = getFlatArray([
|
|
103
|
+
...ups.map(up => [..._getUps(up.entity, model, up.previous.concat({ entity: up.entity, assoc: up.assoc }))])
|
|
104
|
+
])
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return entity.set(hash, dataSubject)
|
|
66
108
|
}
|
|
67
109
|
|
|
68
110
|
const _findRootEntity = (entities, edmName) => {
|
|
@@ -128,6 +170,14 @@ const findCsnTargetFor = (edmName, model, namespace) => {
|
|
|
128
170
|
return mapping[edmName]
|
|
129
171
|
}
|
|
130
172
|
|
|
173
|
+
const getElementDeep = (entity, ref) => {
|
|
174
|
+
let current = entity
|
|
175
|
+
for (const r of ref) {
|
|
176
|
+
current = current && current.elements && current.elements[r]
|
|
177
|
+
}
|
|
178
|
+
return current
|
|
179
|
+
}
|
|
180
|
+
|
|
131
181
|
const isRootEntity = (definitions, entityName) => {
|
|
132
182
|
const entity = definitions[entityName]
|
|
133
183
|
if (!entity) return false
|
|
@@ -156,6 +206,8 @@ const isRootEntity = (definitions, entityName) => {
|
|
|
156
206
|
module.exports = {
|
|
157
207
|
getEtagElement,
|
|
158
208
|
findCsnTargetFor,
|
|
209
|
+
getElementDeep,
|
|
159
210
|
getDependents,
|
|
160
|
-
isRootEntity
|
|
211
|
+
isRootEntity,
|
|
212
|
+
getDataSubject
|
|
161
213
|
}
|
|
@@ -1,39 +1,3 @@
|
|
|
1
|
-
// REVISIT: use follow projection
|
|
2
|
-
|
|
3
|
-
const getError = require('../error')
|
|
4
|
-
|
|
5
|
-
const _renameData = (query, data) => {
|
|
6
|
-
if (query.SELECT && query.SELECT.columns) {
|
|
7
|
-
for (const col of query.SELECT.columns) {
|
|
8
|
-
if (typeof col === 'object' && col.ref && col.as && col.ref[0] !== col.as) {
|
|
9
|
-
if (data[col.as]) {
|
|
10
|
-
data[col.ref[0]] = data[col.as]
|
|
11
|
-
delete data[col.as]
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const getTargetData = (target, data = {}) => {
|
|
19
|
-
if (target.query) {
|
|
20
|
-
_renameData(target.query, data)
|
|
21
|
-
|
|
22
|
-
if (target.query._target) {
|
|
23
|
-
return getTargetData(target.query._target, data)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (!target.query.from || target.query.from.length > 1 || target.query.where) {
|
|
27
|
-
// REVISIT: when is this the case?! getTargetData only used in deleteDraftUtils...
|
|
28
|
-
throw getError(501, 'Insert, Update or Delete on views with join|union|where is not supported')
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
return { target: target.query.from[0].absolute, data }
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return { target, data }
|
|
35
|
-
}
|
|
36
|
-
|
|
37
1
|
// REVISIT: remove once not needed anymore
|
|
38
2
|
const getDataFromCQN = query => (query.INSERT && query.INSERT.entries) || (query.UPDATE && query.UPDATE.data)
|
|
39
3
|
|
|
@@ -47,7 +11,6 @@ const setDataFromCQN = req => {
|
|
|
47
11
|
}
|
|
48
12
|
|
|
49
13
|
module.exports = {
|
|
50
|
-
getTargetData,
|
|
51
14
|
getDataFromCQN,
|
|
52
15
|
setDataFromCQN
|
|
53
16
|
}
|
|
@@ -85,7 +85,7 @@ module.exports = (data, { query, target }, { model }) => {
|
|
|
85
85
|
} else if (query.UPDATE) {
|
|
86
86
|
const where = _getWhereFromUpdate(query, target, model)
|
|
87
87
|
if (!where || !where.length) return
|
|
88
|
-
|
|
88
|
+
if (!data) data = query.UPDATE.data = {} // REVISIT: We should not expect data to be present always!
|
|
89
89
|
_addKeysFromWhereToData(where, target, data)
|
|
90
90
|
}
|
|
91
91
|
}
|
|
@@ -1,38 +1,21 @@
|
|
|
1
1
|
const { ensureNoDraftsSuffix } = require('../../common/utils/draft')
|
|
2
2
|
|
|
3
|
-
const _entityFromRef = ref => {
|
|
4
|
-
if (ref) return ref[0].id || ref[0]
|
|
5
|
-
}
|
|
6
|
-
|
|
7
3
|
const getEntityNameFromCQN = cqn => {
|
|
8
|
-
while (cqn.SELECT)
|
|
9
|
-
cqn = cqn.SELECT.from
|
|
10
|
-
}
|
|
4
|
+
while (cqn.SELECT) cqn = cqn.SELECT.from
|
|
11
5
|
|
|
12
|
-
|
|
13
|
-
|
|
6
|
+
// Do the most likely first -> {ref}
|
|
7
|
+
if (cqn.ref) {
|
|
8
|
+
return cqn.ref[0].id || cqn.ref[0]
|
|
9
|
+
}
|
|
14
10
|
|
|
15
|
-
const _getEntityNameFromUnionCQN = cqn => {
|
|
16
11
|
// TODO cleanup
|
|
17
12
|
// REVISIT infer should do this for req.target
|
|
18
13
|
// REVISIT2 No, req.target doesn't make sense for joins
|
|
19
14
|
if (cqn.SET) {
|
|
20
|
-
return cqn.SET.args
|
|
21
|
-
.map(arg => {
|
|
22
|
-
return getEntityNameFromCQN(arg)
|
|
23
|
-
})
|
|
24
|
-
.filter(name => {
|
|
25
|
-
return name !== 'DRAFT.DraftAdministrativeData'
|
|
26
|
-
})[0]
|
|
15
|
+
return cqn.SET.args.map(getEntityNameFromCQN).find(n => n !== 'DRAFT.DraftAdministrativeData')
|
|
27
16
|
}
|
|
28
17
|
if (cqn.join) {
|
|
29
|
-
return cqn.args
|
|
30
|
-
.map(arg => {
|
|
31
|
-
return getEntityNameFromCQN(arg)
|
|
32
|
-
})
|
|
33
|
-
.filter(name => {
|
|
34
|
-
return name !== 'DRAFT.DraftAdministrativeData'
|
|
35
|
-
})[0]
|
|
18
|
+
return cqn.args.map(getEntityNameFromCQN).find(n => n !== 'DRAFT.DraftAdministrativeData')
|
|
36
19
|
}
|
|
37
20
|
}
|
|
38
21
|
|