@sap/cds 7.9.3 → 8.0.3
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 +126 -3655
- package/_i18n/i18n_en_US_saptrc.properties +113 -0
- package/_i18n/i18n_zh_CN.properties +7 -4
- package/app/index.css +129 -0
- package/app/index.html +16 -64
- package/app/index.js +14 -9
- package/bin/args.js +34 -0
- package/bin/serve.js +18 -24
- package/bin/test.js +97 -0
- package/common.cds +5 -12
- package/eslint.config.mjs +133 -0
- package/lib/auth/basic-auth.js +16 -20
- package/lib/auth/dummy-auth.js +1 -1
- package/lib/auth/ias-auth.js +9 -41
- package/lib/auth/index.js +1 -14
- package/lib/auth/jwt-auth.js +10 -40
- package/lib/compile/cds-compile.js +1 -2
- package/lib/compile/cdsc.js +21 -26
- package/lib/compile/etc/_localized.js +1 -6
- package/lib/compile/etc/csv.js +1 -1
- package/lib/compile/etc/properties.js +1 -1
- package/lib/compile/for/java.js +1 -1
- package/lib/compile/for/lean_drafts.js +4 -6
- package/lib/compile/for/nodejs.js +1 -1
- package/lib/compile/parse.js +4 -0
- package/lib/compile/resolve.js +4 -4
- package/lib/compile/to/edm-files.js +16 -23
- package/lib/compile/to/hana.js +27 -0
- package/lib/compile/to/json.js +1 -1
- package/lib/compile/to/sql.js +5 -1
- package/lib/compile/to/yaml.js +3 -3
- package/lib/dbs/cds-deploy.js +4 -2
- package/lib/env/cds-env.js +10 -14
- package/lib/env/cds-requires.js +29 -13
- package/lib/env/defaults.js +46 -16
- package/lib/env/plugins.js +1 -1
- package/lib/env/schemas/cds-rc.js +8 -4
- package/lib/env/schemas/index.js +7 -7
- package/lib/env/serviceBindings.js +1 -1
- package/lib/index.js +12 -10
- package/lib/lazy.js +1 -1
- package/lib/linked/classes.js +36 -8
- package/lib/linked/entities.js +2 -10
- package/lib/linked/models.js +2 -1
- package/lib/linked/validate.js +292 -0
- package/lib/log/cds-error.js +0 -6
- package/lib/log/cds-log.js +3 -3
- package/lib/log/format/json.js +1 -1
- package/lib/log/service/index.js +0 -1
- package/lib/plugins.js +2 -2
- package/lib/ql/Query.js +2 -10
- package/lib/ql/SELECT.js +1 -1
- package/lib/ql/Whereable.js +3 -2
- package/lib/req/cds-context.js +14 -25
- package/lib/req/context.js +23 -25
- package/lib/req/request.js +1 -34
- package/lib/req/user.js +47 -35
- package/lib/srv/bindings.js +1 -1
- package/lib/srv/cds-connect.js +4 -4
- package/lib/srv/cds-serve.js +2 -2
- package/lib/srv/factory.js +1 -1
- package/lib/srv/middlewares/cds-context.js +11 -22
- package/lib/srv/middlewares/ctx-model.js +2 -3
- package/lib/srv/middlewares/errors.js +41 -8
- package/lib/srv/middlewares/index.js +3 -3
- package/lib/srv/middlewares/trace.js +0 -2
- package/lib/srv/protocols/hcql.js +15 -10
- package/lib/srv/protocols/http.js +44 -49
- package/lib/srv/protocols/index.js +1 -23
- package/lib/srv/protocols/odata-v4.js +12 -74
- package/lib/srv/protocols/rest.js +1 -13
- package/lib/srv/srv-api.js +0 -20
- package/lib/srv/srv-dispatch.js +3 -2
- package/lib/srv/srv-handlers.js +22 -11
- package/lib/srv/srv-methods.js +2 -2
- package/lib/srv/srv-models.js +3 -36
- package/lib/test/expect.js +343 -0
- package/lib/test/index.js +2 -0
- package/lib/test/reporter.js +176 -0
- package/lib/utils/axios.js +10 -9
- package/lib/utils/cds-test.js +85 -36
- package/lib/utils/cds-utils.js +54 -7
- package/lib/utils/check-version.js +0 -4
- package/lib/utils/colors.js +49 -0
- package/lib/utils/data.js +5 -4
- package/libx/_runtime/cds-services/adapter/odata-v4/OData.js +2 -7
- package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +3 -30
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/error.js +6 -12
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +1 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +0 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +4 -7
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +12 -6
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +2 -4
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/applyToCQN.js +1 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/expandToCQN.js +1 -1
- 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/readToCQN.js +1 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/utils.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/edm/AbstractEdmStructuredType.js +1 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/deserializer/ResourceJsonDeserializer.js +5 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/serializer/ContextURLFactory.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +9 -43
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/metaInfo.js +0 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +8 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/request.js +4 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +1 -3
- package/libx/_runtime/cds-services/util/assert.js +1 -1
- package/libx/_runtime/cds.js +10 -3
- package/libx/_runtime/common/Service.js +12 -32
- package/libx/_runtime/common/aspects/any.js +1 -0
- package/libx/_runtime/common/code-ext/execute.js +1 -1
- package/libx/_runtime/common/code-ext/worker.js +0 -1
- package/libx/_runtime/common/composition/data.js +0 -1
- package/libx/_runtime/common/composition/delete.js +0 -1
- package/libx/_runtime/common/composition/insert.js +2 -2
- package/libx/_runtime/common/composition/tree.js +0 -1
- package/libx/_runtime/common/composition/update.js +3 -3
- package/libx/_runtime/common/error/frontend.js +21 -12
- package/libx/_runtime/common/error/log.js +36 -0
- package/libx/_runtime/common/error/utils.js +2 -5
- package/libx/_runtime/common/generic/auth/autoexpose.js +18 -17
- package/libx/_runtime/common/generic/auth/expand.js +1 -1
- package/libx/_runtime/common/generic/auth/readOnly.js +1 -2
- package/libx/_runtime/common/generic/auth/restrict.js +23 -42
- package/libx/_runtime/common/generic/auth/restrictions.js +2 -7
- package/libx/_runtime/common/generic/auth/utils.js +91 -88
- package/libx/_runtime/common/generic/crud.js +6 -5
- package/libx/_runtime/common/generic/etag.js +7 -12
- package/libx/_runtime/common/generic/input.js +70 -68
- package/libx/_runtime/common/generic/paging.js +1 -0
- package/libx/_runtime/common/generic/sorting.js +1 -0
- package/libx/_runtime/common/generic/temporal.js +8 -2
- package/libx/_runtime/common/i18n/index.js +1 -1
- package/libx/_runtime/common/i18n/messages.properties +3 -1
- package/libx/_runtime/common/utils/binary.js +8 -2
- package/libx/_runtime/common/utils/compareJson.js +5 -1
- package/libx/_runtime/common/utils/copy.js +6 -11
- package/libx/_runtime/common/utils/cqn2cqn4sql.js +16 -14
- package/libx/_runtime/common/utils/differ.js +3 -6
- package/libx/_runtime/common/utils/keys.js +77 -18
- package/libx/_runtime/common/utils/postProcess.js +12 -15
- package/libx/_runtime/common/utils/propagateForeignKeys.js +0 -1
- package/libx/_runtime/common/utils/resolveView.js +2 -3
- package/libx/_runtime/common/utils/restrictions.js +45 -17
- package/libx/_runtime/common/utils/rewriteAsterisks.js +1 -8
- package/libx/_runtime/common/utils/stream.js +3 -16
- package/libx/_runtime/common/utils/streamProp.js +8 -18
- package/libx/_runtime/common/utils/structured.js +1 -1
- package/libx/_runtime/common/utils/ucsn.js +0 -2
- package/libx/_runtime/db/Service.js +0 -72
- package/libx/_runtime/db/data-conversion/post-processing.js +0 -1
- package/libx/_runtime/db/expand/expandCQNToJoin.js +9 -9
- package/libx/_runtime/db/expand/rawToExpanded.js +0 -8
- package/libx/_runtime/db/generic/input.js +3 -8
- package/libx/_runtime/db/generic/rewrite.js +1 -0
- package/libx/_runtime/db/query/read.js +2 -2
- package/libx/_runtime/db/sql-builder/ExpressionBuilder.js +0 -1
- package/libx/_runtime/db/sql-builder/InsertBuilder.js +1 -1
- package/libx/_runtime/db/utils/columns.js +2 -6
- package/libx/_runtime/fiori/lean-draft.js +138 -56
- package/libx/_runtime/hana/Service.js +0 -1
- package/libx/_runtime/hana/driver.js +1 -1
- package/libx/_runtime/hana/dynatrace.js +1 -2
- package/libx/_runtime/hana/pool.js +11 -21
- package/libx/_runtime/hana/streaming.js +0 -1
- package/libx/_runtime/messaging/common-utils/AMQPClient.js +0 -1
- package/libx/_runtime/messaging/common-utils/authorizedRequest.js +1 -1
- package/libx/_runtime/messaging/common-utils/normalizeIncomingMessage.js +1 -1
- package/libx/_runtime/messaging/enterprise-messaging-utils/getTenantInfo.js +1 -1
- package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +19 -33
- package/libx/_runtime/messaging/event-broker.js +0 -12
- package/libx/_runtime/messaging/file-based.js +3 -3
- package/libx/_runtime/messaging/http-utils/token.js +1 -1
- package/libx/_runtime/messaging/kafka.js +2 -2
- package/libx/_runtime/messaging/redis-messaging.js +0 -1
- package/libx/_runtime/remote/Service.js +25 -25
- package/libx/_runtime/remote/utils/client.js +4 -5
- package/libx/_runtime/remote/utils/cloudSdkProvider.js +0 -3
- package/libx/_runtime/remote/utils/data.js +0 -1
- package/libx/_runtime/sqlite/Service.js +1 -2
- package/libx/_runtime/ucl/Service.js +37 -78
- package/libx/common/assert/index.js +22 -21
- package/libx/common/assert/type-relaxed.js +39 -0
- package/libx/common/assert/utils.js +3 -2
- package/libx/common/assert/validation.js +3 -8
- package/libx/common/utils/index.js +5 -0
- package/libx/common/utils/path.js +51 -0
- package/libx/odata/ODataAdapter.js +126 -0
- package/libx/odata/index.js +15 -2
- package/libx/odata/middleware/batch.js +261 -72
- package/libx/odata/middleware/body-parser.js +33 -0
- package/libx/odata/middleware/create.js +44 -59
- package/libx/odata/middleware/delete.js +23 -12
- package/libx/odata/middleware/error.js +30 -6
- package/libx/odata/middleware/metadata.js +38 -26
- package/libx/odata/middleware/operation.js +93 -69
- package/libx/odata/middleware/parse.js +6 -8
- package/libx/odata/middleware/read.js +117 -93
- package/libx/odata/middleware/service-document.js +22 -19
- package/libx/odata/middleware/stream.js +54 -56
- package/libx/odata/middleware/update.js +79 -87
- package/libx/odata/parse/afterburner.js +191 -175
- package/libx/odata/parse/cqn2odata.js +8 -8
- package/libx/odata/parse/grammar.peggy +27 -20
- package/libx/odata/parse/multipartToJson.js +17 -9
- package/libx/odata/parse/parser.js +1 -1
- package/libx/odata/utils/etag.js +14 -6
- package/libx/odata/utils/index.js +84 -12
- package/libx/odata/utils/metadata.js +161 -0
- package/libx/odata/utils/postProcess.js +89 -0
- package/libx/odata/utils/readAfterWrite.js +134 -17
- package/libx/odata/utils/result.js +36 -142
- package/libx/outbox/index.js +4 -3
- package/libx/rest/RestAdapter.js +115 -182
- package/libx/rest/middleware/create.js +28 -24
- package/libx/rest/middleware/delete.js +7 -10
- package/libx/rest/middleware/error.js +19 -16
- package/libx/rest/middleware/operation.js +48 -41
- package/libx/rest/middleware/parse.js +128 -126
- package/libx/rest/middleware/read.js +20 -27
- package/libx/rest/middleware/update.js +26 -31
- package/package.json +17 -8
- package/server.js +4 -2
- package/tasks/enterprise-messaging-deploy.js +1 -1
- package/apis/cds.d.ts +0 -3
- package/apis/core.d.ts +0 -21
- package/apis/cqn.d.ts +0 -18
- package/apis/csn.d.ts +0 -21
- package/apis/events.d.ts +0 -18
- package/apis/internal/inference.d.ts +0 -18
- package/apis/linked.d.ts +0 -18
- package/apis/log.d.ts +0 -20
- package/apis/models.d.ts +0 -18
- package/apis/ql.d.ts +0 -18
- package/apis/reflect.d.ts +0 -32
- package/apis/server.d.ts +0 -18
- package/apis/services.d.ts +0 -22
- package/bin/cds-serve.js +0 -56
- package/lib/compile/to/gql.js +0 -15
- package/lib/srv/protocols/_legacy.js +0 -44
- package/lib/utils/jest.js +0 -43
- package/libx/_runtime/auth/index.js +0 -193
- package/libx/_runtime/auth/strategies/JWT.js +0 -37
- package/libx/_runtime/auth/strategies/basic.js +0 -20
- package/libx/_runtime/auth/strategies/dummy.js +0 -14
- package/libx/_runtime/auth/strategies/ias-auth.js +0 -1
- package/libx/_runtime/auth/strategies/mock.js +0 -77
- package/libx/_runtime/auth/strategies/xssecUtils.js +0 -93
- package/libx/_runtime/auth/strategies/xsuaa.js +0 -38
- package/libx/_runtime/common/perf/index.js +0 -19
- package/libx/_runtime/common/utils/ensureIEEE754.js +0 -29
- package/libx/_runtime/fiori/draft.js +0 -2
- package/libx/_runtime/fiori/generic/activate.js +0 -190
- package/libx/_runtime/fiori/generic/before.js +0 -201
- package/libx/_runtime/fiori/generic/cancel.js +0 -19
- package/libx/_runtime/fiori/generic/delete.js +0 -21
- package/libx/_runtime/fiori/generic/edit.js +0 -157
- package/libx/_runtime/fiori/generic/index.js +0 -25
- package/libx/_runtime/fiori/generic/new.js +0 -82
- package/libx/_runtime/fiori/generic/patch.js +0 -101
- package/libx/_runtime/fiori/generic/prepare.js +0 -57
- package/libx/_runtime/fiori/generic/read.js +0 -1340
- package/libx/_runtime/fiori/generic/readOverDraft.js +0 -146
- package/libx/_runtime/fiori/utils/csn.js +0 -13
- package/libx/_runtime/fiori/utils/delete.js +0 -114
- package/libx/_runtime/fiori/utils/handler.js +0 -264
- package/libx/_runtime/fiori/utils/lockInfo.js +0 -27
- package/libx/_runtime/fiori/utils/req.js +0 -23
- package/libx/_runtime/fiori/utils/stream.js +0 -36
- package/libx/_runtime/fiori/utils/where.js +0 -254
- package/libx/_runtime/index.js +0 -22
- package/libx/odata/utils/handler.js +0 -120
- package/libx/odata/utils/metaInfo.js +0 -410
- package/libx/odata/utils/path.js +0 -75
- package/libx/rest/RestRequest.js +0 -32
- package/libx/rest/index.js +0 -3
- package/libx/rest/readme.md +0 -1
- /package/libx/common/assert/{type.js → type-strict.js} +0 -0
|
@@ -1,48 +1,58 @@
|
|
|
1
1
|
const cds = require('../../../')
|
|
2
2
|
const { UPDATE } = cds.ql
|
|
3
3
|
|
|
4
|
-
const {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
const {
|
|
5
|
+
calculateLocationHeader,
|
|
6
|
+
handleSapMessages,
|
|
7
|
+
getPreferReturnHeader,
|
|
8
|
+
extractIfNoneMatch,
|
|
9
|
+
isStream
|
|
10
|
+
} = require('../utils')
|
|
11
|
+
const getODataMetadata = require('../utils/metadata')
|
|
12
|
+
const postProcess = require('../utils/postProcess')
|
|
13
|
+
const readAfterWrite4 = require('../utils/readAfterWrite')
|
|
14
|
+
const getODataResult = require('../utils/result')
|
|
15
|
+
|
|
16
|
+
const { getKeysAndParamsFromPath } = require('../../common/utils')
|
|
10
17
|
|
|
11
18
|
const _isUpsertAllowed = ({ target, data, event }) => {
|
|
12
19
|
return (
|
|
13
20
|
!(cds.env.runtime && cds.env.runtime.allow_upsert === false) &&
|
|
14
|
-
!(target && target._isDraftEnabled &&
|
|
21
|
+
!(target && target._isDraftEnabled && !data.IsActiveEntity && event === 'PATCH')
|
|
15
22
|
)
|
|
16
23
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const nav = pathExpression.ref && pathExpression.ref.length !== 0 && pathExpression.ref[1]
|
|
25
|
-
const parent = pathExpression.ref && pathExpression.ref[0].id
|
|
24
|
+
// Not supported:
|
|
25
|
+
// 1) If some parent entity needs to be updated, reason: we only generate one CQN statement for the target.
|
|
26
|
+
// 2) If the foreign key is not known, i.e. when having no key information of the immediate parent, e.g. /Root(1)/foo/bar
|
|
27
|
+
const upsertSupported = (pathExpression, model) => {
|
|
28
|
+
const pathExpressionRef = pathExpression?.ref
|
|
26
29
|
|
|
27
30
|
// not a navigation
|
|
28
|
-
if (
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
if (pathExpressionRef.length < 2) return true
|
|
32
|
+
|
|
33
|
+
// foreign key is not known
|
|
34
|
+
if (!pathExpressionRef[pathExpressionRef.length - 2].where) return false
|
|
31
35
|
|
|
32
|
-
|
|
33
|
-
|
|
36
|
+
let currentEntity = model.definitions[pathExpressionRef[0].id]
|
|
37
|
+
let navElement
|
|
34
38
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
39
|
+
for (let i = 1; i < pathExpressionRef.length; i++) {
|
|
40
|
+
const id = typeof pathExpressionRef[i] === 'string' ? pathExpressionRef[i] : pathExpressionRef[i].id
|
|
41
|
+
navElement = currentEntity.elements[id]
|
|
42
|
+
currentEntity = navElement._target
|
|
38
43
|
}
|
|
39
44
|
|
|
40
|
-
|
|
41
|
-
|
|
45
|
+
// disallow processing of requests along associations to one and containments
|
|
46
|
+
if (!navElement.is2one || navElement._isContained) return true
|
|
47
|
+
|
|
48
|
+
return navElement._foreignKeys.every(foreignKey => foreignKey.parentElement.key)
|
|
42
49
|
}
|
|
43
50
|
|
|
44
|
-
module.exports =
|
|
45
|
-
|
|
51
|
+
module.exports = adapter => {
|
|
52
|
+
const { service } = adapter
|
|
53
|
+
const _readAfterWrite = readAfterWrite4(adapter, 'update')
|
|
54
|
+
|
|
55
|
+
return function update(req, res, next) {
|
|
46
56
|
// REVISIT: better solution for _propertyAccess
|
|
47
57
|
const {
|
|
48
58
|
SELECT: { one, from },
|
|
@@ -60,23 +70,12 @@ module.exports = (srv, router) =>
|
|
|
60
70
|
}
|
|
61
71
|
|
|
62
72
|
// payload & params
|
|
63
|
-
|
|
64
|
-
const { keys, params } = getKeysAndParamsFromPath(from,
|
|
73
|
+
const data = _propertyAccess ? { [_propertyAccess]: req.body.value } : req.body
|
|
74
|
+
const { keys, params } = getKeysAndParamsFromPath(from, service)
|
|
65
75
|
// add keys from url into payload (overwriting if already present)
|
|
66
76
|
if (!_propertyAccess) Object.assign(data, keys)
|
|
67
77
|
|
|
68
|
-
|
|
69
|
-
if (!_propertyAccess) {
|
|
70
|
-
// assert complex
|
|
71
|
-
const assertOptions = { filter: true, http: { req }, mandatories: req.method === 'PUT' || undefined }
|
|
72
|
-
const errs = cds.assert(data, target, assertOptions)
|
|
73
|
-
if (errs) {
|
|
74
|
-
if (errs.length === 1) throw errs[0]
|
|
75
|
-
throw Object.assign(new Error('MULTIPLE_ERRORS'), { statusCode: 400, details: errs })
|
|
76
|
-
}
|
|
77
|
-
} else {
|
|
78
|
-
// TODO: assert primitive
|
|
79
|
-
}
|
|
78
|
+
const _isDraft = target.drafts && data.IsActiveEntity !== true
|
|
80
79
|
|
|
81
80
|
// query
|
|
82
81
|
let query = UPDATE.entity(from).with(data)
|
|
@@ -85,78 +84,71 @@ module.exports = (srv, router) =>
|
|
|
85
84
|
const headers = { ...cds.context.http.req.headers, ...req.headers }
|
|
86
85
|
|
|
87
86
|
// we need a cds.Request for multiple reasons, incl. params, headers, sap-messages, read after write, ...
|
|
88
|
-
|
|
89
|
-
Object.defineProperty(cdsReq, 'protocol', { value: 'odata-v4' })
|
|
90
|
-
|
|
91
|
-
// API for subrequests of $batch (or incoming request)
|
|
92
|
-
cdsReq.req = req
|
|
93
|
-
cdsReq.res = res
|
|
94
|
-
|
|
95
|
-
// REVISIT: adjust in getter?
|
|
96
|
-
if (req.method === 'PUT') cdsReq.method = 'PUT'
|
|
87
|
+
const cdsReq = adapter.request4({ method: req.method, query, params, headers, req, res })
|
|
97
88
|
|
|
98
89
|
// rewrite event for draft-enabled entities
|
|
99
|
-
if (
|
|
100
|
-
|
|
101
|
-
//
|
|
102
|
-
//
|
|
103
|
-
//
|
|
104
|
-
|
|
90
|
+
if (_isDraft) cdsReq.event = 'PATCH'
|
|
91
|
+
|
|
92
|
+
// NOTES:
|
|
93
|
+
// - only via srv.run in combination with srv.dispatch inside,
|
|
94
|
+
// we automatically either use a single auto-managed tx for the req (i.e., insert and read after write in same tx)
|
|
95
|
+
// or the auto-managed tx opened for the respective atomicity group, if exists
|
|
96
|
+
// - in the then block of .run(), the transaction is committed (i.e., before sending the response) if a single auto-managed tx is used
|
|
97
|
+
return service
|
|
105
98
|
.run(() => {
|
|
106
|
-
return
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
//
|
|
110
|
-
if (cdsReq._.readAfterWrite && !(_propertyAccess && !target._etag))
|
|
111
|
-
return readAfterWrite(cdsReq, srv, SELECT.one(cdsReq.subject))
|
|
112
|
-
}
|
|
113
|
-
|
|
99
|
+
return service.dispatch(cdsReq).then(result => {
|
|
100
|
+
// REVISIT: shouldn't read after write be the default behavior (that could be suppressed)?
|
|
101
|
+
// generic handlers indicate that read after write is required
|
|
102
|
+
// REVISIT: what does target._etag have to do with it?
|
|
103
|
+
if (cdsReq._.readAfterWrite && !(_propertyAccess && !target._etag)) return _readAfterWrite(cdsReq)
|
|
114
104
|
return result
|
|
115
105
|
})
|
|
116
106
|
})
|
|
117
107
|
.then(result => {
|
|
118
|
-
|
|
108
|
+
handleSapMessages(cdsReq, req, res)
|
|
119
109
|
|
|
110
|
+
// case: read after write returns no results, e.g., due to auth (academic but possible)
|
|
120
111
|
if (result == null) return res.sendStatus(204)
|
|
121
112
|
|
|
122
|
-
// REVISIT: metaInfo needs original query in case of property access, but why?
|
|
123
|
-
const info = metaInfo(_propertyAccess ? req._query : query, 'UPDATE', srv, result, req)
|
|
124
|
-
|
|
125
113
|
const isMinimal = getPreferReturnHeader(req) === 'minimal'
|
|
114
|
+
postProcess(cdsReq.target, service, result, isMinimal)
|
|
126
115
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
116
|
+
if (isMinimal && !target._isSingleton) {
|
|
117
|
+
// determine calculation based on result with req.data as fallback
|
|
118
|
+
res.set('location', calculateLocationHeader(cdsReq.target, service, result || cdsReq.data))
|
|
119
|
+
}
|
|
120
|
+
if (result?.$etag) res.set('ETag', result.$etag) //> must be done after post processing
|
|
130
121
|
|
|
131
|
-
if (isMinimal || (
|
|
122
|
+
if (isMinimal || (_propertyAccess && result[_propertyAccess] == null) || isStream(req._query)) {
|
|
132
123
|
return res.sendStatus(204)
|
|
133
124
|
}
|
|
134
125
|
|
|
135
|
-
|
|
136
|
-
|
|
126
|
+
const metadata = getODataMetadata(_propertyAccess ? req._query : query, { result })
|
|
127
|
+
result = getODataResult(result, metadata, { property: _propertyAccess })
|
|
137
128
|
res.send(result)
|
|
138
129
|
})
|
|
139
130
|
.catch(e => {
|
|
131
|
+
handleSapMessages(cdsReq, req, res)
|
|
132
|
+
|
|
140
133
|
// if UPSERT is allowed, redirect to POST
|
|
141
134
|
const is404 = e.code === 404 || e.status === 404 || e.statusCode === 404
|
|
142
135
|
const isForcedInsert =
|
|
143
|
-
(e.code === 412 || e.status === 412 || e.statusCode === 412) &&
|
|
136
|
+
(e.code === 412 || e.status === 412 || e.statusCode === 412) &&
|
|
137
|
+
extractIfNoneMatch(req.headers?.['if-none-match']) === '*'
|
|
144
138
|
if (!_propertyAccess && (is404 || isForcedInsert) && _isUpsertAllowed({ target, data, event: req.method })) {
|
|
145
139
|
// PUT / PATCH with if-match header means "only if already exists" -> no insert if it does not
|
|
146
|
-
if (req.headers['if-match']) {
|
|
147
|
-
return next(Object.assign(new Error('412'), { statusCode: 412 }))
|
|
148
|
-
}
|
|
149
|
-
// (check only works with req.body and not with data)
|
|
150
|
-
if (_isNavigationWithKeyInParent(target.keys, req.body, from, srv.model)) {
|
|
151
|
-
return next(Object.assign(new Error('422'), { statusCode: 422 }))
|
|
152
|
-
}
|
|
153
|
-
// -> redirect to POST
|
|
154
|
-
return router.handle(Object.assign(Object.create(req), { method: 'POST' }), res)
|
|
155
|
-
}
|
|
140
|
+
if (req.headers['if-match']) return next(Object.assign(new Error('412'), { statusCode: 412 }))
|
|
156
141
|
|
|
157
|
-
|
|
142
|
+
if (!upsertSupported(from, service.model)) return next(Object.assign(new Error('422'), { statusCode: 422 }))
|
|
143
|
+
|
|
144
|
+
// -> forward to POST
|
|
145
|
+
req.method = 'POST'
|
|
146
|
+
req.body = JSON.parse(req._raw) // REVISIT: Why do we need that?
|
|
147
|
+
return next()
|
|
148
|
+
}
|
|
158
149
|
|
|
159
150
|
// continue with caught error
|
|
160
151
|
next(e)
|
|
161
152
|
})
|
|
162
153
|
}
|
|
154
|
+
}
|