@sap/cds 6.4.1 → 6.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 +79 -6
- package/README.md +5 -0
- package/apis/cqn.d.ts +14 -3
- package/apis/ql.d.ts +8 -8
- package/apis/services.d.ts +37 -65
- package/apis/test.d.ts +7 -0
- package/bin/build/buildTaskEngine.js +9 -14
- package/bin/build/buildTaskFactory.js +1 -1
- package/bin/build/buildTaskHandler.js +3 -14
- package/bin/build/index.js +8 -2
- package/bin/build/provider/buildTaskProviderInternal.js +18 -13
- package/bin/build/provider/fiori/index.js +5 -10
- package/bin/build/provider/hana/2migration.js +11 -2
- package/bin/build/provider/hana/index.js +17 -14
- package/bin/build/provider/hana/template/.hdiconfig-hanacloud +137 -0
- package/bin/build/provider/hana/template/package.json +3 -0
- package/bin/build/provider/mtx/resourcesTarBuilder.js +12 -3
- package/bin/build/provider/mtx-extension/index.js +57 -37
- package/bin/build/provider/mtx-sidecar/index.js +1 -1
- package/bin/build/util.js +18 -1
- package/bin/cds.js +1 -5
- package/bin/deploy/to-hana/hana.js +10 -3
- package/bin/serve.js +36 -20
- package/common.cds +7 -0
- package/lib/auth/jwt-auth.js +8 -7
- package/lib/compile/for/lean_drafts.js +55 -6
- package/lib/compile/minify.js +3 -3
- package/lib/dbs/cds-deploy.js +18 -17
- package/lib/env/cds-requires.js +1 -1
- package/lib/env/defaults.js +5 -1
- package/lib/env/schemas/cds-rc.json +74 -3
- package/lib/index.js +4 -2
- package/lib/lazy.js +6 -8
- package/lib/log/cds-error.js +2 -2
- package/lib/ql/Whereable.js +22 -11
- package/lib/ql/cds-ql.js +1 -1
- package/lib/req/cds-context.js +3 -3
- package/lib/req/response.js +8 -3
- package/lib/req/user.js +12 -2
- package/lib/srv/bindings.js +1 -2
- package/lib/srv/cds-serve.js +2 -1
- package/lib/srv/middlewares/trace.js +31 -15
- package/lib/srv/protocols/odata-v2-proxy.js +8 -8
- package/lib/srv/srv-handlers.js +26 -7
- package/lib/srv/srv-methods.js +2 -2
- package/lib/srv/srv-models.js +8 -3
- package/lib/utils/cds-test.js +7 -5
- package/lib/utils/cds-utils.js +3 -1
- package/lib/utils/tar.js +6 -3
- package/libx/_runtime/auth/strategies/JWT.js +1 -0
- package/libx/_runtime/auth/strategies/ias-auth.js +3 -2
- package/libx/_runtime/auth/strategies/mock.js +12 -1
- package/libx/_runtime/auth/strategies/xssecUtils.js +7 -8
- package/libx/_runtime/auth/strategies/xsuaa.js +1 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/OData.js +6 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/action.js +1 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +26 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +8 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/readToCQN.js +11 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/utils/PrimitiveValueDecoder.js +8 -8
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/utils/ValueConverter.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/validator/ValueValidator.js +14 -14
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/deserializer/DeserializerFactory.js +1 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/serializer/ResourceJsonSerializer.js +3 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/utils/UriHelper.js +2 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/metaInfo.js +3 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +7 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/stream.js +0 -3
- package/libx/_runtime/cds-services/services/Service.js +11 -19
- package/libx/_runtime/cds-services/services/utils/columns.js +42 -40
- package/libx/_runtime/cds-services/util/assert.js +7 -1
- package/libx/_runtime/common/code-ext/WorkerReq.js +81 -0
- package/libx/_runtime/common/code-ext/config.js +13 -0
- package/libx/_runtime/common/code-ext/execute.js +113 -0
- package/libx/_runtime/common/code-ext/handlers.js +49 -0
- package/libx/_runtime/common/code-ext/worker.js +40 -0
- package/libx/_runtime/common/code-ext/workerQuery.js +45 -0
- package/libx/_runtime/common/code-ext/workerQueryExecutor.js +36 -0
- package/libx/_runtime/common/composition/data.js +5 -2
- package/libx/_runtime/common/composition/tree.js +2 -0
- package/libx/_runtime/common/generic/auth/restrict.js +1 -1
- package/libx/_runtime/common/generic/crud.js +4 -0
- package/libx/_runtime/common/generic/etag.js +3 -1
- package/libx/_runtime/common/generic/input.js +12 -14
- package/libx/_runtime/common/i18n/index.js +1 -1
- package/libx/_runtime/common/utils/cqn2cqn4sql.js +47 -22
- package/libx/_runtime/common/utils/path.js +5 -26
- package/libx/_runtime/common/utils/search2cqn4sql.js +16 -9
- package/libx/_runtime/common/utils/templateProcessorPathSerializer.js +19 -13
- package/libx/_runtime/db/data-conversion/post-processing.js +1 -1
- package/libx/_runtime/db/expand/expandCQNToJoin.js +7 -4
- package/libx/_runtime/db/expand/rawToExpanded.js +3 -2
- package/libx/_runtime/db/generic/input.js +2 -2
- package/libx/_runtime/db/generic/integrity.js +1 -0
- package/libx/_runtime/db/generic/virtual.js +1 -0
- package/libx/_runtime/db/query/read.js +3 -2
- package/libx/_runtime/db/utils/localized.js +1 -1
- package/libx/_runtime/fiori/generic/activate.js +7 -1
- package/libx/_runtime/fiori/generic/before.js +9 -1
- package/libx/_runtime/fiori/generic/edit.js +8 -1
- package/libx/_runtime/fiori/generic/new.js +2 -0
- package/libx/_runtime/fiori/generic/patch.js +2 -0
- package/libx/_runtime/fiori/generic/prepare.js +2 -0
- package/libx/_runtime/fiori/generic/read.js +16 -5
- package/libx/_runtime/fiori/generic/readOverDraft.js +2 -0
- package/libx/_runtime/fiori/lean-draft.js +505 -241
- package/libx/_runtime/fiori/utils/delete.js +2 -0
- package/libx/_runtime/hana/customBuilder/CustomSelectBuilder.js +5 -5
- package/libx/_runtime/hana/pool.js +1 -1
- package/libx/_runtime/hana/search2cqn4sql.js +51 -51
- package/libx/_runtime/messaging/Outbox.js +1 -1
- package/libx/_runtime/messaging/enterprise-messaging-utils/getTenantInfo.js +1 -0
- package/libx/_runtime/messaging/enterprise-messaging.js +2 -6
- package/libx/_runtime/messaging/file-based.js +1 -2
- package/libx/_runtime/messaging/outbox/OutboxRunner.js +1 -1
- package/libx/_runtime/messaging/outbox/utils.js +1 -1
- package/libx/_runtime/messaging/service.js +0 -1
- package/libx/_runtime/remote/Service.js +1 -0
- package/libx/_runtime/sqlite/convertDraftAdminPathExpression.js +19 -3
- package/libx/_runtime/sqlite/customBuilder/CustomExpressionBuilder.js +0 -18
- package/libx/_runtime/sqlite/customBuilder/CustomFunctionBuilder.js +0 -18
- package/libx/_runtime/sqlite/customBuilder/CustomSelectBuilder.js +0 -24
- package/libx/_runtime/sqlite/customBuilder/CustomUpsertBuilder.js +2 -1
- package/libx/_runtime/sqlite/customBuilder/index.js +47 -32
- package/libx/odata/afterburner.js +23 -8
- package/libx/odata/cqn2odata.js +1 -1
- package/libx/odata/grammar.pegjs +3 -4
- package/libx/odata/index.js +5 -1
- package/libx/odata/parseToCqn.js +3 -3
- package/libx/odata/parser.js +1 -1
- package/libx/odata/utils.js +58 -1
- package/libx/rest/middleware/parse.js +26 -4
- package/package.json +1 -1
- package/server.js +1 -1
- package/libx/_runtime/sqlite/customBuilder/CustomDeleteBuilder.js +0 -17
- package/libx/_runtime/sqlite/customBuilder/CustomReferenceBuilder.js +0 -11
- package/libx/_runtime/sqlite/customBuilder/CustomUpdateBuilder.js +0 -17
- /package/bin/build/provider/hana/template/{.hdiconfig → .hdiconfig-haas} +0 -0
|
@@ -112,9 +112,11 @@ const fioriGenericActivate = async function (req) {
|
|
|
112
112
|
req.query.SELECT.from.ref.length > 2 ||
|
|
113
113
|
!isDraftRootEntity(this.model.definitions, ensureNoDraftsSuffix(req.target.name))
|
|
114
114
|
) {
|
|
115
|
-
req.reject(400)
|
|
115
|
+
req.reject(400, 'Action "draftActivate" can only be called on the root draft entity')
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
+
if (!cds.db) req.reject('NO_DATABASE_CONNECTION')
|
|
119
|
+
|
|
118
120
|
const { draftData, activeData, adminData } = await _draftCompositionTree(this, req)
|
|
119
121
|
|
|
120
122
|
if (!draftData) req.reject(404)
|
|
@@ -174,6 +176,10 @@ const fioriGenericActivate = async function (req) {
|
|
|
174
176
|
})
|
|
175
177
|
])
|
|
176
178
|
|
|
179
|
+
// REVISIT: we need to use okra API here because it must be set in the batched request
|
|
180
|
+
// status code must be set in handler to allow overriding for FE V2
|
|
181
|
+
req?._?.odataRes.setStatusCode(201)
|
|
182
|
+
|
|
177
183
|
return result
|
|
178
184
|
}
|
|
179
185
|
|
|
@@ -78,6 +78,7 @@ const _getRoot = req => {
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
const _getDraftDataFromExistingDraft = async (req, root, isBoundAction) => {
|
|
81
|
+
if (!cds.db) req.reject('NO_DATABASE_CONNECTION')
|
|
81
82
|
if (!root) return []
|
|
82
83
|
if (root?.IsActiveEntity === false) {
|
|
83
84
|
const query = _getSelectDraftDataCqn(root.entityName, root.where)
|
|
@@ -155,6 +156,13 @@ const _validateDraftBoundAction = async function (req) {
|
|
|
155
156
|
if (result && result.length > 0) _validateDraft(req, result, isBoundAction)
|
|
156
157
|
}
|
|
157
158
|
|
|
159
|
+
const _allowEntityCollectionOnAction = action => {
|
|
160
|
+
return (
|
|
161
|
+
action['@cds.odata.bindingparameter.collection'] ||
|
|
162
|
+
(action.params && Object.values(action.params).some(e => e?.items?.type === '$self'))
|
|
163
|
+
)
|
|
164
|
+
}
|
|
165
|
+
|
|
158
166
|
const _registerBoundActionHandlers = function (entityName, actions) {
|
|
159
167
|
if (!actions) return
|
|
160
168
|
|
|
@@ -164,7 +172,7 @@ const _registerBoundActionHandlers = function (entityName, actions) {
|
|
|
164
172
|
action.name !== 'draftPrepare' &&
|
|
165
173
|
action.name !== 'draftEdit' &&
|
|
166
174
|
action.name !== 'draftActivate' &&
|
|
167
|
-
!action
|
|
175
|
+
!_allowEntityCollectionOnAction(action)
|
|
168
176
|
)
|
|
169
177
|
|
|
170
178
|
for (const action of boundActions) {
|
|
@@ -70,9 +70,11 @@ const _select = async (lockRecordCQN, draftExistsCQN, selectCQNs, req, dbtx) =>
|
|
|
70
70
|
*/
|
|
71
71
|
const fioriGenericEdit = async function (req) {
|
|
72
72
|
if (!isActiveEntityRequested(req.query.SELECT.where || [])) {
|
|
73
|
-
req.reject(400)
|
|
73
|
+
req.reject(400, 'Action "draftEdit" can only be called on the active entity')
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
if (!cds.db) req.reject('NO_DATABASE_CONNECTION')
|
|
77
|
+
|
|
76
78
|
const { definitions } = this.model
|
|
77
79
|
|
|
78
80
|
// TODO replace with generic where filter
|
|
@@ -156,6 +158,11 @@ const fioriGenericEdit = async function (req) {
|
|
|
156
158
|
}
|
|
157
159
|
|
|
158
160
|
await Promise.all(insertCQNs.map(CQN => dbtx.run(CQN)))
|
|
161
|
+
|
|
162
|
+
// REVISIT: we need to use okra API here because it must be set in the batched request
|
|
163
|
+
// status code must be set in handler to allow overriding for FE V2
|
|
164
|
+
req?._?.odataRes.setStatusCode(201)
|
|
165
|
+
|
|
159
166
|
return results[0][0]
|
|
160
167
|
}
|
|
161
168
|
|
|
@@ -61,6 +61,8 @@ const _joinDraftAdministrativeData = (selectResolved, target) => {
|
|
|
61
61
|
const fioriGenericPatch = async function (req) {
|
|
62
62
|
if (req.data.IsActiveEntity === true) req.reject(400, 'Patch can only be applied to a draft entity')
|
|
63
63
|
|
|
64
|
+
if (!cds.db) req.reject('NO_DATABASE_CONNECTION')
|
|
65
|
+
|
|
64
66
|
const dbtx = cds.tx(req)
|
|
65
67
|
|
|
66
68
|
const selectResolved = cqn2cqn4sql(_getSelectCQN(req), this.model)
|
|
@@ -16,6 +16,8 @@ const fioriGenericPrepare = async function (req) {
|
|
|
16
16
|
req.reject(400, 'Action "draftPrepare" can only be called on a draft entity')
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
if (!cds.db) req.reject('NO_DATABASE_CONNECTION')
|
|
20
|
+
|
|
19
21
|
const target = ensureDraftsSuffix(req.target.name)
|
|
20
22
|
const columns = getColumns(this.model.definitions[ensureNoDraftsSuffix(req.target.name)], {
|
|
21
23
|
keysOnly: true,
|
|
@@ -18,6 +18,7 @@ const {
|
|
|
18
18
|
} = require('../utils/handler')
|
|
19
19
|
const { deleteCondition, readAndDeleteKeywords, removeIsActiveEntityRecursively } = require('../utils/where')
|
|
20
20
|
const { adaptStreamCQN } = require('../../cds-services/adapter/odata-v4/utils/stream')
|
|
21
|
+
const getError = require('../../common/error')
|
|
21
22
|
|
|
22
23
|
const _findSubselect = where => {
|
|
23
24
|
return where.find((e, i) => {
|
|
@@ -37,15 +38,16 @@ const _findRootSubSelectFor = query => {
|
|
|
37
38
|
|
|
38
39
|
// append where with clauses from @restrict
|
|
39
40
|
const _getWhereWithAppendedDraftRestrictions = (where = [], req) => {
|
|
41
|
+
const restrictions = []
|
|
40
42
|
if (req.query._draftRestrictions) {
|
|
41
43
|
for (const each of req.query._draftRestrictions) {
|
|
42
44
|
const xpr = each._xpr
|
|
43
45
|
if (each.target.name === ensureUnlocalized(req.target.name)) {
|
|
44
|
-
if (where.length) where.push('and')
|
|
45
46
|
// restriction might contain or clause -> use xpr for grouping
|
|
46
|
-
|
|
47
|
+
if (restrictions.length) restrictions.push('or')
|
|
48
|
+
xpr.includes('or') ? restrictions.push({ xpr }) : restrictions.push(...xpr)
|
|
47
49
|
} else {
|
|
48
|
-
//
|
|
50
|
+
// restriction inherited from parent via autoexposure
|
|
49
51
|
// find inner most sub select if available and append restriction to where clause
|
|
50
52
|
const rootSubSelect = _findRootSubSelectFor({ SELECT: { where } })
|
|
51
53
|
if (rootSubSelect && rootSubSelect.SELECT.from) {
|
|
@@ -62,6 +64,10 @@ const _getWhereWithAppendedDraftRestrictions = (where = [], req) => {
|
|
|
62
64
|
}
|
|
63
65
|
}
|
|
64
66
|
|
|
67
|
+
if (restrictions.length) {
|
|
68
|
+
if (where.length) where.push('and', { xpr: restrictions })
|
|
69
|
+
else where.push(...restrictions)
|
|
70
|
+
}
|
|
65
71
|
return where
|
|
66
72
|
}
|
|
67
73
|
|
|
@@ -1177,7 +1183,7 @@ const _getOriginalColumns = req => {
|
|
|
1177
1183
|
const originalColumns = {}
|
|
1178
1184
|
// expanded columns are handled generically in db
|
|
1179
1185
|
for (const c of req.query.SELECT.columns) {
|
|
1180
|
-
originalColumns[c.ref
|
|
1186
|
+
originalColumns[c.as || (c.ref && c.ref[c.ref.length - 1]) || c] = true
|
|
1181
1187
|
}
|
|
1182
1188
|
|
|
1183
1189
|
return originalColumns
|
|
@@ -1221,6 +1227,9 @@ const _postProcess = (result, req, cqnScenario, deleteLastChangeDateTime) => {
|
|
|
1221
1227
|
}
|
|
1222
1228
|
}
|
|
1223
1229
|
|
|
1230
|
+
if (result.HasActiveEntity === null) result.HasActiveEntity = false
|
|
1231
|
+
if (result.HasDraftEntity === null) result.HasDraftEntity = false
|
|
1232
|
+
if (result.IsActiveEntity === null) result.IsActiveEntity = false
|
|
1224
1233
|
return result
|
|
1225
1234
|
}
|
|
1226
1235
|
|
|
@@ -1261,6 +1270,8 @@ const _adaptColumns4readAfterWrite = (req, cqnScenario, query4sql) => {
|
|
|
1261
1270
|
* @param req
|
|
1262
1271
|
*/
|
|
1263
1272
|
const fioriGenericRead = async function (req) {
|
|
1273
|
+
if (!cds.db) req.reject('NO_DATABASE_CONNECTION')
|
|
1274
|
+
|
|
1264
1275
|
const query = req.query
|
|
1265
1276
|
const originalFrom = _copyCQNPartial(query.SELECT.from)
|
|
1266
1277
|
|
|
@@ -1293,7 +1304,7 @@ const fioriGenericRead = async function (req) {
|
|
|
1293
1304
|
cqnScenario = _generateCQN(reqClone, nonDraftColumns, originalFrom, this.model)
|
|
1294
1305
|
}
|
|
1295
1306
|
|
|
1296
|
-
if (!cqnScenario)
|
|
1307
|
+
if (!cqnScenario) throw getError(501)
|
|
1297
1308
|
|
|
1298
1309
|
// ensure base columns for calculation are selected in draft admin expand
|
|
1299
1310
|
_adaptDraftAdminExpand(cqnScenario.cqn)
|
|
@@ -109,6 +109,8 @@ const _shouldReadOverDraft = (req, definitions) => {
|
|
|
109
109
|
* @returns {Promise<Array>}
|
|
110
110
|
*/
|
|
111
111
|
const _readOverDraftHandler = async function (req, next) {
|
|
112
|
+
if (!cds.db) req.reject('NO_DATABASE_CONNECTION')
|
|
113
|
+
|
|
112
114
|
const definitions = this.model.definitions
|
|
113
115
|
|
|
114
116
|
// determine whether the request is handled here (read over draft handler),
|