@sap/cds 5.9.1 → 5.9.4
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 +48 -0
- package/lib/compile/etc/_localized.js +3 -2
- package/lib/compile/for/drafts.js +1 -1
- package/lib/connect/bindings.js +1 -1
- package/lib/connect/index.js +2 -3
- package/lib/env/requires.js +1 -1
- package/lib/index.js +2 -1
- package/lib/serve/Service-methods.js +28 -1
- package/lib/serve/adapters.js +6 -6
- package/lib/serve/factory.js +14 -9
- package/lib/serve/index.js +4 -3
- package/libx/_runtime/auth/index.js +16 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/OData.js +6 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/deserializer/BatchRequestListBuilder.js +3 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/dispatcherUtils.js +11 -6
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/stream.js +1 -3
- package/libx/_runtime/cds-services/services/Service.js +1 -1
- package/libx/_runtime/common/aspects/utils.js +8 -2
- package/libx/_runtime/common/composition/data.js +22 -13
- package/libx/_runtime/common/composition/delete.js +14 -12
- package/libx/_runtime/common/generic/auth/expand.js +1 -0
- package/libx/_runtime/common/generic/auth/restrict.js +3 -1
- package/libx/_runtime/{cds-services/services/utils → common/generic/auth}/restrictions.js +8 -1
- package/libx/_runtime/common/generic/input.js +1 -0
- package/libx/_runtime/common/generic/put.js +1 -0
- package/libx/_runtime/common/utils/cqn.js +5 -10
- package/libx/_runtime/common/utils/cqn2cqn4sql.js +37 -63
- package/libx/_runtime/common/utils/foreignKeyPropagations.js +28 -8
- package/libx/_runtime/common/utils/path.js +3 -3
- package/libx/_runtime/common/utils/require.js +2 -1
- package/libx/_runtime/common/utils/resolveView.js +3 -0
- package/libx/_runtime/common/utils/structured.js +6 -1
- package/libx/_runtime/db/Service.js +10 -0
- package/libx/_runtime/db/expand/expand-v2.js +13 -5
- package/libx/_runtime/db/expand/expandCQNToJoin.js +56 -26
- package/libx/_runtime/db/utils/generateAliases.js +9 -0
- package/libx/_runtime/extensibility/uiflex/handler/transformWRITE.js +1 -0
- package/libx/_runtime/fiori/generic/read.js +83 -31
- package/libx/_runtime/fiori/generic/readOverDraft.js +31 -19
- package/libx/_runtime/fiori/utils/handler.js +3 -0
- package/libx/_runtime/fiori/utils/where.js +38 -25
- package/libx/_runtime/hana/execute.js +18 -1
- package/libx/_runtime/hana/search2cqn4sql.js +4 -1
- package/libx/_runtime/sqlite/convertAssocToOneManaged.js +19 -12
- package/package.json +1 -1
|
@@ -12,7 +12,6 @@ const { getEntityNameFromCQN } = require('./entityFromCqn')
|
|
|
12
12
|
const getError = require('../../common/error')
|
|
13
13
|
const { rewriteAsterisks } = require('./rewriteAsterisks')
|
|
14
14
|
const { getPathFromRef, getEntityFromPath } = require('../../common/utils/path')
|
|
15
|
-
const { addToWhere } = require('../../common/utils/cqn')
|
|
16
15
|
const { removeIsActiveEntityRecursively } = require('../../fiori/utils/where')
|
|
17
16
|
const { addRefToWhereIfNecessary } = require('../../../odata/afterburner')
|
|
18
17
|
const { addAliasToExpression, PARENT_ALIAS, FOREIGN_ALIAS } = require('../../db/utils/generateAliases')
|
|
@@ -240,11 +239,14 @@ const _convertCountNavigation = (SELECT, target) => {
|
|
|
240
239
|
}
|
|
241
240
|
|
|
242
241
|
const _addTableName = (where, tableName) => {
|
|
243
|
-
return where.map(
|
|
244
|
-
if (
|
|
245
|
-
|
|
242
|
+
return where.map(whereEl => {
|
|
243
|
+
if (whereEl.xpr) {
|
|
244
|
+
return { xpr: _addTableName(whereEl.xpr, tableName) }
|
|
246
245
|
}
|
|
247
|
-
|
|
246
|
+
if (whereEl.ref) {
|
|
247
|
+
whereEl.ref.unshift(tableName)
|
|
248
|
+
}
|
|
249
|
+
return whereEl
|
|
248
250
|
})
|
|
249
251
|
}
|
|
250
252
|
|
|
@@ -444,10 +446,7 @@ const convertWhereExists = (query, model, options, currentTarget) => {
|
|
|
444
446
|
outerAlias = as || PARENT_ALIAS + lambdaIteration
|
|
445
447
|
innerAlias = FOREIGN_ALIAS + lambdaIteration
|
|
446
448
|
} else {
|
|
447
|
-
|
|
448
|
-
if (element && element.isAssociation) {
|
|
449
|
-
queryTarget = element._target
|
|
450
|
-
}
|
|
449
|
+
queryTarget = getEntityFromPath({ ref }, currentTarget)
|
|
451
450
|
}
|
|
452
451
|
|
|
453
452
|
if (where) {
|
|
@@ -501,8 +500,9 @@ const _convertNotEqual = (container, partName = 'where') => {
|
|
|
501
500
|
}
|
|
502
501
|
}
|
|
503
502
|
|
|
504
|
-
if (el
|
|
505
|
-
_convertNotEqual(el.SELECT, partName)
|
|
503
|
+
if (el) {
|
|
504
|
+
if (el.SELECT) _convertNotEqual(el.SELECT, partName)
|
|
505
|
+
if (el.xpr) _convertNotEqual(el, 'xpr')
|
|
506
506
|
}
|
|
507
507
|
})
|
|
508
508
|
|
|
@@ -561,6 +561,10 @@ const _convertOrderByOrWhereCQN = (orderByOrWhereCQN, target, model, alias, proc
|
|
|
561
561
|
const queryTarget = model.definitions[ensureNoDraftsSuffix(target)]
|
|
562
562
|
|
|
563
563
|
orderByOrWhereCQN.forEach((el, index) => {
|
|
564
|
+
if (el.xpr) {
|
|
565
|
+
_convertOrderByOrWhereCQN(el.xpr, target, model, alias, processFn)
|
|
566
|
+
return
|
|
567
|
+
}
|
|
564
568
|
if (el.ref && _skip(queryTarget, el.ref, alias, model)) processFn(orderByOrWhereCQN, index)
|
|
565
569
|
})
|
|
566
570
|
}
|
|
@@ -602,86 +606,56 @@ const _convertRefWhereInExpand = columns => {
|
|
|
602
606
|
}
|
|
603
607
|
}
|
|
604
608
|
|
|
605
|
-
const
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
if (
|
|
609
|
-
if (cqn.from) _flattenCQN(cqn.from)
|
|
610
|
-
if (cqn.ref) _flattenCQN(cqn.ref)
|
|
611
|
-
if (cqn.SET) _flattenCQN(cqn.SET)
|
|
612
|
-
if (cqn.args) _flattenCQN(cqn.args)
|
|
613
|
-
if (cqn.columns) _flattenCQN(cqn.columns)
|
|
614
|
-
if (cqn.expand) _flattenCQN(cqn.expand)
|
|
615
|
-
if (cqn.where) _flattenXpr(cqn.where)
|
|
616
|
-
if (cqn.having) _flattenXpr(cqn.having)
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
const _flattenXpr = cqn => {
|
|
621
|
-
if (!Array.isArray(cqn)) {
|
|
622
|
-
if (cqn.xpr) cqn = cqn.xpr
|
|
623
|
-
return
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
let idx = cqn.findIndex(el => el.xpr)
|
|
627
|
-
while (idx > -1) {
|
|
628
|
-
cqn.splice(idx, 1, '(', ...cqn[idx].xpr, ')')
|
|
629
|
-
idx = cqn.findIndex(el => el.xpr)
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
cqn.forEach(_flattenCQN)
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
const _convertPathExpression = (SELECT, model, options = {}) => {
|
|
636
|
-
const prevAlias = SELECT.from.as
|
|
637
|
-
for (const whereEl of SELECT.where || []) {
|
|
638
|
-
if (typeof whereEl === 'object' && whereEl.SELECT) _convertPathExpression(whereEl.SELECT, model)
|
|
609
|
+
const _convertPathExpression = (query, model, options = {}) => {
|
|
610
|
+
const prevAlias = query.SELECT.from.as
|
|
611
|
+
for (const whereEl of query.SELECT.where || []) {
|
|
612
|
+
if (typeof whereEl === 'object' && whereEl.SELECT) _convertPathExpression(whereEl, model)
|
|
639
613
|
}
|
|
640
|
-
const conversion = convertPathExpressionToWhere(SELECT.from, model, options)
|
|
614
|
+
const conversion = convertPathExpressionToWhere(query.SELECT.from, model, options)
|
|
641
615
|
if (!conversion) return
|
|
642
616
|
const { target, alias, where, cardinality, columns, args } = conversion
|
|
643
617
|
|
|
644
618
|
// REVISIT: It's not possible to just change the reference (i.e. SELECT.from.ref = [target])
|
|
645
619
|
// as many parts of our code base still refer to SELECT.from (e.g. authorization)
|
|
646
620
|
if (args) {
|
|
647
|
-
SELECT.from = { ref: [{ id: target, args }] }
|
|
621
|
+
query.SELECT.from = { ref: [{ id: target, args }] }
|
|
648
622
|
} else {
|
|
649
|
-
SELECT.from = { ref: [target] }
|
|
623
|
+
query.SELECT.from = { ref: [target] }
|
|
650
624
|
}
|
|
651
625
|
if (alias) {
|
|
652
|
-
SELECT.from.as = alias
|
|
653
|
-
if (SELECT.where && alias !== prevAlias) {
|
|
654
|
-
SELECT.where = addAliasToExpression(SELECT.where, alias)
|
|
626
|
+
query.SELECT.from.as = alias
|
|
627
|
+
if (query.SELECT.where && alias !== prevAlias) {
|
|
628
|
+
query.SELECT.where = addAliasToExpression(query.SELECT.where, alias)
|
|
655
629
|
}
|
|
656
630
|
}
|
|
657
631
|
if (columns) {
|
|
658
632
|
// TODO: use streaming as outer property
|
|
659
|
-
if (options.isStreaming) SELECT.columns = columns
|
|
633
|
+
if (options.isStreaming) query.SELECT.columns = columns
|
|
660
634
|
else {
|
|
661
|
-
if (!SELECT.columns) {
|
|
635
|
+
if (!query.SELECT.columns) {
|
|
662
636
|
// Okra always wants to have the key values, remove once we relax this requirement
|
|
663
637
|
if (model.definitions[target] && model.definitions[target].keys) {
|
|
664
|
-
SELECT.columns = Object.keys(model.definitions[target].keys)
|
|
638
|
+
query.SELECT.columns = Object.keys(model.definitions[target].keys)
|
|
665
639
|
.filter(
|
|
666
640
|
k =>
|
|
667
641
|
!model.definitions[target].keys[k].isAssociation &&
|
|
668
642
|
!columns.find(element => element.ref && element.ref[element.ref.length - 1] === k)
|
|
669
643
|
)
|
|
670
644
|
.map(k => ({ ref: [k] }))
|
|
671
|
-
} else SELECT.columns = []
|
|
645
|
+
} else query.SELECT.columns = []
|
|
672
646
|
}
|
|
673
|
-
SELECT.columns.push(...columns)
|
|
647
|
+
query.SELECT.columns.push(...columns)
|
|
674
648
|
}
|
|
675
649
|
}
|
|
676
650
|
if (cardinality && cardinality.max === 1) {
|
|
677
|
-
SELECT.one = true
|
|
651
|
+
query.SELECT.one = true
|
|
678
652
|
}
|
|
679
653
|
// TODO: REVISIT: We need to add alias to subselect in .where, .columns, .from, ... etc
|
|
680
654
|
if (where) {
|
|
681
655
|
if (options._4fiori) {
|
|
682
|
-
|
|
656
|
+
query.where(where)
|
|
683
657
|
} else {
|
|
684
|
-
|
|
658
|
+
query.where(removeIsActiveEntityRecursively(where))
|
|
685
659
|
}
|
|
686
660
|
}
|
|
687
661
|
}
|
|
@@ -692,6 +666,9 @@ const _convertToOneEqNullInFilter = (query, target) => {
|
|
|
692
666
|
|
|
693
667
|
for (let i = 0; i < query.where.length; i++) {
|
|
694
668
|
const w = query.where[i]
|
|
669
|
+
if (w.xpr) {
|
|
670
|
+
_convertToOneEqNullInFilter({ where: w.xpr }, target)
|
|
671
|
+
}
|
|
695
672
|
const w2 = query.where[i + 2]
|
|
696
673
|
if (!w2 || !w.ref || w2.val !== null) {
|
|
697
674
|
continue
|
|
@@ -730,9 +707,6 @@ const _convertSelect = (query, model, _options) => {
|
|
|
730
707
|
query.SELECT.from = _convertSelect(query.SELECT.from, model, options)
|
|
731
708
|
}
|
|
732
709
|
|
|
733
|
-
// REVISIT: a temporary workaround for xpr from new parser
|
|
734
|
-
if (cds.env.features.odata_new_parser) _flattenCQN(query)
|
|
735
|
-
|
|
736
710
|
// lambda functions
|
|
737
711
|
convertWhereExists(query.SELECT, model, options)
|
|
738
712
|
|
|
@@ -742,7 +716,7 @@ const _convertSelect = (query, model, _options) => {
|
|
|
742
716
|
_convertNotEqual(query.SELECT, 'having')
|
|
743
717
|
}
|
|
744
718
|
|
|
745
|
-
_convertPathExpression(query
|
|
719
|
+
_convertPathExpression(query, model, options)
|
|
746
720
|
rewriteAsterisks(query, model, options)
|
|
747
721
|
if (query.SELECT.where) {
|
|
748
722
|
const entityName =
|
|
@@ -1,24 +1,44 @@
|
|
|
1
|
-
const
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const subOns = []
|
|
1
|
+
const _normalizedRef = o => (o && o.ref && o.ref.length > 1 && o.ref[0] === '$self' ? { ref: o.ref.slice(1) } : o)
|
|
2
|
+
|
|
3
|
+
const _sub = (newOn, subOns = []) => {
|
|
5
4
|
let currArr = []
|
|
6
5
|
|
|
7
|
-
for (
|
|
8
|
-
|
|
6
|
+
for (let i = 0; i < newOn.length; i++) {
|
|
7
|
+
const onEl = newOn[i]
|
|
8
|
+
|
|
9
|
+
if (onEl === 'or') {
|
|
10
|
+
// abort condition for or
|
|
11
|
+
subOns.push([])
|
|
12
|
+
return subOns
|
|
13
|
+
}
|
|
14
|
+
if (onEl.xpr) {
|
|
15
|
+
_sub(onEl.xpr, subOns)
|
|
16
|
+
// after xpr there usually should be and/or
|
|
17
|
+
i++
|
|
18
|
+
continue
|
|
19
|
+
}
|
|
20
|
+
if (currArr.length === 0) {
|
|
21
|
+
subOns.push(currArr)
|
|
22
|
+
}
|
|
9
23
|
if (onEl !== 'and') currArr.push(onEl)
|
|
10
24
|
else {
|
|
11
25
|
currArr = []
|
|
12
26
|
}
|
|
13
27
|
}
|
|
14
28
|
|
|
29
|
+
return subOns
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const _getSubOns = element => {
|
|
33
|
+
const newOn = element.on || []
|
|
34
|
+
const subOns = _sub(newOn)
|
|
35
|
+
|
|
15
36
|
for (const subOn of subOns) {
|
|
16
37
|
// We don't support anything else than
|
|
17
38
|
// A = B AND C = D AND ...
|
|
18
39
|
if (subOn.length !== 3) return []
|
|
19
40
|
}
|
|
20
|
-
|
|
21
|
-
return subOns
|
|
41
|
+
return subOns.map(subOn => subOn.map(ref => _normalizedRef(ref)))
|
|
22
42
|
}
|
|
23
43
|
|
|
24
44
|
const _parentFieldsFromSimpleOnCond = (element, subOn) => {
|
|
@@ -17,14 +17,14 @@ const getPathFromRef = ref => {
|
|
|
17
17
|
/*
|
|
18
18
|
* returns the target entity for the given path
|
|
19
19
|
*/
|
|
20
|
-
const getEntityFromPath = (path,
|
|
21
|
-
let current = { elements:
|
|
20
|
+
const getEntityFromPath = (path, def) => {
|
|
21
|
+
let current = def.definitions ? { elements: def.definitions } : def
|
|
22
22
|
path = typeof path === 'string' ? cds.parse.path(path) : path
|
|
23
23
|
const segments = [...path.ref]
|
|
24
24
|
while (segments.length) {
|
|
25
25
|
const segment = segments.shift()
|
|
26
26
|
current = current.elements[segment.id || segment]
|
|
27
|
-
if (current && current.target) current =
|
|
27
|
+
if (current && current.target) current = current._target
|
|
28
28
|
}
|
|
29
29
|
return current
|
|
30
30
|
}
|
|
@@ -243,6 +243,9 @@ const _newEntries = (entries = [], transition, service) =>
|
|
|
243
243
|
|
|
244
244
|
const _newWhere = (where = [], transition, tableName, alias, isSubselect = false) => {
|
|
245
245
|
const newWhere = where.map(whereElement => {
|
|
246
|
+
if (whereElement.xpr) {
|
|
247
|
+
return { xpr: _newWhere(whereElement.xpr, transition, tableName, alias, isSubselect) }
|
|
248
|
+
}
|
|
246
249
|
const newWhereElement = { ...whereElement }
|
|
247
250
|
if (!whereElement.ref && !whereElement.SELECT && !whereElement.func) return whereElement
|
|
248
251
|
if (whereElement.SELECT && whereElement.SELECT.where) {
|
|
@@ -47,7 +47,8 @@ const _flattenStructuredInExpand = (column, { _target: expandedEntity }) => {
|
|
|
47
47
|
if (orderBy) {
|
|
48
48
|
column.orderBy = orderBy
|
|
49
49
|
}
|
|
50
|
-
|
|
50
|
+
const columnWhere = flattenStructuredWhereHaving(column.where, expandedEntity)
|
|
51
|
+
if (columnWhere) column.where = columnWhere
|
|
51
52
|
column.expand = column.expand.filter(e => !e.ref || !toBeDeleted.includes(e.ref[e.ref.length - 1]))
|
|
52
53
|
column.expand.push(...flattenedElements)
|
|
53
54
|
}
|
|
@@ -205,6 +206,10 @@ const flattenStructuredWhereHaving = (filterArray, csnEntity, model) => {
|
|
|
205
206
|
|
|
206
207
|
const newFilterArray = []
|
|
207
208
|
for (let i = 0; i < filterArray.length; i++) {
|
|
209
|
+
if (filterArray[i].xpr) {
|
|
210
|
+
newFilterArray.push({ xpr: flattenStructuredWhereHaving(filterArray[i].xpr, csnEntity, model) })
|
|
211
|
+
continue
|
|
212
|
+
}
|
|
208
213
|
if (filterArray[i + 1] in OPERATIONS_MAP) {
|
|
209
214
|
const refElement = filterArray[i].ref ? filterArray[i] : filterArray[i + 2]
|
|
210
215
|
|
|
@@ -38,6 +38,16 @@ class DatabaseService extends cds.Service {
|
|
|
38
38
|
// REVISIT: how to generic handler registration?
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
/** Database services don't support custom-defined operations */
|
|
42
|
+
operations() {
|
|
43
|
+
return []
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Database services don't support custom-defined events */
|
|
47
|
+
events() {
|
|
48
|
+
return []
|
|
49
|
+
}
|
|
50
|
+
|
|
41
51
|
/*
|
|
42
52
|
* tx
|
|
43
53
|
*/
|
|
@@ -79,16 +79,24 @@ const _autoExpandNavsAndAttachToResult = async (entity, previousResult, depth, o
|
|
|
79
79
|
return previousResult
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
const _fkForOnCOnd = (onCond, requiredFks) => {
|
|
83
|
+
for (const ele of onCond) {
|
|
84
|
+
if (ele.xpr) {
|
|
85
|
+
_fkForOnCOnd(ele.xpr, requiredFks)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (ele.ref && ele.ref[0] === 'parent') {
|
|
89
|
+
requiredFks.add(ele.ref.slice(1).join('_'))
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
82
94
|
const _foreignKeysOfTopLevelNavs = (entity, options) => {
|
|
83
95
|
const requiredFks = new Set()
|
|
84
96
|
for (const nav in entity._associations) {
|
|
85
97
|
if (options.onlyCompositions && entity._associations[nav]._isAssociationEffective) continue
|
|
86
98
|
const onCond = entity._relations[nav].join('child', 'parent')
|
|
87
|
-
|
|
88
|
-
if (ele.ref && ele.ref[0] === 'parent') {
|
|
89
|
-
requiredFks.add(ele.ref.slice(1).join('_'))
|
|
90
|
-
}
|
|
91
|
-
}
|
|
99
|
+
_fkForOnCOnd(onCond, requiredFks)
|
|
92
100
|
}
|
|
93
101
|
return [...requiredFks]
|
|
94
102
|
}
|
|
@@ -395,6 +395,9 @@ class JoinCQNFromExpanded {
|
|
|
395
395
|
*/
|
|
396
396
|
_adaptWhereSELECT(aliasedTable, where, tableAlias) {
|
|
397
397
|
return where.map(element => {
|
|
398
|
+
if (element.xpr) {
|
|
399
|
+
return { xpr: this._adaptWhereSELECT(aliasedTable, element.xpr, tableAlias) }
|
|
400
|
+
}
|
|
398
401
|
return this._elementAliasNeedsReplacement(element, aliasedTable)
|
|
399
402
|
? Object.assign({}, element, { ref: [tableAlias, element.ref[1]] })
|
|
400
403
|
: element
|
|
@@ -870,13 +873,21 @@ class JoinCQNFromExpanded {
|
|
|
870
873
|
const aliases = this._getAliases(subSelectColumns)
|
|
871
874
|
const on = entity._relations[tableAlias === columns[0] ? columns.slice(1) : columns].join(tableAlias, parentAlias)
|
|
872
875
|
|
|
876
|
+
this._adjustAliases(on, aliases)
|
|
877
|
+
|
|
878
|
+
return on
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
_adjustAliases(on, aliases) {
|
|
873
882
|
for (const element of on) {
|
|
883
|
+
if (element.xpr) {
|
|
884
|
+
this._adjustAliases(element.xpr, aliases)
|
|
885
|
+
continue
|
|
886
|
+
}
|
|
874
887
|
if (element.ref && aliases[element.ref[0]] && aliases[element.ref[0]][element.ref[1]]) {
|
|
875
888
|
element.ref[1] = aliases[element.ref[0]][element.ref[1]]
|
|
876
889
|
}
|
|
877
890
|
}
|
|
878
|
-
|
|
879
|
-
return on
|
|
880
891
|
}
|
|
881
892
|
|
|
882
893
|
_addJoinKeyColumnsToUnion(args, on, parentAlias) {
|
|
@@ -899,23 +910,27 @@ class JoinCQNFromExpanded {
|
|
|
899
910
|
}
|
|
900
911
|
|
|
901
912
|
_addColumns(columns, on, parentAlias, withAlias = false) {
|
|
902
|
-
const
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
913
|
+
for (const entry of on) {
|
|
914
|
+
if (entry.xpr) {
|
|
915
|
+
this._addColumns(columns, entry.xpr, parentAlias, withAlias)
|
|
916
|
+
continue
|
|
917
|
+
}
|
|
918
|
+
if (
|
|
919
|
+
entry.ref &&
|
|
920
|
+
entry.ref[0] === parentAlias &&
|
|
921
|
+
!columns.some(column => column.ref && column.ref[column.ref.length - 1] === entry.ref[1])
|
|
922
|
+
) {
|
|
923
|
+
columns.push(
|
|
924
|
+
withAlias
|
|
925
|
+
? { ref: [parentAlias, entry.ref[1]], as: `${parentAlias}_${entry.ref[1]}` }
|
|
926
|
+
: { ref: [entry.ref[1]] }
|
|
908
927
|
)
|
|
909
|
-
}
|
|
910
|
-
|
|
911
|
-
withAlias ? { ref: [parentAlias, entry.ref[1]], as: `${parentAlias}_${entry.ref[1]}` } : { ref: [entry.ref[1]] }
|
|
912
|
-
)
|
|
913
|
-
if (keyColumns.length === 0) return
|
|
914
|
-
columns.push(...keyColumns)
|
|
928
|
+
}
|
|
929
|
+
}
|
|
915
930
|
}
|
|
916
931
|
|
|
917
932
|
/**
|
|
918
|
-
* Add
|
|
933
|
+
* Add a unique alias to each column, to avoid ambiguity.
|
|
919
934
|
* Add this information to the post process config.
|
|
920
935
|
*
|
|
921
936
|
* @param {object} column
|
|
@@ -1318,6 +1333,26 @@ class JoinCQNFromExpanded {
|
|
|
1318
1333
|
return newObj
|
|
1319
1334
|
}
|
|
1320
1335
|
|
|
1336
|
+
_getFilterColumns(readToOneCQN, on, parentAlias) {
|
|
1337
|
+
const columns = []
|
|
1338
|
+
const outerColumns = []
|
|
1339
|
+
|
|
1340
|
+
for (const entry of on) {
|
|
1341
|
+
if (entry.xpr) {
|
|
1342
|
+
const { columns: cols, outerColumns: outerCols } = this._getFilterColumns(readToOneCQN, entry.xpr, parentAlias)
|
|
1343
|
+
columns.push(...cols)
|
|
1344
|
+
outerColumns.push(...outerCols)
|
|
1345
|
+
continue
|
|
1346
|
+
}
|
|
1347
|
+
if (typeof entry === 'object' && entry.ref && entry.ref[0] === 'filterExpand') {
|
|
1348
|
+
columns.push(this._getColumnObjectForFilterExpand(readToOneCQN, parentAlias, entry.ref[1]))
|
|
1349
|
+
outerColumns.push({ ref: [entry.ref[1]] })
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
return { columns, outerColumns }
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1321
1356
|
/**
|
|
1322
1357
|
* Reduce column list to column(s) needed to merge the result into one.
|
|
1323
1358
|
*
|
|
@@ -1329,22 +1364,13 @@ class JoinCQNFromExpanded {
|
|
|
1329
1364
|
* @private
|
|
1330
1365
|
*/
|
|
1331
1366
|
_getFilterExpandCQN(readToOneCQN, on, parentAlias, keyObject) {
|
|
1332
|
-
const columns = []
|
|
1333
|
-
|
|
1334
|
-
const outerColumns = []
|
|
1335
|
-
|
|
1336
|
-
for (const entry of on) {
|
|
1337
|
-
if (typeof entry === 'object' && entry.ref && entry.ref[0] === 'filterExpand') {
|
|
1338
|
-
columns.push(this._getColumnObjectForFilterExpand(readToOneCQN, parentAlias, entry.ref[1]))
|
|
1339
|
-
outerColumns.push({ ref: [entry.ref[1]] })
|
|
1340
|
-
}
|
|
1341
|
-
}
|
|
1342
|
-
|
|
1343
1367
|
const keys = Object.keys(keyObject).filter(
|
|
1344
1368
|
key =>
|
|
1345
1369
|
key !== 'IsActiveEntity' && !keyObject[key].is2one && !keyObject[key].is2many && !keyObject[key]._isStructured
|
|
1346
1370
|
)
|
|
1347
1371
|
|
|
1372
|
+
const { columns, outerColumns } = this._getFilterColumns(readToOneCQN, on, parentAlias)
|
|
1373
|
+
|
|
1348
1374
|
for (const key of keys) {
|
|
1349
1375
|
if (!columns.map(entry => entry.as).includes(key)) {
|
|
1350
1376
|
columns.push(this._getColumnObjectForFilterExpand(readToOneCQN, parentAlias, key))
|
|
@@ -1455,6 +1481,10 @@ class JoinCQNFromExpanded {
|
|
|
1455
1481
|
this._addColumNames(entity, parentAlias, columnNames)
|
|
1456
1482
|
|
|
1457
1483
|
for (const entry of on) {
|
|
1484
|
+
if (entry.xpr) {
|
|
1485
|
+
columns.push(...this._getJoinColumnsFromOnAddToMapping(mapping, parentAlias, entry.xpr, entity))
|
|
1486
|
+
continue
|
|
1487
|
+
}
|
|
1458
1488
|
if (typeof entry === 'object' && entry.ref && entry.ref[0] !== 'filterExpand') {
|
|
1459
1489
|
const as = entry.ref.join('_')
|
|
1460
1490
|
columns.push({
|
|
@@ -20,6 +20,11 @@ const _redirectXpr = (xpr, aliasMap) => {
|
|
|
20
20
|
return
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
if (element.xpr) {
|
|
24
|
+
_redirectXpr(element.xpr, aliasMap)
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
|
|
23
28
|
if (element.func) {
|
|
24
29
|
_redirectXpr(element.args, aliasMap)
|
|
25
30
|
return
|
|
@@ -98,6 +103,10 @@ const generateAliases = query => {
|
|
|
98
103
|
|
|
99
104
|
const _addParentAlias = (where, alias) => {
|
|
100
105
|
where.forEach(e => {
|
|
106
|
+
if (e.xpr) {
|
|
107
|
+
_addParentAlias(e.xpr, alias)
|
|
108
|
+
return
|
|
109
|
+
}
|
|
101
110
|
if (e.ref && e.ref[0].match(PARENT_ALIAS_REGEX)) {
|
|
102
111
|
e.ref[0] = alias
|
|
103
112
|
}
|
|
@@ -21,6 +21,7 @@ const _processorFn = ({ row, key }) => {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
function transformExtendedFieldsCREATE(req) {
|
|
24
|
+
if (!req.query) return // FIXME: the code below expects req.query to be defined
|
|
24
25
|
if (!req.target) return
|
|
25
26
|
if (!req.query.INSERT.entries) return // REVISIT: breaks at cds.deploy -> should anyways not kick in during cds.deploy
|
|
26
27
|
|