@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
|
@@ -7,6 +7,7 @@ const replaceManagedData = require('../utils/dollar')
|
|
|
7
7
|
const { deepCopyArray } = require('../utils/copy')
|
|
8
8
|
|
|
9
9
|
const onlyKeysRemain = require('../utils/onlyKeysRemain')
|
|
10
|
+
const { getColumns } = require('../../cds-services/services/utils/columns')
|
|
10
11
|
|
|
11
12
|
const _targetEntityDoesNotExist = async req => {
|
|
12
13
|
const { query } = req
|
|
@@ -29,12 +30,13 @@ const _processorFn = req => {
|
|
|
29
30
|
const { event, user, timestamp } = req
|
|
30
31
|
const ts = new Date(timestamp).toISOString()
|
|
31
32
|
|
|
32
|
-
return ({ row, key, plain }) => {
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
for (const category of categories) {
|
|
36
|
-
if (category === '@cds.on.update' || (event === 'CREATE' && category === '@cds.on.insert')) {
|
|
33
|
+
return ({ row, key, plain, isRoot }) => {
|
|
34
|
+
for (const category of plain.categories) {
|
|
35
|
+
if (event === 'CREATE' && category === '@cds.on.insert') {
|
|
37
36
|
replaceManagedData(row, key, user, ts)
|
|
37
|
+
} else if (category === '@cds.on.update') {
|
|
38
|
+
if (isRoot) replaceManagedData(row, key, user, ts)
|
|
39
|
+
else if (row[key] === '$user' || row[key] === '$now') delete row[key]
|
|
38
40
|
}
|
|
39
41
|
}
|
|
40
42
|
}
|
|
@@ -92,16 +94,18 @@ module.exports = cds.service.impl(function () {
|
|
|
92
94
|
if (res.length === 0) req.reject(404)
|
|
93
95
|
}
|
|
94
96
|
|
|
97
|
+
// REVISIT: remove block with cds^6 (i.e., update_managed_properties is always true)
|
|
95
98
|
// no changes, no op (otherwise, @cds.on.update gets new values), but we need to check existence
|
|
96
|
-
if (req.event === 'UPDATE' && onlyKeysRemain(req)) {
|
|
99
|
+
if (cds.env.features.update_managed_properties === false && req.event === 'UPDATE' && onlyKeysRemain(req)) {
|
|
97
100
|
if (await _targetEntityDoesNotExist(req)) req.reject(404)
|
|
98
101
|
result = req.data
|
|
99
102
|
}
|
|
100
103
|
|
|
101
|
-
if (req.event
|
|
102
|
-
if (!req.target['@odata.singleton.nullable']) req.reject(400, 'SINGLETON_NOT_NULLABLE')
|
|
103
|
-
|
|
104
|
-
const
|
|
104
|
+
if (req.event in { DELETE: 1, UPDATE: 1 } && req.target && req.target._isSingleton) {
|
|
105
|
+
if (req.event === 'DELETE' && !req.target['@odata.singleton.nullable']) req.reject(400, 'SINGLETON_NOT_NULLABLE')
|
|
106
|
+
const keyColumns = getColumns(req.target, { onlyNames: true, keysOnly: true })
|
|
107
|
+
const selectSingleton = SELECT.one(req.target).columns(keyColumns)
|
|
108
|
+
const singleton = await cds.tx(req).run(selectSingleton)
|
|
105
109
|
if (!singleton) req.reject(404)
|
|
106
110
|
req.query.where(singleton)
|
|
107
111
|
}
|
|
@@ -34,9 +34,8 @@ const getSimpleCategory = category => {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
const rowKeysGenerator = eventName => {
|
|
37
|
+
if (eventName === 'UPDATE') return
|
|
37
38
|
return (keyNames, row, template) => {
|
|
38
|
-
if (eventName === 'UPDATE') return
|
|
39
|
-
|
|
40
39
|
for (const keyName of keyNames) {
|
|
41
40
|
if (Object.prototype.hasOwnProperty.call(row, keyName)) {
|
|
42
41
|
continue
|
|
@@ -59,7 +58,10 @@ const _isDraftCoreComputed = (req, element, event) =>
|
|
|
59
58
|
element['@Core.Computed'] &&
|
|
60
59
|
!((event === 'CREATE' && element['@cds.on.insert']) || element['@cds.on.update'])
|
|
61
60
|
|
|
62
|
-
const
|
|
61
|
+
const _isStreamingProperty = (elements, row, property) =>
|
|
62
|
+
Object.values(elements).some(
|
|
63
|
+
element => element['@Core.MediaType'] && element['@Core.MediaType']['='] === property && row[element.name]
|
|
64
|
+
)
|
|
63
65
|
|
|
64
66
|
const _getMediaTypeValue = req =>
|
|
65
67
|
req._.req &&
|
|
@@ -101,15 +103,15 @@ const _processCategory = ({ row, key, category, isRoot, event, value, req, eleme
|
|
|
101
103
|
}
|
|
102
104
|
|
|
103
105
|
// set media type from content-type header if streaming
|
|
104
|
-
const
|
|
106
|
+
const isStreaming = _isStreamingProperty(element.parent.elements, row, key)
|
|
105
107
|
const mtValue = _getMediaTypeValue(req)
|
|
106
|
-
if (category === 'stream' &&
|
|
108
|
+
if (category === 'stream' && isStreaming && mtValue) row[key] = mtValue
|
|
107
109
|
}
|
|
108
110
|
|
|
109
111
|
const processorFn = (errors, req) => {
|
|
110
112
|
const { event } = req
|
|
111
113
|
|
|
112
|
-
return ({ row, key, element, plain, isRoot,
|
|
114
|
+
return ({ row, key, element, plain, isRoot, path }) => {
|
|
113
115
|
const categories = plain.categories
|
|
114
116
|
// ugly pointer passing for sonar
|
|
115
117
|
const value = { mandatory: false, val: row && row[key] }
|
|
@@ -123,7 +125,7 @@ const processorFn = (errors, req) => {
|
|
|
123
125
|
}
|
|
124
126
|
|
|
125
127
|
// REVISIT: Convert checkInputConstraints to template mechanism
|
|
126
|
-
checkInputConstraints({ element, value: value.val, errors,
|
|
128
|
+
checkInputConstraints({ element, value: value.val, errors, path, event })
|
|
127
129
|
}
|
|
128
130
|
}
|
|
129
131
|
|
|
@@ -153,11 +155,11 @@ const _pick = element => {
|
|
|
153
155
|
categories.push('associationEffective')
|
|
154
156
|
}
|
|
155
157
|
|
|
156
|
-
if (element.key && !DRAFT_COLUMNS_MAP[element.name] && element.
|
|
158
|
+
if (element.key && !DRAFT_COLUMNS_MAP[element.name] && element.isUUID) {
|
|
157
159
|
categories.push('uuid')
|
|
158
160
|
}
|
|
159
161
|
|
|
160
|
-
if (element['@Core.
|
|
162
|
+
if (element['@Core.IsMediaType']) categories.push('stream')
|
|
161
163
|
|
|
162
164
|
if (categories.length) return { categories }
|
|
163
165
|
}
|
|
@@ -188,38 +190,34 @@ function _handler(req) {
|
|
|
188
190
|
if (template.elements.size === 0) return
|
|
189
191
|
|
|
190
192
|
const errors = []
|
|
193
|
+
const args = {
|
|
194
|
+
processFn: processorFn(errors, req),
|
|
195
|
+
template,
|
|
196
|
+
pathOptions: {
|
|
197
|
+
rowKeysGenerator: rowKeysGenerator(req.event),
|
|
198
|
+
includeKeyValues: true,
|
|
199
|
+
path: []
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
if (_isBoundAction(req)) {
|
|
203
|
+
const pathSegment = _getBoundActionBindingParameter(req)
|
|
204
|
+
const keys = req._ && req._.params && req._.params[0]
|
|
205
|
+
if (pathSegment) {
|
|
206
|
+
args.pathOptions.path.push({ key: pathSegment, url: pathSegment })
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (keys && 'IsActiveEntity' in keys) {
|
|
210
|
+
args.pathOptions.extraKeys = { IsActiveEntity: keys.IsActiveEntity }
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
191
214
|
const data = getDataFromCQN(req.query) // REVISIT: req.data should point into req.query
|
|
192
215
|
|
|
193
216
|
enrichDataWithKeysFromWhere(data, req, this)
|
|
194
217
|
|
|
195
218
|
const arrayData = Array.isArray(data) ? data : [data]
|
|
196
219
|
for (const row of arrayData) {
|
|
197
|
-
|
|
198
|
-
let extraKeys
|
|
199
|
-
|
|
200
|
-
if (_isBoundAction(req)) {
|
|
201
|
-
const pathSegment = _getBoundActionBindingParameter(req)
|
|
202
|
-
const keys = req._ && req._.params && req._.params[0]
|
|
203
|
-
pathSegments = pathSegment ? [pathSegment] : []
|
|
204
|
-
|
|
205
|
-
if (keys && 'IsActiveEntity' in keys) {
|
|
206
|
-
extraKeys = { IsActiveEntity: keys.IsActiveEntity }
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
const args = {
|
|
211
|
-
processFn: processorFn(errors, req),
|
|
212
|
-
row,
|
|
213
|
-
template,
|
|
214
|
-
pathOptions: {
|
|
215
|
-
extraKeys,
|
|
216
|
-
rowKeysGenerator: rowKeysGenerator(req.event),
|
|
217
|
-
segments: pathSegments,
|
|
218
|
-
includeKeyValues: true
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
templateProcessor(args)
|
|
220
|
+
templateProcessor(Object.assign(args, { row }))
|
|
223
221
|
}
|
|
224
222
|
|
|
225
223
|
setDataFromCQN(req) // REVISIT: req.data should point into req.query
|
|
@@ -257,6 +255,7 @@ const _processActionFunctionRow = (row, param, key, errors, event, service) => {
|
|
|
257
255
|
const _processActionFunction = (row, eventParams, errors, event, service) => {
|
|
258
256
|
for (const key in eventParams) {
|
|
259
257
|
let param = eventParams[key]
|
|
258
|
+
// .type of action/function behaves different to .type of other csn elements
|
|
260
259
|
const _type = param.type
|
|
261
260
|
if (!_type && param.items) param = param.items
|
|
262
261
|
_processActionFunctionRow(row, param, key, errors, event, service)
|
|
@@ -292,6 +291,7 @@ function _actionFunctionHandler(req) {
|
|
|
292
291
|
// REVISIT: find better solution, maybe compiler?
|
|
293
292
|
// resolve enums like format, range, etc.
|
|
294
293
|
for (const param of Object.values(eventParams)) {
|
|
294
|
+
// .type of action/function behaves different to .type of other csn elements
|
|
295
295
|
const _type = param.type && this.model && this.model.definitions[param.type]
|
|
296
296
|
if (_type) {
|
|
297
297
|
param.enum = _type.enum
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
const cds = require('../../cds')
|
|
2
2
|
const LOG = cds.log('app')
|
|
3
3
|
const { getAllKeys } = require('../../cds-services/adapter/odata-v4/odata-to-cqn/utils')
|
|
4
|
-
|
|
5
|
-
const DRAFT_COLUMNS = ['IsActiveEntity', 'HasDraftEntity', 'HasActiveEntity']
|
|
4
|
+
const { DRAFT_COLUMNS_MAP } = require('../../common/constants/draft')
|
|
6
5
|
|
|
7
6
|
const _getStaticOrders = req => {
|
|
8
7
|
const { target: entity, query } = req
|
|
@@ -20,7 +19,7 @@ const _getStaticOrders = req => {
|
|
|
20
19
|
if (cds.env.features.implicit_sorting !== false && (req.target._isSingleton || query.SELECT.limit)) {
|
|
21
20
|
const keys = getAllKeys(entity, true)
|
|
22
21
|
for (const key of keys) {
|
|
23
|
-
if (!
|
|
22
|
+
if (!(key in DRAFT_COLUMNS_MAP) && !defaultOrders.some(o => o.by['='] === key)) {
|
|
24
23
|
ordersFromKeys.push({ by: { '=': key } })
|
|
25
24
|
}
|
|
26
25
|
}
|
|
@@ -21,14 +21,14 @@ const _getTimeDelta = (target, queryOption) => {
|
|
|
21
21
|
|
|
22
22
|
if (
|
|
23
23
|
_isDate(queryOption) ||
|
|
24
|
-
Object.values(target.elements).some(el => el['@cds.valid.from'] && el.
|
|
24
|
+
Object.values(target.elements).some(el => el['@cds.valid.from'] && el._type === 'cds.Date')
|
|
25
25
|
) {
|
|
26
26
|
return 1000 * 60 * 60 * 24
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
if (
|
|
30
30
|
_isTimestamp(queryOption) &&
|
|
31
|
-
Object.values(target.elements).some(el => el['@cds.valid.from'] && el.
|
|
31
|
+
Object.values(target.elements).some(el => el['@cds.valid.from'] && el._type === 'cds.Timestamp')
|
|
32
32
|
) {
|
|
33
33
|
return 1
|
|
34
34
|
}
|
|
@@ -2,7 +2,6 @@ const fs = require('fs')
|
|
|
2
2
|
const path = require('path')
|
|
3
3
|
|
|
4
4
|
const cds = require('../../cds')
|
|
5
|
-
const LOG = cds.log('app')
|
|
6
5
|
|
|
7
6
|
const dirs = (cds.env.i18n && cds.env.i18n.folders) || []
|
|
8
7
|
|
|
@@ -50,36 +49,8 @@ function init(locale, file) {
|
|
|
50
49
|
if (!file) file = findFile(locale)
|
|
51
50
|
if (!file) return
|
|
52
51
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
raw = fs.readFileSync(file, 'utf-8')
|
|
56
|
-
} catch (e) {
|
|
57
|
-
if (LOG._warn) {
|
|
58
|
-
e.message = `Unable to load file "${file}" for locale "${locale}" due to error: ` + e.message
|
|
59
|
-
LOG.warn(e)
|
|
60
|
-
}
|
|
61
|
-
return
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
try {
|
|
65
|
-
const pairs = raw
|
|
66
|
-
.replace(/\r/g, '')
|
|
67
|
-
.split(/\n/)
|
|
68
|
-
.map(ele => ele.trim())
|
|
69
|
-
.filter(ele => ele && !ele.startsWith('#'))
|
|
70
|
-
.map(ele => {
|
|
71
|
-
const del = ele.indexOf('=')
|
|
72
|
-
return [ele.slice(0, del), ele.slice(del + 1)].map(ele => ele.trim())
|
|
73
|
-
})
|
|
74
|
-
for (const [key, value] of pairs) {
|
|
75
|
-
i18ns[locale][key] = value
|
|
76
|
-
}
|
|
77
|
-
} catch (e) {
|
|
78
|
-
if (LOG._warn) {
|
|
79
|
-
e.message = `Unable to process file "${file}" for locale "${locale}" due to error: ` + e.message
|
|
80
|
-
LOG.warn(e)
|
|
81
|
-
}
|
|
82
|
-
}
|
|
52
|
+
const props = cds.load.properties(file)
|
|
53
|
+
i18ns[locale] = props
|
|
83
54
|
}
|
|
84
55
|
|
|
85
56
|
init('default', path.join(__dirname, 'messages.properties'))
|
|
@@ -71,7 +71,7 @@ ENTITY_IS_INSERT_ONLY=Entity "{0}" is insert-only
|
|
|
71
71
|
ENTITY_IS_READ_ONLY=Entity "{0}" is read-only
|
|
72
72
|
ENTITY_IS_NOT_CRUD=Entity "{0}" is not {1}
|
|
73
73
|
ENTITY_IS_NOT_CRUD_VIA_NAVIGATION=Entity "{0}" is not {1} via association "{2}"
|
|
74
|
-
ENTITY_IS_AUTOEXPOSED=Entity "{0}" is not
|
|
74
|
+
ENTITY_IS_AUTOEXPOSED=Entity "{0}" is not explicitly exposed as part of the service
|
|
75
75
|
EXPAND_IS_RESTRICTED=Navigation property "{0}" is not allowed for expand operation
|
|
76
76
|
EXPAND_COUNT_UNSUPPORTED="$count" is not supported for expand operation
|
|
77
77
|
ORDERBY_LAMBDA_UNSUPPORTED="$orderby" does not support lambda
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* addition for feature toggles
|
|
3
|
+
*/
|
|
4
|
+
module.exports = cds => {
|
|
5
|
+
if (!cds.requires.toggles) return (req, res, next) => next()
|
|
6
|
+
|
|
7
|
+
return (req, res, next) => {
|
|
8
|
+
// inject features from dwc header
|
|
9
|
+
const fth = req.headers['dwc-product-configuration']
|
|
10
|
+
if (fth) {
|
|
11
|
+
const { features } = JSON.parse(Buffer.from(fth, 'base64').toString('utf-8'))
|
|
12
|
+
req.features = features
|
|
13
|
+
.filter(f => f.enabled)
|
|
14
|
+
.map(f => f.name)
|
|
15
|
+
.sort((a, b) => a.localeCompare(b))
|
|
16
|
+
Object.freeze(req.features)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
next()
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -29,7 +29,16 @@ const deepCopyObject = obj => {
|
|
|
29
29
|
return clone
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
const deepCopy = data => {
|
|
33
|
+
if (Array.isArray(data)) {
|
|
34
|
+
return deepCopyArray(data)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return deepCopyObject(data)
|
|
38
|
+
}
|
|
39
|
+
|
|
32
40
|
module.exports = {
|
|
33
41
|
deepCopyObject,
|
|
34
|
-
deepCopyArray
|
|
42
|
+
deepCopyArray,
|
|
43
|
+
deepCopy
|
|
35
44
|
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
/* eslint-disable complexity */
|
|
2
|
+
|
|
1
3
|
const cds = require('../../cds')
|
|
2
4
|
const { SELECT, INSERT, DELETE, UPDATE } = cds.ql
|
|
3
5
|
const Query = require('../../../../lib/ql/Query')
|
|
4
6
|
|
|
5
7
|
const { resolveView } = require('./resolveView')
|
|
6
|
-
const { ensureNoDraftsSuffix } = require('./draft')
|
|
8
|
+
const { ensureNoDraftsSuffix, getDraftColumnsCQNForDraft } = require('./draft')
|
|
7
9
|
const { flattenStructuredSelect } = require('./structured')
|
|
8
10
|
const search2cqn4sql = require('./search2cqn4sql')
|
|
9
11
|
const { getEntityNameFromCQN } = require('./entityFromCqn')
|
|
@@ -14,8 +16,12 @@ const { addToWhere } = require('../../common/utils/cqn')
|
|
|
14
16
|
const { removeIsActiveEntityRecursively } = require('../../fiori/utils/where')
|
|
15
17
|
const { addRefToWhereIfNecessary } = require('../../../odata/afterburner')
|
|
16
18
|
const { addAliasToExpression, PARENT_ALIAS, FOREIGN_ALIAS } = require('../../db/utils/generateAliases')
|
|
19
|
+
const { getColumns } = require('../../cds-services/services/utils/columns')
|
|
17
20
|
|
|
18
|
-
const
|
|
21
|
+
const OPERATIONS_MAP = ['=', '>', '<', '!=', '<>', '>=', '<=', 'like', 'between', 'in', 'not in'].reduce((acc, cur) => {
|
|
22
|
+
acc[cur] = 1
|
|
23
|
+
return acc
|
|
24
|
+
}, {})
|
|
19
25
|
|
|
20
26
|
const _elementFromRef = (name, entity) => {
|
|
21
27
|
if (!entity) return
|
|
@@ -104,7 +110,7 @@ const convertPathExpressionToWhere = (fromClause, model, options) => {
|
|
|
104
110
|
}
|
|
105
111
|
}
|
|
106
112
|
|
|
107
|
-
const
|
|
113
|
+
const _convertPathExpressionForInsert = (intoClause, model) => {
|
|
108
114
|
// .into is plain string or csn entity
|
|
109
115
|
if (typeof intoClause === 'string' || intoClause.name) {
|
|
110
116
|
return intoClause
|
|
@@ -177,10 +183,7 @@ const _getWindColumns = (columns, groupBy, bottomTop) => {
|
|
|
177
183
|
return [].concat(columns, _getWindowXpr(groupBy, bottomTop))
|
|
178
184
|
}
|
|
179
185
|
|
|
180
|
-
const _convertCountNavigation = (SELECT,
|
|
181
|
-
const entityName = SELECT.from.ref[0].id || SELECT.from.ref[0]
|
|
182
|
-
const entity = model.definitions[entityName]
|
|
183
|
-
|
|
186
|
+
const _convertCountNavigation = (SELECT, target) => {
|
|
184
187
|
const newWhere = []
|
|
185
188
|
for (let i = 0; i < SELECT.where.length; i++) {
|
|
186
189
|
const element = SELECT.where[i]
|
|
@@ -192,8 +195,8 @@ const _convertCountNavigation = (SELECT, model) => {
|
|
|
192
195
|
|
|
193
196
|
const navigations = element.args[0].ref
|
|
194
197
|
const navigationName = navigations[0].id || navigations[0]
|
|
195
|
-
if (
|
|
196
|
-
let currentEntity =
|
|
198
|
+
if (target.elements[navigationName]) {
|
|
199
|
+
let currentEntity = target
|
|
197
200
|
let topQuery
|
|
198
201
|
let lastQuery
|
|
199
202
|
|
|
@@ -344,7 +347,7 @@ const _getWhereExistsSubSelect = (queryTarget, outerAlias, innerAlias, ref, mode
|
|
|
344
347
|
}
|
|
345
348
|
|
|
346
349
|
subSelect.where(queryTarget._relations[navName].join(innerAlias, outerAlias))
|
|
347
|
-
if (cds.env.effective.odata.structs) {
|
|
350
|
+
if (cds.env.effective.odata.structs || cds.env.features.ucsn_struct_conversion) {
|
|
348
351
|
flattenStructuredSelect(subSelect, model)
|
|
349
352
|
}
|
|
350
353
|
subSelect.columns([{ val: 1 }])
|
|
@@ -459,7 +462,7 @@ const convertWhereExists = (query, model, options, currentTarget) => {
|
|
|
459
462
|
}
|
|
460
463
|
|
|
461
464
|
if (element.xpr) {
|
|
462
|
-
convertWhereExists({ ...query, where: element.xpr }, model, options) // > recursing into nested {xpr}
|
|
465
|
+
convertWhereExists({ ...query, where: element.xpr }, model, options, currentTarget) // > recursing into nested {xpr}
|
|
463
466
|
} else if (element === 'exists' && where[i + 1].ref) {
|
|
464
467
|
if (query.from) {
|
|
465
468
|
query.from.as = outerAlias
|
|
@@ -551,7 +554,7 @@ const _convertOrderByIfSkip = (orderByCQN, index) => {
|
|
|
551
554
|
|
|
552
555
|
const _convertWhereIfSkip = (whereCQN, index) => {
|
|
553
556
|
whereCQN.splice(index, 1, '1 = 1')
|
|
554
|
-
|
|
557
|
+
whereCQN[index + 1] in OPERATIONS_MAP ? whereCQN.splice(index + 1, 2) : whereCQN.splice(index - 2, 2)
|
|
555
558
|
}
|
|
556
559
|
|
|
557
560
|
const _convertOrderByOrWhereCQN = (orderByOrWhereCQN, target, model, alias, processFn) => {
|
|
@@ -564,7 +567,7 @@ const _convertOrderByOrWhereCQN = (orderByOrWhereCQN, target, model, alias, proc
|
|
|
564
567
|
|
|
565
568
|
const _convertOrderByOrWhereIfSkip = (cqn, target, model) => {
|
|
566
569
|
const alias = cqn.SELECT.from.as
|
|
567
|
-
if (cqn.SELECT.orderBy && cqn.SELECT.orderBy.length
|
|
570
|
+
if (cqn.SELECT.orderBy && cqn.SELECT.orderBy.length) {
|
|
568
571
|
_convertOrderByOrWhereCQN(cqn.SELECT.orderBy, target, model, alias, _convertOrderByIfSkip)
|
|
569
572
|
}
|
|
570
573
|
|
|
@@ -659,7 +662,11 @@ const _convertPathExpression = (SELECT, model, options = {}) => {
|
|
|
659
662
|
// Okra always wants to have the key values, remove once we relax this requirement
|
|
660
663
|
if (model.definitions[target] && model.definitions[target].keys) {
|
|
661
664
|
SELECT.columns = Object.keys(model.definitions[target].keys)
|
|
662
|
-
.filter(
|
|
665
|
+
.filter(
|
|
666
|
+
k =>
|
|
667
|
+
!model.definitions[target].keys[k].isAssociation &&
|
|
668
|
+
!columns.find(element => element.ref && element.ref[element.ref.length - 1] === k)
|
|
669
|
+
)
|
|
663
670
|
.map(k => ({ ref: [k] }))
|
|
664
671
|
} else SELECT.columns = []
|
|
665
672
|
}
|
|
@@ -679,6 +686,33 @@ const _convertPathExpression = (SELECT, model, options = {}) => {
|
|
|
679
686
|
}
|
|
680
687
|
}
|
|
681
688
|
|
|
689
|
+
const _convertToOneEqNullInFilter = (query, target) => {
|
|
690
|
+
// we do not handle join or union
|
|
691
|
+
if (!target) return
|
|
692
|
+
|
|
693
|
+
for (let i = 0; i < query.where.length; i++) {
|
|
694
|
+
const w = query.where[i]
|
|
695
|
+
const w2 = query.where[i + 2]
|
|
696
|
+
if (!w2 || !w.ref || w2.val !== null) {
|
|
697
|
+
continue
|
|
698
|
+
}
|
|
699
|
+
const element = target.elements[w.ref[w.ref.length - 1]]
|
|
700
|
+
if (element && element.is2one && !element.on) {
|
|
701
|
+
const foreignKeys = Object.values(element.parent.elements).filter(e => e._foreignKey4 === element.name)
|
|
702
|
+
const replacedKeys = foreignKeys.reduce((arr, e, idx) => {
|
|
703
|
+
arr.push({ ref: [...w.ref.slice(0, w.ref.length - 1), e.name] }, query.where[i + 1], query.where[i + 2])
|
|
704
|
+
if (idx < foreignKeys.length - 1) {
|
|
705
|
+
arr.push('and')
|
|
706
|
+
}
|
|
707
|
+
return arr
|
|
708
|
+
}, [])
|
|
709
|
+
|
|
710
|
+
query.where.splice(i, 3, '(', ...replacedKeys, ')')
|
|
711
|
+
i += replacedKeys.length + 2
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
|
|
682
716
|
// eslint-disable-next-line complexity
|
|
683
717
|
const _convertSelect = (query, model, _options) => {
|
|
684
718
|
const options = Object.assign(
|
|
@@ -688,6 +722,7 @@ const _convertSelect = (query, model, _options) => {
|
|
|
688
722
|
},
|
|
689
723
|
_options
|
|
690
724
|
)
|
|
725
|
+
|
|
691
726
|
// ensure query is ql enabled
|
|
692
727
|
if (!(query instanceof Query)) Object.setPrototypeOf(query, Object.getPrototypeOf(SELECT()))
|
|
693
728
|
if (query.SELECT.from && query.SELECT.from.SELECT) {
|
|
@@ -709,8 +744,14 @@ const _convertSelect = (query, model, _options) => {
|
|
|
709
744
|
|
|
710
745
|
_convertPathExpression(query.SELECT, model, options)
|
|
711
746
|
rewriteAsterisks(query, model, options)
|
|
712
|
-
if (query.SELECT.where
|
|
713
|
-
|
|
747
|
+
if (query.SELECT.where) {
|
|
748
|
+
const entityName =
|
|
749
|
+
(query.SELECT.from.ref && (query.SELECT.from.ref[0].id || query.SELECT.from.ref[0])) || query.SELECT.from
|
|
750
|
+
const target = model.definitions[entityName]
|
|
751
|
+
if (_isCountNavigation(query.SELECT.where)) {
|
|
752
|
+
_convertCountNavigation(query.SELECT, target)
|
|
753
|
+
}
|
|
754
|
+
_convertToOneEqNullInFilter(query.SELECT, target)
|
|
714
755
|
}
|
|
715
756
|
|
|
716
757
|
// extract where clause if it is in column expand ref
|
|
@@ -727,7 +768,7 @@ const _convertSelect = (query, model, _options) => {
|
|
|
727
768
|
search2cqn4sql(query, model, { ...query._searchOptions, ...{ entityName, alias } })
|
|
728
769
|
}
|
|
729
770
|
|
|
730
|
-
if (query.SELECT.columns && cds.env.effective.odata.structs) {
|
|
771
|
+
if (query.SELECT.columns && (cds.env.effective.odata.structs || cds.env.features.ucsn_struct_conversion)) {
|
|
731
772
|
flattenStructuredSelect(query, model)
|
|
732
773
|
}
|
|
733
774
|
|
|
@@ -736,30 +777,43 @@ const _convertSelect = (query, model, _options) => {
|
|
|
736
777
|
_createWindowCQN(query.SELECT, model)
|
|
737
778
|
}
|
|
738
779
|
|
|
780
|
+
// best-effort ensure columns
|
|
781
|
+
if (options._4db && !query.SELECT.columns) {
|
|
782
|
+
let target = query._target
|
|
783
|
+
if (target && target._unresolved && typeof target.name === 'string') {
|
|
784
|
+
target = model.definitions[ensureNoDraftsSuffix(target.name)] || target
|
|
785
|
+
}
|
|
786
|
+
if (target && !target._unresolved) {
|
|
787
|
+
const cols = getColumns(target, { onlyNames: true })
|
|
788
|
+
query.columns(cols)
|
|
789
|
+
if (target._isDraftEnabled && query._target._unresolved) {
|
|
790
|
+
query.SELECT.columns.push(...getDraftColumnsCQNForDraft(target))
|
|
791
|
+
query.SELECT.columns.push({ ref: ['DraftAdministrativeData_DraftUUID'] })
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
|
|
739
796
|
return query
|
|
740
797
|
}
|
|
741
798
|
|
|
742
799
|
const _convertInsert = (query, model, options) => {
|
|
743
800
|
// resolve path expression
|
|
744
|
-
const resolvedIntoClause =
|
|
801
|
+
const resolvedIntoClause = _convertPathExpressionForInsert(query.INSERT.into, model)
|
|
745
802
|
|
|
746
803
|
// overwrite only .into, foreign keys are already set
|
|
747
|
-
|
|
804
|
+
// 'a' added as placeholder since its overwritten by Object.assign below
|
|
805
|
+
const insert = INSERT.into('a')
|
|
748
806
|
|
|
749
807
|
// REVISIT flatten structured types, currently its done in SQL builder
|
|
750
808
|
|
|
751
809
|
// We add all previous properties ot the newly created query.
|
|
752
810
|
// Reason is to not lose the query API functionality
|
|
753
|
-
Object.assign(insert.INSERT, query.INSERT, { into: resolvedIntoClause })
|
|
754
|
-
|
|
755
|
-
const targetName = insert.INSERT.into.name || insert.INSERT.into
|
|
811
|
+
Object.assign(insert.INSERT, query.INSERT, { into: { ref: [resolvedIntoClause], as: query.INSERT.into.as } })
|
|
756
812
|
|
|
757
|
-
const target = model.definitions[
|
|
813
|
+
const target = model.definitions[resolvedIntoClause]
|
|
758
814
|
if (!target) return insert
|
|
759
815
|
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
return resolvedView
|
|
816
|
+
return resolveView(insert, model, cds.db)
|
|
763
817
|
}
|
|
764
818
|
|
|
765
819
|
function _modifyNavigationInWhere(whereClause, target) {
|
|
@@ -783,6 +837,11 @@ function _modifyNavigationInWhere(whereClause, target) {
|
|
|
783
837
|
const _plainDelete = (cqn, model) => {
|
|
784
838
|
const name = cqn.DELETE.from.name || (cqn.DELETE.from.ref && cqn.DELETE.from.ref[0]) || cqn.DELETE.from
|
|
785
839
|
const target = model.definitions[name]
|
|
840
|
+
|
|
841
|
+
if (cqn.DELETE.where) {
|
|
842
|
+
_convertToOneEqNullInFilter(cqn.DELETE, target)
|
|
843
|
+
}
|
|
844
|
+
|
|
786
845
|
if (!target) return cqn
|
|
787
846
|
|
|
788
847
|
return resolveView(cqn, model, cds.db)
|
|
@@ -804,9 +863,13 @@ const _convertDelete = (query, model, options) => {
|
|
|
804
863
|
|
|
805
864
|
if (alias) deleet.DELETE.from = { ref: [target], as: alias }
|
|
806
865
|
if (where) deleet.where(where)
|
|
807
|
-
if (query.DELETE.where) deleet.where(addAliasToExpression(query.DELETE.where, alias))
|
|
808
866
|
|
|
809
867
|
const targetEntity = model.definitions[target]
|
|
868
|
+
if (query.DELETE.where) {
|
|
869
|
+
deleet.where(addAliasToExpression(query.DELETE.where, alias))
|
|
870
|
+
_convertToOneEqNullInFilter(deleet.DELETE, targetEntity)
|
|
871
|
+
}
|
|
872
|
+
|
|
810
873
|
if (!targetEntity) return deleet
|
|
811
874
|
|
|
812
875
|
return resolveView(deleet, model, cds.db)
|
|
@@ -815,6 +878,11 @@ const _convertDelete = (query, model, options) => {
|
|
|
815
878
|
function _plainUpdate(cqn, model) {
|
|
816
879
|
const name = cqn.UPDATE.entity.name || (cqn.UPDATE.entity.ref && cqn.UPDATE.entity.ref[0]) || cqn.UPDATE.entity
|
|
817
880
|
const target = model.definitions[name]
|
|
881
|
+
|
|
882
|
+
if (cqn.UPDATE.where) {
|
|
883
|
+
_convertToOneEqNullInFilter(cqn.UPDATE, target)
|
|
884
|
+
}
|
|
885
|
+
|
|
818
886
|
if (!target) return cqn
|
|
819
887
|
|
|
820
888
|
return resolveView(cqn, model, cds.db)
|
|
@@ -841,9 +909,12 @@ const _convertUpdate = (query, model, options) => {
|
|
|
841
909
|
|
|
842
910
|
if (alias) update.UPDATE.entity = { ref: [target], as: alias }
|
|
843
911
|
if (where) update.where(where)
|
|
844
|
-
if (query.UPDATE.where) update.where(addAliasToExpression(query.UPDATE.where, alias))
|
|
845
|
-
|
|
846
912
|
const targetEntity = model.definitions[target]
|
|
913
|
+
if (query.UPDATE.where) {
|
|
914
|
+
update.where(addAliasToExpression(query.UPDATE.where, alias))
|
|
915
|
+
_convertToOneEqNullInFilter(update.UPDATE, targetEntity)
|
|
916
|
+
}
|
|
917
|
+
|
|
847
918
|
if (!targetEntity) return update
|
|
848
919
|
|
|
849
920
|
return resolveView(update, model, cds.db)
|