@sap/cds 5.5.2 → 5.6.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 +150 -17
- 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 +31 -4
- 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/lib/utils/tests.js +5 -3
- 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 +14 -19
- 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 +1 -12
- 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 +20 -10
- 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 +11 -25
- 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 +9 -1
- 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,41 +1,21 @@
|
|
|
1
1
|
const cds = require('../../cds')
|
|
2
2
|
const { SELECT, INSERT, DELETE, UPDATE } = cds.ql
|
|
3
3
|
|
|
4
|
-
const { getOnCond } = require('./generateOnCond')
|
|
5
4
|
const { resolveView } = require('./resolveView')
|
|
6
5
|
const { ensureNoDraftsSuffix } = require('./draft')
|
|
7
6
|
const { flattenStructuredSelect } = require('./structured')
|
|
8
|
-
const { foreignKeyPropagations } = require('./foreignKeyPropagations')
|
|
9
7
|
const search2cqn4sql = require('./search2cqn4sql')
|
|
10
8
|
const { getEntityNameFromCQN } = require('./entityFromCqn')
|
|
11
9
|
const getError = require('../../common/error')
|
|
10
|
+
const { rewriteAsterisks } = require('./rewriteAsterisks')
|
|
12
11
|
const { getPathFromRef, getEntityFromPath } = require('../../common/utils/path')
|
|
12
|
+
const { removeIsActiveEntityRecursively } = require('../../fiori/utils/where')
|
|
13
13
|
|
|
14
14
|
const PARENT_ALIAS = '_parent_'
|
|
15
15
|
const PARENT_ALIAS_REGEX = new RegExp('^' + PARENT_ALIAS + '\\d*$')
|
|
16
16
|
const FOREIGN_ALIAS = '_foreign_'
|
|
17
17
|
const OPERATIONS = ['=', '>', '<', '!=', '<>', '>=', '<=', 'like', 'between', 'in', 'not in']
|
|
18
18
|
|
|
19
|
-
const _addOnCondToWhere = (cqn, entity, navigation, tableAlias, identifier, csn, prefix) => {
|
|
20
|
-
const onConditionOptions = {
|
|
21
|
-
associationNames: [...prefix, navigation],
|
|
22
|
-
csn: csn,
|
|
23
|
-
aliases: {
|
|
24
|
-
select: tableAlias,
|
|
25
|
-
join: identifier
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
let element = csn.definitions[entity]
|
|
30
|
-
for (let i = 0; i < onConditionOptions.associationNames.length; i++) {
|
|
31
|
-
element = element.elements[onConditionOptions.associationNames[i]]
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const onCond = getOnCond(element, onConditionOptions)
|
|
35
|
-
|
|
36
|
-
cqn.where(onCond)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
19
|
// special case in lambda functions
|
|
40
20
|
const _addParentAlias = (where, alias) => {
|
|
41
21
|
where.forEach(e => {
|
|
@@ -136,14 +116,9 @@ const convertPathExpressionToWhere = (fromClause, model, options) => {
|
|
|
136
116
|
}
|
|
137
117
|
|
|
138
118
|
if (previousSelect) {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
previousEntityName,
|
|
142
|
-
_getTargetFromRef(fromClause.ref[i]),
|
|
143
|
-
tableAlias,
|
|
144
|
-
previousTableAlias,
|
|
145
|
-
model,
|
|
146
|
-
prefix
|
|
119
|
+
const navigation = _getTargetFromRef(fromClause.ref[i])
|
|
120
|
+
previousSelect.where(
|
|
121
|
+
model.definitions[previousEntityName]._relations[[...prefix, navigation]].join(tableAlias, previousTableAlias)
|
|
147
122
|
)
|
|
148
123
|
_convertSelect(previousSelect, model, options)
|
|
149
124
|
currentSelect.where('exists', previousSelect)
|
|
@@ -248,6 +223,7 @@ const _createWindowCQN = (SELECT, model) => {
|
|
|
248
223
|
from: SELECT.from
|
|
249
224
|
}
|
|
250
225
|
}
|
|
226
|
+
|
|
251
227
|
delete SELECT.groupBy
|
|
252
228
|
}
|
|
253
229
|
|
|
@@ -260,6 +236,7 @@ const _isAll = element => {
|
|
|
260
236
|
return last && last.id && last.where && last.where[0] === 'not' && last.where[1].xpr
|
|
261
237
|
}
|
|
262
238
|
|
|
239
|
+
// eslint-disable-next-line complexity
|
|
263
240
|
const _getLambdaSubSelect = (cqn, where, index, lambdaOp, model, options) => {
|
|
264
241
|
const _unshiftRefsWithNavigation = nav => el => {
|
|
265
242
|
if (el.ref) return { ref: [...nav, ...el.ref] }
|
|
@@ -268,12 +245,14 @@ const _getLambdaSubSelect = (cqn, where, index, lambdaOp, model, options) => {
|
|
|
268
245
|
}
|
|
269
246
|
|
|
270
247
|
if (!options.lambdaIteration) options.lambdaIteration = 1
|
|
271
|
-
|
|
272
|
-
|
|
248
|
+
const outerAlias =
|
|
249
|
+
(cqn.SELECT.from.ref && cqn.SELECT.from.as) ||
|
|
250
|
+
(cqn.SELECT.from.args && cqn.SELECT.from.args[0].ref && cqn.SELECT.from.args[0].as) ||
|
|
251
|
+
PARENT_ALIAS + options.lambdaIteration
|
|
273
252
|
const innerAlias = FOREIGN_ALIAS + options.lambdaIteration
|
|
274
253
|
cqn.SELECT.from.as = outerAlias
|
|
275
|
-
|
|
276
|
-
const queryTarget = getEntityFromPath(getPathFromRef(
|
|
254
|
+
const ref = cqn.SELECT.from.ref || (cqn.SELECT.from.args && cqn.SELECT.from.args[0].ref)
|
|
255
|
+
const queryTarget = getEntityFromPath(getPathFromRef(ref), model)
|
|
277
256
|
|
|
278
257
|
const nav = where[index].ref.map(el => (el.id ? el.id : el))
|
|
279
258
|
const last = where[index].ref.slice(-1)[0]
|
|
@@ -296,15 +275,6 @@ const _getLambdaSubSelect = (cqn, where, index, lambdaOp, model, options) => {
|
|
|
296
275
|
? last.where.map(_unshiftRefsWithNavigation(nav.slice(1)))
|
|
297
276
|
: last.where
|
|
298
277
|
: undefined
|
|
299
|
-
const onConditionOptions = {
|
|
300
|
-
associationNames: navName,
|
|
301
|
-
csn: model,
|
|
302
|
-
aliases: {
|
|
303
|
-
select: innerAlias,
|
|
304
|
-
join: outerAlias
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
const onCondition = getOnCond(navElement, onConditionOptions)
|
|
308
278
|
|
|
309
279
|
const subSelect = SELECT.from({ ref: [navElement.target], as: innerAlias })
|
|
310
280
|
if (condition) {
|
|
@@ -322,7 +292,7 @@ const _getLambdaSubSelect = (cqn, where, index, lambdaOp, model, options) => {
|
|
|
322
292
|
}
|
|
323
293
|
subSelect.where(condition)
|
|
324
294
|
}
|
|
325
|
-
subSelect.where(
|
|
295
|
+
subSelect.where(queryTarget._relations[navName].join(innerAlias, outerAlias))
|
|
326
296
|
if (cds.env.effective.odata.structs) {
|
|
327
297
|
flattenStructuredSelect(subSelect, model)
|
|
328
298
|
}
|
|
@@ -412,6 +382,7 @@ const _convertNotEqual = container => {
|
|
|
412
382
|
})
|
|
413
383
|
}
|
|
414
384
|
}
|
|
385
|
+
|
|
415
386
|
const _ifOrderByOrWhereSkip = (queryTarget, ref, model) => {
|
|
416
387
|
if (!queryTarget.elements[ref[0]]) return
|
|
417
388
|
return ref.some(el => {
|
|
@@ -474,6 +445,7 @@ const _convertExpand = expand => {
|
|
|
474
445
|
}
|
|
475
446
|
})
|
|
476
447
|
}
|
|
448
|
+
|
|
477
449
|
const _convertRefWhereInExpand = columns => {
|
|
478
450
|
if (columns) {
|
|
479
451
|
columns.forEach(col => {
|
|
@@ -484,83 +456,92 @@ const _convertRefWhereInExpand = columns => {
|
|
|
484
456
|
}
|
|
485
457
|
}
|
|
486
458
|
|
|
487
|
-
const
|
|
488
|
-
if (
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
const draftName = `${entity.name}_drafts`
|
|
500
|
-
const subSelect = SELECT.from(draftName).columns([1])
|
|
501
|
-
for (const k in entity.keys) {
|
|
502
|
-
if (k !== 'IsActiveEntity') subSelect.where([{ ref: [entity.name, k] }, '=', { ref: [draftName, k] }])
|
|
503
|
-
}
|
|
504
|
-
addAliasToColumns.push({
|
|
505
|
-
xpr: ['case', 'when', 'exists', subSelect, 'then', 'true', 'else', 'false', 'end'],
|
|
506
|
-
as: 'HasDraftEntity',
|
|
507
|
-
cast: { type: 'cds.Boolean' }
|
|
508
|
-
})
|
|
509
|
-
} else addAliasToColumns.push({ ref: [column], as: column })
|
|
510
|
-
}
|
|
511
|
-
return addAliasToColumns
|
|
459
|
+
const _flattenCQN = cqn => {
|
|
460
|
+
if (Array.isArray(cqn)) cqn.forEach(_flattenCQN)
|
|
461
|
+
else if (cqn) {
|
|
462
|
+
if (cqn.SELECT) _flattenCQN(cqn.SELECT)
|
|
463
|
+
if (cqn.from) _flattenCQN(cqn.from)
|
|
464
|
+
if (cqn.ref) _flattenCQN(cqn.ref)
|
|
465
|
+
if (cqn.SET) _flattenCQN(cqn.SET)
|
|
466
|
+
if (cqn.args) _flattenCQN(cqn.args)
|
|
467
|
+
if (cqn.columns) _flattenCQN(cqn.columns)
|
|
468
|
+
if (cqn.expand) _flattenCQN(cqn.expand)
|
|
469
|
+
if (cqn.where) _flattenXpr(cqn.where)
|
|
470
|
+
if (cqn.having) _flattenXpr(cqn.having)
|
|
512
471
|
}
|
|
513
472
|
}
|
|
514
473
|
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
474
|
+
const _flattenXpr = cqn => {
|
|
475
|
+
if (!Array.isArray(cqn)) {
|
|
476
|
+
if (cqn.xpr) cqn = cqn.xpr
|
|
477
|
+
return
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
let idx = cqn.findIndex(el => el.xpr)
|
|
481
|
+
while (idx > -1) {
|
|
482
|
+
cqn.splice(idx, 1, '(', ...cqn[idx].xpr, ')')
|
|
483
|
+
idx = cqn.findIndex(el => el.xpr)
|
|
521
484
|
}
|
|
522
485
|
|
|
486
|
+
cqn.forEach(_flattenCQN)
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// eslint-disable-next-line complexity
|
|
490
|
+
const _convertSelect = (query, model, options) => {
|
|
491
|
+
const isDB = options.service instanceof cds.DatabaseService
|
|
492
|
+
const isDraft = options.draft
|
|
493
|
+
// REVISIT: a temporary workaround for xpr from new parser
|
|
494
|
+
if (cds.env.features.odata_new_parser) _flattenCQN(query)
|
|
495
|
+
|
|
523
496
|
// lambda functions
|
|
524
|
-
_convertLambda(
|
|
497
|
+
_convertLambda(query, model, options)
|
|
525
498
|
|
|
526
499
|
// add 'or is null' in case of '!='
|
|
527
|
-
if (
|
|
528
|
-
|
|
529
|
-
// extract where clause if it is in column expand ref
|
|
530
|
-
_convertRefWhereInExpand(cqn.SELECT.columns)
|
|
500
|
+
if (query.SELECT._4odata) _convertNotEqual(query.SELECT)
|
|
531
501
|
|
|
532
|
-
let searchOptions =
|
|
533
|
-
const cqnSelectFromRef =
|
|
502
|
+
let searchOptions = query._searchOptions
|
|
503
|
+
const cqnSelectFromRef = query.SELECT.from.ref
|
|
534
504
|
|
|
535
505
|
// no path expression
|
|
536
506
|
if (!cqnSelectFromRef || (cqnSelectFromRef.length === 1 && !cqnSelectFromRef[0].where)) {
|
|
507
|
+
rewriteAsterisks(query, cqnSelectFromRef && model.definitions[cqnSelectFromRef[0]], isDB, isDraft)
|
|
508
|
+
// extract where clause if it is in column expand ref
|
|
509
|
+
_convertRefWhereInExpand(query.SELECT.columns)
|
|
537
510
|
// remove virtual and with skip annotated fields in orderby and where
|
|
538
|
-
_convertOrderByOrWhereIfSkip(
|
|
511
|
+
_convertOrderByOrWhereIfSkip(query, getEntityNameFromCQN(query), model)
|
|
539
512
|
|
|
540
|
-
if (cqnSelectFromRef &&
|
|
513
|
+
if (cqnSelectFromRef && query.SELECT.search && !options.suppressSearch) {
|
|
541
514
|
searchOptions = { ...searchOptions, ...{ targetName: cqnSelectFromRef[0] } }
|
|
542
|
-
search2cqn4sql(
|
|
515
|
+
search2cqn4sql(query, model, searchOptions)
|
|
543
516
|
}
|
|
544
517
|
|
|
545
|
-
if (
|
|
546
|
-
flattenStructuredSelect(
|
|
518
|
+
if (query.SELECT.columns && cds.env.effective.odata.structs) {
|
|
519
|
+
flattenStructuredSelect(query, model)
|
|
547
520
|
}
|
|
548
521
|
|
|
549
522
|
// topcount with groupby
|
|
550
|
-
if (
|
|
551
|
-
_createWindowCQN(
|
|
523
|
+
if (query.SELECT.columns && _isBottomTop(query.SELECT.columns)) {
|
|
524
|
+
_createWindowCQN(query.SELECT, model)
|
|
552
525
|
}
|
|
553
526
|
|
|
554
|
-
return
|
|
527
|
+
return query
|
|
555
528
|
}
|
|
556
529
|
|
|
557
530
|
// path expression handling
|
|
558
|
-
const { target, alias, where, cardinality, columns } = convertPathExpressionToWhere(
|
|
531
|
+
const { target, alias, where, cardinality, columns } = convertPathExpressionToWhere(query.SELECT.from, model, options)
|
|
532
|
+
rewriteAsterisks(query, model.definitions[target], isDB, isDraft, !!columns)
|
|
533
|
+
if (columns) {
|
|
534
|
+
if (query._streaming) query.SELECT.columns = columns
|
|
535
|
+
else query.SELECT.columns.push(...columns)
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// extract where clause if it is in column expand ref
|
|
539
|
+
_convertRefWhereInExpand(query.SELECT.columns)
|
|
559
540
|
|
|
560
541
|
// remove virtual and with skip annotated fields in orderby and where
|
|
561
|
-
_convertOrderByOrWhereIfSkip(
|
|
542
|
+
_convertOrderByOrWhereIfSkip(query, target, model)
|
|
562
543
|
|
|
563
|
-
const select = SELECT.from(target,
|
|
544
|
+
const select = SELECT.from(target, query.SELECT.columns)
|
|
564
545
|
|
|
565
546
|
if (alias) {
|
|
566
547
|
select.SELECT.from.as = alias
|
|
@@ -568,25 +549,29 @@ const _convertSelect = (cqn, model, options) => {
|
|
|
568
549
|
|
|
569
550
|
// TODO: REVISIT: We need to add alias to subselect in .where, .columns, .from, ... etc
|
|
570
551
|
if (where) {
|
|
571
|
-
|
|
552
|
+
if (!isDraft) {
|
|
553
|
+
select.where(removeIsActiveEntityRecursively(where))
|
|
554
|
+
} else {
|
|
555
|
+
select.where(where)
|
|
556
|
+
}
|
|
572
557
|
}
|
|
573
558
|
|
|
574
559
|
if (cardinality && cardinality.max === 1) {
|
|
575
|
-
|
|
560
|
+
query.SELECT.one = true
|
|
576
561
|
}
|
|
577
562
|
|
|
578
|
-
if (
|
|
563
|
+
if (query.SELECT.search) {
|
|
579
564
|
searchOptions = { ...searchOptions, ...{ targetName: target } }
|
|
580
|
-
search2cqn4sql(
|
|
565
|
+
search2cqn4sql(query, model, searchOptions)
|
|
581
566
|
}
|
|
582
567
|
|
|
583
|
-
if (
|
|
584
|
-
select.where(_addAliasToExpression(
|
|
568
|
+
if (query.SELECT.where) {
|
|
569
|
+
select.where(_addAliasToExpression(query.SELECT.where, select.SELECT.from.as))
|
|
585
570
|
}
|
|
586
571
|
|
|
587
572
|
// We add all previous properties ot the newly created query.
|
|
588
573
|
// Reason is to not lose the query API functionality
|
|
589
|
-
Object.assign(select.SELECT,
|
|
574
|
+
Object.assign(select.SELECT, query.SELECT, {
|
|
590
575
|
columns: select.SELECT.columns,
|
|
591
576
|
from: select.SELECT.from,
|
|
592
577
|
where: select.SELECT.where
|
|
@@ -599,9 +584,9 @@ const _convertSelect = (cqn, model, options) => {
|
|
|
599
584
|
return select
|
|
600
585
|
}
|
|
601
586
|
|
|
602
|
-
const _convertInsert = (
|
|
587
|
+
const _convertInsert = (query, model, options) => {
|
|
603
588
|
// resolve path expression
|
|
604
|
-
const resolvedIntoClause = _convertPathExpressionForInsertOrDelete(
|
|
589
|
+
const resolvedIntoClause = _convertPathExpressionForInsertOrDelete(query.INSERT.into, model)
|
|
605
590
|
|
|
606
591
|
// overwrite only .into, foreign keys are already set
|
|
607
592
|
const insert = INSERT.into(resolvedIntoClause)
|
|
@@ -610,7 +595,7 @@ const _convertInsert = (cqn, model) => {
|
|
|
610
595
|
|
|
611
596
|
// We add all previous properties ot the newly created query.
|
|
612
597
|
// Reason is to not lose the query API functionality
|
|
613
|
-
Object.assign(insert.INSERT,
|
|
598
|
+
Object.assign(insert.INSERT, query.INSERT, { into: resolvedIntoClause })
|
|
614
599
|
|
|
615
600
|
const targetName = insert.INSERT.into.name || insert.INSERT.into
|
|
616
601
|
|
|
@@ -619,10 +604,10 @@ const _convertInsert = (cqn, model) => {
|
|
|
619
604
|
|
|
620
605
|
const resolvedView = resolveView(insert, model, cds.db)
|
|
621
606
|
|
|
622
|
-
if (
|
|
623
|
-
const copyFrom = [...
|
|
607
|
+
if (query.INSERT.into.ref && query.INSERT.into.ref.length > 1) {
|
|
608
|
+
const copyFrom = [...query.INSERT.into.ref]
|
|
624
609
|
copyFrom.pop()
|
|
625
|
-
resolvedView._validationQuery = _convertSelect(SELECT.from({ ref: copyFrom }).columns([1]), model)
|
|
610
|
+
resolvedView._validationQuery = _convertSelect(SELECT.from({ ref: copyFrom }).columns([1]), model, options)
|
|
626
611
|
}
|
|
627
612
|
|
|
628
613
|
return resolvedView
|
|
@@ -634,11 +619,11 @@ function _modifyNavigationInWhere(whereClause, target) {
|
|
|
634
619
|
if (e.ref && e.ref.length > 1 && target.elements[e.ref[0]]) {
|
|
635
620
|
const element = target.elements[e.ref[0]]
|
|
636
621
|
if (!element.isAssociation) return
|
|
637
|
-
const foreignKeys =
|
|
622
|
+
const foreignKeys = element._foreignKeys
|
|
638
623
|
const joined = e.ref.join('_')
|
|
639
624
|
|
|
640
|
-
for (const {
|
|
641
|
-
if (
|
|
625
|
+
for (const { parentElement } of foreignKeys) {
|
|
626
|
+
if (parentElement && parentElement.name === joined) {
|
|
642
627
|
e.ref = [joined]
|
|
643
628
|
}
|
|
644
629
|
}
|
|
@@ -654,23 +639,23 @@ const _plainDelete = (cqn, model) => {
|
|
|
654
639
|
return resolveView(cqn, model, cds.db)
|
|
655
640
|
}
|
|
656
641
|
|
|
657
|
-
const _convertDelete = (
|
|
642
|
+
const _convertDelete = (query, model, options) => {
|
|
658
643
|
// .from is plain string or csn entity
|
|
659
644
|
if (
|
|
660
|
-
typeof
|
|
661
|
-
|
|
662
|
-
(
|
|
645
|
+
typeof query.DELETE.from === 'string' ||
|
|
646
|
+
query.DELETE.from.name ||
|
|
647
|
+
(query.DELETE.from.ref && typeof query.DELETE.from.ref[0] === 'string')
|
|
663
648
|
) {
|
|
664
|
-
return _plainDelete(
|
|
649
|
+
return _plainDelete(query, model)
|
|
665
650
|
}
|
|
666
651
|
|
|
667
|
-
const { target, alias, where } = convertPathExpressionToWhere(
|
|
652
|
+
const { target, alias, where } = convertPathExpressionToWhere(query.DELETE.from, model, options)
|
|
668
653
|
const deleet = DELETE('x')
|
|
669
|
-
Object.assign(deleet.DELETE,
|
|
654
|
+
Object.assign(deleet.DELETE, query.DELETE, { from: target, where: undefined })
|
|
670
655
|
|
|
671
656
|
if (alias) deleet.DELETE.from = { ref: [target], as: alias }
|
|
672
657
|
if (where) deleet.where(where)
|
|
673
|
-
if (
|
|
658
|
+
if (query.DELETE.where) deleet.where(_addAliasToExpression(query.DELETE.where, alias))
|
|
674
659
|
|
|
675
660
|
const targetEntity = model.definitions[target]
|
|
676
661
|
if (!targetEntity) return deleet
|
|
@@ -686,28 +671,28 @@ function _plainUpdate(cqn, model) {
|
|
|
686
671
|
return resolveView(cqn, model, cds.db)
|
|
687
672
|
}
|
|
688
673
|
|
|
689
|
-
const _convertUpdate = (
|
|
674
|
+
const _convertUpdate = (query, model, options) => {
|
|
690
675
|
// REVISIT flatten structured types, currently its done in SQL builder
|
|
691
676
|
|
|
692
677
|
// .into is plain string or csn entity
|
|
693
678
|
if (
|
|
694
|
-
typeof
|
|
695
|
-
|
|
696
|
-
(
|
|
679
|
+
typeof query.UPDATE.entity === 'string' ||
|
|
680
|
+
query.UPDATE.entity.name ||
|
|
681
|
+
(query.UPDATE.entity.ref && typeof query.UPDATE.entity.ref[0] === 'string' && query.UPDATE.entity.ref.length === 1)
|
|
697
682
|
) {
|
|
698
|
-
return _plainUpdate(
|
|
683
|
+
return _plainUpdate(query, model)
|
|
699
684
|
}
|
|
700
685
|
|
|
701
|
-
const { target, alias, where } = convertPathExpressionToWhere(
|
|
686
|
+
const { target, alias, where } = convertPathExpressionToWhere(query.UPDATE.entity, model, options)
|
|
702
687
|
|
|
703
688
|
// link .with and .data and set query target and remove current where clause
|
|
704
689
|
// REVISIT: update statement does not accept cqn partial as input
|
|
705
690
|
const update = UPDATE('x')
|
|
706
|
-
Object.assign(update.UPDATE,
|
|
691
|
+
Object.assign(update.UPDATE, query.UPDATE, { entity: target, where: undefined })
|
|
707
692
|
|
|
708
693
|
if (alias) update.UPDATE.entity = { ref: [target], as: alias }
|
|
709
694
|
if (where) update.where(where)
|
|
710
|
-
if (
|
|
695
|
+
if (query.UPDATE.where) update.where(_addAliasToExpression(query.UPDATE.where, alias))
|
|
711
696
|
|
|
712
697
|
const targetEntity = model.definitions[target]
|
|
713
698
|
if (!targetEntity) return update
|
|
@@ -721,30 +706,31 @@ const _convertUpdate = (cqn, model, options) => {
|
|
|
721
706
|
* REVISIT structured
|
|
722
707
|
* REVISIT topcount when the additional layer for Analytics before SQLBuilder is ready
|
|
723
708
|
*
|
|
724
|
-
* @param {object}
|
|
709
|
+
* @param {object} query - incoming query
|
|
725
710
|
* @param {object} model - csn model
|
|
726
711
|
* @param {import('../../types/api').cqn2cqn4sqlOptions} [options] Additional options.
|
|
727
712
|
*/
|
|
728
|
-
const cqn2cqn4sql = (
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
if (cqn.SELECT) {
|
|
732
|
-
return _convertSelect(cqn, model, options)
|
|
713
|
+
const cqn2cqn4sql = (query, model, options = { suppressSearch: false }) => {
|
|
714
|
+
if (query.SELECT) {
|
|
715
|
+
return _convertSelect(query, model, options)
|
|
733
716
|
}
|
|
734
717
|
|
|
735
|
-
if (
|
|
736
|
-
return _convertUpdate(
|
|
718
|
+
if (query.UPDATE) {
|
|
719
|
+
return _convertUpdate(query, model, options)
|
|
737
720
|
}
|
|
738
721
|
|
|
739
|
-
if (
|
|
740
|
-
return _convertInsert(
|
|
722
|
+
if (query.INSERT) {
|
|
723
|
+
return _convertInsert(query, model, options)
|
|
741
724
|
}
|
|
742
725
|
|
|
743
|
-
if (
|
|
744
|
-
return _convertDelete(
|
|
726
|
+
if (query.DELETE) {
|
|
727
|
+
return _convertDelete(query, model, options)
|
|
745
728
|
}
|
|
746
729
|
|
|
747
|
-
return
|
|
730
|
+
return query
|
|
748
731
|
}
|
|
749
732
|
|
|
750
|
-
module.exports =
|
|
733
|
+
module.exports = {
|
|
734
|
+
cqn2cqn4sql,
|
|
735
|
+
convertPathExpressionToWhere
|
|
736
|
+
}
|
|
@@ -1,29 +1,11 @@
|
|
|
1
1
|
const cds = require('../../cds')
|
|
2
2
|
|
|
3
3
|
const { ensureNoDraftsSuffix } = require('./draft')
|
|
4
|
-
const { getFlatArray } = require('../../db/utils/deep')
|
|
5
4
|
|
|
6
5
|
const getEtagElement = entity => {
|
|
7
6
|
return Object.values(entity.elements).find(element => element['@odata.etag'])
|
|
8
7
|
}
|
|
9
8
|
|
|
10
|
-
const _isBacklink = (assoc, parent, target) => {
|
|
11
|
-
const comps = Object.values(target.associations || {})
|
|
12
|
-
.filter(assoc => assoc._isCompositionEffective)
|
|
13
|
-
.filter(assoc => assoc.target === parent.name)
|
|
14
|
-
if (comps.length === 0) return false
|
|
15
|
-
|
|
16
|
-
let backlink = false
|
|
17
|
-
for (const comp of comps) {
|
|
18
|
-
const on = comp.on.find(ele => typeof ele === 'object' && ele.ref[0] !== '$self')
|
|
19
|
-
if (on.ref.length === 2 && on.ref[on.ref.length - 1] === assoc.name) {
|
|
20
|
-
backlink = true
|
|
21
|
-
break
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
return backlink
|
|
25
|
-
}
|
|
26
|
-
|
|
27
9
|
const _isDependent = (assoc, parent, target) => {
|
|
28
10
|
return (
|
|
29
11
|
assoc._isAssociationStrict &&
|
|
@@ -33,7 +15,7 @@ const _isDependent = (assoc, parent, target) => {
|
|
|
33
15
|
assoc['@assert.integrity'] !== false &&
|
|
34
16
|
parent['@assert.integrity'] !== false &&
|
|
35
17
|
(!parent._service || parent._service['@assert.integrity'] !== false) &&
|
|
36
|
-
!
|
|
18
|
+
!assoc._isCompositionBacklink
|
|
37
19
|
)
|
|
38
20
|
}
|
|
39
21
|
|
|
@@ -65,18 +47,14 @@ const getDependents = (entity, model) => {
|
|
|
65
47
|
return entity.set('__dependents', dependents)
|
|
66
48
|
}
|
|
67
49
|
|
|
68
|
-
const _getUps = (entity, model
|
|
50
|
+
const _getUps = (entity, model) => {
|
|
69
51
|
const ups = []
|
|
70
52
|
for (const def of Object.values(model.definitions)) {
|
|
71
53
|
if (def.kind !== 'entity') continue
|
|
72
54
|
if (!def.associations) continue
|
|
73
|
-
for (const
|
|
74
|
-
if (
|
|
75
|
-
ups.push(
|
|
76
|
-
entity: assoc.parent,
|
|
77
|
-
assoc: assoc,
|
|
78
|
-
previous
|
|
79
|
-
})
|
|
55
|
+
for (const element of Object.values(def.associations)) {
|
|
56
|
+
if (element.target !== entity.name || element._isBacklink) continue
|
|
57
|
+
ups.push(element)
|
|
80
58
|
}
|
|
81
59
|
}
|
|
82
60
|
return ups
|
|
@@ -86,31 +64,35 @@ const _ifDataSubject = (entity, role) => {
|
|
|
86
64
|
return entity['@PersonalData.EntitySemantics'] === 'DataSubject' && entity['@PersonalData.DataSubjectRole'] === role
|
|
87
65
|
}
|
|
88
66
|
|
|
89
|
-
const
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
67
|
+
const _getDataSubjectUp = (role, model, element, first = element) => {
|
|
68
|
+
const upElements = _getUps(element.parent, model)
|
|
69
|
+
for (const element of upElements) {
|
|
70
|
+
if (_ifDataSubject(element.parent, role)) {
|
|
71
|
+
return { element: first, up: { element }, entity: element.parent }
|
|
72
|
+
}
|
|
73
|
+
// dfs is a must here
|
|
74
|
+
const dataSubject = _getDataSubjectUp(role, model, element, first)
|
|
75
|
+
if (dataSubject) {
|
|
76
|
+
dataSubject.up = { element, up: dataSubject.up }
|
|
77
|
+
return dataSubject
|
|
100
78
|
}
|
|
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
79
|
}
|
|
80
|
+
}
|
|
106
81
|
|
|
107
|
-
|
|
82
|
+
const getDataSubject = (entity, model, role, element) => {
|
|
83
|
+
const hash = '__dataSubject4' + role
|
|
84
|
+
if (entity.own(hash)) return entity[hash]
|
|
85
|
+
if (_ifDataSubject(element.parent, role)) return entity.set(hash, { element, entity: element.parent })
|
|
86
|
+
return entity.set(hash, _getDataSubjectUp(role, model, element))
|
|
108
87
|
}
|
|
109
88
|
|
|
110
|
-
const
|
|
89
|
+
const _resolve = (name, model, namespace) =>
|
|
90
|
+
model.entities(namespace)[name] || model.definitions[`${namespace}.${name}`]
|
|
91
|
+
|
|
92
|
+
const _findRootEntity = (model, edmName, namespace) => {
|
|
111
93
|
const parts = edmName.split('_')
|
|
112
94
|
let csnName = parts.shift()
|
|
113
|
-
let target =
|
|
95
|
+
let target = _resolve(csnName, model, namespace)
|
|
114
96
|
const len = parts.length
|
|
115
97
|
// try to find a correct entity "greedy" and count leftovers (x4 case below)
|
|
116
98
|
// e.g. we have 2 entities: 'C_root_' and dependant 'C_root_.kid_'
|
|
@@ -124,10 +106,10 @@ const _findRootEntity = (entities, edmName) => {
|
|
|
124
106
|
* if target in entities connect with .
|
|
125
107
|
* if target not in entities connect with _
|
|
126
108
|
*/
|
|
127
|
-
csnName = `${csnName}${
|
|
109
|
+
csnName = `${csnName}${_resolve(csnName, model, namespace) ? '.' : '_'}${parts[i]}`
|
|
128
110
|
++acc
|
|
129
|
-
if (
|
|
130
|
-
target =
|
|
111
|
+
if (_resolve(csnName, model, namespace)) {
|
|
112
|
+
target = _resolve(csnName, model, namespace)
|
|
131
113
|
left -= acc
|
|
132
114
|
acc = 0
|
|
133
115
|
}
|
|
@@ -145,12 +127,13 @@ const findCsnTargetFor = (edmName, model, namespace) => {
|
|
|
145
127
|
|
|
146
128
|
if (mapping[edmName]) return mapping[edmName]
|
|
147
129
|
|
|
148
|
-
const entities = model.entities(namespace)
|
|
149
130
|
// simple cases
|
|
150
|
-
let target =
|
|
131
|
+
let target = _resolve(edmName, model, namespace) || _resolve(edmName.replace(/_/g, '.'), model, namespace)
|
|
132
|
+
|
|
133
|
+
// hard cases
|
|
151
134
|
if (!target) {
|
|
152
135
|
// probably, a combination of '_' and '.', resolving
|
|
153
|
-
const finding = _findRootEntity(
|
|
136
|
+
const finding = _findRootEntity(model, edmName, namespace)
|
|
154
137
|
target = finding.target
|
|
155
138
|
// something left in navigation path => x4 navigation
|
|
156
139
|
// resolving within found entity
|
|
@@ -203,11 +186,26 @@ const isRootEntity = (definitions, entityName) => {
|
|
|
203
186
|
return true
|
|
204
187
|
}
|
|
205
188
|
|
|
189
|
+
function alias2ref(service, edm) {
|
|
190
|
+
const defs = edm[service.definition.name]
|
|
191
|
+
for (const each of Object.values(service.entities)) {
|
|
192
|
+
const def = defs[each.name.replace(service.definition.name + '.', '').replace(/\./g, '_')]
|
|
193
|
+
if (!def || !def.$Key || def.$Key.every(ele => typeof ele === 'string')) continue
|
|
194
|
+
each._alias2ref = {}
|
|
195
|
+
for (const mapping of def.$Key.filter(ele => typeof ele !== 'string')) {
|
|
196
|
+
for (const [key, value] of Object.entries(mapping)) {
|
|
197
|
+
each._alias2ref[key] = value.split('/')
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
206
203
|
module.exports = {
|
|
207
204
|
getEtagElement,
|
|
208
205
|
findCsnTargetFor,
|
|
209
206
|
getElementDeep,
|
|
210
207
|
getDependents,
|
|
211
208
|
isRootEntity,
|
|
212
|
-
getDataSubject
|
|
209
|
+
getDataSubject,
|
|
210
|
+
alias2ref
|
|
213
211
|
}
|