@sap/cds 5.4.6 → 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 +208 -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 +44 -55
- 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 +4 -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 +6 -22
- 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 +102 -101
- package/libx/_runtime/common/utils/csn.js +47 -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 +223 -171
- package/libx/_runtime/common/utils/rewriteAsterisk.js +46 -26
- package/libx/_runtime/common/utils/structured.js +6 -12
- 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 +22 -30
- 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 +13 -20
- 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 +241 -189
- 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 +2 -2
- 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 +23 -24
- package/libx/_runtime/sqlite/localized.js +12 -7
- package/libx/_runtime/types/api.js +10 -0
- package/package.json +1 -1
- 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
|
@@ -23,6 +23,7 @@ const _getNestedVal = (row, prefix) => {
|
|
|
23
23
|
let val = row
|
|
24
24
|
const splitted = prefix.split('_')
|
|
25
25
|
let k = ''
|
|
26
|
+
|
|
26
27
|
while (splitted.length > 0) {
|
|
27
28
|
k += splitted.shift()
|
|
28
29
|
if (k in val) {
|
|
@@ -32,11 +33,13 @@ const _getNestedVal = (row, prefix) => {
|
|
|
32
33
|
k += '_'
|
|
33
34
|
}
|
|
34
35
|
}
|
|
36
|
+
|
|
35
37
|
return val
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
const _propagateToChid = (foreignKeyPropagation, row, childRow) => {
|
|
39
41
|
const { parentFieldName, childFieldName, prefix, parentFieldValue } = foreignKeyPropagation
|
|
42
|
+
|
|
40
43
|
if (parentFieldName) {
|
|
41
44
|
if (prefix) {
|
|
42
45
|
const nested = _getNestedVal(row, prefix)
|
|
@@ -54,18 +57,26 @@ const _propagateToParent = (foreignKeyPropagations, childRow, row) => {
|
|
|
54
57
|
const deep = foreignKeyPropagations.deep
|
|
55
58
|
_propagateToParent(deep.propagation, childRow[deep.targetName], childRow)
|
|
56
59
|
}
|
|
57
|
-
|
|
60
|
+
|
|
61
|
+
if (childRow && Object.prototype.hasOwnProperty.call(childRow, foreignKeyPropagations.childFieldName)) {
|
|
58
62
|
row[foreignKeyPropagations.parentFieldName] = childRow[foreignKeyPropagations.childFieldName]
|
|
63
|
+
}
|
|
59
64
|
}
|
|
60
65
|
|
|
61
|
-
const propagateForeignKeys = (tKey, row, foreignKeyPropagations) => {
|
|
66
|
+
const propagateForeignKeys = (tKey, row, foreignKeyPropagations, opts = {}) => {
|
|
62
67
|
const childRows = Array.isArray(row[tKey]) ? row[tKey] : [row[tKey]]
|
|
68
|
+
|
|
63
69
|
for (const childRow of childRows) {
|
|
64
70
|
if (!childRow) return
|
|
71
|
+
|
|
65
72
|
for (const foreignKeyPropagation of foreignKeyPropagations) {
|
|
66
73
|
if (foreignKeyPropagation.fillChild) {
|
|
67
74
|
_generateParentField(foreignKeyPropagation, row)
|
|
68
|
-
|
|
75
|
+
if (opts.onlyWriteCompositionEffective && !foreignKeyPropagations._element._isCompositionEffective) {
|
|
76
|
+
delete row[tKey]
|
|
77
|
+
} else {
|
|
78
|
+
_propagateToChid(foreignKeyPropagation, row, childRow)
|
|
79
|
+
}
|
|
69
80
|
} else {
|
|
70
81
|
_generateChildField(foreignKeyPropagation, childRow)
|
|
71
82
|
_propagateToParent(foreignKeyPropagation, childRow, row)
|
|
@@ -79,6 +90,7 @@ const _getSubOns = on => {
|
|
|
79
90
|
const newOn = on.filter(e => e !== '(' && e !== ')')
|
|
80
91
|
const subOns = []
|
|
81
92
|
let currArr = []
|
|
93
|
+
|
|
82
94
|
for (const onEl of newOn) {
|
|
83
95
|
if (currArr.length === 0) subOns.push(currArr)
|
|
84
96
|
if (onEl !== 'and') currArr.push(onEl)
|
|
@@ -86,11 +98,13 @@ const _getSubOns = on => {
|
|
|
86
98
|
currArr = []
|
|
87
99
|
}
|
|
88
100
|
}
|
|
101
|
+
|
|
89
102
|
for (const subOn of subOns) {
|
|
90
103
|
// We don't support anything else than
|
|
91
104
|
// A = B AND C = D AND ...
|
|
92
105
|
if (subOn.length !== 3) return []
|
|
93
106
|
}
|
|
107
|
+
|
|
94
108
|
return subOns
|
|
95
109
|
}
|
|
96
110
|
|
|
@@ -99,6 +113,7 @@ const _autoGenerate = el => el && el.type === 'cds.UUID' && el.key
|
|
|
99
113
|
const _parentFieldsFromSimpleOnCond = (element, subOn) => {
|
|
100
114
|
const idxChildField = subOn.findIndex(o => o.ref && o.ref[0] === element.name)
|
|
101
115
|
if (idxChildField === -1 || subOn[1] !== '=') return
|
|
116
|
+
|
|
102
117
|
const childFieldName = subOn[idxChildField].ref && subOn[idxChildField].ref.slice(1).join('_')
|
|
103
118
|
const childElement = element._target.elements[childFieldName]
|
|
104
119
|
const idxParentField = idxChildField === 2 ? 0 : 2
|
|
@@ -126,9 +141,11 @@ const _parentFieldsFromSimpleOnCond = (element, subOn) => {
|
|
|
126
141
|
if (!childElement.on && parentRef && parentRef.length === 1) {
|
|
127
142
|
return _foreignKeyPropagationsFromToManyOn(element, parentRef, childFieldName)
|
|
128
143
|
}
|
|
144
|
+
|
|
129
145
|
if ('val' in subOn[idxParentField]) {
|
|
130
146
|
return _foreignKeyPropagationsFromStaticOn(childFieldName, idxParentField, subOn)
|
|
131
147
|
}
|
|
148
|
+
|
|
132
149
|
if (childElement._isAssociationStrict && childElement.on) {
|
|
133
150
|
return _foreignKeyPropagationsFromCustomBacklink(element, childElement)
|
|
134
151
|
}
|
|
@@ -144,6 +161,7 @@ const _foreignKeyPropagationsFromToManyOn = (element, parentRef, childFieldName)
|
|
|
144
161
|
const parentFieldName = parentRef[0]
|
|
145
162
|
if (parentFieldName === '$self') {
|
|
146
163
|
const foreignKeys = _foreignKeysForTarget(element, childFieldName)
|
|
164
|
+
|
|
147
165
|
// REVISIT foreignKeys is empty if we have deep operations where a sub element is annotated with persistence skip
|
|
148
166
|
if (foreignKeys && foreignKeys.length) {
|
|
149
167
|
const parentKeys = _parentKeys(element)
|
|
@@ -167,11 +185,13 @@ const _foreignKeyPropagationsFromToManyOn = (element, parentRef, childFieldName)
|
|
|
167
185
|
const _foreignKeyPropagationsFromCustomBacklink = (element, childElement) => {
|
|
168
186
|
const foreignKeyPropagations = []
|
|
169
187
|
const subOns = _getSubOns(childElement.on)
|
|
188
|
+
|
|
170
189
|
for (const subOn of subOns) {
|
|
171
190
|
if (subOn[1] === '=') {
|
|
172
191
|
const parentFieldIdx = subOn.findIndex(o => o.ref && o.ref[0] === childElement.name)
|
|
173
192
|
const otherFieldIdx = parentFieldIdx === 0 ? 2 : 0
|
|
174
193
|
const otherField = subOn[otherFieldIdx]
|
|
194
|
+
|
|
175
195
|
if (otherField.ref && otherField.ref.length === 1) {
|
|
176
196
|
const parentFieldName = subOn[parentFieldIdx].ref[1]
|
|
177
197
|
foreignKeyPropagations.push({
|
|
@@ -192,17 +212,19 @@ const _foreignKeyPropagationsFromCustomBacklink = (element, childElement) => {
|
|
|
192
212
|
}
|
|
193
213
|
}
|
|
194
214
|
}
|
|
215
|
+
|
|
195
216
|
return foreignKeyPropagations
|
|
196
217
|
}
|
|
197
218
|
|
|
198
219
|
const _foreignKeyPropagationsFromOn = (element, on) => {
|
|
199
220
|
const subOns = _getSubOns(on)
|
|
200
|
-
|
|
201
221
|
const foreignKeyPropagations = []
|
|
222
|
+
|
|
202
223
|
for (const subOn of subOns) {
|
|
203
224
|
const subParentFields = _parentFieldsFromSimpleOnCond(element, subOn)
|
|
204
225
|
if (subParentFields) foreignKeyPropagations.push(...subParentFields)
|
|
205
226
|
}
|
|
227
|
+
|
|
206
228
|
return foreignKeyPropagations
|
|
207
229
|
}
|
|
208
230
|
|
|
@@ -226,6 +248,7 @@ const _resolve4struct = (others, struct, fkps, fillChild, childIsStruct, i) => {
|
|
|
226
248
|
for (const k in struct.elements) {
|
|
227
249
|
const other = others[i + j]
|
|
228
250
|
const current = struct.elements[k]
|
|
251
|
+
|
|
229
252
|
if (current._isStructured) {
|
|
230
253
|
// call recursive and increment skip
|
|
231
254
|
j += _resolve4struct(others, current, fkps, fillChild, childIsStruct, i + j)
|
|
@@ -239,6 +262,7 @@ const _resolve4struct = (others, struct, fkps, fillChild, childIsStruct, i) => {
|
|
|
239
262
|
prefix = cur.name + '_' + prefix
|
|
240
263
|
cur = cur.parent
|
|
241
264
|
}
|
|
265
|
+
|
|
242
266
|
// push propagation
|
|
243
267
|
fkps.push({
|
|
244
268
|
childFieldName: childIsStruct ? current.name : other.name,
|
|
@@ -248,6 +272,7 @@ const _resolve4struct = (others, struct, fkps, fillChild, childIsStruct, i) => {
|
|
|
248
272
|
prefix,
|
|
249
273
|
deep: !fillChild && _resolveTargetForeignKey(childIsStruct ? current : other)
|
|
250
274
|
})
|
|
275
|
+
|
|
251
276
|
// increment skip
|
|
252
277
|
j++
|
|
253
278
|
}
|
|
@@ -259,8 +284,8 @@ const _resolve4struct = (others, struct, fkps, fillChild, childIsStruct, i) => {
|
|
|
259
284
|
const _resolveTargetForeignKey = targetKey => {
|
|
260
285
|
const targetName = targetKey['@odata.foreignKey4']
|
|
261
286
|
if (!targetName) return
|
|
262
|
-
const
|
|
263
|
-
const propagation =
|
|
287
|
+
const _foreignKeyProps = foreignKeyPropagations(targetKey.parent.elements[targetName])
|
|
288
|
+
const propagation = _foreignKeyProps.find(_fkp => targetKey.name === _fkp.parentFieldName)
|
|
264
289
|
return { targetName, propagation }
|
|
265
290
|
}
|
|
266
291
|
|
|
@@ -289,7 +314,7 @@ const resolvedKeys = (foreignKeys, targetKeys, fillChild) => {
|
|
|
289
314
|
return foreignKeyPropagations
|
|
290
315
|
}
|
|
291
316
|
|
|
292
|
-
const
|
|
317
|
+
const _foreignKeyPropagations = element => {
|
|
293
318
|
if (element.is2many && element.on) {
|
|
294
319
|
return _foreignKeyPropagationsFromOn(element, element.on)
|
|
295
320
|
}
|
|
@@ -297,6 +322,7 @@ const foreignKeyPropagations = element => {
|
|
|
297
322
|
if (element.is2one) {
|
|
298
323
|
if (!element.on) {
|
|
299
324
|
const foreignKeys = _foreignKeys(element)
|
|
325
|
+
|
|
300
326
|
if (foreignKeys) {
|
|
301
327
|
const targetKeys = _targetKeys(element)
|
|
302
328
|
return resolvedKeys(foreignKeys, targetKeys)
|
|
@@ -310,6 +336,12 @@ const foreignKeyPropagations = element => {
|
|
|
310
336
|
}
|
|
311
337
|
}
|
|
312
338
|
|
|
339
|
+
const foreignKeyPropagations = element => {
|
|
340
|
+
const foreignKeyProps = _foreignKeyPropagations(element)
|
|
341
|
+
if (foreignKeyProps) foreignKeyProps._element = element
|
|
342
|
+
return foreignKeyProps
|
|
343
|
+
}
|
|
344
|
+
|
|
313
345
|
const _foreignKeys = csnElement => {
|
|
314
346
|
return Object.values(csnElement.parent.elements).filter(element => element['@odata.foreignKey4'] === csnElement.name)
|
|
315
347
|
}
|
|
@@ -74,20 +74,19 @@ const _foreignToOn = (csnElement, options) => {
|
|
|
74
74
|
const foreignKeys = foreignKeyPropagations(csnElement)
|
|
75
75
|
|
|
76
76
|
// for external services, there might be no foreign keys
|
|
77
|
-
if (foreignKeys)
|
|
78
|
-
for (const key of foreignKeys) {
|
|
79
|
-
if (on.length !== 0) {
|
|
80
|
-
on.push('and')
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// TODO static values possible here?
|
|
77
|
+
if (!foreignKeys) return on
|
|
84
78
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
_toRef(aliases.join, _structPrefix(csnElement) + key.parentFieldName)
|
|
89
|
-
)
|
|
79
|
+
for (const key of foreignKeys) {
|
|
80
|
+
if (on.length !== 0) {
|
|
81
|
+
on.push('and')
|
|
90
82
|
}
|
|
83
|
+
|
|
84
|
+
// TODO static values possible here?
|
|
85
|
+
|
|
86
|
+
const ref1 = _toRef(aliases.select, key.prefix ? `${key.prefix}_${key.childFieldName}` : key.childFieldName)
|
|
87
|
+
const structPrefix = _structPrefix(csnElement)
|
|
88
|
+
const ref2 = _toRef(aliases.join, `${structPrefix}${key.parentFieldName}`)
|
|
89
|
+
on.push(ref1, '=', ref2)
|
|
91
90
|
}
|
|
92
91
|
|
|
93
92
|
return on
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
module.exports = req => {
|
|
2
|
+
// if custom handlers uses only expression like {col: {'+=': 1}},
|
|
3
|
+
// req.data will only contain the keys
|
|
4
|
+
if (req.query.UPDATE.with && Object.keys(req.query.UPDATE.with).length > 0) {
|
|
5
|
+
return false
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const keys = Object.keys(req.target.keys || {})
|
|
9
|
+
return !Object.keys(req.data).some(k => !keys.includes(k))
|
|
10
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const cds = require('../../cds')
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* returns path like <service>.<entity>:<prop1>.<prop2> for ref = [{ id: '<service>.<entity>' }, '<prop1>', '<prop2>']
|
|
5
|
+
*/
|
|
6
|
+
const getPathFromRef = ref => {
|
|
7
|
+
const x = ref.reduce((acc, cur) => {
|
|
8
|
+
acc += (acc ? ':' : '') + (cur.id ? cur.id : cur)
|
|
9
|
+
return acc
|
|
10
|
+
}, '')
|
|
11
|
+
const y = x.split(':')
|
|
12
|
+
let z = y.shift()
|
|
13
|
+
if (y.length) z += ':' + y.join('.')
|
|
14
|
+
return z
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/*
|
|
18
|
+
* returns the target entity for the given path
|
|
19
|
+
*/
|
|
20
|
+
const getEntityFromPath = (path, model) => {
|
|
21
|
+
let current = { elements: model.definitions }
|
|
22
|
+
path = typeof path === 'string' ? cds.parse.path(path) : path
|
|
23
|
+
const segments = [...path.ref]
|
|
24
|
+
while (segments.length) {
|
|
25
|
+
const segment = segments.shift()
|
|
26
|
+
current = current.elements[segment.id || segment]
|
|
27
|
+
if (current.target) current = model.definitions[current.target]
|
|
28
|
+
}
|
|
29
|
+
return current
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
module.exports = {
|
|
33
|
+
getPathFromRef,
|
|
34
|
+
getEntityFromPath
|
|
35
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
const { revertData } = require('./resolveView')
|
|
2
|
+
|
|
3
|
+
// creates a map with key "remote origin name" and value { as: "projection name"}
|
|
4
|
+
// if it is an expand, it contains an additional property .expand with classic ref/as syntax
|
|
5
|
+
// ref/as syntax is kept in order to reuse handleAliasInResult
|
|
6
|
+
const _createAliasMap = columns => {
|
|
7
|
+
if (columns) {
|
|
8
|
+
let aliasMap
|
|
9
|
+
for (const col of columns) {
|
|
10
|
+
const processor = {}
|
|
11
|
+
if (col.as) {
|
|
12
|
+
processor.as = col.as
|
|
13
|
+
aliasMap || (aliasMap = new Map())
|
|
14
|
+
if (col.ref) {
|
|
15
|
+
aliasMap.set(col.ref[col.ref.length - 1], processor)
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
if (col.expand) {
|
|
19
|
+
processor.expand = col.expand
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return aliasMap
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Transforms the result of the remote service according to the provided aliases
|
|
28
|
+
const handleAliasInResult = (columns, result) => {
|
|
29
|
+
const postProcessor = _createAliasMap(columns)
|
|
30
|
+
const resultArray = Array.isArray(result) ? result : [result]
|
|
31
|
+
if (postProcessor) {
|
|
32
|
+
for (const row of resultArray) {
|
|
33
|
+
// we need to use a cache because of cross renamings
|
|
34
|
+
// e. g. column a is renamed to b and column b is renamed to a
|
|
35
|
+
const tempCache = new Map()
|
|
36
|
+
|
|
37
|
+
for (const col in row) {
|
|
38
|
+
const processor = postProcessor.get(col)
|
|
39
|
+
if (processor && processor.as !== col) {
|
|
40
|
+
// if a value for the alias is already present, add it to the cache
|
|
41
|
+
if (row[processor.as]) {
|
|
42
|
+
tempCache.set(processor.as, row[processor.as])
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// get the value from cache if present
|
|
46
|
+
row[processor.as] = tempCache.get(col) || row[col]
|
|
47
|
+
|
|
48
|
+
// if it was not overridden because of a renaming,
|
|
49
|
+
// delete it from the row
|
|
50
|
+
if (!tempCache.has(processor.as)) {
|
|
51
|
+
delete row[col]
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (processor && processor.expand) {
|
|
56
|
+
handleAliasInResult(processor.expand, row[processor.as || col])
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// REVISIT: todo renaming for expanded entities
|
|
64
|
+
// REVISIT: todo renaming for deep operations
|
|
65
|
+
const postProcess = (query, result, onlySelectAliases = false) => {
|
|
66
|
+
if (query.SELECT) {
|
|
67
|
+
handleAliasInResult(query.SELECT.columns, result)
|
|
68
|
+
|
|
69
|
+
if (!onlySelectAliases) {
|
|
70
|
+
const transition =
|
|
71
|
+
query.SELECT && query.SELECT._transitions && query.SELECT._transitions[query.SELECT._transitions.length - 1]
|
|
72
|
+
if (transition) return revertData(result, transition)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return result
|
|
76
|
+
}
|
|
77
|
+
if (query.DELETE) return result
|
|
78
|
+
let transition
|
|
79
|
+
if (query.INSERT) transition = query.INSERT._transitions[query.INSERT._transitions.length - 1]
|
|
80
|
+
if (query.UPDATE) transition = query.UPDATE._transitions[query.UPDATE._transitions.length - 1]
|
|
81
|
+
return revertData(result, transition)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
module.exports = {
|
|
85
|
+
postProcess
|
|
86
|
+
}
|
|
@@ -1,39 +1,50 @@
|
|
|
1
1
|
const cds = require('../../cds')
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const keywords = require('@sap/cds-compiler/lib/base/keywords')
|
|
8
|
-
_COMPILER_RESERVED.hana = new Set(keywords.hana)
|
|
9
|
-
_COMPILER_RESERVED.sqlite = new Set(keywords.sqlite)
|
|
10
|
-
} catch (e) {
|
|
11
|
-
// ignore
|
|
12
|
-
}
|
|
3
|
+
const keywords = require('@sap/cds-compiler/lib/base/keywords')
|
|
4
|
+
const { smartId } = require('@sap/cds-compiler/lib/sql-identifier')
|
|
5
|
+
|
|
6
|
+
let _dialect
|
|
13
7
|
|
|
14
|
-
// fallback
|
|
15
8
|
const _DEFAULT_RESERVED = new Set(['WHERE', 'GROUP', 'ORDER', 'BY', 'AT', 'NO', 'LIMIT'])
|
|
16
|
-
|
|
9
|
+
const _COMPILER_RESERVED = {
|
|
10
|
+
hana: new Set(keywords.hana),
|
|
11
|
+
sqlite: new Set(keywords.sqlite)
|
|
12
|
+
}
|
|
13
|
+
let _reserved = _DEFAULT_RESERVED
|
|
17
14
|
|
|
18
|
-
|
|
19
|
-
const
|
|
15
|
+
const _isTruthy = s => s
|
|
16
|
+
const _isQuoted = s => s.match(/^".*"$/)
|
|
20
17
|
|
|
21
|
-
const _slugify =
|
|
18
|
+
const _slugify = s => s.replace(/\./g, '_')
|
|
19
|
+
const _smartId = s => smartId(_slugify(s), _dialect || 'plain')
|
|
20
|
+
const _smartElement = s => {
|
|
21
|
+
if (s === '*' || _isQuoted(s)) return s
|
|
22
|
+
const upper = s.toUpperCase()
|
|
23
|
+
if (_reserved.has(upper)) return upper
|
|
24
|
+
return _smartId(s)
|
|
25
|
+
}
|
|
22
26
|
|
|
23
27
|
module.exports = {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
+
plain: s => {
|
|
29
|
+
// set _dialect and _reserved once cds.db.kind is set
|
|
30
|
+
if (!_dialect && cds.db && cds.db.kind) {
|
|
31
|
+
_dialect = cds.db.options.dialect || cds.db.kind
|
|
32
|
+
_reserved = _COMPILER_RESERVED[_dialect] || _DEFAULT_RESERVED
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// * or already quoted?
|
|
36
|
+
if (s === '*' || _isQuoted(s)) return s
|
|
28
37
|
|
|
29
|
-
|
|
30
|
-
|
|
38
|
+
// expr or space in name?
|
|
39
|
+
// REVISIT: default behavior in cds^6?
|
|
40
|
+
if (s.match(/\s/) && !cds.env.sql.spaced_columns) {
|
|
41
|
+
return s.split(' ').filter(_isTruthy).map(_smartElement).join(' ')
|
|
31
42
|
}
|
|
32
43
|
|
|
33
|
-
|
|
34
|
-
return RESERVED.has(upper) ? `"${upper}"` : _slugify(name)
|
|
44
|
+
return _smartId(s)
|
|
35
45
|
},
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
46
|
+
quoted: s => `"${s}"`,
|
|
47
|
+
bracketed: s => `[${s}]`,
|
|
48
|
+
'all-upper': s => `"${_slugify(s.toUpperCase())}"`,
|
|
49
|
+
'all-lower': s => `"${_slugify(s.toLowerCase())}"`
|
|
39
50
|
}
|