@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.
Files changed (206) hide show
  1. package/CHANGELOG.md +77 -8
  2. package/apis/cds.d.ts +18 -6
  3. package/apis/connect.d.ts +1 -1
  4. package/apis/cqn.d.ts +1 -1
  5. package/apis/log.d.ts +23 -5
  6. package/apis/ql.d.ts +128 -61
  7. package/apis/services.d.ts +11 -0
  8. package/apis/test.d.ts +61 -0
  9. package/apis/utils.d.ts +15 -0
  10. package/app/fiori/preview.js +1 -0
  11. package/bin/build/buildTaskEngine.js +70 -22
  12. package/bin/build/buildTaskFactory.js +18 -11
  13. package/bin/build/buildTaskHandler.js +1 -1
  14. package/bin/build/buildTaskProviderFactory.js +3 -13
  15. package/bin/build/constants.js +0 -1
  16. package/bin/build/index.js +14 -6
  17. package/bin/build/provider/buildTaskHandlerEdmx.js +2 -3
  18. package/bin/build/provider/buildTaskHandlerFeatureToggles.js +2 -2
  19. package/bin/build/provider/buildTaskHandlerInternal.js +3 -6
  20. package/bin/build/provider/buildTaskProviderInternal.js +51 -39
  21. package/bin/build/provider/fiori/index.js +3 -3
  22. package/bin/build/provider/hana/2migration.js +1 -1
  23. package/bin/build/provider/hana/index.js +34 -27
  24. package/bin/build/provider/java/index.js +6 -7
  25. package/bin/build/provider/mtx/index.js +20 -18
  26. package/bin/build/provider/mtx/resourcesTarBuilder.js +8 -11
  27. package/bin/build/provider/mtx-sidecar/index.js +13 -17
  28. package/bin/build/provider/nodejs/index.js +8 -7
  29. package/bin/build/util.js +22 -4
  30. package/bin/cds.js +8 -4
  31. package/bin/deploy/to-hana/cfUtil.js +53 -18
  32. package/bin/mtx/in-cds.js +1 -0
  33. package/bin/serve.js +37 -30
  34. package/lib/auth/basic-auth.js +33 -0
  35. package/lib/auth/dummy-auth.js +7 -0
  36. package/lib/auth/ias-auth.js +2 -0
  37. package/lib/auth/index.js +31 -0
  38. package/lib/auth/jwt-auth.js +3 -0
  39. package/lib/auth/mocked-users.js +72 -0
  40. package/lib/auth/passport-basic.js +12 -0
  41. package/lib/auth/passport-digest.js +14 -0
  42. package/lib/auth/xsuaa-auth.js +3 -0
  43. package/lib/compile/cds-compile.js +3 -3
  44. package/lib/compile/to/cdl.js +5 -1
  45. package/lib/compile/to/edm.js +8 -0
  46. package/lib/compile/to/gql.js +1 -0
  47. package/lib/compile/to/json.js +30 -5
  48. package/lib/compile/to/sql.js +3 -1
  49. package/lib/core/index.js +5 -1
  50. package/lib/dbs/cds-deploy.js +36 -6
  51. package/lib/env/cds-env.js +15 -5
  52. package/lib/env/cds-requires.js +51 -58
  53. package/lib/env/defaults.js +1 -0
  54. package/lib/env/schemas/cds-package.json +4 -0
  55. package/lib/env/schemas/cds-rc.json +63 -77
  56. package/lib/i18n/localize.js +16 -5
  57. package/lib/index.js +9 -4
  58. package/lib/log/cds-error.js +4 -6
  59. package/lib/log/cds-log.js +89 -53
  60. package/lib/log/service/index.js +1 -0
  61. package/lib/ql/CREATE.js +2 -5
  62. package/lib/ql/DELETE.js +1 -1
  63. package/lib/ql/DROP.js +1 -3
  64. package/lib/ql/INSERT.js +3 -3
  65. package/lib/ql/Query.js +10 -23
  66. package/lib/ql/SELECT.js +1 -2
  67. package/lib/ql/UPDATE.js +2 -2
  68. package/lib/ql/Whereable.js +7 -15
  69. package/lib/ql/cds-ql.js +9 -3
  70. package/lib/req/cds-context.js +11 -3
  71. package/lib/req/context.js +29 -23
  72. package/lib/req/locale.js +9 -5
  73. package/lib/req/request.js +1 -0
  74. package/lib/req/user.js +2 -1
  75. package/lib/srv/cds-connect.js +1 -1
  76. package/lib/srv/cds-serve.js +21 -14
  77. package/lib/srv/middlewares/cds-context.js +29 -0
  78. package/lib/srv/middlewares/ctx-model.js +24 -0
  79. package/lib/srv/middlewares/errors.js +9 -0
  80. package/lib/srv/middlewares/index.js +22 -0
  81. package/lib/srv/middlewares/sap-statistics.js +13 -0
  82. package/lib/srv/middlewares/trace.js +102 -0
  83. package/lib/srv/protocols/_legacy.js +42 -0
  84. package/lib/srv/protocols/graphql.js +39 -0
  85. package/lib/srv/protocols/hcql.js +37 -0
  86. package/lib/srv/protocols/index.js +86 -0
  87. package/lib/srv/protocols/odata-v2-proxy.js +3767 -0
  88. package/lib/srv/protocols/odata-v2.js +26 -0
  89. package/lib/srv/protocols/odata-v4.js +16 -0
  90. package/lib/srv/protocols/rest.js +13 -0
  91. package/lib/srv/srv-api.js +5 -0
  92. package/lib/srv/srv-models.js +4 -6
  93. package/lib/utils/axios.js +3 -2
  94. package/lib/utils/cds-test.js +27 -21
  95. package/lib/utils/cds-utils.js +19 -20
  96. package/lib/utils/tar.js +175 -0
  97. package/libx/_runtime/audit/generic/personal/utils.js +18 -7
  98. package/libx/_runtime/audit/utils/v2.js +1 -0
  99. package/libx/_runtime/auth/index.js +4 -0
  100. package/libx/_runtime/auth/strategies/ias-auth.js +76 -0
  101. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/error.js +8 -3
  102. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +15 -4
  103. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/expandToCQN.js +1 -1
  104. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/orderByToCQN.js +1 -1
  105. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/utils.js +1 -1
  106. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/ResourcePathParser.js +9 -0
  107. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/UriInfo.js +5 -1
  108. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/UriParser.js +12 -0
  109. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/utils/BufferedWriter.js +6 -2
  110. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/validator/RequestValidator.js +47 -7
  111. package/libx/_runtime/cds-services/adapter/odata-v4/to.js +1 -1
  112. package/libx/_runtime/cds-services/util/assert.js +4 -0
  113. package/libx/_runtime/common/aspects/relation.js +1 -1
  114. package/libx/_runtime/common/composition/data.js +61 -15
  115. package/libx/_runtime/common/composition/delete.js +0 -1
  116. package/libx/_runtime/common/composition/insert.js +0 -1
  117. package/libx/_runtime/common/composition/tree.js +4 -10
  118. package/libx/_runtime/common/composition/update.js +44 -21
  119. package/libx/_runtime/common/generic/auth/capabilities.js +8 -10
  120. package/libx/_runtime/common/generic/crud.js +1 -2
  121. package/libx/_runtime/common/generic/etag.js +4 -4
  122. package/libx/_runtime/common/generic/input.js +4 -4
  123. package/libx/_runtime/common/generic/paging.js +3 -3
  124. package/libx/_runtime/common/generic/put.js +3 -3
  125. package/libx/_runtime/common/generic/sorting.js +4 -4
  126. package/libx/_runtime/common/generic/temporal.js +3 -3
  127. package/libx/_runtime/common/i18n/messages.properties +0 -7
  128. package/libx/_runtime/common/utils/cqn2cqn4sql.js +11 -6
  129. package/libx/_runtime/common/utils/csn.js +0 -28
  130. package/libx/_runtime/common/utils/draft.js +8 -1
  131. package/libx/_runtime/common/utils/path.js +7 -1
  132. package/libx/_runtime/common/utils/resolveView.js +2 -3
  133. package/libx/_runtime/db/data-conversion/post-processing.js +3 -44
  134. package/libx/_runtime/db/generic/input.js +3 -3
  135. package/libx/_runtime/db/sql-builder/dataTypes.js +4 -0
  136. package/libx/_runtime/fiori/generic/activate.js +2 -2
  137. package/libx/_runtime/fiori/generic/before.js +40 -72
  138. package/libx/_runtime/fiori/generic/cancel.js +2 -2
  139. package/libx/_runtime/fiori/generic/delete.js +2 -2
  140. package/libx/_runtime/fiori/generic/edit.js +2 -2
  141. package/libx/_runtime/fiori/generic/new.js +2 -2
  142. package/libx/_runtime/fiori/generic/patch.js +49 -37
  143. package/libx/_runtime/fiori/generic/prepare.js +2 -2
  144. package/libx/_runtime/fiori/generic/read.js +27 -37
  145. package/libx/_runtime/fiori/utils/where.js +4 -2
  146. package/libx/_runtime/hana/Service.js +1 -3
  147. package/libx/_runtime/hana/conversion.js +3 -0
  148. package/libx/_runtime/hana/driver.js +33 -3
  149. package/libx/_runtime/hana/dynatrace.js +1 -0
  150. package/libx/_runtime/hana/search2Contains.js +12 -1
  151. package/libx/_runtime/hana/search2cqn4sql.js +10 -27
  152. package/libx/_runtime/hana/streaming.js +1 -0
  153. package/libx/_runtime/messaging/AMQPWebhookMessaging.js +4 -2
  154. package/libx/_runtime/messaging/common-utils/AMQPClient.js +1 -0
  155. package/libx/_runtime/messaging/enterprise-messaging-utils/getTenantInfo.js +5 -2
  156. package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +2 -0
  157. package/libx/_runtime/messaging/enterprise-messaging.js +62 -3
  158. package/libx/_runtime/messaging/outbox/utils.js +1 -1
  159. package/libx/_runtime/messaging/redis-messaging.js +1 -0
  160. package/libx/_runtime/remote/Service.js +2 -2
  161. package/libx/_runtime/remote/utils/client.js +8 -3
  162. package/libx/_runtime/remote/utils/data.js +7 -2
  163. package/libx/_runtime/sqlite/Service.js +18 -7
  164. package/libx/_runtime/sqlite/conversion.js +3 -0
  165. package/libx/_runtime/sqlite/convertAssocToOneManaged.js +3 -3
  166. package/libx/_runtime/sqlite/localized.js +8 -8
  167. package/libx/odata/afterburner.js +39 -7
  168. package/libx/odata/cqn2odata.js +6 -3
  169. package/libx/odata/grammar.pegjs +66 -18
  170. package/libx/odata/index.js +3 -2
  171. package/libx/odata/parser.js +1 -1
  172. package/libx/odata/utils.js +2 -0
  173. package/libx/rest/RestAdapter.js +62 -43
  174. package/libx/rest/middleware/parse.js +2 -1
  175. package/libx/rest/middleware/update.js +1 -1
  176. package/package.json +2 -2
  177. package/server.js +5 -4
  178. package/srv/mtx.cds +1 -1
  179. package/srv/mtx.js +4 -33
  180. package/lib/srv/adapters.js +0 -85
  181. package/lib/utils/resources/index.js +0 -48
  182. package/lib/utils/resources/tar.js +0 -49
  183. package/lib/utils/resources/utils.js +0 -11
  184. package/libx/_runtime/extensibility/activate.js +0 -69
  185. package/libx/_runtime/extensibility/add.js +0 -50
  186. package/libx/_runtime/extensibility/addExtension.js +0 -72
  187. package/libx/_runtime/extensibility/defaults.js +0 -34
  188. package/libx/_runtime/extensibility/handler/transformREAD.js +0 -121
  189. package/libx/_runtime/extensibility/handler/transformRESULT.js +0 -51
  190. package/libx/_runtime/extensibility/handler/transformWRITE.js +0 -64
  191. package/libx/_runtime/extensibility/linter/allowlist_checker.js +0 -373
  192. package/libx/_runtime/extensibility/linter/annotations_checker.js +0 -113
  193. package/libx/_runtime/extensibility/linter/checker_base.js +0 -20
  194. package/libx/_runtime/extensibility/linter/namespace_checker.js +0 -180
  195. package/libx/_runtime/extensibility/linter.js +0 -32
  196. package/libx/_runtime/extensibility/push.js +0 -118
  197. package/libx/_runtime/extensibility/service.js +0 -38
  198. package/libx/_runtime/extensibility/token.js +0 -57
  199. package/libx/_runtime/extensibility/utils.js +0 -131
  200. package/libx/_runtime/extensibility/validation.js +0 -50
  201. package/libx/_runtime/extensibility/views.js +0 -12
  202. package/srv/extensibility-service.cds +0 -60
  203. package/srv/extensibility-service.js +0 -1
  204. package/srv/extensions.cds +0 -8
  205. package/srv/model-provider.cds +0 -61
  206. package/srv/model-provider.js +0 -143
package/srv/mtx.js CHANGED
@@ -1,37 +1,8 @@
1
- const cds = require ('../lib')
2
- const DEBUG = cds.debug('mtx')
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
- // else...
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
+ }
@@ -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,11 +0,0 @@
1
- const fs = require('fs')
2
-
3
- const exists = async fileOrDir => {
4
- try {
5
- return await fs.promises.stat(fileOrDir)
6
- } catch (_) {
7
- return false
8
- }
9
- }
10
-
11
- module.exports = { exists }
@@ -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
- }