@sap/cds 5.8.2 → 5.9.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 +214 -78
- package/app/fiori/preview.js +16 -11
- package/app/fiori/routes.js +3 -0
- package/app/index.js +1 -1
- package/bin/build/buildTaskFactory.js +3 -3
- package/bin/build/buildTaskProviderFactory.js +1 -1
- package/bin/build/constants.js +1 -1
- package/bin/build/provider/buildTaskHandlerEdmx.js +12 -7
- package/bin/build/provider/buildTaskHandlerInternal.js +1 -1
- package/bin/build/provider/buildTaskProviderInternal.js +8 -2
- package/bin/build/provider/hana/2migration.js +27 -24
- package/bin/build/provider/hana/index.js +17 -18
- package/bin/build/provider/hana/migrationtable.js +9 -10
- package/bin/build/provider/java-cf/index.js +4 -5
- package/bin/build/provider/node-cf/index.js +99 -6
- package/bin/cds.js +20 -17
- package/bin/deploy/to-hana/cfUtil.js +16 -19
- package/bin/deploy/to-hana/hana.js +7 -24
- package/bin/deploy/to-hana/hdiDeployUtil.js +8 -4
- package/bin/mtx/in-cds.js +2 -2
- package/bin/serve.js +12 -5
- package/bin/utils/modules.js +7 -0
- package/bin/version.js +56 -3
- package/lib/compile/cdsc.js +26 -3
- package/lib/compile/etc/_localized.js +36 -25
- package/lib/compile/etc/csv.js +8 -8
- package/lib/compile/for/drafts.js +9 -0
- package/lib/compile/for/java.js +16 -0
- package/lib/compile/for/nodejs.js +12 -0
- package/lib/compile/for/odata.js +1 -1
- package/lib/compile/index.js +3 -0
- package/lib/compile/minify.js +16 -2
- package/lib/compile/parse.js +2 -2
- package/lib/compile/resolve.js +35 -18
- package/lib/compile/to/json.js +3 -1
- package/lib/compile/to/sql.js +2 -2
- package/lib/compile/to/srvinfo.js +4 -2
- package/lib/connect/index.js +1 -1
- package/lib/core/entities.js +15 -14
- package/lib/core/index.js +39 -36
- package/lib/core/reflect.js +4 -2
- package/lib/deploy.js +114 -127
- package/lib/env/defaults.js +1 -0
- package/lib/env/index.js +165 -165
- package/lib/env/presets.js +1 -0
- package/lib/env/requires.js +120 -49
- package/lib/index.js +1 -0
- package/lib/log/format/kibana.js +2 -2
- package/lib/ql/SELECT.js +10 -0
- package/lib/ql/parse.js +1 -0
- package/lib/req/cds-context.js +4 -1
- package/lib/req/context.js +50 -56
- package/lib/req/event.js +1 -6
- package/lib/req/locale.js +6 -5
- package/lib/req/request.js +2 -0
- package/lib/req/user.js +7 -5
- package/lib/serve/Service-api.js +10 -7
- package/lib/serve/Service-dispatch.js +9 -11
- package/lib/serve/Service-methods.js +30 -41
- package/lib/serve/Transaction.js +10 -7
- package/lib/serve/adapters.js +7 -5
- package/lib/serve/index.js +24 -12
- package/lib/utils/data.js +1 -1
- package/lib/utils/index.js +27 -30
- package/lib/utils/resources/index.js +101 -0
- package/lib/utils/resources/tar.js +71 -0
- package/lib/utils/resources/utils.js +11 -0
- package/libx/_runtime/audit/Service.js +36 -39
- package/libx/_runtime/audit/generic/personal/access.js +3 -4
- package/libx/_runtime/audit/generic/personal/modification.js +3 -4
- package/libx/_runtime/audit/utils/v2.js +1 -2
- package/libx/_runtime/auth/index.js +126 -84
- package/libx/_runtime/auth/strategies/JWT.js +12 -19
- package/libx/_runtime/auth/strategies/dummy.js +1 -5
- package/libx/_runtime/auth/strategies/dwc.js +11 -9
- package/libx/_runtime/auth/strategies/mock.js +0 -4
- package/libx/_runtime/auth/strategies/{utils/xssec.js → xssecUtils.js} +7 -4
- package/libx/_runtime/auth/strategies/xsuaa.js +12 -19
- package/libx/_runtime/auth/utils.js +22 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/Dispatcher.js +104 -98
- package/libx/_runtime/cds-services/adapter/odata-v4/OData.js +2 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/action.js +13 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/language.js +2 -8
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +4 -29
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +2 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +3 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +2 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +4 -6
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/expandToCQN.js +24 -21
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/index.js +8 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/UriHelper.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/deserializer/DeserializerFactory.js +2 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/deserializer/ResourceJsonDeserializer.js +5 -6
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/invocation/DispatcherCommand.js +2 -6
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/utils/UriHelper.js +4 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/to.js +1 -12
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +33 -9
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/dispatcherUtils.js +50 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +2 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/request.js +10 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +9 -11
- package/libx/_runtime/cds-services/adapter/rest/RestRequest.js +6 -3
- package/libx/_runtime/cds-services/adapter/rest/handlers/operation.js +4 -2
- package/libx/_runtime/cds-services/adapter/rest/rest-to-cqn/utils.js +1 -1
- package/libx/_runtime/cds-services/adapter/rest/utils/binary.js +1 -1
- package/libx/_runtime/cds-services/adapter/rest/utils/key-value-utils.js +2 -3
- package/libx/_runtime/cds-services/adapter/rest/utils/parse-url.js +6 -4
- package/libx/_runtime/cds-services/adapter/rest/utils/result.js +1 -0
- package/libx/_runtime/cds-services/adapter/rest/utils/validation-checks.js +8 -5
- package/libx/_runtime/cds-services/services/Service.js +40 -0
- package/libx/_runtime/cds-services/services/utils/columns.js +4 -3
- package/libx/_runtime/cds-services/services/utils/compareJson.js +4 -4
- package/libx/_runtime/cds-services/services/utils/differ.js +3 -3
- package/libx/_runtime/cds-services/services/utils/handlerUtils.js +4 -4
- package/libx/_runtime/cds-services/services/utils/restrictions.js +78 -0
- package/libx/_runtime/cds-services/util/assert.js +20 -14
- package/libx/_runtime/cds.js +9 -1
- package/libx/_runtime/common/aspects/any.js +5 -0
- package/libx/_runtime/common/aspects/entity.js +25 -7
- package/libx/_runtime/common/aspects/utils.js +2 -2
- package/libx/_runtime/common/composition/data.js +6 -0
- package/libx/_runtime/common/composition/insert.js +3 -2
- package/libx/_runtime/common/composition/tree.js +4 -10
- package/libx/_runtime/common/composition/update.js +4 -4
- package/libx/_runtime/common/constants/draft.js +29 -26
- package/libx/_runtime/common/error/constants.js +2 -2
- package/libx/_runtime/common/error/frontend.js +7 -15
- package/libx/_runtime/common/generic/auth/capabilities.js +59 -0
- package/libx/_runtime/common/generic/auth/constants.js +20 -0
- package/libx/_runtime/common/generic/auth/expand.js +54 -0
- package/libx/_runtime/common/generic/auth/index.js +32 -0
- package/libx/_runtime/common/generic/auth/insertOnly.js +15 -0
- package/libx/_runtime/common/generic/auth/readOnly.js +26 -0
- package/libx/_runtime/common/generic/auth/requires.js +34 -0
- package/libx/_runtime/common/generic/auth/restrict.js +296 -0
- package/libx/_runtime/common/generic/auth/utils.js +213 -0
- package/libx/_runtime/common/generic/crud.js +14 -10
- package/libx/_runtime/common/generic/etag.js +1 -1
- package/libx/_runtime/common/generic/input.js +35 -35
- package/libx/_runtime/common/generic/sorting.js +2 -3
- package/libx/_runtime/common/generic/temporal.js +2 -2
- package/libx/_runtime/common/i18n/index.js +2 -31
- package/libx/_runtime/common/i18n/messages.properties +1 -1
- package/libx/_runtime/common/toggles/handler.js +21 -0
- package/libx/_runtime/common/utils/copy.js +10 -1
- package/libx/_runtime/common/utils/cqn2cqn4sql.js +100 -29
- package/libx/_runtime/common/utils/csn.js +63 -1
- package/libx/_runtime/common/utils/dollar.js +10 -1
- package/libx/_runtime/common/utils/draft.js +46 -7
- package/libx/_runtime/common/utils/entityFromCqn.js +13 -9
- package/libx/_runtime/common/utils/extensibilityUtils.js +18 -0
- package/libx/_runtime/common/utils/foreignKeyPropagations.js +88 -104
- package/libx/_runtime/common/utils/generateOnCond.js +9 -6
- package/libx/_runtime/common/utils/quotingStyles.js +2 -0
- package/libx/_runtime/common/utils/resolveStructured.js +25 -9
- package/libx/_runtime/common/utils/resolveView.js +4 -1
- package/libx/_runtime/common/utils/rewriteAsterisks.js +3 -16
- package/libx/_runtime/common/utils/structured.js +33 -37
- package/libx/_runtime/common/utils/template.js +17 -8
- package/libx/_runtime/common/utils/templateProcessor.js +28 -28
- package/libx/_runtime/db/data-conversion/post-processing.js +118 -417
- package/libx/_runtime/db/expand/expandCQNToJoin.js +45 -41
- package/libx/_runtime/db/expand/rawToExpanded.js +29 -8
- package/libx/_runtime/db/generic/index.js +1 -3
- package/libx/_runtime/db/generic/input.js +5 -10
- package/libx/_runtime/db/generic/rewrite.js +5 -2
- package/libx/_runtime/db/generic/structured.js +2 -2
- package/libx/_runtime/db/query/delete.js +2 -2
- package/libx/_runtime/db/query/insert.js +1 -1
- package/libx/_runtime/db/query/update.js +9 -14
- package/libx/_runtime/db/sql-builder/CreateBuilder.js +4 -3
- package/libx/_runtime/db/sql-builder/InsertBuilder.js +14 -1
- package/libx/_runtime/db/sql-builder/SelectBuilder.js +3 -2
- package/libx/_runtime/db/sql-builder/dataTypes.js +3 -3
- package/libx/_runtime/db/utils/columns.js +3 -3
- package/libx/_runtime/db/utils/normalizeTimeData.js +2 -2
- package/libx/_runtime/db/utils/propagateForeignKeys.js +6 -2
- package/libx/_runtime/extensibility/mps/index.js +5 -0
- package/libx/_runtime/extensibility/mps/service.js +111 -0
- package/libx/_runtime/extensibility/mps/tar.js +42 -0
- package/libx/_runtime/extensibility/mps/utils.js +11 -0
- package/libx/_runtime/{fiori → extensibility}/uiflex/handler/transformREAD.js +0 -0
- package/libx/_runtime/{fiori → extensibility}/uiflex/handler/transformRESULT.js +17 -5
- package/libx/_runtime/{fiori → extensibility}/uiflex/handler/transformWRITE.js +1 -0
- package/libx/_runtime/extensibility/uiflex/index.js +54 -0
- package/libx/_runtime/extensibility/uiflex/service.js +276 -0
- package/libx/_runtime/{fiori → extensibility}/uiflex/utils.js +22 -7
- package/libx/_runtime/fiori/generic/activate.js +2 -2
- package/libx/_runtime/fiori/generic/before.js +4 -4
- package/libx/_runtime/fiori/generic/new.js +3 -3
- package/libx/_runtime/fiori/generic/patch.js +1 -1
- package/libx/_runtime/fiori/generic/read.js +58 -66
- package/libx/_runtime/fiori/generic/readOverDraft.js +71 -16
- package/libx/_runtime/fiori/utils/handler.js +6 -13
- package/libx/_runtime/fiori/utils/where.js +6 -5
- package/libx/_runtime/hana/Service.js +4 -10
- package/libx/_runtime/hana/customBuilder/CustomSelectBuilder.js +2 -2
- package/libx/_runtime/hana/driver.js +2 -2
- package/libx/_runtime/hana/execute.js +29 -75
- package/libx/_runtime/hana/pool.js +1 -1
- package/libx/_runtime/hana/streaming.js +2 -1
- package/libx/_runtime/index.js +6 -6
- package/libx/_runtime/messaging/AMQPWebhookMessaging.js +5 -21
- package/libx/_runtime/messaging/Outbox.js +2 -2
- package/libx/_runtime/messaging/common-utils/AMQPClient.js +4 -14
- package/libx/_runtime/messaging/common-utils/connections.js +5 -7
- package/libx/_runtime/messaging/common-utils/normalizeIncomingMessage.js +30 -0
- package/libx/_runtime/messaging/enterprise-messaging-shared.js +2 -1
- package/libx/_runtime/messaging/enterprise-messaging-utils/EMManagement.js +36 -30
- package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +19 -12
- package/libx/_runtime/messaging/enterprise-messaging.js +8 -8
- package/libx/_runtime/messaging/file-based.js +5 -5
- package/libx/_runtime/messaging/message-queuing.js +14 -12
- package/libx/_runtime/messaging/outbox/utils.js +18 -19
- package/libx/_runtime/messaging/redis-messaging.js +91 -0
- package/libx/_runtime/messaging/service.js +8 -6
- package/libx/_runtime/remote/Service.js +44 -8
- package/libx/_runtime/remote/utils/client.js +25 -13
- package/libx/_runtime/remote/utils/data.js +11 -11
- package/libx/_runtime/sqlite/Service.js +6 -9
- package/libx/_runtime/sqlite/customBuilder/CustomFunctionBuilder.js +5 -2
- package/libx/_runtime/types/api.js +10 -2
- package/libx/common/utils/ucsn.js +109 -0
- package/libx/gql/resolvers/crud/create.js +6 -1
- package/libx/gql/resolvers/crud/delete.js +6 -1
- package/libx/gql/resolvers/crud/read.js +6 -1
- package/libx/gql/resolvers/crud/update.js +9 -1
- package/libx/gql/resolvers/parse/ast2cqn/columns.js +3 -1
- package/libx/gql/schema/typeDefMap.js +2 -2
- package/libx/odata/afterburner.js +110 -16
- package/libx/odata/grammar.pegjs +9 -1
- package/libx/odata/parseToCqn.js +39 -0
- package/libx/odata/parser.js +1 -1
- package/libx/rest/RestAdapter.js +9 -1
- package/libx/rest/middleware/input.js +54 -0
- package/libx/rest/middleware/operation.js +14 -1
- package/libx/rest/middleware/parse.js +11 -7
- package/package.json +1 -1
- package/server.js +34 -19
- package/srv/audit-log.cds +2 -2
- package/srv/flex.cds +8 -2
- package/srv/flex.js +1 -1
- package/srv/mps.cds +23 -0
- package/srv/mps.js +1 -0
- package/libx/_runtime/auth/strategies/utils/uaa.js +0 -21
- package/libx/_runtime/common/generic/auth.js +0 -874
- package/libx/_runtime/common/toggles/alpha.js +0 -43
- package/libx/_runtime/db/generic/arrayed.js +0 -33
- package/libx/_runtime/fiori/uiflex/index.js +0 -35
- package/libx/_runtime/fiori/uiflex/service.js +0 -150
- package/libx/rest/utils/data.js +0 -60
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const cds = require('../../cds')
|
|
2
|
+
const resolveStructured = require('../../common/utils/resolveStructured')
|
|
2
3
|
|
|
3
4
|
const { ensureNoDraftsSuffix } = require('./draft')
|
|
4
5
|
|
|
@@ -140,6 +141,7 @@ const findCsnTargetFor = (edmName, model, namespace) => {
|
|
|
140
141
|
// probably, a combination of '_' and '.', resolving
|
|
141
142
|
const finding = _findRootEntity(model, edmName, namespace)
|
|
142
143
|
target = finding.target
|
|
144
|
+
|
|
143
145
|
// something left in navigation path => x4 navigation
|
|
144
146
|
// resolving within found entity
|
|
145
147
|
if (target && finding.left > 0) {
|
|
@@ -151,10 +153,12 @@ const findCsnTargetFor = (edmName, model, namespace) => {
|
|
|
151
153
|
}
|
|
152
154
|
}
|
|
153
155
|
}
|
|
156
|
+
|
|
154
157
|
// remember edm <-> csn
|
|
155
158
|
if (target) {
|
|
156
159
|
mapping[edmName] = target
|
|
157
160
|
}
|
|
161
|
+
|
|
158
162
|
return mapping[edmName]
|
|
159
163
|
}
|
|
160
164
|
|
|
@@ -191,7 +195,40 @@ const isRootEntity = (definitions, entityName) => {
|
|
|
191
195
|
return true
|
|
192
196
|
}
|
|
193
197
|
|
|
198
|
+
function _alias2RefRest(service) {
|
|
199
|
+
for (const each of Object.values(service.entities)) {
|
|
200
|
+
each._alias2ref = {}
|
|
201
|
+
const keys = each.keys
|
|
202
|
+
for (const key in keys) {
|
|
203
|
+
if (keys[key].elements) {
|
|
204
|
+
const structKeys = resolveStructured({ structName: key, structProperties: [] }, keys[key].elements, false, true)
|
|
205
|
+
for (const structKey of structKeys) {
|
|
206
|
+
if (each._alias2ref[structKey.key] != null) {
|
|
207
|
+
// key clash, aliasing not possible
|
|
208
|
+
each._alias2ref = {}
|
|
209
|
+
return
|
|
210
|
+
}
|
|
211
|
+
each._alias2ref[structKey.key] = structKey.resolved
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const prefixForStruct = element => {
|
|
219
|
+
const prefixes = []
|
|
220
|
+
let parent = element.parent
|
|
221
|
+
while (parent && parent.kind !== 'entity') {
|
|
222
|
+
prefixes.push(parent.name)
|
|
223
|
+
parent = parent.parent
|
|
224
|
+
}
|
|
225
|
+
return prefixes.length ? prefixes.reverse().join('_') + '_' : ''
|
|
226
|
+
}
|
|
227
|
+
|
|
194
228
|
function alias2ref(service, edm) {
|
|
229
|
+
if (!edm) {
|
|
230
|
+
return _alias2RefRest(service)
|
|
231
|
+
}
|
|
195
232
|
const defs = edm[service.definition.name]
|
|
196
233
|
for (const each of Object.values(service.entities)) {
|
|
197
234
|
const def = defs[each.name.replace(service.definition.name + '.', '').replace(/\./g, '_')]
|
|
@@ -205,6 +242,29 @@ function alias2ref(service, edm) {
|
|
|
205
242
|
}
|
|
206
243
|
}
|
|
207
244
|
|
|
245
|
+
function getDraftTreeRoot(entity, model) {
|
|
246
|
+
if (entity.own('__draftTreeRoot')) return entity.__draftTreeRoot
|
|
247
|
+
|
|
248
|
+
let parent
|
|
249
|
+
let current = entity
|
|
250
|
+
while (current && !current['@Common.DraftRoot.ActivationAction']) {
|
|
251
|
+
const parents = []
|
|
252
|
+
for (const k in model.definitions) {
|
|
253
|
+
const e = model.definitions[k]
|
|
254
|
+
if (e.kind !== 'entity' || !e.compositions) continue
|
|
255
|
+
for (const c in e.compositions) if (e.compositions[c].target === current.name) parents.push(e)
|
|
256
|
+
}
|
|
257
|
+
if (parents.length > 1 && parents.some(p => p !== parents[0])) {
|
|
258
|
+
// > unable to determine single parent
|
|
259
|
+
parent = undefined
|
|
260
|
+
break
|
|
261
|
+
}
|
|
262
|
+
current = parent = parents[0]
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return entity.set('__draftTreeRoot', parent)
|
|
266
|
+
}
|
|
267
|
+
|
|
208
268
|
module.exports = {
|
|
209
269
|
getEtagElement,
|
|
210
270
|
findCsnTargetFor,
|
|
@@ -212,5 +272,7 @@ module.exports = {
|
|
|
212
272
|
isRootEntity,
|
|
213
273
|
getDataSubject,
|
|
214
274
|
alias2ref,
|
|
215
|
-
getComp2oneParents
|
|
275
|
+
getComp2oneParents,
|
|
276
|
+
prefixForStruct,
|
|
277
|
+
getDraftTreeRoot
|
|
216
278
|
}
|
|
@@ -11,7 +11,16 @@ module.exports = (entryOrRow, keyOrIndex, user, timestamp) => {
|
|
|
11
11
|
else if (entryOrRow[keyOrIndex] === '$now') entryOrRow[keyOrIndex] = timestamp
|
|
12
12
|
else if (entryOrRow[keyOrIndex] === '$uuid') entryOrRow[keyOrIndex] = cds.utils.uuid()
|
|
13
13
|
else if (typeof entryOrRow[keyOrIndex] === 'string') {
|
|
14
|
+
// NOTE: with xsuaa, user attributes are always arrays
|
|
14
15
|
const attr = entryOrRow[keyOrIndex].match(/^\$user\.(.*)/)
|
|
15
|
-
if (attr && attr.length > 1)
|
|
16
|
+
if (attr && attr.length > 1) {
|
|
17
|
+
const val = (user.attr && user.attr[attr[1]]) || null
|
|
18
|
+
if (Array.isArray(val)) {
|
|
19
|
+
if (val.length > 1) entryOrRow[keyOrIndex] = JSON.stringify(val)
|
|
20
|
+
else entryOrRow[keyOrIndex] = val.length > 0 ? val[0] : null
|
|
21
|
+
} else {
|
|
22
|
+
entryOrRow[keyOrIndex] = val
|
|
23
|
+
}
|
|
24
|
+
}
|
|
16
25
|
}
|
|
17
26
|
}
|
|
@@ -18,18 +18,57 @@ const ensureUnlocalized = table => {
|
|
|
18
18
|
return _table
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
const ensureDraftsSuffix = name => {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
21
|
+
const ensureDraftsSuffix = name => (name.endsWith('_drafts') ? name : `${ensureUnlocalized(name)}_drafts`)
|
|
22
|
+
|
|
23
|
+
const ensureNoDraftsSuffix = name => name.replace(/_drafts$/g, '')
|
|
25
24
|
|
|
26
|
-
|
|
25
|
+
const getDraftColumnsCQNForActive = target => {
|
|
26
|
+
const draftName = ensureDraftsSuffix(target.name)
|
|
27
|
+
const subSelect = SELECT.from(draftName).columns([1])
|
|
28
|
+
for (const key in target.keys) {
|
|
29
|
+
if (key !== 'IsActiveEntity') subSelect.where([{ ref: [target.name, key] }, '=', { ref: [draftName, key] }])
|
|
30
|
+
}
|
|
31
|
+
return [
|
|
32
|
+
{ val: true, as: 'IsActiveEntity', cast: { type: 'cds.Boolean' } },
|
|
33
|
+
{ val: false, as: 'HasActiveEntity', cast: { type: 'cds.Boolean' } },
|
|
34
|
+
{
|
|
35
|
+
xpr: ['case', 'when', 'exists', subSelect, 'then', 'true', 'else', 'false', 'end'],
|
|
36
|
+
as: 'HasDraftEntity',
|
|
37
|
+
cast: { type: 'cds.Boolean' }
|
|
38
|
+
}
|
|
39
|
+
]
|
|
27
40
|
}
|
|
28
41
|
|
|
29
|
-
const
|
|
42
|
+
const getDraftColumnsCQNForDraft = target => {
|
|
43
|
+
/*
|
|
44
|
+
* NOTE: the following with xpr could be used to detect if there really is an active or not, but that breaks tests
|
|
45
|
+
*/
|
|
46
|
+
// const activeName = ensureNoDraftsSuffix(target.name)
|
|
47
|
+
// const subSelect = SELECT.from(activeName).columns([1])
|
|
48
|
+
// for (const key in target.keys) {
|
|
49
|
+
// if (key !== 'IsActiveEntity') subSelect.where([{ ref: [target.name, key] }, '=', { ref: [activeName, key] }])
|
|
50
|
+
// }
|
|
51
|
+
// return [
|
|
52
|
+
// { val: false, as: 'IsActiveEntity', cast: { type: 'cds.Boolean' } },
|
|
53
|
+
// {
|
|
54
|
+
// xpr: ['case', 'when', 'exists', subSelect, 'then', 'true', 'else', 'false', 'end'],
|
|
55
|
+
// as: 'HasActiveEntity',
|
|
56
|
+
// cast: { type: 'cds.Boolean' }
|
|
57
|
+
// },
|
|
58
|
+
// { val: false, as: 'HasDraftEntity', cast: { type: 'cds.Boolean' } }
|
|
59
|
+
// ]
|
|
60
|
+
|
|
61
|
+
return [
|
|
62
|
+
{ val: false, as: 'IsActiveEntity', cast: { type: 'cds.Boolean' } },
|
|
63
|
+
{ ref: ['HasActiveEntity'], cast: { type: 'cds.Boolean' } },
|
|
64
|
+
{ val: false, as: 'HasDraftEntity', cast: { type: 'cds.Boolean' } }
|
|
65
|
+
]
|
|
66
|
+
}
|
|
30
67
|
|
|
31
68
|
module.exports = {
|
|
32
69
|
ensureUnlocalized,
|
|
33
70
|
ensureDraftsSuffix,
|
|
34
|
-
ensureNoDraftsSuffix
|
|
71
|
+
ensureNoDraftsSuffix,
|
|
72
|
+
getDraftColumnsCQNForActive,
|
|
73
|
+
getDraftColumnsCQNForDraft
|
|
35
74
|
}
|
|
@@ -1,23 +1,26 @@
|
|
|
1
1
|
const { ensureNoDraftsSuffix } = require('../../common/utils/draft')
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const traverseFroms = (cqn, cb) => {
|
|
4
4
|
while (cqn.SELECT) cqn = cqn.SELECT.from
|
|
5
5
|
|
|
6
6
|
// Do the most likely first -> {ref}
|
|
7
7
|
if (cqn.ref) {
|
|
8
|
-
return
|
|
8
|
+
return cb(cqn)
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
// TODO cleanup
|
|
12
|
-
// REVISIT infer should do this for req.target
|
|
13
|
-
// REVISIT2 No, req.target doesn't make sense for joins
|
|
14
11
|
if (cqn.SET) {
|
|
15
|
-
return cqn.SET.args.map(
|
|
12
|
+
return cqn.SET.args.map(a => traverseFroms(a, cb))
|
|
16
13
|
}
|
|
14
|
+
|
|
17
15
|
if (cqn.join) {
|
|
18
|
-
return cqn.args.map(
|
|
16
|
+
return cqn.args.map(a => traverseFroms(a, cb))
|
|
19
17
|
}
|
|
20
|
-
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const getEntityNameFromCQN = cqn => {
|
|
21
|
+
const res = []
|
|
22
|
+
traverseFroms(cqn, from => res.push({ entityName: from.ref[0].id || from.ref[0], alias: from.as }))
|
|
23
|
+
return res.length === 1 ? res[0] : res.find(n => n.entityName !== 'DRAFT.DraftAdministrativeData') || {}
|
|
21
24
|
}
|
|
22
25
|
|
|
23
26
|
// Note: This also works for the common draft scenarios
|
|
@@ -31,5 +34,6 @@ const getEntityFromCQN = (req, service) => {
|
|
|
31
34
|
|
|
32
35
|
module.exports = {
|
|
33
36
|
getEntityFromCQN,
|
|
34
|
-
getEntityNameFromCQN
|
|
37
|
+
getEntityNameFromCQN,
|
|
38
|
+
traverseFroms
|
|
35
39
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const optionsApp = require('./vcap.js')
|
|
2
|
+
|
|
3
|
+
const BASE_TENANT = 'anonymous'
|
|
4
|
+
|
|
5
|
+
const channelName = () => {
|
|
6
|
+
// REVISIT: Why so complicated?
|
|
7
|
+
|
|
8
|
+
const appName = optionsApp.appName || 'CAP'
|
|
9
|
+
const appID = optionsApp.appID || '00000000'
|
|
10
|
+
const shrunkAppID = appID.substring(0, 4)
|
|
11
|
+
|
|
12
|
+
return `${appName}/${shrunkAppID}`
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
module.exports = {
|
|
16
|
+
BASE_TENANT,
|
|
17
|
+
channelName
|
|
18
|
+
}
|
|
@@ -60,8 +60,7 @@ const _foreignKeyPropagationsFromToManyOn = (element, childFieldName) => {
|
|
|
60
60
|
const foreignKeys = _foreignKeysForTarget(element, childFieldName)
|
|
61
61
|
// REVISIT foreignKeys is empty if we have deep operations where a sub element is annotated with persistence skip
|
|
62
62
|
if (foreignKeys && foreignKeys.length) {
|
|
63
|
-
|
|
64
|
-
return _resolvedKeys(parentKeys, foreignKeys, true)
|
|
63
|
+
return _resolvedKeys(foreignKeys, true)
|
|
65
64
|
}
|
|
66
65
|
return []
|
|
67
66
|
}
|
|
@@ -118,62 +117,11 @@ const _foreignKeyPropagationsFromOn = element => {
|
|
|
118
117
|
return foreignKeyPropagations
|
|
119
118
|
}
|
|
120
119
|
|
|
121
|
-
/*
|
|
122
|
-
* recursive resolvedKeys for a structured element
|
|
123
|
-
* returns how many indexes can be skipped in the outer loop
|
|
124
|
-
* example:
|
|
125
|
-
* foo: {
|
|
126
|
-
* bar: {
|
|
127
|
-
* moo: Integer;
|
|
128
|
-
* shu: Integer;
|
|
129
|
-
* };
|
|
130
|
-
* baz: Integer;
|
|
131
|
-
* };
|
|
132
|
-
* -> foo_bar_moo, foo_bar_shu, foo_baz
|
|
133
|
-
* -> processed three instead of one from outer loop perspective
|
|
134
|
-
*/
|
|
135
|
-
const _resolve4struct = (others, struct, fkps, fillChild, childIsStruct, i) => {
|
|
136
|
-
let j = 0
|
|
137
|
-
|
|
138
|
-
for (const k in struct.elements) {
|
|
139
|
-
const other = others[i + j]
|
|
140
|
-
const current = struct.elements[k]
|
|
141
|
-
|
|
142
|
-
if (current._isStructured) {
|
|
143
|
-
// call recursive and increment skip
|
|
144
|
-
j += _resolve4struct(others, current, fkps, fillChild, childIsStruct, i + j)
|
|
145
|
-
} else if (current.isAssociation) {
|
|
146
|
-
continue
|
|
147
|
-
} else {
|
|
148
|
-
// calc prefix
|
|
149
|
-
let prefix = struct.name
|
|
150
|
-
let cur = struct.parent
|
|
151
|
-
while (cur._isStructured) {
|
|
152
|
-
prefix = cur.name + '_' + prefix
|
|
153
|
-
cur = cur.parent
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// push propagation
|
|
157
|
-
fkps.push({
|
|
158
|
-
childElement: childIsStruct ? current : other,
|
|
159
|
-
parentElement: childIsStruct ? other : current,
|
|
160
|
-
fillChild,
|
|
161
|
-
prefix,
|
|
162
|
-
deep: !fillChild && _resolveTargetForeignKey(childIsStruct ? current : other)
|
|
163
|
-
})
|
|
164
|
-
|
|
165
|
-
// increment skip
|
|
166
|
-
j++
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
return j
|
|
171
|
-
}
|
|
172
|
-
|
|
173
120
|
const _resolveTargetForeignKey = targetKey => {
|
|
174
|
-
const targetName = targetKey
|
|
121
|
+
const targetName = targetKey._foreignKey4
|
|
175
122
|
if (!targetName) return
|
|
176
|
-
const
|
|
123
|
+
const parentElements = targetKey.parent.elements
|
|
124
|
+
const _foreignKeyProps = foreignKeyPropagations(parentElements[targetName])
|
|
177
125
|
const propagation = _foreignKeyProps.find(_fkp => _fkp.parentElement && targetKey.name === _fkp.parentElement.name)
|
|
178
126
|
return { targetName, propagation }
|
|
179
127
|
}
|
|
@@ -184,39 +132,22 @@ const _resolveColumnsFromQuery = query => {
|
|
|
184
132
|
return []
|
|
185
133
|
}
|
|
186
134
|
|
|
187
|
-
const _resolvedKeys = (
|
|
188
|
-
const
|
|
135
|
+
const _resolvedKeys = (keys, fillChild) => {
|
|
136
|
+
const foreignKeys = fillChild ? keys.map(fk => Object.getPrototypeOf(fk)) : keys
|
|
137
|
+
const targetKeys = fillChild ? keys : keys.map(fk => Object.getPrototypeOf(fk))
|
|
189
138
|
|
|
139
|
+
const foreignKeyPropagations = []
|
|
190
140
|
for (let i = 0; i < foreignKeys.length; i++) {
|
|
191
141
|
const fk = foreignKeys[i]
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
*/
|
|
200
|
-
const tkCol = _resolveColumnsFromQuery(targetKeys[i].parent.query).find(
|
|
201
|
-
c => c.ref && `${fk['@odata.foreignKey4']}_${c.ref.join('_')}` === fk.name
|
|
202
|
-
)
|
|
203
|
-
tk = tkCol && targetKeys.find(tk => tk.name === (tkCol.as ? tkCol.as : tkCol.ref.join('_')))
|
|
204
|
-
// with composition of aspects, the lookup fails -> we need this final fallback
|
|
205
|
-
if (!tk) tk = targetKeys[i]
|
|
206
|
-
|
|
207
|
-
if (fk._isStructured) {
|
|
208
|
-
i += _resolve4struct(targetKeys, fk, foreignKeyPropagations, fillChild, false, i)
|
|
209
|
-
} else if (tk._isStructured) {
|
|
210
|
-
i += _resolve4struct(foreignKeys, tk, foreignKeyPropagations, fillChild, true, i)
|
|
211
|
-
} else {
|
|
212
|
-
foreignKeyPropagations.push({
|
|
213
|
-
fillChild,
|
|
214
|
-
parentElement: fk,
|
|
215
|
-
childElement: tk,
|
|
216
|
-
// needed only for child -> parent propagation since template loops in other direction
|
|
217
|
-
deep: !fillChild && _resolveTargetForeignKey(tk)
|
|
218
|
-
})
|
|
142
|
+
const tk = targetKeys[i]
|
|
143
|
+
const propagation = {
|
|
144
|
+
fillChild,
|
|
145
|
+
parentElement: fk,
|
|
146
|
+
childElement: tk,
|
|
147
|
+
// needed only for child -> parent propagation since template loops in other direction
|
|
148
|
+
deep: !fillChild && _resolveTargetForeignKey(tk)
|
|
219
149
|
}
|
|
150
|
+
foreignKeyPropagations.push(propagation)
|
|
220
151
|
}
|
|
221
152
|
|
|
222
153
|
return foreignKeyPropagations
|
|
@@ -229,10 +160,7 @@ const foreignKeyPropagations = element => {
|
|
|
229
160
|
if (element.is2one) {
|
|
230
161
|
if (!element.on) {
|
|
231
162
|
const foreignKeys = _foreignKeys(element)
|
|
232
|
-
if (foreignKeys)
|
|
233
|
-
const targetKeys = _targetKeys(element)
|
|
234
|
-
return _resolvedKeys(foreignKeys, targetKeys)
|
|
235
|
-
}
|
|
163
|
+
if (foreignKeys) return _resolvedKeys(foreignKeys, false)
|
|
236
164
|
} else {
|
|
237
165
|
// It's a link through a backlink
|
|
238
166
|
return _foreignKeyPropagationsFromOn(element)
|
|
@@ -241,29 +169,85 @@ const foreignKeyPropagations = element => {
|
|
|
241
169
|
return []
|
|
242
170
|
}
|
|
243
171
|
|
|
244
|
-
|
|
245
|
-
|
|
172
|
+
// REVISIT: Flattening shouldn't be necessary in the future.
|
|
173
|
+
// It's better to deal with structures instead, but
|
|
174
|
+
// that would require changing a lot of code.
|
|
175
|
+
const _foreignKeys = element => {
|
|
176
|
+
const foreignKeys = element.foreignKeys
|
|
177
|
+
const path = [element.name]
|
|
178
|
+
const parent = element.parent
|
|
179
|
+
const result = []
|
|
180
|
+
_addToForeignKeysRec(foreignKeys, path, parent, result)
|
|
181
|
+
return result
|
|
246
182
|
}
|
|
247
183
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
184
|
+
/*
|
|
185
|
+
* REVISIT: poor man's look-up of target key
|
|
186
|
+
* Look at elements, then try to find it in query and resolve recursively until you have the full path.
|
|
187
|
+
* Once you have the full path, you can find it in the target entity.
|
|
188
|
+
* NOTE: There can be projections upon projections and renamings in every projection. -> not yet covered!!!
|
|
189
|
+
*/
|
|
190
|
+
const _poorMansLookup = (el, name, foreignKeySource) => {
|
|
191
|
+
// REVISIT: Dirty hack
|
|
192
|
+
const tkCol = _resolveColumnsFromQuery(el.parent.query).find(
|
|
193
|
+
c => c.ref && `${foreignKeySource}_${c.ref.join('_')}` === name
|
|
252
194
|
)
|
|
195
|
+
return tkCol && Object.values(el.parent.elements).find(tk => tk.name === (tkCol.as ? tkCol.as : tkCol.ref.join('_')))
|
|
253
196
|
}
|
|
254
197
|
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
)
|
|
198
|
+
const _createForeignKey = (name, el, parent, foreignKeySource) => {
|
|
199
|
+
const tk = _poorMansLookup(el, name, foreignKeySource)
|
|
200
|
+
const navigationCsn = parent.elements[foreignKeySource]
|
|
201
|
+
const foreignKeyCsn = Object.assign(Object.create(tk || el), { parent, name, foreignKeySource })
|
|
202
|
+
// annotation propagation is not possible via prototyping
|
|
203
|
+
for (const key of Object.keys(navigationCsn).filter(key => key.startsWith('@')))
|
|
204
|
+
foreignKeyCsn[key] = navigationCsn[key]
|
|
205
|
+
return foreignKeyCsn
|
|
259
206
|
}
|
|
260
207
|
|
|
261
|
-
const
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
208
|
+
const _addToForeignKeysRec = (elements, path, parent, result) => {
|
|
209
|
+
for (const elName in elements) {
|
|
210
|
+
const el = elements[elName]
|
|
211
|
+
const foreignKeySource = path[0]
|
|
212
|
+
const newPath = [...path, elName]
|
|
213
|
+
if (el.isAssociation) {
|
|
214
|
+
const foreignKeysOftarget = _foreignKeys(el)
|
|
215
|
+
for (const fk of foreignKeysOftarget) {
|
|
216
|
+
const name = [...path, fk.name].join('_')
|
|
217
|
+
if (result.some(x => x.name === name)) return
|
|
218
|
+
const foreignKeyCsn = _createForeignKey(name, fk, parent, foreignKeySource)
|
|
219
|
+
result.push(foreignKeyCsn)
|
|
220
|
+
}
|
|
221
|
+
} else if (!el.elements) {
|
|
222
|
+
const name = newPath.join('_')
|
|
223
|
+
if (result.some(x => x.name === name)) return
|
|
224
|
+
const foreignKeyCsn = _createForeignKey(name, el, parent, foreignKeySource)
|
|
225
|
+
result.push(foreignKeyCsn)
|
|
226
|
+
} else _addToForeignKeysRec(el.elements, newPath, parent, result)
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const _foreignKeysForTarget = (csnElement, name) => {
|
|
231
|
+
const target = csnElement._target.elements[name || csnElement.name]
|
|
232
|
+
return _foreignKeys(target)
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const foreignKey4 = element => {
|
|
236
|
+
if (!element || !element.parent) return
|
|
237
|
+
const parentElements = element.parent.elements
|
|
238
|
+
for (const assoc of Object.keys(parentElements)
|
|
239
|
+
.map(n => parentElements[n])
|
|
240
|
+
.filter(e => e.isAssociation)) {
|
|
241
|
+
const foreignKeys = _foreignKeys(assoc)
|
|
242
|
+
if (!foreignKeys.length) continue
|
|
243
|
+
const target = foreignKeys.find(fk => fk.name === element.name)
|
|
244
|
+
if (target) {
|
|
245
|
+
return target && target.foreignKeySource
|
|
246
|
+
}
|
|
247
|
+
}
|
|
265
248
|
}
|
|
266
249
|
|
|
267
250
|
module.exports = {
|
|
268
|
-
foreignKeyPropagations
|
|
251
|
+
foreignKeyPropagations,
|
|
252
|
+
foreignKey4
|
|
269
253
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
+
const { prefixForStruct } = require('./csn')
|
|
2
|
+
|
|
1
3
|
const _toRef = (alias, column) => {
|
|
2
4
|
if (Array.isArray(column)) column = column.join('_')
|
|
3
5
|
return { ref: alias ? [alias, column] : [column] }
|
|
4
6
|
}
|
|
5
7
|
|
|
6
8
|
const _adaptRefs = (onCond, path, { select, join }) => {
|
|
7
|
-
const
|
|
9
|
+
const _adaptEl = el => {
|
|
8
10
|
const ref = el.ref
|
|
9
|
-
|
|
10
11
|
if (ref) {
|
|
11
12
|
if (ref[0] === path.join('_') && ref[1]) {
|
|
12
13
|
return _toRef(select, ref.slice(1))
|
|
@@ -18,12 +19,13 @@ const _adaptRefs = (onCond, path, { select, join }) => {
|
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
return _toRef(join, ref.slice(0))
|
|
22
|
+
} else if (el.xpr) {
|
|
23
|
+
return { xpr: el.xpr.map(_adaptEl) }
|
|
21
24
|
}
|
|
22
25
|
|
|
23
26
|
return el
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return adaptedOnCondition
|
|
27
|
+
}
|
|
28
|
+
return onCond.map(_adaptEl)
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
const _args = (csnElement, path, aliases) => {
|
|
@@ -73,7 +75,8 @@ const _foreignToOn = (csnElement, path, { select, join }) => {
|
|
|
73
75
|
if (on.length !== 0) {
|
|
74
76
|
on.push('and')
|
|
75
77
|
}
|
|
76
|
-
const
|
|
78
|
+
const prefixChild = prefixForStruct(key.childElement)
|
|
79
|
+
const ref1 = _toRef(select, prefixChild + key.childElement.name)
|
|
77
80
|
const structPrefix = path.length > 1 ? path.slice(0, -1) : []
|
|
78
81
|
const ref2 = _toRef(join, [...structPrefix, key.parentElement.name])
|
|
79
82
|
on.push(ref1, '=', ref2)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const _flattenProps = (subElement, structName, structProperties, structElement, asRef) => {
|
|
1
|
+
const _flattenProps = (subElement, structName, structProperties, structElement, asRef, withKey) => {
|
|
2
2
|
if (subElement.elements) {
|
|
3
3
|
return _resolveStructured(
|
|
4
4
|
{
|
|
@@ -6,34 +6,50 @@ const _flattenProps = (subElement, structName, structProperties, structElement,
|
|
|
6
6
|
structProperties: structProperties.slice(1)
|
|
7
7
|
},
|
|
8
8
|
subElement.elements,
|
|
9
|
-
asRef
|
|
9
|
+
asRef,
|
|
10
|
+
withKey
|
|
10
11
|
)
|
|
11
12
|
} else if (subElement.isAssociation) {
|
|
12
13
|
if (structProperties.length && subElement.is2one && !subElement.on) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
: [
|
|
14
|
+
const flattenedName = `${structName}_${structProperties.join('_')}`
|
|
15
|
+
if (withKey) {
|
|
16
|
+
return [{ key: structElement, resolved: [flattenedName] }]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return asRef ? [{ ref: [flattenedName] }] : [flattenedName]
|
|
16
20
|
}
|
|
17
21
|
|
|
18
22
|
return []
|
|
19
23
|
}
|
|
20
|
-
|
|
24
|
+
const flattenedName = `${structName}_${structElement}`
|
|
25
|
+
if (withKey) {
|
|
26
|
+
return [{ key: structElement, resolved: [flattenedName] }]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return asRef ? [{ ref: [flattenedName] }] : [flattenedName]
|
|
21
30
|
}
|
|
22
31
|
|
|
23
|
-
const _resolveStructured = ({ structName, structProperties }, subElements, asRef = true) => {
|
|
32
|
+
const _resolveStructured = ({ structName, structProperties }, subElements, asRef = true, withKey = false) => {
|
|
24
33
|
if (!subElements) {
|
|
25
34
|
return []
|
|
26
35
|
}
|
|
27
36
|
|
|
28
37
|
// only add from structProperties
|
|
29
38
|
if (structProperties.length) {
|
|
30
|
-
return _flattenProps(
|
|
39
|
+
return _flattenProps(
|
|
40
|
+
subElements[structProperties[0]],
|
|
41
|
+
structName,
|
|
42
|
+
structProperties,
|
|
43
|
+
structProperties[0],
|
|
44
|
+
asRef,
|
|
45
|
+
withKey
|
|
46
|
+
)
|
|
31
47
|
}
|
|
32
48
|
|
|
33
49
|
const flattenedElements = []
|
|
34
50
|
for (const structElement in subElements) {
|
|
35
51
|
flattenedElements.push(
|
|
36
|
-
..._flattenProps(subElements[structElement], structName, structProperties, structElement, asRef)
|
|
52
|
+
..._flattenProps(subElements[structElement], structName, structProperties, structElement, asRef, withKey)
|
|
37
53
|
)
|
|
38
54
|
}
|
|
39
55
|
return flattenedElements
|
|
@@ -346,7 +346,10 @@ const _newSelect = (query, transitions, service) => {
|
|
|
346
346
|
}
|
|
347
347
|
if (!newSelect.columns && targetTransition.mapping.size) newSelect.columns = _initialColumns(targetTransition)
|
|
348
348
|
if (newSelect.columns) {
|
|
349
|
-
rewriteAsterisks({ SELECT: query.SELECT }, service.model, {
|
|
349
|
+
rewriteAsterisks({ SELECT: query.SELECT }, service.model, {
|
|
350
|
+
_4db: service instanceof cds.DatabaseService,
|
|
351
|
+
target: targetTransition.queryTarget
|
|
352
|
+
})
|
|
350
353
|
newSelect.columns = _newColumns(newSelect.columns, targetTransition, service, service.kind !== 'app-service')
|
|
351
354
|
}
|
|
352
355
|
if (newSelect.having) newSelect.having = _newColumns(newSelect.having, targetTransition)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const { getNavigationIfStruct } = require('./structured')
|
|
2
2
|
const getColumns = require('../../db/utils/columns')
|
|
3
|
-
const {
|
|
3
|
+
const { ensureNoDraftsSuffix, getDraftColumnsCQNForActive } = require('./draft')
|
|
4
4
|
const { getEntityNameFromCQN } = require('./entityFromCqn')
|
|
5
5
|
|
|
6
6
|
const isAsteriskColumn = col => col === '*' || (col.ref && col.ref[0] === '*' && !col.expand)
|
|
@@ -14,20 +14,7 @@ const _isDuplicate = newColumn => column => {
|
|
|
14
14
|
|
|
15
15
|
const _cqlDraftColumns = target => {
|
|
16
16
|
if (target.name.endsWith('DraftAdministrativeData')) return []
|
|
17
|
-
|
|
18
|
-
const subSelect = SELECT.from(draftName).columns([1])
|
|
19
|
-
for (const key in target.keys) {
|
|
20
|
-
if (key !== 'IsActiveEntity') subSelect.where([{ ref: [target.name, key] }, '=', { ref: [draftName, key] }])
|
|
21
|
-
}
|
|
22
|
-
return [
|
|
23
|
-
{ val: true, as: 'IsActiveEntity', cast: { type: 'cds.Boolean' } },
|
|
24
|
-
{ val: false, as: 'HasActiveEntity', cast: { type: 'cds.Boolean' } },
|
|
25
|
-
{
|
|
26
|
-
xpr: ['case', 'when', 'exists', subSelect, 'then', 'true', 'else', 'false', 'end'],
|
|
27
|
-
as: 'HasDraftEntity',
|
|
28
|
-
cast: { type: 'cds.Boolean' }
|
|
29
|
-
}
|
|
30
|
-
]
|
|
17
|
+
return getDraftColumnsCQNForActive(target)
|
|
31
18
|
}
|
|
32
19
|
|
|
33
20
|
const _expandColumn = (column, target, _4db) => {
|
|
@@ -135,7 +122,7 @@ const rewriteAsterisks = (query, model, options) => {
|
|
|
135
122
|
return
|
|
136
123
|
}
|
|
137
124
|
|
|
138
|
-
const target = _targetOfQueryIfNotDraft(query, model)
|
|
125
|
+
const target = options.target || _targetOfQueryIfNotDraft(query, model)
|
|
139
126
|
if (!target) return
|
|
140
127
|
|
|
141
128
|
// REVISIT: Also support JOINs/SETs here
|