@sap/cds 5.8.3 → 5.9.1
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 +193 -77
- package/app/fiori/preview.js +16 -11
- package/app/fiori/routes.js +15 -8
- 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 +17 -18
- 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 +10 -3
- package/bin/utils/modules.js +7 -0
- package/bin/version.js +56 -3
- package/lib/compile/cdsc.js +7 -2
- 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/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 +1 -1
- 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-server/deserializer/DeserializerFactory.js +2 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/invocation/DispatcherCommand.js +2 -6
- 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 +51 -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/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 +5 -2
- 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 -412
- 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/FunctionBuilder.js +8 -8
- 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 +1 -1
- package/libx/_runtime/hana/driver.js +2 -2
- package/libx/_runtime/hana/execute.js +27 -74
- 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 +24 -19
- 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/update.js +5 -0
- 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/cqn2odata.js +24 -27
- 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 +2 -2
- 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,43 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* additions for feature toggles
|
|
3
|
-
*/
|
|
4
|
-
module.exports = cds => {
|
|
5
|
-
if (!cds.env.features.alpha_toggles) return (req, res, next) => next()
|
|
6
|
-
|
|
7
|
-
return (req, res, next) => {
|
|
8
|
-
// attach _getHash helper to mtx
|
|
9
|
-
if (!cds.mtx._getHash) {
|
|
10
|
-
cds.mtx._getHash = req => {
|
|
11
|
-
let hash = req.tenant
|
|
12
|
-
if (req.features) hash += ':' + Object.keys(req.features).join(';')
|
|
13
|
-
return hash
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// inject features from dwc header
|
|
18
|
-
const fth = req.headers['dwc-product-configuration']
|
|
19
|
-
if (fth) {
|
|
20
|
-
const { features } = JSON.parse(Buffer.from(fth, 'base64').toString('utf-8'))
|
|
21
|
-
req.features = features
|
|
22
|
-
.sort((a, b) => a.name.localeCompare(b.name))
|
|
23
|
-
.reduce((acc, cur) => {
|
|
24
|
-
if (cur.enabled) acc[cur.name] = 1
|
|
25
|
-
return acc
|
|
26
|
-
}, {})
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// extend @sap/cds's dispatch listener
|
|
30
|
-
const {
|
|
31
|
-
eventEmitter: mtx,
|
|
32
|
-
events: { TENANT_UPDATED }
|
|
33
|
-
} = cds.mtx
|
|
34
|
-
req.on('dispatch', req => {
|
|
35
|
-
// clear ext map for next request as soon as it was dispatched
|
|
36
|
-
mtx.emit(TENANT_UPDATED, cds.mtx._getHash(req._.req))
|
|
37
|
-
// set cds.context.features here so we don't need to touch @sap/cds
|
|
38
|
-
cds.context.features = req._.req.features
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
next()
|
|
42
|
-
}
|
|
43
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
const { getEntityFromCQN } = require('../../common/utils/entityFromCqn')
|
|
2
|
-
const getTemplate = require('../../common/utils/template')
|
|
3
|
-
const templateProcessor = require('../../common/utils/templateProcessor')
|
|
4
|
-
|
|
5
|
-
const _pick = element => {
|
|
6
|
-
if (element.kind === 'element' && element.items) return 'arrayed'
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const _processFn = ({ row, key, plain }) => {
|
|
10
|
-
if (plain === 'arrayed' && row && row[key] && (typeof row[key] === 'string' || Buffer.isBuffer(row[key]))) {
|
|
11
|
-
row[key] = JSON.parse(row[key])
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Formats JSON Strings to arrayed data
|
|
17
|
-
*
|
|
18
|
-
* @param result - the result of the DB query
|
|
19
|
-
* @param req - the context object
|
|
20
|
-
* @returns {Promise}
|
|
21
|
-
*/
|
|
22
|
-
module.exports = function (result, req) {
|
|
23
|
-
if (!this.model) return
|
|
24
|
-
|
|
25
|
-
const entity = getEntityFromCQN(req, this)
|
|
26
|
-
if (!entity) return
|
|
27
|
-
|
|
28
|
-
const template = getTemplate('db-arrayed', this, entity, { pick: _pick })
|
|
29
|
-
if (template.elements.size === 0) return
|
|
30
|
-
|
|
31
|
-
for (const row of Array.isArray(result) ? result : [result])
|
|
32
|
-
templateProcessor({ processFn: _processFn, row, template })
|
|
33
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
module.exports = async () => {
|
|
2
|
-
const cds = require('../../cds')
|
|
3
|
-
if (!cds.requires.db) return
|
|
4
|
-
|
|
5
|
-
const db = await cds.connect.to({ ...cds.requires.db, model: null, silent: true })
|
|
6
|
-
const rs = await db.read('cds_r.Extensions')
|
|
7
|
-
if (rs.length !== 0) {
|
|
8
|
-
const extensions = []
|
|
9
|
-
rs.forEach(row => extensions.push(...JSON.parse(row.csn).extensions))
|
|
10
|
-
cds.once('loaded', csn => {
|
|
11
|
-
if (cds.model) return // extend cds.model only
|
|
12
|
-
const extended = cds.compile({
|
|
13
|
-
'base.csn': cds.compile.to.json(csn),
|
|
14
|
-
'ext.csn': cds.compile.to.json({ extensions })
|
|
15
|
-
})
|
|
16
|
-
csn.definitions = extended.definitions
|
|
17
|
-
})
|
|
18
|
-
}
|
|
19
|
-
await db.disconnect()
|
|
20
|
-
|
|
21
|
-
if (cds.db) return // because of tests
|
|
22
|
-
cds.once('served', () => {
|
|
23
|
-
const { transformExtendedFieldsCREATE, transformExtendedFieldsUPDATE } = require('./handler/transformWRITE')
|
|
24
|
-
const { transformExtendedFieldsREAD } = require('./handler/transformREAD')
|
|
25
|
-
const { transformExtendedFieldsRESULT } = require('./handler/transformRESULT')
|
|
26
|
-
cds.db
|
|
27
|
-
.before('CREATE', transformExtendedFieldsCREATE)
|
|
28
|
-
.before('UPDATE', transformExtendedFieldsUPDATE)
|
|
29
|
-
.before('READ', transformExtendedFieldsREAD)
|
|
30
|
-
.after('READ', transformExtendedFieldsRESULT)
|
|
31
|
-
if ('cds_r.ExtensibilityService' in cds.services) return
|
|
32
|
-
const model = require('path').join(__dirname, '../../../..', 'srv/flex.cds')
|
|
33
|
-
return cds.serve(model, { silent: true }).to('odata').in(cds.app)
|
|
34
|
-
})
|
|
35
|
-
}
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
const cds = require('../../cds')
|
|
2
|
-
const { ensureDraftsSuffix } = require('../../common/utils/draft')
|
|
3
|
-
|
|
4
|
-
const { EXT_BACK_PACK } = require('./utils')
|
|
5
|
-
|
|
6
|
-
const _getDraftTable = (view, cds) => {
|
|
7
|
-
return cds.model.definitions[view]._isDraftEnabled ? ensureDraftsSuffix(view) : undefined
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
const _addAnnotation = extension => {
|
|
11
|
-
Object.values(extension.elements).forEach(el => {
|
|
12
|
-
el['@cds.extension'] = true
|
|
13
|
-
})
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const _isProjection = target => target && target.query && target.query._target
|
|
17
|
-
|
|
18
|
-
const _resolveViews = (target, views_ = []) => {
|
|
19
|
-
if (_isProjection(target)) {
|
|
20
|
-
views_.push(target)
|
|
21
|
-
return _resolveViews(target.query._target, views_)
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
return target
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const _getCsn = req => {
|
|
28
|
-
const csn = {
|
|
29
|
-
extensions: req.data.extensions.map(ext => JSON.parse(ext))
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return csn
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const _addViews = csn => {
|
|
36
|
-
csn.extensions.forEach(extension => {
|
|
37
|
-
const target = cds.model.definitions[extension.extend]
|
|
38
|
-
const views_ = []
|
|
39
|
-
const view = _resolveViews(target, views_)
|
|
40
|
-
extension.extend = view && view.name
|
|
41
|
-
_addAnnotation(extension)
|
|
42
|
-
|
|
43
|
-
// All projection views leading to the db entity are extended with back pack in case view columns are explicitly listed.
|
|
44
|
-
// The views using projections with '*' obtain the back pack automatically.
|
|
45
|
-
views_.forEach(view => {
|
|
46
|
-
if (!view.projection || (view.projection.columns && !view.projection.columns.some(col => col === '*'))) {
|
|
47
|
-
csn.extensions.push({
|
|
48
|
-
extend: view.name,
|
|
49
|
-
columns: Object.keys(extension.elements).map(key => {
|
|
50
|
-
return { ref: [key] }
|
|
51
|
-
})
|
|
52
|
-
})
|
|
53
|
-
}
|
|
54
|
-
})
|
|
55
|
-
})
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const _needsQuotations = t => t instanceof cds.builtin.classes.string || t instanceof cds.builtin.classes.date
|
|
59
|
-
|
|
60
|
-
const _handleDefaults = async (extension, dbEntity, req, cds, draftEntity) => {
|
|
61
|
-
const ext = Object.keys(extension.elements)
|
|
62
|
-
.filter(key => extension.elements[key].default)
|
|
63
|
-
.map(key => {
|
|
64
|
-
const element = extension.elements[key]
|
|
65
|
-
const t = cds.model.definitions[element.type] || cds.builtin.types[element.type]
|
|
66
|
-
const value = t && _needsQuotations(t) ? `"${element.default.val}"` : element.default.val
|
|
67
|
-
return `"${key}":${value}`
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
if (ext.length !== 0) {
|
|
71
|
-
const extStr = ext.join(',')
|
|
72
|
-
const changed = `'{${extStr},' || substr(${EXT_BACK_PACK}, 2, length(${EXT_BACK_PACK})-1)`
|
|
73
|
-
const assign = `${EXT_BACK_PACK} = CASE WHEN ${EXT_BACK_PACK} IS NULL THEN '{${extStr}}' ELSE ${changed} END`
|
|
74
|
-
await UPDATE(dbEntity).with(assign)
|
|
75
|
-
if (draftEntity) await UPDATE(draftEntity).with(assign)
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const _validateCsn = (csn, req) => {
|
|
80
|
-
csn.extensions.forEach(extension => {
|
|
81
|
-
if (!extension.extend || !cds.model.definitions[extension.extend]) {
|
|
82
|
-
req.reject(400, 'Invalid extension. Parameter "extend" missing or malformed')
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (!extension.elements) {
|
|
86
|
-
req.reject(400, 'Invalid extension. Missing parameter "elements"')
|
|
87
|
-
}
|
|
88
|
-
})
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const _validateExtensionFields = async (csn, req) => {
|
|
92
|
-
csn.extensions.forEach(extension => {
|
|
93
|
-
if (extension.elements) {
|
|
94
|
-
Object.keys(extension.elements).forEach(name => {
|
|
95
|
-
if (!/^[A-Za-z]\w*$/.test(name)) {
|
|
96
|
-
req.reject(400, `Invalid extension. Bad element name "${name}"`)
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if (Object.keys(cds.model.definitions[extension.extend].elements).includes(name)) {
|
|
100
|
-
req.reject(400, `Invalid extension. Element "${name}" already exists`)
|
|
101
|
-
}
|
|
102
|
-
})
|
|
103
|
-
}
|
|
104
|
-
})
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const _getCompilerError = messages => {
|
|
108
|
-
const defaultMsg = 'Error while compiling extension'
|
|
109
|
-
if (!messages) return defaultMsg
|
|
110
|
-
|
|
111
|
-
for (const msg of messages) {
|
|
112
|
-
if (msg.severity === 'Error') return msg.message
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
return defaultMsg
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
const _validateExtension = async (csn, req) => {
|
|
119
|
-
try {
|
|
120
|
-
const base = await cds.load('*', cds.options)
|
|
121
|
-
const baseCsn = await cds.compile.to.json(base)
|
|
122
|
-
const extCsn = await cds.compile.to.json(csn)
|
|
123
|
-
await cds.compile.to.csn({ 'base.csn': baseCsn, 'ext.csn': extCsn })
|
|
124
|
-
} catch (err) {
|
|
125
|
-
req.reject(400, _getCompilerError(err.messages))
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
module.exports = function () {
|
|
130
|
-
this.on('addExtension', async req => {
|
|
131
|
-
const csn = _getCsn(req, cds)
|
|
132
|
-
_validateCsn(csn, req)
|
|
133
|
-
await _validateExtensionFields(csn, req)
|
|
134
|
-
_addViews(csn, cds)
|
|
135
|
-
await _validateExtension(csn, req)
|
|
136
|
-
|
|
137
|
-
const ID = cds.utils.uuid()
|
|
138
|
-
await INSERT.into('cds_r.Extensions').entries([{ ID, csn: JSON.stringify(csn) }])
|
|
139
|
-
|
|
140
|
-
for (const ext of req.data.extensions) {
|
|
141
|
-
const extension = JSON.parse(ext)
|
|
142
|
-
const draft = _getDraftTable(extension.extend, cds)
|
|
143
|
-
const target = cds.model.definitions[extension.extend]
|
|
144
|
-
const dbEntity = _resolveViews(target).name
|
|
145
|
-
await _handleDefaults(extension, dbEntity, req, cds, draft)
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
setTimeout(() => process.send('restart'), 1111)
|
|
149
|
-
})
|
|
150
|
-
}
|
package/libx/rest/utils/data.js
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
const { deepCopyObject } = require('../../_runtime/common/utils/copy')
|
|
2
|
-
const { checkKeys, checkStatic } = require('../../_runtime/cds-services/util/assert')
|
|
3
|
-
const { MULTIPLE_ERRORS } = require('../../_runtime/common/error/constants')
|
|
4
|
-
|
|
5
|
-
// this can be reused for flattening data on db layer, if necessary
|
|
6
|
-
// const _getFlattenedCopy = (data, key, entity) => {
|
|
7
|
-
// const d = {}
|
|
8
|
-
// const prefix = key + '_'
|
|
9
|
-
// // TODO: ignore or preserve unknown?
|
|
10
|
-
// const matches = Object.keys(entity.elements)
|
|
11
|
-
// .filter(ele => ele.startsWith(prefix))
|
|
12
|
-
// .map(ele => ele.replace(prefix, ''))
|
|
13
|
-
// if (matches.length) {
|
|
14
|
-
// const current = data[key]
|
|
15
|
-
// for (const k of matches) if (current[k] !== undefined) d[prefix + k] = current[k]
|
|
16
|
-
// const nested = Object.keys(current).filter(k => current[k] && typeof current[k] === 'object')
|
|
17
|
-
// for (const k of nested) Object.assign(d, _getFlattenedCopy({ [prefix + k]: current[k] }, prefix + k, entity))
|
|
18
|
-
// }
|
|
19
|
-
// return d
|
|
20
|
-
// }
|
|
21
|
-
|
|
22
|
-
const _getDeepCopy = (data, definition, model, validations, skipKeys) => {
|
|
23
|
-
skipKeys || (definition.keys && validations.push(...checkKeys(definition, data)))
|
|
24
|
-
validations.push(...checkStatic(definition, data, true))
|
|
25
|
-
|
|
26
|
-
const d = {}
|
|
27
|
-
for (const k in data) {
|
|
28
|
-
const element = (definition.elements && definition.elements[k]) || (definition.params && definition.params[k])
|
|
29
|
-
if (!element) {
|
|
30
|
-
if (!definition['@open']) {
|
|
31
|
-
// ignore input (the default)
|
|
32
|
-
} else {
|
|
33
|
-
d[k] = data[k] && typeof data[k] === 'object' ? deepCopyObject(data[k]) : data[k]
|
|
34
|
-
}
|
|
35
|
-
} else if (element.isAssociation) {
|
|
36
|
-
d[k] = Array.isArray(data[k])
|
|
37
|
-
? data[k].map(d => _getDeepCopy(d, model.definitions[element.target], model, validations))
|
|
38
|
-
: _getDeepCopy(data[k], model.definitions[element.target], model, validations)
|
|
39
|
-
} else if (element._isStructured) {
|
|
40
|
-
d[k] = _getDeepCopy(data[k], element, model, validations)
|
|
41
|
-
} else {
|
|
42
|
-
d[k] = data[k]
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
return d
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const getDeepCopy = (data, definition, model, skipKeys) => {
|
|
49
|
-
const validations = []
|
|
50
|
-
const copy = Array.isArray(data)
|
|
51
|
-
? data.map(d => _getDeepCopy(d, definition, model, validations, skipKeys))
|
|
52
|
-
: _getDeepCopy(data, definition, model, validations, skipKeys)
|
|
53
|
-
if (!validations.length) return [undefined, copy]
|
|
54
|
-
if (validations.length === 1) return [validations[0]]
|
|
55
|
-
return [Object.assign(new Error(MULTIPLE_ERRORS), { details: validations })]
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
module.exports = {
|
|
59
|
-
getDeepCopy
|
|
60
|
-
}
|