@sap/cds 7.9.4 → 8.0.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 +128 -3659
- 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 +30 -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/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 +54 -27
- 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 +320 -84
- 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 +5 -5
- 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 +26 -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/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,146 +0,0 @@
|
|
|
1
|
-
const cds = require('../../cds')
|
|
2
|
-
const { SELECT } = cds.ql
|
|
3
|
-
const { getEnrichedCQN, hasDraft, ensureDraftsSuffix } = require('../utils/handler')
|
|
4
|
-
const { readAndDeleteKeywords } = require('../utils/where')
|
|
5
|
-
const { cqn2cqn4sql } = require('../../common/utils/cqn2cqn4sql')
|
|
6
|
-
const { isActiveEntityRequested } = require('../../../_runtime/fiori/utils/where')
|
|
7
|
-
|
|
8
|
-
const _modifyWhere = (where, context) => {
|
|
9
|
-
for (let i = 0; i < where.length; i++) {
|
|
10
|
-
const element = where[i]
|
|
11
|
-
|
|
12
|
-
if (element.xpr) {
|
|
13
|
-
_modifyWhere(element.xpr, context)
|
|
14
|
-
continue
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
if (element.SELECT) {
|
|
18
|
-
const subCqnDraft = SELECT.from(
|
|
19
|
-
{
|
|
20
|
-
ref: [...element.SELECT.from.ref],
|
|
21
|
-
as: element.SELECT.from.as
|
|
22
|
-
},
|
|
23
|
-
[1]
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
where[i] = subCqnDraft
|
|
27
|
-
_modifyCQN(subCqnDraft, element.SELECT.where, context)
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const _modifyCQN = (cqnDraft, where, context) => {
|
|
33
|
-
const whereDraft = [...where]
|
|
34
|
-
const result = readAndDeleteKeywords(['IsActiveEntity'], whereDraft)
|
|
35
|
-
cqnDraft.where(whereDraft)
|
|
36
|
-
|
|
37
|
-
if (result && result.value.val === false) {
|
|
38
|
-
const fromRef = cqnDraft.SELECT.from.ref
|
|
39
|
-
cqnDraft.SELECT.from.ref[fromRef.length - 1] = ensureDraftsSuffix(fromRef[fromRef.length - 1])
|
|
40
|
-
}
|
|
41
|
-
if (cqnDraft.SELECT.columns) {
|
|
42
|
-
cqnDraft.SELECT.columns = cqnDraft.SELECT.columns.map(e =>
|
|
43
|
-
e.ref && e.ref.includes('IsActiveEntity') ? { val: true, as: 'IsActiveEntity', cast: { type: 'cds.Boolean' } } : e
|
|
44
|
-
)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
_modifyWhere(cqnDraft.SELECT.where, context)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const _hasNavToNonDraftEnclosedAssoc = (pathSegments, definitions, excludeAssoc) => {
|
|
51
|
-
if (pathSegments.length < 2) return false
|
|
52
|
-
const entity = definitions[pathSegments[0]]
|
|
53
|
-
const nav = entity.elements[pathSegments[1]]
|
|
54
|
-
|
|
55
|
-
if (nav._isAssociationStrict) {
|
|
56
|
-
if (nav['@odata.draft.enclosed']) return false
|
|
57
|
-
if (excludeAssoc == null) return true
|
|
58
|
-
if (!excludeAssoc(nav)) return true
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// At this point we know that nav is a composition, so we have to recursively
|
|
62
|
-
// follow the navigation until we reach the end or find an association.
|
|
63
|
-
pathSegments.shift()
|
|
64
|
-
pathSegments[0] = nav.target
|
|
65
|
-
return _hasNavToNonDraftEnclosedAssoc(pathSegments, definitions, excludeAssoc)
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const _shouldReadOverDraft = (req, definitions) => {
|
|
69
|
-
const SELECT = req.query.SELECT
|
|
70
|
-
const fromRef = SELECT.from.ref
|
|
71
|
-
|
|
72
|
-
if (!fromRef) return false
|
|
73
|
-
|
|
74
|
-
// for $expand requests, read over the draft if the navigation target is non-draft-enabled
|
|
75
|
-
// REVISIT: this is an interim workaround to be removed
|
|
76
|
-
if (!req.target._isDraftEnabled && SELECT.columns?.some(column => column.expand)) return true
|
|
77
|
-
|
|
78
|
-
// read over the draft only for navigation scenarios
|
|
79
|
-
if (fromRef.length === 1) return false
|
|
80
|
-
|
|
81
|
-
const firstFromRef = fromRef[0]
|
|
82
|
-
const rootEntityName = typeof firstFromRef === 'string' ? firstFromRef : firstFromRef.id
|
|
83
|
-
const rootEntity = definitions[rootEntityName]
|
|
84
|
-
|
|
85
|
-
// read over the draft only if the root entity is draft-enabled
|
|
86
|
-
if (!rootEntity._isDraftEnabled) return false
|
|
87
|
-
|
|
88
|
-
// read over the draft only if the navigation starts from a draft entity, e.g.,
|
|
89
|
-
// /Books(ID=1, IsActiveEntity=false)
|
|
90
|
-
if (isActiveEntityRequested(firstFromRef.where)) return false
|
|
91
|
-
|
|
92
|
-
const pathSegments = fromRef.map(path => (typeof path === 'string' ? path : path.id))
|
|
93
|
-
const excludeAssoc = assoc => assoc.name === 'DraftAdministrativeData' || assoc.name === 'SiblingEntity'
|
|
94
|
-
|
|
95
|
-
// Read over the draft only if:
|
|
96
|
-
// - the navigation target is an association and
|
|
97
|
-
// - isn't annotated with the @odata.draft.enclosed annotation
|
|
98
|
-
return _hasNavToNonDraftEnclosedAssoc(pathSegments, definitions, excludeAssoc)
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Generic Handler for READ requests.
|
|
103
|
-
*
|
|
104
|
-
* @param {import('../../cds-services/adapter/odata-v4/ODataRequest')} req
|
|
105
|
-
* @param next
|
|
106
|
-
* @returns {Promise<Array>}
|
|
107
|
-
*/
|
|
108
|
-
const _readOverDraftHandler = async function (req, next) {
|
|
109
|
-
if (!cds.db) req.reject('NO_DATABASE_CONNECTION')
|
|
110
|
-
|
|
111
|
-
const definitions = this.model.definitions
|
|
112
|
-
|
|
113
|
-
// determine whether the request is handled here (read over draft handler),
|
|
114
|
-
// or whether it is passed to the next registered handler/route
|
|
115
|
-
if (!_shouldReadOverDraft(req, definitions)) return next()
|
|
116
|
-
|
|
117
|
-
const rows = req.query.SELECT.limit && req.query.SELECT.limit.rows
|
|
118
|
-
if (rows && rows.val === 0) return Promise.resolve([])
|
|
119
|
-
|
|
120
|
-
// REVISIT DRAFT HANDLING: cqn2cqn4sql must not be called here
|
|
121
|
-
const sqlQuery = cqn2cqn4sql(req.query, this.model, { _4db: req.target._isDraftEnabled, _4fiori: true })
|
|
122
|
-
|
|
123
|
-
if (cds.env.features.stream_compat && req.query._streaming) {
|
|
124
|
-
sqlQuery._streaming = true
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const hasDraftEntity = hasDraft(definitions, sqlQuery)
|
|
128
|
-
|
|
129
|
-
if (hasDraftEntity && sqlQuery.SELECT.where && sqlQuery.SELECT.where.length) {
|
|
130
|
-
let cqnDraft = SELECT.from({
|
|
131
|
-
ref: [...sqlQuery.SELECT.from.ref],
|
|
132
|
-
as: sqlQuery.SELECT.from.as
|
|
133
|
-
})
|
|
134
|
-
|
|
135
|
-
cqnDraft.SELECT.columns = sqlQuery.SELECT.columns
|
|
136
|
-
_modifyCQN(cqnDraft, sqlQuery.SELECT.where, req)
|
|
137
|
-
cqnDraft = getEnrichedCQN(cqnDraft, sqlQuery.SELECT, [])
|
|
138
|
-
return cds.tx(req).run(cqnDraft)
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
return cds.tx(req).run(sqlQuery)
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
module.exports = cds.service.impl(function readOverDraft(srv) {
|
|
145
|
-
srv.on('READ', '*', _readOverDraftHandler)
|
|
146
|
-
})
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Returns true/false if entity is root of a document in a draft enabled service.
|
|
3
|
-
*
|
|
4
|
-
* @param {object} definitions Definitions of the reflected model
|
|
5
|
-
* @param {string} entityName Name of the entity
|
|
6
|
-
*/
|
|
7
|
-
const isDraftRootEntity = (definitions, entityName) => {
|
|
8
|
-
return definitions[entityName] && definitions[entityName]['@Common.DraftRoot.PreparationAction']
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
module.exports = {
|
|
12
|
-
isDraftRootEntity
|
|
13
|
-
}
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
const cds = require('../../cds')
|
|
2
|
-
const getError = require('../../common/error')
|
|
3
|
-
const { SELECT, DELETE } = cds.ql
|
|
4
|
-
|
|
5
|
-
const { isDraftRootEntity } = require('./csn')
|
|
6
|
-
const {
|
|
7
|
-
getUpdateDraftAdminCQN,
|
|
8
|
-
ensureDraftsSuffix,
|
|
9
|
-
ensureNoDraftsSuffix,
|
|
10
|
-
getDeleteDraftAdminCqn,
|
|
11
|
-
getCompositionTargets
|
|
12
|
-
} = require('./handler')
|
|
13
|
-
const { extractKeyConditions } = require('./where')
|
|
14
|
-
|
|
15
|
-
const _getSelectCQN = (req, keys) => {
|
|
16
|
-
return SELECT.from(ensureNoDraftsSuffix(req.target.name), [1]).where(keys.keyList)
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const _getDraftSelectCQN = (req, keys) => {
|
|
20
|
-
const draftEntityName = ensureDraftsSuffix(req.target.name)
|
|
21
|
-
|
|
22
|
-
return SELECT.from(draftEntityName, ['DraftUUID'])
|
|
23
|
-
.join('DRAFT.DraftAdministrativeData')
|
|
24
|
-
.on('DraftAdministrativeData_DraftUUID =', { ref: ['DRAFT.DraftAdministrativeData', 'DraftUUID'] })
|
|
25
|
-
.where(keys.keyList)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const _validate = (activeResult, draftResult, req, IsActiveEntity) => {
|
|
29
|
-
if (
|
|
30
|
-
(IsActiveEntity === true && activeResult.length === 0) ||
|
|
31
|
-
(IsActiveEntity === false && draftResult.length === 0)
|
|
32
|
-
) {
|
|
33
|
-
req.reject(req._etagValidationClause ? 412 : 404)
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const deleteDraft = async (req, srv, includingActive = false) => {
|
|
38
|
-
if (!cds.db) req.reject('NO_DATABASE_CONNECTION')
|
|
39
|
-
|
|
40
|
-
const dbtx = cds.tx(req)
|
|
41
|
-
const definitions = srv.model.definitions
|
|
42
|
-
|
|
43
|
-
const where = req.query.DELETE.from.ref?.[req.query.DELETE.from.ref.length - 1].where
|
|
44
|
-
if (!where) {
|
|
45
|
-
req.reject(getError(500, 'Invalid delete draft request'))
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// REVISIT: how to handle delete of to 1 assoc
|
|
49
|
-
const keys = extractKeyConditions(where)
|
|
50
|
-
|
|
51
|
-
// IsActiveEntity is deleted from where clause in auth.js, hence keys.IsActiveEntity is undefined here.
|
|
52
|
-
// Intentional?
|
|
53
|
-
const deleteActive = keys.IsActiveEntity !== false
|
|
54
|
-
|
|
55
|
-
const selectActive = _getSelectCQN(req, keys)
|
|
56
|
-
const selectDraft = _getDraftSelectCQN(req, keys)
|
|
57
|
-
|
|
58
|
-
if (req._etagValidationClause) {
|
|
59
|
-
if (keys.IsActiveEntity) selectActive.where(req._etagValidationClause)
|
|
60
|
-
else selectDraft.where(req._etagValidationClause)
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const [activeResult, draftResult] = await Promise.all([dbtx.run(selectActive), dbtx.run(selectDraft)])
|
|
64
|
-
|
|
65
|
-
_validate(activeResult, draftResult, req, deleteActive)
|
|
66
|
-
|
|
67
|
-
if (isDraftRootEntity(definitions, ensureNoDraftsSuffix(req.target.name)) && !deleteActive) {
|
|
68
|
-
const draftUUID = draftResult[0].DraftUUID
|
|
69
|
-
|
|
70
|
-
const draftTablesToDeleteFrom = [req.target.name + '_drafts']
|
|
71
|
-
for (const [entity] of getCompositionTargets(req.target, srv).entries()) {
|
|
72
|
-
if (!draftTablesToDeleteFrom.includes(entity + '_drafts')) draftTablesToDeleteFrom.push(entity + '_drafts')
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const deleteDraftAdminCqn = getDeleteDraftAdminCqn(draftUUID)
|
|
76
|
-
|
|
77
|
-
return dbtx.run([
|
|
78
|
-
deleteDraftAdminCqn,
|
|
79
|
-
...draftTablesToDeleteFrom.map(dt => {
|
|
80
|
-
const d = DELETE.from(dt).where({ DraftAdministrativeData_DraftUUID: draftUUID })
|
|
81
|
-
d._suppressDeepDelete = true // hidden flag to tell db layer that no deep delete is required
|
|
82
|
-
return d
|
|
83
|
-
})
|
|
84
|
-
])
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const source = definitions[ensureNoDraftsSuffix(req.target.name)]
|
|
88
|
-
const delCQNs = []
|
|
89
|
-
|
|
90
|
-
if (includingActive) {
|
|
91
|
-
const r = new cds.Request({ query: DELETE.from(ensureNoDraftsSuffix(req.target.name)).where(keys.keyList) })
|
|
92
|
-
|
|
93
|
-
// REVISIT: should not be necessary
|
|
94
|
-
r._ = Object.assign(r._, req._)
|
|
95
|
-
r._.query = req.query
|
|
96
|
-
|
|
97
|
-
await dbtx.dispatch(r)
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (draftResult.length !== 0) {
|
|
101
|
-
delCQNs.push(DELETE.from(ensureDraftsSuffix(source.name)).where(keys.keyList))
|
|
102
|
-
|
|
103
|
-
const draftUUID = draftResult[0].DraftUUID
|
|
104
|
-
if (isDraftRootEntity(definitions, ensureNoDraftsSuffix(req.target.name))) {
|
|
105
|
-
delCQNs.push(DELETE.from('DRAFT.DraftAdministrativeData').where({ draftUUID }))
|
|
106
|
-
} else {
|
|
107
|
-
delCQNs.push(getUpdateDraftAdminCQN(req, draftUUID))
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
return Promise.all(delCQNs.map(cqn => dbtx.run(cqn)))
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
module.exports = { deleteDraft }
|
|
@@ -1,264 +0,0 @@
|
|
|
1
|
-
const cds = require('../../cds')
|
|
2
|
-
const { Object_keys } = cds.utils
|
|
3
|
-
const { UPDATE, SELECT } = cds.ql
|
|
4
|
-
const { getColumns } = require('../../common/utils/columns')
|
|
5
|
-
const { ensureNoDraftsSuffix, ensureDraftsSuffix, ensureUnlocalized } = require('../../common/utils/draft')
|
|
6
|
-
const getTemplate = require('../../common/utils/template')
|
|
7
|
-
|
|
8
|
-
const { DRAFT_COLUMNS_MAP } = require('../../common/constants/draft')
|
|
9
|
-
|
|
10
|
-
// unofficial config!
|
|
11
|
-
const MAX_RECURSION_DEPTH = (cds.env.features.recursion_depth && Number(cds.env.features.recursion_depth)) || 2
|
|
12
|
-
|
|
13
|
-
const _getParentCQNWithKeyColumn = (parentCQN, parentKeyName) => {
|
|
14
|
-
const parentCQNWithKeyColumn = Object.assign({}, parentCQN)
|
|
15
|
-
parentCQNWithKeyColumn.SELECT = Object.assign({}, parentCQN.SELECT)
|
|
16
|
-
parentCQNWithKeyColumn.SELECT.columns = [{ ref: [parentKeyName] }]
|
|
17
|
-
return parentCQNWithKeyColumn
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const _getSubSelectFromCQN = (element, columns, selectFromDraft) => {
|
|
21
|
-
return SELECT.from(
|
|
22
|
-
selectFromDraft ? ensureDraftsSuffix(element.source) : element.source,
|
|
23
|
-
selectFromDraft ? [...columns, 'DraftAdministrativeData_DraftUUID'] : columns
|
|
24
|
-
)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const getSubCQNs = ({ definitions, rootCQN, compositionTree, selectFromDraft = false }) => {
|
|
28
|
-
const subCQNs = []
|
|
29
|
-
// only one backLink
|
|
30
|
-
const _generateSubCQNs = (parentCQN, compositionElements, elementMap = new Map()) => {
|
|
31
|
-
for (const element of compositionElements) {
|
|
32
|
-
const backLink = element.backLinks[0] || element.customBackLinks[0]
|
|
33
|
-
if (backLink) {
|
|
34
|
-
const fqn = element.source + ':' + element.name
|
|
35
|
-
const seen = elementMap.get(fqn)
|
|
36
|
-
if (seen && seen >= MAX_RECURSION_DEPTH) {
|
|
37
|
-
// recursion -> abort
|
|
38
|
-
continue
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const columns = getColumns(definitions[element.source], { onlyNames: true, filterVirtual: true })
|
|
42
|
-
const subCQN = _getSubSelectFromCQN(element, columns, selectFromDraft)
|
|
43
|
-
subCQN.where([{ ref: [backLink.entityKey] }, 'in', _getParentCQNWithKeyColumn(parentCQN, backLink.targetKey)])
|
|
44
|
-
subCQNs.push({ cqn: subCQN })
|
|
45
|
-
const newElementMap = new Map(elementMap)
|
|
46
|
-
newElementMap.set(fqn, (seen && seen + 1) || 1)
|
|
47
|
-
_generateSubCQNs(subCQN, element.compositionElements, newElementMap)
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
_generateSubCQNs(rootCQN, compositionTree.compositionElements)
|
|
53
|
-
|
|
54
|
-
return subCQNs
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const proxifyToNoDraftsName = target => {
|
|
58
|
-
const entityProxyHandler = {
|
|
59
|
-
get: (obj, prop) => (prop === 'name' ? ensureNoDraftsSuffix(target.name) : obj[prop])
|
|
60
|
-
}
|
|
61
|
-
return new Proxy(target, entityProxyHandler)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const hasDraft = (definitions, cqn) => {
|
|
65
|
-
if (
|
|
66
|
-
cqn.SELECT.from.ref &&
|
|
67
|
-
definitions[cqn.SELECT.from.ref[cqn.SELECT.from.ref.length - 1]] &&
|
|
68
|
-
definitions[cqn.SELECT.from.ref[cqn.SELECT.from.ref.length - 1]]._isDraftEnabled
|
|
69
|
-
) {
|
|
70
|
-
return true
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (cqn.SELECT.where) {
|
|
74
|
-
for (const element of cqn.SELECT.where) {
|
|
75
|
-
if (element.SELECT && hasDraft(definitions, element)) {
|
|
76
|
-
return true
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return false
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const getUpdateDraftAdminCQN = ({ user }, draftUUID) => {
|
|
85
|
-
const set = {
|
|
86
|
-
InProcessByUser: user.id,
|
|
87
|
-
LastChangedByUser: user.id,
|
|
88
|
-
LastChangeDateTime: new Date()
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return UPDATE('DRAFT.DraftAdministrativeData').data(set).where({ DraftUUID: draftUUID })
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const _addAlias = (where, tableName) => {
|
|
95
|
-
// copy where
|
|
96
|
-
return where.map(element => {
|
|
97
|
-
if (element.xpr) {
|
|
98
|
-
return { xpr: _addAlias(element.xpr, tableName) }
|
|
99
|
-
}
|
|
100
|
-
if (element.ref && element.ref.length === 1) {
|
|
101
|
-
// and copy ref
|
|
102
|
-
return { ref: [tableName, element.ref[0]] }
|
|
103
|
-
}
|
|
104
|
-
return element
|
|
105
|
-
})
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const _getSelectedColumns = (columns, selectedColumns) => {
|
|
109
|
-
return columns.filter(col => {
|
|
110
|
-
if (
|
|
111
|
-
col.ref &&
|
|
112
|
-
selectedColumns.some(sel => sel.ref && sel.ref[sel.ref.length - 1] === col.ref[col.ref.length - 1])
|
|
113
|
-
) {
|
|
114
|
-
return true
|
|
115
|
-
} else if (col.as && selectedColumns.some(sel => sel.as && sel.as === col.as)) {
|
|
116
|
-
return true
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
return false
|
|
120
|
-
})
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const getEnrichedCQN = (cqn, select, draftWhere, scenarioAlias, addLimitOrder = true) => {
|
|
124
|
-
const tableName =
|
|
125
|
-
(cqn.SELECT.from.ref && cqn.SELECT.from.ref[0]) || (cqn.SELECT.from.args && cqn.SELECT.from.args[0].ref[0])
|
|
126
|
-
|
|
127
|
-
if (draftWhere && draftWhere.length !== 0) {
|
|
128
|
-
cqn.where(_addAlias(draftWhere, tableName))
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if (select.distinct) {
|
|
132
|
-
cqn.SELECT.distinct = true
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
const alias = (select.from && select.from.as) || scenarioAlias
|
|
136
|
-
|
|
137
|
-
if (select.count) cqn.SELECT.count = true
|
|
138
|
-
if (select.one) cqn.SELECT.one = true
|
|
139
|
-
|
|
140
|
-
if (select.having) {
|
|
141
|
-
cqn.having(_aliased(select.having, select.columns, alias))
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// groupBy, orderBy and limit do not support partial CQNs
|
|
145
|
-
if (select.groupBy) {
|
|
146
|
-
cqn.SELECT.groupBy = _aliased(select.groupBy, select.columns, alias)
|
|
147
|
-
cqn.SELECT.columns = _getSelectedColumns(cqn.SELECT.columns, select.columns)
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
if (select.orderBy && addLimitOrder) {
|
|
151
|
-
cqn.SELECT.orderBy = _aliased(select.orderBy, select.columns, alias)
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
if (select.limit && addLimitOrder) {
|
|
155
|
-
cqn.SELECT.limit = select.limit
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
return cqn
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
const _aliasRef = (ref, alias) => {
|
|
162
|
-
const newRef = [...ref]
|
|
163
|
-
// we skip draft columns because they are mostly calculated later on
|
|
164
|
-
if (alias && !(ref[ref.length - 1] in DRAFT_COLUMNS_MAP)) {
|
|
165
|
-
newRef.unshift(alias)
|
|
166
|
-
}
|
|
167
|
-
return newRef
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
const getDeleteDraftAdminCqn = draftUUID =>
|
|
171
|
-
DELETE.from('DRAFT.DraftAdministrativeData').where([{ ref: ['DraftUUID'] }, '=', { val: draftUUID }])
|
|
172
|
-
|
|
173
|
-
const _aliased = (arr, columns, alias) =>
|
|
174
|
-
arr.map(item => {
|
|
175
|
-
if (item.ref && columns.some(c => c.as === item.ref[item.ref.length - 1])) {
|
|
176
|
-
// remove table alias if present for a calculated field
|
|
177
|
-
if (item.ref[0] === alias) {
|
|
178
|
-
return item.ref.splice(0, 1)
|
|
179
|
-
}
|
|
180
|
-
} else if (alias && item.ref && item.ref[0] !== alias) {
|
|
181
|
-
return Object.assign({}, item, { ref: _aliasRef(item.ref, alias) })
|
|
182
|
-
}
|
|
183
|
-
return item
|
|
184
|
-
})
|
|
185
|
-
|
|
186
|
-
// Only works for root entity, otherwise the relative position needs to be adapted
|
|
187
|
-
const removeDraftUUIDIfNecessary = req =>
|
|
188
|
-
req.http?.req?.headers?.['x-cds-odata-version'] === 'v2'
|
|
189
|
-
? () => {}
|
|
190
|
-
: result => delete result.DraftAdministrativeData_DraftUUID
|
|
191
|
-
|
|
192
|
-
const addColumnAlias = (columns, alias) => {
|
|
193
|
-
if (!alias) {
|
|
194
|
-
return columns
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
return columns.map(col => {
|
|
198
|
-
if (typeof col === 'string') {
|
|
199
|
-
return { ref: [alias, col] }
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
if (col.ref && !col.expand) {
|
|
203
|
-
const obj = Object.assign({}, col)
|
|
204
|
-
obj.ref = [alias, ...col.ref.slice(0)]
|
|
205
|
-
return obj
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
if (col.func && col.args) {
|
|
209
|
-
const obj = Object.assign({}, col)
|
|
210
|
-
obj.args = addColumnAlias(col.args, alias)
|
|
211
|
-
return obj
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
return col
|
|
215
|
-
})
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
const getCompositionTargets = (entity, srv) => {
|
|
219
|
-
if (!entity.own('_deepCompositionTargets')) {
|
|
220
|
-
const _deepCompositionTargets = []
|
|
221
|
-
getTemplate(undefined, srv, entity, {
|
|
222
|
-
pick: element => {
|
|
223
|
-
if (element.isAssociation && !element._isAssociationStrict && srv.model.definitions[element.target].drafts)
|
|
224
|
-
_deepCompositionTargets.push(element.target)
|
|
225
|
-
},
|
|
226
|
-
ignore: element => !element.isAssociation || element._isAssociationStrict
|
|
227
|
-
})
|
|
228
|
-
entity.set('_deepCompositionTargets', new Set(_deepCompositionTargets))
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
return entity.own('_deepCompositionTargets')
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
const replaceRefWithDraft = ref => {
|
|
235
|
-
if (!ref || !ref[0]) return
|
|
236
|
-
ref[0] = ensureDraftsSuffix(ref[0])
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
const draftIsLocked = lastChangedAt => {
|
|
240
|
-
// default timeout timer is 15 minutes
|
|
241
|
-
const DRAFT_CANCEL_TIMEOUT_IN_MS = ((cds.env.drafts && cds.env.drafts.cancellationTimeout) || 15) * 60 * 1000
|
|
242
|
-
return DRAFT_CANCEL_TIMEOUT_IN_MS > Date.now() - Date.parse(lastChangedAt)
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
const entity_keys = entity =>
|
|
246
|
-
Object_keys(entity.keys).filter(key => key !== 'IsActiveEntity' && !entity.keys[key]._isAssociationStrict)
|
|
247
|
-
|
|
248
|
-
module.exports = {
|
|
249
|
-
getSubCQNs,
|
|
250
|
-
draftIsLocked,
|
|
251
|
-
getUpdateDraftAdminCQN,
|
|
252
|
-
getEnrichedCQN,
|
|
253
|
-
removeDraftUUIDIfNecessary,
|
|
254
|
-
ensureDraftsSuffix,
|
|
255
|
-
ensureNoDraftsSuffix,
|
|
256
|
-
ensureUnlocalized,
|
|
257
|
-
hasDraft,
|
|
258
|
-
proxifyToNoDraftsName,
|
|
259
|
-
addColumnAlias,
|
|
260
|
-
replaceRefWithDraft,
|
|
261
|
-
entity_keys,
|
|
262
|
-
getDeleteDraftAdminCqn,
|
|
263
|
-
getCompositionTargets
|
|
264
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
const cds = require('../../cds')
|
|
2
|
-
const { getTransition } = require('../../common/utils/resolveView')
|
|
3
|
-
const { getKeyData, getLockWhere } = require('../utils/where')
|
|
4
|
-
const { entity_keys } = require('../utils/handler')
|
|
5
|
-
|
|
6
|
-
const getLockInfo = (req, dataSource) => {
|
|
7
|
-
const keys = entity_keys(req.target)
|
|
8
|
-
const keyData = getKeyData(keys, req.query.SELECT.from.ref[0].where)
|
|
9
|
-
const rootWhere = keys.reduce((res, key) => {
|
|
10
|
-
res[key] = keyData[key]
|
|
11
|
-
return res
|
|
12
|
-
}, {})
|
|
13
|
-
|
|
14
|
-
if (dataSource === undefined || dataSource === cds.db) {
|
|
15
|
-
const transition = getTransition(req.target, cds.db)
|
|
16
|
-
|
|
17
|
-
// gets the underlying target entity, as record locking can't be
|
|
18
|
-
// applied to localized views
|
|
19
|
-
const target = transition.target
|
|
20
|
-
const where = getLockWhere(rootWhere, transition.mapping)
|
|
21
|
-
return { target, where, rootWhere }
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
return { target: req.target, where: req.query.SELECT.from.ref[0].where, rootWhere }
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
module.exports = getLockInfo
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
const _ref2name = ref => (ref.id || ref).replace(/_drafts$/, '')
|
|
2
|
-
|
|
3
|
-
const isNavigationToMany = (req, model) => {
|
|
4
|
-
// only one segment -> false
|
|
5
|
-
if (req.subject.ref.length < 2) return
|
|
6
|
-
|
|
7
|
-
// last segment has it's own where -> false
|
|
8
|
-
if (req.subject.ref[req.subject.ref.length - 1].where) return
|
|
9
|
-
|
|
10
|
-
// determine the csn element of the last navigation and return it's is2many property
|
|
11
|
-
let cur
|
|
12
|
-
for (let i = 0; i < req.subject.ref.length - 1; i++) {
|
|
13
|
-
cur = cur
|
|
14
|
-
? model.definitions[cur.elements[_ref2name(req.subject.ref[i])].target]
|
|
15
|
-
: model.definitions[_ref2name(req.subject.ref[i])]
|
|
16
|
-
}
|
|
17
|
-
const last = cur.elements[_ref2name(req.subject.ref[req.subject.ref.length - 1])]
|
|
18
|
-
return last.is2many
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
module.exports = {
|
|
22
|
-
isNavigationToMany
|
|
23
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
const { ensureDraftsSuffix } = require('./handler')
|
|
2
|
-
const { removeIsActiveEntityRecursively, isActiveEntityRequested } = require('./where')
|
|
3
|
-
|
|
4
|
-
const _adaptSubSelectsDraft = select => {
|
|
5
|
-
if (select.SELECT.from.ref) {
|
|
6
|
-
const index = select.SELECT.from.ref.length - 1
|
|
7
|
-
select.SELECT.from.ref[index] = ensureDraftsSuffix(select.SELECT.from.ref[index])
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
if (select.SELECT.where) {
|
|
11
|
-
for (let i = 0; i < select.SELECT.where.length; i++) {
|
|
12
|
-
const element = select.SELECT.where[i]
|
|
13
|
-
if (element.SELECT) {
|
|
14
|
-
_adaptSubSelectsDraft(element)
|
|
15
|
-
} else if (element.xpr) {
|
|
16
|
-
_adaptSubSelectsDraft({ SELECT: { from: {}, where: element.xpr } })
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const adaptStreamCQN = (cqn, isDraft = false) => {
|
|
23
|
-
let draft = isDraft
|
|
24
|
-
if (!draft) {
|
|
25
|
-
draft = !isActiveEntityRequested(cqn.SELECT.where)
|
|
26
|
-
const ref = cqn.SELECT.from?.ref
|
|
27
|
-
if (!draft && ref) draft = !isActiveEntityRequested(ref[ref.length - 1].where)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (draft) _adaptSubSelectsDraft(cqn)
|
|
31
|
-
cqn.SELECT.where = removeIsActiveEntityRecursively(cqn.SELECT.where)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
module.exports = {
|
|
35
|
-
adaptStreamCQN
|
|
36
|
-
}
|