@sap/cds 8.8.3 → 8.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +48 -4
- package/_i18n/i18n_en_US_saptrc.properties +3 -0
- package/bin/colors.js +2 -0
- package/bin/test.js +103 -75
- package/eslint.config.mjs +16 -4
- package/lib/compile/for/lean_drafts.js +4 -0
- package/lib/compile/parse.js +26 -6
- package/lib/env/cds-env.js +3 -1
- package/lib/env/cds-requires.js +0 -3
- package/lib/env/schemas/cds-rc.js +11 -0
- package/lib/log/format/aspects/cls.js +2 -1
- package/lib/log/format/json.js +1 -1
- package/lib/plugins.js +2 -3
- package/lib/ql/SELECT.js +2 -1
- package/lib/ql/cds-ql.js +2 -0
- package/lib/ql/cds.ql-predicates.js +6 -4
- package/lib/ql/resolve.js +46 -0
- package/lib/req/validate.js +1 -0
- package/lib/srv/bindings.js +64 -43
- package/lib/srv/cds-connect.js +1 -1
- package/lib/srv/cds-serve.js +2 -2
- package/lib/srv/middlewares/auth/ias-auth.js +2 -0
- package/lib/srv/protocols/http.js +2 -2
- package/lib/srv/protocols/index.js +1 -1
- package/lib/srv/protocols/odata-v4.js +0 -1
- package/lib/srv/srv-tx.js +1 -1
- package/lib/test/cds-test.js +3 -4
- package/lib/utils/cds-utils.js +19 -19
- package/lib/utils/colors.js +46 -45
- package/lib/utils/csv-reader.js +5 -5
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +1 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/index.js +1 -1
- package/libx/_runtime/common/Service.js +4 -2
- package/libx/_runtime/common/composition/data.js +1 -2
- package/libx/_runtime/common/composition/tree.js +6 -4
- package/libx/_runtime/common/generic/sorting.js +6 -2
- package/libx/_runtime/common/utils/cqn2cqn4sql.js +6 -7
- package/libx/_runtime/common/utils/differ.js +1 -1
- package/libx/_runtime/common/utils/draft.js +1 -1
- package/libx/_runtime/common/utils/foreignKeyPropagations.js +6 -2
- package/libx/_runtime/common/utils/keys.js +13 -84
- package/libx/_runtime/common/utils/propagateForeignKeys.js +4 -3
- package/libx/_runtime/common/utils/resolveView.js +96 -102
- package/libx/_runtime/common/utils/rewriteAsterisks.js +1 -1
- package/libx/_runtime/common/utils/stream.js +2 -3
- package/libx/_runtime/db/utils/columns.js +1 -1
- package/libx/_runtime/fiori/lean-draft.js +11 -7
- package/libx/_runtime/messaging/AMQPWebhookMessaging.js +1 -1
- package/libx/_runtime/messaging/common-utils/normalizeIncomingMessage.js +1 -2
- package/libx/_runtime/messaging/file-based.js +6 -6
- package/libx/_runtime/messaging/kafka.js +5 -7
- package/libx/_runtime/messaging/redis-messaging.js +1 -1
- package/libx/_runtime/messaging/service.js +11 -4
- package/libx/_runtime/remote/Service.js +13 -5
- package/libx/_runtime/remote/utils/client.js +1 -0
- package/libx/_runtime/ucl/Service.js +135 -126
- package/libx/common/utils/path.js +34 -22
- package/libx/odata/middleware/create.js +2 -0
- package/libx/odata/middleware/operation.js +8 -2
- package/libx/odata/middleware/parse.js +1 -1
- package/libx/odata/middleware/stream.js +1 -2
- package/libx/odata/middleware/update.js +2 -0
- package/libx/odata/parse/afterburner.js +17 -9
- package/libx/odata/parse/cqn2odata.js +43 -22
- package/libx/odata/parse/grammar.peggy +21 -19
- package/libx/odata/parse/parser.js +1 -1
- package/libx/odata/utils/metadata.js +8 -2
- package/libx/odata/utils/odataBind.js +36 -0
- package/libx/outbox/index.js +1 -0
- package/libx/rest/middleware/operation.js +9 -8
- package/libx/rest/middleware/parse.js +1 -0
- package/package.json +3 -3
- package/lib/i18n/resources.js +0 -150
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
const cds = require('../../cds')
|
|
2
2
|
const { SELECT, INSERT, DELETE, UPDATE } = cds.ql
|
|
3
3
|
const Query = require('../../../../lib/ql/cds.ql-Query')
|
|
4
|
-
const { resolveView } = require('./resolveView')
|
|
5
4
|
const { ensureNoDraftsSuffix, getDraftColumnsCQNForDraft, ensureDraftsSuffix } = require('./draft')
|
|
6
5
|
const { flattenStructuredSelect, OPERATIONS_MAP } = require('./structured')
|
|
7
6
|
const search2cqn4sql = require('./search2cqn4sql')
|
|
@@ -854,7 +853,7 @@ const _convertUpsert = (query, model) => {
|
|
|
854
853
|
}
|
|
855
854
|
Object.assign(upsert.UPSERT, { into: { ref: [resolvedIntoClause], as: query.UPSERT.into.as } })
|
|
856
855
|
|
|
857
|
-
const resolved =
|
|
856
|
+
const resolved = cds.ql.resolve.resolve4db(upsert, cds.db)
|
|
858
857
|
// required for deploying of extensions, not used anywhere else except UpsertBuilder
|
|
859
858
|
resolved._target = resolved.UPSERT?._transitions?.[0].target || query._target
|
|
860
859
|
// resolved._target = query._target
|
|
@@ -881,7 +880,7 @@ const _convertInsert = (query, model) => {
|
|
|
881
880
|
|
|
882
881
|
const target = model.definitions[resolvedIntoClause]
|
|
883
882
|
if (!target) return insert
|
|
884
|
-
return
|
|
883
|
+
return cds.ql.resolve.resolve4db(insert, cds.db)
|
|
885
884
|
}
|
|
886
885
|
|
|
887
886
|
function _modifyNavigationInWhere(whereClause, target) {
|
|
@@ -913,7 +912,7 @@ const _plainDelete = (cqn, model) => {
|
|
|
913
912
|
|
|
914
913
|
if (!target) return cqn
|
|
915
914
|
|
|
916
|
-
return
|
|
915
|
+
return cds.ql.resolve.resolve4db(cqn, cds.db)
|
|
917
916
|
}
|
|
918
917
|
|
|
919
918
|
const _convertDelete = (query, model, options) => {
|
|
@@ -946,7 +945,7 @@ const _convertDelete = (query, model, options) => {
|
|
|
946
945
|
|
|
947
946
|
if (!targetEntity) return deleet
|
|
948
947
|
|
|
949
|
-
return
|
|
948
|
+
return cds.ql.resolve.resolve4db(deleet, cds.db)
|
|
950
949
|
}
|
|
951
950
|
|
|
952
951
|
function _plainUpdate(cqn, model) {
|
|
@@ -958,7 +957,7 @@ function _plainUpdate(cqn, model) {
|
|
|
958
957
|
}
|
|
959
958
|
|
|
960
959
|
if (!target) return cqn
|
|
961
|
-
return
|
|
960
|
+
return cds.ql.resolve.resolve4db(cqn, cds.db)
|
|
962
961
|
}
|
|
963
962
|
|
|
964
963
|
const _convertUpdate = (query, model, options) => {
|
|
@@ -996,7 +995,7 @@ const _convertUpdate = (query, model, options) => {
|
|
|
996
995
|
|
|
997
996
|
if (!targetEntity) return update
|
|
998
997
|
|
|
999
|
-
return
|
|
998
|
+
return cds.ql.resolve.resolve4db(update, cds.db)
|
|
1000
999
|
}
|
|
1001
1000
|
|
|
1002
1001
|
/**
|
|
@@ -67,7 +67,7 @@ module.exports = class Differ {
|
|
|
67
67
|
const combinedData = providedData || Object.assign({}, req.query.UPDATE.data || {}, req.query.UPDATE.with || {})
|
|
68
68
|
enrichDataWithKeysFromWhere(combinedData, req, this._srv)
|
|
69
69
|
const lastTransition = newQuery.UPDATE._transitions[newQuery.UPDATE._transitions.length - 1]
|
|
70
|
-
const revertedPersistent = revertData(req._.partialPersistentState, lastTransition,
|
|
70
|
+
const revertedPersistent = revertData(req._.partialPersistentState, lastTransition, cds.db)
|
|
71
71
|
const diff = compareJson(combinedData, revertedPersistent, req.target, { ignoreDraftColumns: true })
|
|
72
72
|
return diff
|
|
73
73
|
}
|
|
@@ -68,8 +68,12 @@ const _parentFieldsFromSimpleOnCond = (element, subOn) => {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
if (!childElement.on) {
|
|
71
|
-
|
|
72
|
-
if (
|
|
71
|
+
const propagations = []
|
|
72
|
+
if ('val' in subOn[idxParentField])
|
|
73
|
+
propagations.push({ fillChild: true, parentFieldValue: subOn[idxParentField].val, childElement })
|
|
74
|
+
if (element._isSelfManaged)
|
|
75
|
+
return [...propagations, ..._foreignKeyPropagationsFromToManyOn(element, childFieldName)]
|
|
76
|
+
if (parentElement) return [...propagations, { fillChild: true, parentElement, childElement }]
|
|
73
77
|
}
|
|
74
78
|
|
|
75
79
|
if ('val' in subOn[idxParentField]) {
|
|
@@ -1,35 +1,6 @@
|
|
|
1
1
|
const { where2obj } = require('./cqn')
|
|
2
2
|
const { deepCopy } = require('./copy')
|
|
3
|
-
const {
|
|
4
|
-
|
|
5
|
-
function _getOnCondElements(onCond, onCondElements = []) {
|
|
6
|
-
const andIndex = onCond.indexOf('and')
|
|
7
|
-
|
|
8
|
-
const ref0 = onCond[0].xpr ? onCond[0].xpr[0].ref : onCond[0].ref
|
|
9
|
-
const ref1 = onCond[0].xpr ? onCond[0].xpr[2].ref : onCond[2].ref
|
|
10
|
-
const val0 = onCond[0].xpr ? onCond[0].xpr[0].val : onCond[0].val
|
|
11
|
-
const val1 = onCond[0].xpr ? onCond[0].xpr[2].val : onCond[2].val
|
|
12
|
-
|
|
13
|
-
let entityRef, targetRef, entityVal
|
|
14
|
-
if (ref0?.[0] === 'target') {
|
|
15
|
-
targetRef = ref0
|
|
16
|
-
entityRef = ref1
|
|
17
|
-
entityVal = val1
|
|
18
|
-
} else if (ref1?.[0] === 'target') {
|
|
19
|
-
targetRef = ref1
|
|
20
|
-
entityRef = ref0
|
|
21
|
-
entityVal = val0
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const entityKey = entityRef && entityRef.slice(1).join('.')
|
|
25
|
-
const targetKey = targetRef && targetRef.slice(1).join('.')
|
|
26
|
-
onCondElements.push({ entityKey, targetKey, entityVal })
|
|
27
|
-
|
|
28
|
-
if (andIndex !== -1) {
|
|
29
|
-
_getOnCondElements(onCond.slice(andIndex + 1), onCondElements)
|
|
30
|
-
}
|
|
31
|
-
return onCondElements
|
|
32
|
-
}
|
|
3
|
+
const { foreignKeyPropagations } = require('./foreignKeyPropagations')
|
|
33
4
|
|
|
34
5
|
function _mergeWhere(base, additional) {
|
|
35
6
|
if (additional?.length) {
|
|
@@ -56,16 +27,20 @@ function _buildWhereForNavigations(ref, newWhere, model, target) {
|
|
|
56
27
|
|
|
57
28
|
if (!navigationElement || !navigationElement.on) return
|
|
58
29
|
|
|
59
|
-
const
|
|
60
|
-
const nextKeys = _getOnCondElements(onCond[0].xpr)
|
|
30
|
+
const nextKeys = foreignKeyPropagations(navigationElement)
|
|
61
31
|
|
|
62
32
|
// only add where once in _modifyWhereWithNavigations
|
|
63
33
|
let whereAdded = false
|
|
64
34
|
for (const key of nextKeys) {
|
|
65
|
-
const targetKeyElement = navigationElement._target.elements[key.
|
|
35
|
+
const targetKeyElement = navigationElement._target.elements[key.childElement.name]
|
|
66
36
|
|
|
67
37
|
if (targetKeyElement && (targetKeyElement.isAssociation || targetKeyElement._foreignKey4)) {
|
|
68
|
-
_modifyWhereWithNavigations(
|
|
38
|
+
_modifyWhereWithNavigations(
|
|
39
|
+
!whereAdded && currentRef.where,
|
|
40
|
+
newWhere,
|
|
41
|
+
key.childElement.name,
|
|
42
|
+
key.parentElement.name
|
|
43
|
+
)
|
|
69
44
|
whereAdded = true
|
|
70
45
|
}
|
|
71
46
|
}
|
|
@@ -76,6 +51,9 @@ function _buildWhereForNavigations(ref, newWhere, model, target) {
|
|
|
76
51
|
function _renameOnUp(newWhere, entityKey, targetKey) {
|
|
77
52
|
let renamed = false
|
|
78
53
|
newWhere.forEach(element => {
|
|
54
|
+
if (element.xpr && element.xpr.length) {
|
|
55
|
+
renamed = _renameOnUp(element.xpr, entityKey, targetKey) || renamed
|
|
56
|
+
}
|
|
79
57
|
if (element.ref && element.ref[0] === targetKey) {
|
|
80
58
|
element.ref = [entityKey]
|
|
81
59
|
renamed = true
|
|
@@ -84,54 +62,6 @@ function _renameOnUp(newWhere, entityKey, targetKey) {
|
|
|
84
62
|
return renamed
|
|
85
63
|
}
|
|
86
64
|
|
|
87
|
-
function calculateWhereForNavigationsFromRefPath(ref, newWhere, target) {
|
|
88
|
-
const currentRef = ref[0]
|
|
89
|
-
const nextRef = ref[1]
|
|
90
|
-
|
|
91
|
-
if (nextRef) {
|
|
92
|
-
const csnEntity = target
|
|
93
|
-
const navigationElement = csnEntity && csnEntity.elements[nextRef.id || nextRef]
|
|
94
|
-
|
|
95
|
-
if (!navigationElement || !navigationElement.on) return
|
|
96
|
-
|
|
97
|
-
const onCond = target._relations[nextRef.id || nextRef].join('target', 'source')
|
|
98
|
-
const nextKeys = _getOnCondElements(onCond[0].xpr)
|
|
99
|
-
|
|
100
|
-
const seg_keys = where2obj(currentRef.where ?? [])
|
|
101
|
-
for (const key of nextKeys) {
|
|
102
|
-
if (navigationElement.is2one && csnEntity.elements[key.entityKey] && !navigationElement._isSelfManaged) {
|
|
103
|
-
// foreign key in root
|
|
104
|
-
continue
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const targetKeyElement = navigationElement._target.elements[key.targetKey]
|
|
108
|
-
|
|
109
|
-
if (targetKeyElement && key.targetKey && key.entityKey) {
|
|
110
|
-
if (newWhere.length) {
|
|
111
|
-
if (_renameOnUp(newWhere, key.targetKey, key.entityKey)) {
|
|
112
|
-
continue
|
|
113
|
-
}
|
|
114
|
-
newWhere.push('and')
|
|
115
|
-
}
|
|
116
|
-
newWhere.push({ ref: [key.targetKey] }, '=', { val: seg_keys[key.entityKey] })
|
|
117
|
-
} else if (targetKeyElement && key.targetKey && key.entityVal !== undefined) {
|
|
118
|
-
if (newWhere.length) newWhere.push('and')
|
|
119
|
-
newWhere.push({ ref: [key.targetKey] }, '=', { val: key.entityVal })
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
calculateWhereForNavigationsFromRefPath(ref.slice(1), newWhere, navigationElement._target)
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function getKeysForNavigationFromRefPath(ref, target) {
|
|
127
|
-
const where = []
|
|
128
|
-
calculateWhereForNavigationsFromRefPath(ref, where, target)
|
|
129
|
-
if (where.length) {
|
|
130
|
-
return where2obj(where)
|
|
131
|
-
}
|
|
132
|
-
return {}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
65
|
function _getWhereFromInsert(query, model) {
|
|
136
66
|
const where = []
|
|
137
67
|
if (query.INSERT.into.ref && query.INSERT.into.ref.length > 1) {
|
|
@@ -172,6 +102,5 @@ function enrichDataWithKeysFromWhere(data, { query, target }, { model }) {
|
|
|
172
102
|
|
|
173
103
|
module.exports = {
|
|
174
104
|
where2obj,
|
|
175
|
-
enrichDataWithKeysFromWhere
|
|
176
|
-
getKeysForNavigationFromRefPath
|
|
105
|
+
enrichDataWithKeysFromWhere
|
|
177
106
|
}
|
|
@@ -5,6 +5,7 @@ const { prefixForStruct } = require('../../common/utils/csn')
|
|
|
5
5
|
const _autoGenerate = e => e && e.isUUID && e.key
|
|
6
6
|
|
|
7
7
|
const _set = (row, value, element, enumerable) => {
|
|
8
|
+
if (value === undefined) return // only if properly propagated/generated
|
|
8
9
|
if (!element.parent.elements[element.name]) return // only when in model
|
|
9
10
|
if (!enumerable && element.foreignKeySource) {
|
|
10
11
|
// only for foreign keys
|
|
@@ -86,7 +87,7 @@ module.exports = (
|
|
|
86
87
|
row,
|
|
87
88
|
foreignKeyPropagations,
|
|
88
89
|
isCompositionEffective,
|
|
89
|
-
{ deleteAssocs = false, enumerable = true } = {}
|
|
90
|
+
{ deleteAssocs = false, enumerable = true, generateKeys = true } = {}
|
|
90
91
|
) => {
|
|
91
92
|
if (!row || !(tKey in row)) return
|
|
92
93
|
if (row[tKey] === null) {
|
|
@@ -109,11 +110,11 @@ module.exports = (
|
|
|
109
110
|
// propagate or generate in parent
|
|
110
111
|
const pk = foreignKeyPropagation.parentElement && foreignKeyPropagation.parentElement.name
|
|
111
112
|
if (pk && !(pk in row)) _propagateToParent(foreignKeyPropagation, childRow, row, enumerable)
|
|
112
|
-
if (!(pk in row)) _generateParentField(foreignKeyPropagation, row, enumerable)
|
|
113
|
+
if (!(pk in row) && generateKeys) _generateParentField(foreignKeyPropagation, row, enumerable, generateKeys)
|
|
113
114
|
|
|
114
115
|
if (isCompositionEffective) _propagateToChild(foreignKeyPropagation, row, childRow, enumerable)
|
|
115
116
|
} else {
|
|
116
|
-
if (isCompositionEffective) _generateChildField(foreignKeyPropagation, childRow, enumerable)
|
|
117
|
+
if (isCompositionEffective && generateKeys) _generateChildField(foreignKeyPropagation, childRow, enumerable)
|
|
117
118
|
_propagateToParent(foreignKeyPropagation, childRow, row, enumerable)
|
|
118
119
|
}
|
|
119
120
|
}
|