@sap/cds 6.1.3 → 6.2.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 +77 -8
- package/apis/cds.d.ts +18 -6
- package/apis/connect.d.ts +1 -1
- package/apis/cqn.d.ts +1 -1
- package/apis/log.d.ts +23 -5
- package/apis/ql.d.ts +128 -61
- package/apis/services.d.ts +11 -0
- package/apis/test.d.ts +61 -0
- package/apis/utils.d.ts +15 -0
- package/app/fiori/preview.js +1 -0
- package/bin/build/buildTaskEngine.js +70 -22
- package/bin/build/buildTaskFactory.js +18 -11
- package/bin/build/buildTaskHandler.js +1 -1
- package/bin/build/buildTaskProviderFactory.js +3 -13
- package/bin/build/constants.js +0 -1
- package/bin/build/index.js +14 -6
- package/bin/build/provider/buildTaskHandlerEdmx.js +2 -3
- package/bin/build/provider/buildTaskHandlerFeatureToggles.js +2 -2
- package/bin/build/provider/buildTaskHandlerInternal.js +3 -6
- package/bin/build/provider/buildTaskProviderInternal.js +51 -39
- package/bin/build/provider/fiori/index.js +3 -3
- package/bin/build/provider/hana/2migration.js +1 -1
- package/bin/build/provider/hana/index.js +34 -27
- package/bin/build/provider/java/index.js +6 -7
- package/bin/build/provider/mtx/index.js +20 -18
- package/bin/build/provider/mtx/resourcesTarBuilder.js +8 -11
- package/bin/build/provider/mtx-sidecar/index.js +13 -17
- package/bin/build/provider/nodejs/index.js +8 -7
- package/bin/build/util.js +22 -4
- package/bin/cds.js +8 -4
- package/bin/deploy/to-hana/cfUtil.js +53 -18
- package/bin/mtx/in-cds.js +1 -0
- package/bin/serve.js +37 -30
- package/lib/auth/basic-auth.js +33 -0
- package/lib/auth/dummy-auth.js +7 -0
- package/lib/auth/ias-auth.js +2 -0
- package/lib/auth/index.js +31 -0
- package/lib/auth/jwt-auth.js +3 -0
- package/lib/auth/mocked-users.js +72 -0
- package/lib/auth/passport-basic.js +12 -0
- package/lib/auth/passport-digest.js +14 -0
- package/lib/auth/xsuaa-auth.js +3 -0
- package/lib/compile/cds-compile.js +3 -3
- package/lib/compile/to/cdl.js +5 -1
- package/lib/compile/to/edm.js +8 -0
- package/lib/compile/to/gql.js +1 -0
- package/lib/compile/to/json.js +30 -5
- package/lib/compile/to/sql.js +3 -1
- package/lib/core/index.js +5 -1
- package/lib/dbs/cds-deploy.js +36 -6
- package/lib/env/cds-env.js +15 -5
- package/lib/env/cds-requires.js +51 -58
- package/lib/env/defaults.js +1 -0
- package/lib/env/schemas/cds-package.json +4 -0
- package/lib/env/schemas/cds-rc.json +63 -77
- package/lib/i18n/localize.js +16 -5
- package/lib/index.js +9 -4
- package/lib/log/cds-error.js +4 -6
- package/lib/log/cds-log.js +89 -53
- package/lib/log/service/index.js +1 -0
- package/lib/ql/CREATE.js +2 -5
- package/lib/ql/DELETE.js +1 -1
- package/lib/ql/DROP.js +1 -3
- package/lib/ql/INSERT.js +3 -3
- package/lib/ql/Query.js +10 -23
- package/lib/ql/SELECT.js +1 -2
- package/lib/ql/UPDATE.js +2 -2
- package/lib/ql/Whereable.js +7 -15
- package/lib/ql/cds-ql.js +9 -3
- package/lib/req/cds-context.js +11 -3
- package/lib/req/context.js +29 -23
- package/lib/req/locale.js +9 -5
- package/lib/req/request.js +1 -0
- package/lib/req/user.js +2 -1
- package/lib/srv/cds-connect.js +1 -1
- package/lib/srv/cds-serve.js +21 -14
- package/lib/srv/middlewares/cds-context.js +29 -0
- package/lib/srv/middlewares/ctx-model.js +24 -0
- package/lib/srv/middlewares/errors.js +9 -0
- package/lib/srv/middlewares/index.js +22 -0
- package/lib/srv/middlewares/sap-statistics.js +13 -0
- package/lib/srv/middlewares/trace.js +102 -0
- package/lib/srv/protocols/_legacy.js +42 -0
- package/lib/srv/protocols/graphql.js +39 -0
- package/lib/srv/protocols/hcql.js +37 -0
- package/lib/srv/protocols/index.js +86 -0
- package/lib/srv/protocols/odata-v2-proxy.js +3767 -0
- package/lib/srv/protocols/odata-v2.js +26 -0
- package/lib/srv/protocols/odata-v4.js +16 -0
- package/lib/srv/protocols/rest.js +13 -0
- package/lib/srv/srv-api.js +5 -0
- package/lib/srv/srv-models.js +4 -6
- package/lib/utils/axios.js +3 -2
- package/lib/utils/cds-test.js +27 -21
- package/lib/utils/cds-utils.js +19 -20
- package/lib/utils/tar.js +175 -0
- package/libx/_runtime/audit/generic/personal/utils.js +18 -7
- package/libx/_runtime/audit/utils/v2.js +1 -0
- package/libx/_runtime/auth/index.js +4 -0
- package/libx/_runtime/auth/strategies/ias-auth.js +76 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/error.js +8 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +15 -4
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/expandToCQN.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/orderByToCQN.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/utils.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/ResourcePathParser.js +9 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/UriInfo.js +5 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/UriParser.js +12 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/utils/BufferedWriter.js +6 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/validator/RequestValidator.js +47 -7
- package/libx/_runtime/cds-services/adapter/odata-v4/to.js +1 -1
- package/libx/_runtime/cds-services/util/assert.js +4 -0
- package/libx/_runtime/common/aspects/relation.js +1 -1
- package/libx/_runtime/common/composition/data.js +61 -15
- package/libx/_runtime/common/composition/delete.js +0 -1
- package/libx/_runtime/common/composition/insert.js +0 -1
- package/libx/_runtime/common/composition/tree.js +4 -10
- package/libx/_runtime/common/composition/update.js +44 -21
- package/libx/_runtime/common/generic/auth/capabilities.js +8 -10
- package/libx/_runtime/common/generic/crud.js +1 -2
- package/libx/_runtime/common/generic/etag.js +4 -4
- package/libx/_runtime/common/generic/input.js +4 -4
- package/libx/_runtime/common/generic/paging.js +3 -3
- package/libx/_runtime/common/generic/put.js +3 -3
- package/libx/_runtime/common/generic/sorting.js +4 -4
- package/libx/_runtime/common/generic/temporal.js +3 -3
- package/libx/_runtime/common/i18n/messages.properties +0 -7
- package/libx/_runtime/common/utils/cqn2cqn4sql.js +11 -6
- package/libx/_runtime/common/utils/csn.js +0 -28
- package/libx/_runtime/common/utils/draft.js +8 -1
- package/libx/_runtime/common/utils/path.js +7 -1
- package/libx/_runtime/common/utils/resolveView.js +2 -3
- package/libx/_runtime/db/data-conversion/post-processing.js +3 -44
- package/libx/_runtime/db/generic/input.js +3 -3
- package/libx/_runtime/db/sql-builder/dataTypes.js +4 -0
- package/libx/_runtime/fiori/generic/activate.js +2 -2
- package/libx/_runtime/fiori/generic/before.js +40 -72
- package/libx/_runtime/fiori/generic/cancel.js +2 -2
- package/libx/_runtime/fiori/generic/delete.js +2 -2
- package/libx/_runtime/fiori/generic/edit.js +2 -2
- package/libx/_runtime/fiori/generic/new.js +2 -2
- package/libx/_runtime/fiori/generic/patch.js +49 -37
- package/libx/_runtime/fiori/generic/prepare.js +2 -2
- package/libx/_runtime/fiori/generic/read.js +27 -37
- package/libx/_runtime/fiori/utils/where.js +4 -2
- package/libx/_runtime/hana/Service.js +1 -3
- package/libx/_runtime/hana/conversion.js +3 -0
- package/libx/_runtime/hana/driver.js +33 -3
- package/libx/_runtime/hana/dynatrace.js +1 -0
- package/libx/_runtime/hana/search2Contains.js +12 -1
- package/libx/_runtime/hana/search2cqn4sql.js +10 -27
- package/libx/_runtime/hana/streaming.js +1 -0
- package/libx/_runtime/messaging/AMQPWebhookMessaging.js +4 -2
- package/libx/_runtime/messaging/common-utils/AMQPClient.js +1 -0
- package/libx/_runtime/messaging/enterprise-messaging-utils/getTenantInfo.js +5 -2
- package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +2 -0
- package/libx/_runtime/messaging/enterprise-messaging.js +62 -3
- package/libx/_runtime/messaging/outbox/utils.js +1 -1
- package/libx/_runtime/messaging/redis-messaging.js +1 -0
- package/libx/_runtime/remote/Service.js +2 -2
- package/libx/_runtime/remote/utils/client.js +8 -3
- package/libx/_runtime/remote/utils/data.js +7 -2
- package/libx/_runtime/sqlite/Service.js +18 -7
- package/libx/_runtime/sqlite/conversion.js +3 -0
- package/libx/_runtime/sqlite/convertAssocToOneManaged.js +3 -3
- package/libx/_runtime/sqlite/localized.js +8 -8
- package/libx/odata/afterburner.js +39 -7
- package/libx/odata/cqn2odata.js +6 -3
- package/libx/odata/grammar.pegjs +66 -18
- package/libx/odata/index.js +3 -2
- package/libx/odata/parser.js +1 -1
- package/libx/odata/utils.js +2 -0
- package/libx/rest/RestAdapter.js +62 -43
- package/libx/rest/middleware/parse.js +2 -1
- package/libx/rest/middleware/update.js +1 -1
- package/package.json +2 -2
- package/server.js +5 -4
- package/srv/mtx.cds +1 -1
- package/srv/mtx.js +4 -33
- package/lib/srv/adapters.js +0 -85
- package/lib/utils/resources/index.js +0 -48
- package/lib/utils/resources/tar.js +0 -49
- package/lib/utils/resources/utils.js +0 -11
- package/libx/_runtime/extensibility/activate.js +0 -69
- package/libx/_runtime/extensibility/add.js +0 -50
- package/libx/_runtime/extensibility/addExtension.js +0 -72
- package/libx/_runtime/extensibility/defaults.js +0 -34
- package/libx/_runtime/extensibility/handler/transformREAD.js +0 -121
- package/libx/_runtime/extensibility/handler/transformRESULT.js +0 -51
- package/libx/_runtime/extensibility/handler/transformWRITE.js +0 -64
- package/libx/_runtime/extensibility/linter/allowlist_checker.js +0 -373
- package/libx/_runtime/extensibility/linter/annotations_checker.js +0 -113
- package/libx/_runtime/extensibility/linter/checker_base.js +0 -20
- package/libx/_runtime/extensibility/linter/namespace_checker.js +0 -180
- package/libx/_runtime/extensibility/linter.js +0 -32
- package/libx/_runtime/extensibility/push.js +0 -118
- package/libx/_runtime/extensibility/service.js +0 -38
- package/libx/_runtime/extensibility/token.js +0 -57
- package/libx/_runtime/extensibility/utils.js +0 -131
- package/libx/_runtime/extensibility/validation.js +0 -50
- package/libx/_runtime/extensibility/views.js +0 -12
- package/srv/extensibility-service.cds +0 -60
- package/srv/extensibility-service.js +0 -1
- package/srv/extensions.cds +0 -8
- package/srv/model-provider.cds +0 -61
- package/srv/model-provider.js +0 -143
package/srv/mtx.js
CHANGED
|
@@ -1,37 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
const
|
|
3
|
-
|
|
4
|
-
class MTXServices extends cds.Service { async init(){
|
|
1
|
+
module.exports = ()=> {
|
|
2
|
+
const cds = require ('../lib')
|
|
5
3
|
if (cds.mtx) {
|
|
4
|
+
const DEBUG = cds.debug('mtx')
|
|
6
5
|
DEBUG && DEBUG ('bootstrapping old MTX...')
|
|
7
6
|
return cds.mtx.in (cds.app) // old mtx
|
|
8
7
|
}
|
|
9
|
-
|
|
10
|
-
DEBUG && DEBUG ('bootstrapping MTX services...')
|
|
11
|
-
let defs = cds.model.definitions
|
|
12
|
-
let sources = []
|
|
13
|
-
|
|
14
|
-
if (cds.requires.multitenancy && !('cds.xt.SaasProvisioningService' in defs)) {
|
|
15
|
-
sources.push('@sap/cds-mtxs/srv/cf/saas-provisioning-service')
|
|
16
|
-
sources.push('@sap/cds/srv/model-provider')
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
if (cds.requires.multitenancy && !('cds.xt.DeploymentService' in defs)) {
|
|
20
|
-
sources.push('@sap/cds-mtxs/srv/deployment-service')
|
|
21
|
-
sources.push('@sap/cds/srv/model-provider')
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
if (cds.requires.extensibility && !('cds.xt.ExtensibilityService' in defs)) {
|
|
25
|
-
sources.push('@sap/cds/srv/extensibility-service')
|
|
26
|
-
sources.push('@sap/cds/srv/model-provider')
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (cds.requires.toggles && !('cds.xt.ModelProviderService' in defs)) {
|
|
30
|
-
sources.push('@sap/cds/srv/model-provider')
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
let models = cds.resolve(sources); if (!models) return
|
|
34
|
-
let base = cds.model.$sources; models = models.filter(m => !base.includes(m))
|
|
35
|
-
if (models.length) return cds.serve(models).in(cds.app)
|
|
36
|
-
}}
|
|
37
|
-
module.exports = MTXServices
|
|
8
|
+
}
|
package/lib/srv/adapters.js
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
const lib = require('../../libx/_runtime')
|
|
2
|
-
const cds = require('../index')
|
|
3
|
-
const registry = {
|
|
4
|
-
get rest() { return lib.to.rest },
|
|
5
|
-
get odata() { return lib.to.odata_v4 },
|
|
6
|
-
get odata_v2() { return lib.to.odata_v4 },
|
|
7
|
-
get odata_v4() { return lib.to.odata_v4 },
|
|
8
|
-
get fiori() { return lib.to.odata_v4 },
|
|
9
|
-
none: ()=>{}
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class ProtocolAdapter {
|
|
14
|
-
|
|
15
|
-
static at (protocol) {
|
|
16
|
-
const factory = registry[protocol]; if (factory) return factory
|
|
17
|
-
else throw new Error (`Service protocol ${protocol} is not supported`)
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Constructs / returns a ProtocolAdapter for the given service and protocol.
|
|
22
|
-
* The constructed adapters are cached per service, so subsequent calls
|
|
23
|
-
* for same service and protocol returns the formerly constructed one.
|
|
24
|
-
* @returns {ProtocolAdapter}
|
|
25
|
-
*/
|
|
26
|
-
static serve (srv, protocol = _protocol4(srv)) {
|
|
27
|
-
const cached = (srv._adapters || (srv._adapters={})) [protocol]; if (cached) return cached
|
|
28
|
-
const adapter = Object.defineProperties (this.at (protocol) (srv), _prototype)
|
|
29
|
-
return (adapter.service = srv)._adapters[protocol] = adapter
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Mounts the adapter to an express app.
|
|
34
|
-
*/
|
|
35
|
-
in (app) {
|
|
36
|
-
const srv = this.service
|
|
37
|
-
app.use (srv.path+'/webapp/', (_,res)=> res.sendStatus(404))
|
|
38
|
-
const cds_context_model = require('./srv-models')
|
|
39
|
-
app.use (srv.path, logger, lib.perf, lib.auth(srv), cds_context_model.middleware4(srv), this)
|
|
40
|
-
return srv
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Returns a proxy handler function with the specified service
|
|
45
|
-
* as its prototype to allow usages like this:
|
|
46
|
-
*
|
|
47
|
-
* const { CatalogService } = cds.serve(...)
|
|
48
|
-
* app.use ('/cats', CatalogService)
|
|
49
|
-
*/
|
|
50
|
-
asRouter() {
|
|
51
|
-
let router = this._router
|
|
52
|
-
if (!router) {
|
|
53
|
-
router = this._router = (...args) => this (...args)
|
|
54
|
-
Object.defineProperty (router, 'name', {value: this.service.name})
|
|
55
|
-
Object.setPrototypeOf (router, this.service)
|
|
56
|
-
}
|
|
57
|
-
return router
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const _protocol4 = (srv) => {
|
|
63
|
-
const {to} = srv.options; if (to) return to
|
|
64
|
-
return _protocol4Service(srv.definition)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const _protocol4Service = (service) => {
|
|
68
|
-
return !service ? default_protocol : service['@protocol'] || service['@rest'] && 'rest' || service['@odata'] && 'odata_v4' || default_protocol
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const LOG = cds.log(), DEBUG = cds.debug('server')
|
|
73
|
-
const logger = function cap_req_logger (req,_,next) {
|
|
74
|
-
LOG && LOG (req.method, decodeURI(req.originalUrl), req.body||'')
|
|
75
|
-
if (/\$batch/.test(req.url)) req.on ('dispatch', (req) => {
|
|
76
|
-
LOG && LOG ('>', req.event, decodeURI(req._path), req._query||'')
|
|
77
|
-
if (DEBUG && req.query) DEBUG (req.query)
|
|
78
|
-
})
|
|
79
|
-
next()
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
const default_protocol = 'odata_v4'
|
|
84
|
-
const _prototype = Object.getOwnPropertyDescriptors (ProtocolAdapter.prototype)
|
|
85
|
-
module.exports = { ProtocolAdapter, _protocol4Service }
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
const fs = require('fs')
|
|
2
|
-
const path = require('path')
|
|
3
|
-
|
|
4
|
-
const { packArchiveCLI, unpackArchiveCLI } = require('./tar')
|
|
5
|
-
const { exists } = require('./utils')
|
|
6
|
-
|
|
7
|
-
const TEMP_DIR = fs.realpathSync(require('os').tmpdir())
|
|
8
|
-
|
|
9
|
-
const packTarArchive = async (files, root, flat = false) => {
|
|
10
|
-
if (typeof files === 'string') return await packArchiveCLI(files)
|
|
11
|
-
|
|
12
|
-
let tgzBuffer, temp
|
|
13
|
-
try {
|
|
14
|
-
temp = await fs.promises.mkdtemp(`${TEMP_DIR}${path.sep}tar-`)
|
|
15
|
-
for (const file of files) {
|
|
16
|
-
const fname = flat ? path.basename(file) : path.relative(root, file)
|
|
17
|
-
const destination = path.join(temp, fname)
|
|
18
|
-
const dirname = path.dirname(destination)
|
|
19
|
-
if (!await exists(dirname)) await fs.promises.mkdir(dirname, { recursive: true })
|
|
20
|
-
await fs.promises.copyFile(file, destination)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
tgzBuffer = await packArchiveCLI(temp)
|
|
24
|
-
} finally {
|
|
25
|
-
if (await exists(temp)) {
|
|
26
|
-
await fs.promises.rm(temp, { recursive: true, force: true })
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return tgzBuffer
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const unpackTarArchive = async (buffer, folder) => {
|
|
34
|
-
const temp = await fs.promises.mkdtemp(`${TEMP_DIR}${path.sep}tar-`)
|
|
35
|
-
const tgz = path.join(temp, 'resources.tgz')
|
|
36
|
-
await fs.promises.writeFile(tgz, Buffer.from(buffer), 'binary')
|
|
37
|
-
|
|
38
|
-
try {
|
|
39
|
-
await unpackArchiveCLI(tgz, folder)
|
|
40
|
-
} finally {
|
|
41
|
-
if (await exists(temp)) await fs.promises.rm(temp, { recursive: true, force: true })
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
module.exports = {
|
|
46
|
-
packTarArchive,
|
|
47
|
-
unpackTarArchive
|
|
48
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
const fs = require('fs')
|
|
2
|
-
const path = require('path')
|
|
3
|
-
const exec = require('child_process').exec
|
|
4
|
-
const cds = require('../../../libx/_runtime/cds')
|
|
5
|
-
const { exists } = require('./utils')
|
|
6
|
-
|
|
7
|
-
const TEMP_DIR = fs.realpathSync(require('os').tmpdir())
|
|
8
|
-
|
|
9
|
-
const _createArchiveCLI = (root, output) => {
|
|
10
|
-
const cmd = 'tar -zcvf ' + output + ' -C ' + root + ' .'
|
|
11
|
-
|
|
12
|
-
return new Promise((resolve, reject) => {
|
|
13
|
-
exec(cmd, err => {
|
|
14
|
-
if (err) reject(err)
|
|
15
|
-
else resolve()
|
|
16
|
-
})
|
|
17
|
-
})
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const packArchiveCLI = async (root) => {
|
|
21
|
-
const temp = await fs.promises.mkdtemp(`${TEMP_DIR}${path.sep}tar-`)
|
|
22
|
-
const output = path.join(temp, `${cds.utils.uuid()}.tgz`)
|
|
23
|
-
try {
|
|
24
|
-
await _createArchiveCLI(root, output)
|
|
25
|
-
|
|
26
|
-
return fs.promises.readFile(output)
|
|
27
|
-
}
|
|
28
|
-
finally {
|
|
29
|
-
if (await exists(temp)) {
|
|
30
|
-
await fs.promises.rm(temp, { recursive: true, force: true })
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const unpackArchiveCLI = async (tgz, folder) => {
|
|
36
|
-
const cmd = 'tar -xzf ' + tgz + ' -C ' + folder
|
|
37
|
-
|
|
38
|
-
return new Promise((resolve, reject) => {
|
|
39
|
-
exec(cmd, err => {
|
|
40
|
-
if (err) reject(err)
|
|
41
|
-
else resolve()
|
|
42
|
-
})
|
|
43
|
-
})
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
module.exports = {
|
|
47
|
-
packArchiveCLI,
|
|
48
|
-
unpackArchiveCLI
|
|
49
|
-
}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
const cds = require('../cds')
|
|
2
|
-
|
|
3
|
-
const handleDefaults = require('./defaults')
|
|
4
|
-
const Extensions = 'cds.xt.Extensions'
|
|
5
|
-
|
|
6
|
-
// REVISIT: Reuse ratio = 0
|
|
7
|
-
const _calculateExtensions = async function (ID, tag) {
|
|
8
|
-
let active, inactive
|
|
9
|
-
if (tag || ID) {
|
|
10
|
-
const inactiveCqn = SELECT.from(Extensions).where({ activated: 'propertyBag' })
|
|
11
|
-
if (ID) {
|
|
12
|
-
inactiveCqn.where('ID !=', ID)
|
|
13
|
-
} else {
|
|
14
|
-
inactiveCqn.where('(tag !=', tag, 'or tag =', null, ')')
|
|
15
|
-
}
|
|
16
|
-
inactive = await cds.db.run(inactiveCqn)
|
|
17
|
-
const activeCqn = SELECT.from(Extensions).where({ activated: 'database' })
|
|
18
|
-
if (ID) {
|
|
19
|
-
activeCqn.or({ ID })
|
|
20
|
-
} else if (tag) {
|
|
21
|
-
activeCqn.or({ tag })
|
|
22
|
-
}
|
|
23
|
-
active = await cds.db.run(activeCqn)
|
|
24
|
-
if (inactive.length) {
|
|
25
|
-
const deleteCqn = DELETE.from(Extensions).where(inactiveCqn.SELECT.where)
|
|
26
|
-
await cds.db.run(deleteCqn)
|
|
27
|
-
}
|
|
28
|
-
} else {
|
|
29
|
-
// activate all
|
|
30
|
-
inactive = []
|
|
31
|
-
active = await cds.db.run(SELECT.from(Extensions))
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return { active, inactive }
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// REVISIT: Reuse ratio = 0
|
|
38
|
-
const _restoreExtensions = async function (active, inactive, appCsn) {
|
|
39
|
-
// delete all extensions
|
|
40
|
-
await cds.db.run(DELETE.from(Extensions))
|
|
41
|
-
// active
|
|
42
|
-
active.forEach(row => {
|
|
43
|
-
row.csn = row.csn.replace(/,"@cds.extension":true/g, '')
|
|
44
|
-
row.activated = 'database'
|
|
45
|
-
row.timestamp = '$now'
|
|
46
|
-
})
|
|
47
|
-
await cds.db.run(INSERT.into(Extensions).entries(active))
|
|
48
|
-
// inactive
|
|
49
|
-
if (inactive.length) {
|
|
50
|
-
for (const na of inactive) {
|
|
51
|
-
for (const extension of JSON.parse(na.csn).extensions) {
|
|
52
|
-
await handleDefaults(extension, appCsn, cds.db)
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
await cds.db.run(INSERT.into(Extensions).entries(inactive))
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// REVISIT: Review with Vitaly: (1) Delete Inactives > (2) DS.extend(t) > (3) Delete All > (4) Restore All ???
|
|
60
|
-
const activate = async function (ID, tag, tenant, appCsn) {
|
|
61
|
-
const { active, inactive } = await _calculateExtensions(ID, tag)
|
|
62
|
-
|
|
63
|
-
const { 'cds.xt.DeploymentService': ds } = cds.services
|
|
64
|
-
await ds.extend(tenant)
|
|
65
|
-
|
|
66
|
-
await _restoreExtensions(active, inactive, appCsn)
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
module.exports = activate
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
const cds = require('../cds')
|
|
2
|
-
const LOG = cds.log('mtx')
|
|
3
|
-
|
|
4
|
-
const { validateExtension } = require('./validation')
|
|
5
|
-
const handleDefaults = require('./defaults')
|
|
6
|
-
const activateExt = require('./activate')
|
|
7
|
-
|
|
8
|
-
const _isCSN = str => str.substring(0, 1) === '{'
|
|
9
|
-
|
|
10
|
-
const add = async function (req) {
|
|
11
|
-
let { extension, tag, activate } = req.data
|
|
12
|
-
if (!extension || !extension.length) req.reject(400, 'Missing extension')
|
|
13
|
-
if (!activate) activate = 'database'
|
|
14
|
-
if (!tag) tag = null
|
|
15
|
-
const tenant = (req.user.is('internal-user') && req.data.tenant) || req.tenant
|
|
16
|
-
|
|
17
|
-
const extCsn = _isCSN(extension) ? JSON.parse(extension) : cds.parse.cdl(extension)
|
|
18
|
-
if (extCsn.requires) delete extCsn.requires
|
|
19
|
-
|
|
20
|
-
LOG.info(`validating extension '${tag}' ...`)
|
|
21
|
-
const { 'cds.xt.ModelProviderService': mps } = cds.services
|
|
22
|
-
const csn = await mps.getCsn(tenant, ['*'])
|
|
23
|
-
validateExtension(extCsn, csn, req)
|
|
24
|
-
|
|
25
|
-
if (tenant) cds.context = { tenant }
|
|
26
|
-
const ID = cds.utils.uuid()
|
|
27
|
-
await cds.db.run(
|
|
28
|
-
INSERT.into('cds.xt.Extensions').entries([{ ID, tag, csn: JSON.stringify(extCsn), activated: activate }])
|
|
29
|
-
)
|
|
30
|
-
const njCsn = cds.compile.for.nodejs(csn)
|
|
31
|
-
LOG.info(`activating extension to '${activate}' ...`)
|
|
32
|
-
if (activate === 'propertyBag' && extCsn.extensions)
|
|
33
|
-
extCsn.extensions.forEach(async ext => await handleDefaults(ext, njCsn))
|
|
34
|
-
if (activate === 'database') await activateExt(ID, tag, tenant, njCsn)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const promote = async function (req) {
|
|
38
|
-
let { tag, activate } = req.data
|
|
39
|
-
if (!activate) activate = 'database'
|
|
40
|
-
if (!tag) tag = null
|
|
41
|
-
const tenant = req.tenant || (req.user.is('internal-user') && req.data.tenant) || ''
|
|
42
|
-
if (activate !== 'database') req.reject(400, 'Promote to propertyBag is not supported')
|
|
43
|
-
|
|
44
|
-
const { 'cds.xt.ModelProviderService': mps } = cds.services
|
|
45
|
-
const njCsn = await mps.getCsn(tenant, ['*'], 'nodejs')
|
|
46
|
-
if (tenant) cds.context = { tenant }
|
|
47
|
-
await activateExt(null, tag, tenant, njCsn)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
module.exports = { add, promote }
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
const cds = require('../cds')
|
|
2
|
-
|
|
3
|
-
const { validateCsn, validateExtensionFields, validateExtension } = require('./validation')
|
|
4
|
-
const handleDefaults = require('./defaults')
|
|
5
|
-
const resolveViews = require('./views')
|
|
6
|
-
|
|
7
|
-
const _getCsn = req => {
|
|
8
|
-
const csn = {
|
|
9
|
-
extensions: req.data.extensions.map(ext => JSON.parse(ext))
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
return csn
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const _addAnnotation = extension => {
|
|
16
|
-
Object.values(extension.elements).forEach(el => {
|
|
17
|
-
el['@cds.extension'] = true
|
|
18
|
-
})
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const _addViews = (csn, appCsn) => {
|
|
22
|
-
csn.extensions.forEach(extension => {
|
|
23
|
-
const target = appCsn.definitions[extension.extend]
|
|
24
|
-
const views_ = []
|
|
25
|
-
const view = resolveViews(target, views_)
|
|
26
|
-
extension.extend = view && view.name
|
|
27
|
-
_addAnnotation(extension)
|
|
28
|
-
|
|
29
|
-
// All projection views leading to the db entity are extended with back pack in case view columns are explicitly listed.
|
|
30
|
-
// The views using projections with '*' obtain the back pack automatically.
|
|
31
|
-
views_.forEach(view => {
|
|
32
|
-
if (!view.projection || (view.projection.columns && !view.projection.columns.some(col => col === '*'))) {
|
|
33
|
-
csn.extensions.push({
|
|
34
|
-
extend: view.name,
|
|
35
|
-
columns: Object.keys(extension.elements).map(key => {
|
|
36
|
-
return { ref: [key] }
|
|
37
|
-
})
|
|
38
|
-
})
|
|
39
|
-
}
|
|
40
|
-
})
|
|
41
|
-
})
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const _addExtension = async function (csn, appCsn, req) {
|
|
45
|
-
if (req.tenant) cds.context = { tenant: req.tenant }
|
|
46
|
-
await cds.db.run(
|
|
47
|
-
INSERT.into('cds.xt.Extensions').entries([
|
|
48
|
-
{ ID: cds.utils.uuid(), tag: 'uiflex', csn: JSON.stringify(csn), activated: 'propertyBag' }
|
|
49
|
-
])
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
for (const ext of req.data.extensions) {
|
|
53
|
-
const extension = JSON.parse(ext)
|
|
54
|
-
await handleDefaults(extension, appCsn, false)
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const addExtension = async function (req) {
|
|
59
|
-
const { 'cds.xt.ModelProviderService': mps } = cds.services
|
|
60
|
-
const csn = await mps.getCsn(req.tenant, ['*'])
|
|
61
|
-
const extCsn = _getCsn(req)
|
|
62
|
-
const njCsn = cds.compile.for['nodejs'](csn)
|
|
63
|
-
// REVISIT: Optimize the validations
|
|
64
|
-
// REVISIT: Why do we need njCsn?
|
|
65
|
-
validateCsn(extCsn, njCsn, req)
|
|
66
|
-
validateExtensionFields(extCsn, njCsn, req)
|
|
67
|
-
_addViews(extCsn, njCsn)
|
|
68
|
-
validateExtension(extCsn, csn, req)
|
|
69
|
-
await _addExtension(extCsn, njCsn, req)
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
module.exports = addExtension
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
const cds = require('../cds')
|
|
2
|
-
const resolveViews = require('./views')
|
|
3
|
-
const builtin = cds.builtin.types
|
|
4
|
-
const needsQuotes = Symbol()
|
|
5
|
-
builtin.string[needsQuotes] = true
|
|
6
|
-
builtin.date[needsQuotes] = true
|
|
7
|
-
|
|
8
|
-
const handleDefaults = async (extension, { definitions }, checkDb = true) => {
|
|
9
|
-
const target = definitions[extension.extend]
|
|
10
|
-
const entity = resolveViews(target)
|
|
11
|
-
if (checkDb && target !== entity) return // only db entities
|
|
12
|
-
|
|
13
|
-
const elements = extension.elements
|
|
14
|
-
const defaults = Object.keys(elements)
|
|
15
|
-
.filter(key => elements[key].default)
|
|
16
|
-
.map(key => {
|
|
17
|
-
const e = elements[key],
|
|
18
|
-
{ val } = e.default
|
|
19
|
-
const t = definitions[e.type] || builtin[e.type]
|
|
20
|
-
return `"${key}":${t && t[needsQuotes] ? `"${val}"` : val}`
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
if (defaults.length) {
|
|
24
|
-
const newDefaults = defaults.join(',')
|
|
25
|
-
const newBagpack = `extensions__ = CASE
|
|
26
|
-
WHEN extensions__ is null THEN '{${newDefaults}}'
|
|
27
|
-
ELSE '{${newDefaults},' || substr(extensions__, 2, length(extensions__)-1)
|
|
28
|
-
END`
|
|
29
|
-
await Promise.all([UPDATE(entity).with(newBagpack), entity.drafts && UPDATE(entity.drafts).with(newBagpack)])
|
|
30
|
-
// NOTE: We don't need the model definitions for `entity` in cds.db.model to run these queries
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
module.exports = handleDefaults
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
const { EXT_BACK_PACK, getExtendedFields, hasExtendedEntity, isExtendedEntity, getTargetRead } = require('../utils')
|
|
2
|
-
|
|
3
|
-
const _addBackPack = (columns, extFields, alias) => {
|
|
4
|
-
if (!columns) return
|
|
5
|
-
|
|
6
|
-
const hasBackPack = columns.some(
|
|
7
|
-
col => col.ref && col.ref[col.ref.length - 1] === EXT_BACK_PACK && _hasAlias(col.ref, alias)
|
|
8
|
-
)
|
|
9
|
-
if (hasBackPack) return // get out early, avoiding overhead of second check
|
|
10
|
-
|
|
11
|
-
const hasExtFields = columns.some(
|
|
12
|
-
col => col.ref && extFields.includes(col.ref[col.ref.length - 1]) && _hasAlias(col.ref, alias)
|
|
13
|
-
)
|
|
14
|
-
|
|
15
|
-
if (hasExtFields) {
|
|
16
|
-
const col = { ref: [EXT_BACK_PACK] }
|
|
17
|
-
if (alias) col.ref.unshift(alias)
|
|
18
|
-
columns.push(col)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/*
|
|
22
|
-
Removing backpack if not needed doesn't work. Probably ref copy problem.
|
|
23
|
-
if (hasBackPack && !hasExtFields) remove backpack.
|
|
24
|
-
*/
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const _hasAlias = (ref, alias) => {
|
|
28
|
-
return (ref.length === 1 && !alias) || (ref.length > 1 && ref[0] === alias)
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const _removeExtendedFields = (columns, extFields, alias) => {
|
|
32
|
-
if (!columns) return
|
|
33
|
-
|
|
34
|
-
let i = columns.length
|
|
35
|
-
while (i--) {
|
|
36
|
-
const col = columns[i]
|
|
37
|
-
if (col.ref && extFields.includes(col.ref[col.ref.length - 1]) && _hasAlias(col.ref, alias)) {
|
|
38
|
-
columns.splice(i, 1)
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const _transformUnion = (req, model) => {
|
|
44
|
-
// second element is active entity
|
|
45
|
-
if (req.target) {
|
|
46
|
-
const name = req.target.name.SET ? req.target.name.SET.args[1]._target.name : req.target.name
|
|
47
|
-
const extFields = getExtendedFields(name, model)
|
|
48
|
-
_addBackPack(req.query.SELECT.columns, extFields)
|
|
49
|
-
_removeExtendedFields(req.query.SELECT.columns, extFields)
|
|
50
|
-
|
|
51
|
-
_addBackPack(
|
|
52
|
-
req.query.SELECT.from.SET.args[0].SELECT.columns,
|
|
53
|
-
extFields,
|
|
54
|
-
req.query.SELECT.from.SET.args[0].SELECT.from.args[0].as
|
|
55
|
-
)
|
|
56
|
-
_addBackPack(req.query.SELECT.from.SET.args[1].SELECT.columns, extFields)
|
|
57
|
-
_removeExtendedFields(
|
|
58
|
-
req.query.SELECT.from.SET.args[0].SELECT.columns,
|
|
59
|
-
extFields,
|
|
60
|
-
req.query.SELECT.from.SET.args[0].SELECT.from.args[0].as
|
|
61
|
-
)
|
|
62
|
-
_removeExtendedFields(req.query.SELECT.from.SET.args[1].SELECT.columns, extFields)
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const _getAliasedEntitiesForJoin = (args, model) => {
|
|
67
|
-
const extEntities = []
|
|
68
|
-
|
|
69
|
-
args.forEach(arg => {
|
|
70
|
-
if (arg.ref && arg.ref[0] !== 'DRAFT.DraftAdministativeData' && isExtendedEntity(arg.ref[0], model)) {
|
|
71
|
-
const extFields = getExtendedFields(arg.ref[0], model)
|
|
72
|
-
extEntities.push({ name: arg.ref[0], as: arg.as, extFields })
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
if (arg.join) {
|
|
76
|
-
extEntities.push(..._getAliasedEntitiesForJoin(arg.args, model))
|
|
77
|
-
}
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
return extEntities
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const _transformJoin = (req, model) => {
|
|
84
|
-
const extEntities = _getAliasedEntitiesForJoin(req.query.SELECT.from.args, model)
|
|
85
|
-
|
|
86
|
-
extEntities.forEach(ext => {
|
|
87
|
-
_addBackPack(req.query.SELECT.columns, ext.extFields, ext.as)
|
|
88
|
-
_removeExtendedFields(req.query.SELECT.columns, ext.extFields, ext.as)
|
|
89
|
-
})
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const _transformColumns = (columns, targetName, model) => {
|
|
93
|
-
if (!columns) return
|
|
94
|
-
|
|
95
|
-
const extFields = getExtendedFields(targetName, model)
|
|
96
|
-
if (extFields.length !== 0) {
|
|
97
|
-
_addBackPack(columns, extFields)
|
|
98
|
-
_removeExtendedFields(columns, extFields)
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
columns.forEach(col => {
|
|
102
|
-
if (col.ref && col.expand) {
|
|
103
|
-
const expTargetName = model.definitions[targetName].elements[col.ref[0]].target
|
|
104
|
-
_transformColumns(col.expand, expTargetName, model)
|
|
105
|
-
}
|
|
106
|
-
})
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function transformExtendedFieldsREAD(req) {
|
|
110
|
-
if (!hasExtendedEntity(req, this.model)) return
|
|
111
|
-
|
|
112
|
-
const target = getTargetRead(req)
|
|
113
|
-
_transformColumns(req.query.SELECT.columns, target.name, this.model)
|
|
114
|
-
|
|
115
|
-
if (req.query.SELECT.from.SET) return _transformUnion(req, this.model) // union
|
|
116
|
-
if (req.query.SELECT.from.join && req.query.SELECT.from.args) return _transformJoin(req, this.model) // join
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
module.exports = {
|
|
120
|
-
transformExtendedFieldsREAD
|
|
121
|
-
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
const { EXT_BACK_PACK, hasExtendedEntity, getTargetRead } = require('../utils')
|
|
2
|
-
|
|
3
|
-
const getTemplate = require('../../common/utils/template')
|
|
4
|
-
const templateProcessor = require('../../common/utils/templateProcessor')
|
|
5
|
-
|
|
6
|
-
const _pick = element => {
|
|
7
|
-
return element['@cds.extension']
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
// The problem here are the extended columss, which are in SELECT.column, but not in the backpack.
|
|
11
|
-
// Otherwise all backpack values could be inserted for row at once.
|
|
12
|
-
const _processorFn = ({ row, key }) => {
|
|
13
|
-
if (row[EXT_BACK_PACK]) {
|
|
14
|
-
const extensions = JSON.parse(row[EXT_BACK_PACK])
|
|
15
|
-
if (extensions[key]) {
|
|
16
|
-
row[key] = extensions[key]
|
|
17
|
-
delete extensions[key]
|
|
18
|
-
if (Object.keys(extensions).length === 0) {
|
|
19
|
-
delete row[EXT_BACK_PACK]
|
|
20
|
-
} else {
|
|
21
|
-
row[EXT_BACK_PACK] = JSON.stringify(extensions)
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
return
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Extended fields are not in SELECT.columns.
|
|
29
|
-
// Workaround for fields not from backpack: provide them all
|
|
30
|
-
row[key] = null
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function transformExtendedFieldsRESULT(result, req) {
|
|
34
|
-
if (!result || !hasExtendedEntity(req, this.model)) return
|
|
35
|
-
|
|
36
|
-
const template = getTemplate('transform-result', this, getTargetRead(req), {
|
|
37
|
-
pick: _pick
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
if (template.elements.size > 0) {
|
|
41
|
-
const result_ = Array.isArray(result) ? result : [result]
|
|
42
|
-
for (const row of result_) {
|
|
43
|
-
const args = { processFn: _processorFn, row, template }
|
|
44
|
-
templateProcessor(args)
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
module.exports = {
|
|
50
|
-
transformExtendedFieldsRESULT
|
|
51
|
-
}
|