@sap/cds 6.8.4 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (214) hide show
  1. package/CHANGELOG.md +58 -5
  2. package/README.md +0 -1
  3. package/bin/cds-serve.js +50 -3
  4. package/bin/deploy/to-hana.js +1 -0
  5. package/bin/serve.js +16 -20
  6. package/lib/auth/basic-auth.js +6 -4
  7. package/lib/auth/index.js +4 -3
  8. package/lib/auth/jwt-auth.js +2 -5
  9. package/lib/compile/cds-compile.js +34 -89
  10. package/lib/compile/cdsc.js +11 -0
  11. package/lib/compile/etc/properties.js +2 -2
  12. package/lib/compile/for/lean_drafts.js +36 -69
  13. package/lib/compile/for/nodejs.js +2 -1
  14. package/lib/compile/load.js +1 -1
  15. package/lib/compile/minify.js +2 -0
  16. package/lib/compile/to/csn.js +74 -0
  17. package/{bin/build/provider/hana/2tabledata.js → lib/compile/to/hdbtabledata.js} +4 -6
  18. package/lib/compile/to/json.js +1 -1
  19. package/lib/compile/to/sql.js +8 -6
  20. package/lib/dbs/cds-deploy.js +174 -114
  21. package/lib/env/cds-env.js +64 -79
  22. package/lib/env/cds-requires.js +11 -28
  23. package/lib/env/defaults.js +13 -3
  24. package/lib/env/plugins.js +1 -12
  25. package/lib/env/presets.js +25 -21
  26. package/lib/index.js +121 -147
  27. package/lib/{core/reflect.js → linked/models.js} +2 -2
  28. package/lib/{core/infer.js → linked/queries.js} +2 -0
  29. package/lib/{core/index.js → linked/types.js} +2 -1
  30. package/lib/log/cds-error.js +13 -7
  31. package/lib/log/format/cf.js +1 -1
  32. package/lib/plugins.js +49 -0
  33. package/lib/ql/Query.js +0 -9
  34. package/lib/ql/STREAM.js +0 -1
  35. package/lib/req/context.js +2 -7
  36. package/lib/req/request.js +6 -2
  37. package/lib/req/response.js +23 -10
  38. package/lib/srv/middlewares/ctx-model.js +1 -1
  39. package/lib/srv/middlewares/errors.js +1 -1
  40. package/lib/srv/protocols/_legacy.js +1 -0
  41. package/lib/srv/protocols/graphql.js +7 -16
  42. package/lib/srv/protocols/index.js +59 -45
  43. package/lib/srv/protocols/odata-v2-proxy.js +2 -70
  44. package/lib/srv/srv-api.js +9 -3
  45. package/lib/srv/srv-dispatch.js +12 -9
  46. package/lib/srv/srv-models.js +4 -21
  47. package/lib/srv/srv-tx.js +15 -12
  48. package/lib/utils/cds-test.js +14 -9
  49. package/lib/utils/cds-utils.js +2 -12
  50. package/lib/utils/check-version.js +17 -0
  51. package/{bin/build → lib/utils}/csv-reader.js +23 -24
  52. package/libx/_runtime/auth/index.js +27 -23
  53. package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +15 -72
  54. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/create.js +1 -1
  55. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +0 -2
  56. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +33 -63
  57. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +14 -18
  58. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +15 -5
  59. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +5 -4
  60. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/readToCQN.js +37 -40
  61. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/updateToCQN.js +7 -1
  62. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/utils.js +101 -38
  63. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/errors/AbstractError.js +5 -1
  64. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/utils/ValueConverter.js +2 -1
  65. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/deserializer/ResourceJsonDeserializer.js +9 -8
  66. package/libx/_runtime/cds-services/adapter/odata-v4/to.js +1 -1
  67. package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +15 -11
  68. package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +4 -0
  69. package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +5 -2
  70. package/libx/_runtime/cds-services/adapter/odata-v4/utils/stream.js +1 -123
  71. package/libx/_runtime/cds-services/services/Service.js +79 -107
  72. package/libx/_runtime/cds-services/services/utils/columns.js +23 -19
  73. package/libx/_runtime/cds-services/services/utils/compareJson.js +11 -1
  74. package/libx/_runtime/cds-services/services/utils/differ.js +7 -2
  75. package/libx/_runtime/cds-services/util/assert.js +65 -2
  76. package/libx/_runtime/common/composition/data.js +1 -0
  77. package/libx/_runtime/common/generic/auth/expand.js +1 -1
  78. package/libx/_runtime/common/generic/auth/restrict.js +5 -10
  79. package/libx/_runtime/common/generic/auth/restrictions.js +40 -0
  80. package/libx/_runtime/common/generic/auth/utils.js +1 -2
  81. package/libx/_runtime/common/generic/crud.js +32 -16
  82. package/libx/_runtime/common/generic/etag.js +133 -104
  83. package/libx/_runtime/common/generic/input.js +6 -21
  84. package/libx/_runtime/common/generic/put.js +1 -1
  85. package/libx/_runtime/common/generic/stream.js +52 -0
  86. package/libx/_runtime/common/generic/temporal.js +25 -8
  87. package/libx/_runtime/common/i18n/messages.properties +0 -2
  88. package/libx/_runtime/common/utils/cqn.js +1 -1
  89. package/libx/_runtime/common/utils/cqn2cqn4sql.js +5 -2
  90. package/libx/_runtime/common/utils/csn.js +0 -51
  91. package/libx/_runtime/common/utils/etag.js +30 -0
  92. package/libx/_runtime/common/utils/keys.js +1 -1
  93. package/libx/_runtime/common/utils/normalizeTimestamp.js +25 -0
  94. package/libx/_runtime/common/utils/path.js +1 -1
  95. package/libx/_runtime/common/utils/resolveView.js +2 -1
  96. package/libx/_runtime/common/utils/rewriteAsterisks.js +6 -4
  97. package/libx/_runtime/common/utils/search2cqn4sql.js +12 -16
  98. package/libx/_runtime/common/utils/stream.js +140 -0
  99. package/libx/_runtime/common/utils/streamProp.js +29 -12
  100. package/libx/_runtime/common/utils/templateProcessorPathSerializer.js +0 -2
  101. package/libx/_runtime/db/generic/index.js +0 -2
  102. package/libx/_runtime/db/query/delete.js +2 -2
  103. package/libx/_runtime/db/query/insert.js +2 -2
  104. package/libx/_runtime/db/query/read.js +2 -2
  105. package/libx/_runtime/db/query/run.js +2 -2
  106. package/libx/_runtime/db/query/update.js +2 -2
  107. package/libx/_runtime/db/sql-builder/BaseBuilder.js +0 -6
  108. package/libx/_runtime/db/sql-builder/ExpressionBuilder.js +23 -12
  109. package/libx/_runtime/db/sql-builder/FunctionBuilder.js +18 -6
  110. package/libx/_runtime/db/sql-builder/InsertBuilder.js +1 -0
  111. package/libx/_runtime/db/sql-builder/SelectBuilder.js +3 -7
  112. package/libx/_runtime/db/sql-builder/UpsertBuilder.js +1 -0
  113. package/libx/_runtime/db/utils/normalizeTimeData.js +7 -3
  114. package/libx/_runtime/fiori/draft.js +2 -0
  115. package/libx/_runtime/fiori/generic/activate.js +8 -9
  116. package/libx/_runtime/fiori/generic/before.js +30 -20
  117. package/libx/_runtime/fiori/generic/cancel.js +5 -3
  118. package/libx/_runtime/fiori/generic/delete.js +5 -3
  119. package/libx/_runtime/fiori/generic/edit.js +7 -7
  120. package/libx/_runtime/fiori/generic/index.js +10 -16
  121. package/libx/_runtime/fiori/generic/new.js +5 -3
  122. package/libx/_runtime/fiori/generic/patch.js +11 -8
  123. package/libx/_runtime/fiori/generic/prepare.js +13 -6
  124. package/libx/_runtime/fiori/generic/read.js +12 -6
  125. package/libx/_runtime/fiori/lean-draft.js +207 -152
  126. package/libx/_runtime/fiori/utils/delete.js +10 -5
  127. package/libx/_runtime/fiori/utils/req.js +17 -5
  128. package/libx/_runtime/fiori/utils/stream.js +36 -0
  129. package/libx/_runtime/hana/Service.js +12 -9
  130. package/libx/_runtime/hana/conversion.js +10 -15
  131. package/libx/_runtime/hana/driver.js +2 -0
  132. package/libx/_runtime/hana/execute.js +28 -6
  133. package/libx/_runtime/hana/pool.js +36 -122
  134. package/libx/_runtime/hana/search2cqn4sql.js +34 -36
  135. package/libx/_runtime/messaging/enterprise-messaging-utils/getTenantInfo.js +2 -6
  136. package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +3 -1
  137. package/libx/_runtime/messaging/enterprise-messaging.js +10 -58
  138. package/libx/_runtime/messaging/outbox/utils.js +1 -1
  139. package/libx/_runtime/remote/Service.js +20 -1
  140. package/libx/_runtime/remote/utils/client.js +3 -5
  141. package/libx/_runtime/sqlite/Service.js +4 -6
  142. package/libx/_runtime/sqlite/conversion.js +3 -13
  143. package/libx/_runtime/sqlite/customBuilder/CustomFunctionBuilder.js +9 -6
  144. package/libx/_runtime/sqlite/customBuilder/CustomUpsertBuilder.js +6 -1
  145. package/libx/_runtime/sqlite/execute.js +5 -16
  146. package/libx/odata/afterburner.js +22 -6
  147. package/libx/odata/grammar.pegjs +6 -1
  148. package/libx/odata/parser.js +1 -1
  149. package/libx/rest/RestAdapter.js +16 -9
  150. package/libx/rest/RestRequest.js +1 -1
  151. package/libx/rest/middleware/input.js +2 -1
  152. package/libx/rest/middleware/operation.js +1 -0
  153. package/libx/rest/middleware/parse.js +3 -2
  154. package/libx/rest/middleware/payload.js +9 -8
  155. package/libx/rest/middleware/read.js +1 -0
  156. package/package.json +9 -16
  157. package/app/fiori/preview.js +0 -270
  158. package/app/fiori/routes.js +0 -59
  159. package/bin/build/buildTaskEngine.js +0 -360
  160. package/bin/build/buildTaskFactory.js +0 -283
  161. package/bin/build/buildTaskHandler.js +0 -241
  162. package/bin/build/buildTaskProvider.js +0 -22
  163. package/bin/build/buildTaskProviderFactory.js +0 -175
  164. package/bin/build/cds.js +0 -5
  165. package/bin/build/constants.js +0 -66
  166. package/bin/build/index.js +0 -58
  167. package/bin/build/provider/buildTaskHandlerEdmx.js +0 -82
  168. package/bin/build/provider/buildTaskHandlerFeatureToggles.js +0 -131
  169. package/bin/build/provider/buildTaskHandlerInternal.js +0 -254
  170. package/bin/build/provider/buildTaskProviderInternal.js +0 -383
  171. package/bin/build/provider/fiori/index.js +0 -171
  172. package/bin/build/provider/hana/2migration.js +0 -179
  173. package/bin/build/provider/hana/index.js +0 -505
  174. package/bin/build/provider/hana/migrationtable.js +0 -472
  175. package/bin/build/provider/hana/template/.hdiconfig-haas +0 -163
  176. package/bin/build/provider/hana/template/.hdiconfig-hanacloud +0 -137
  177. package/bin/build/provider/hana/template/.hdinamespace +0 -4
  178. package/bin/build/provider/hana/template/package.json +0 -12
  179. package/bin/build/provider/hana/template/undeploy.json +0 -5
  180. package/bin/build/provider/java/index.js +0 -111
  181. package/bin/build/provider/java-cf/index.js +0 -1
  182. package/bin/build/provider/mtx/index.js +0 -268
  183. package/bin/build/provider/mtx/resourcesTarBuilder.js +0 -95
  184. package/bin/build/provider/mtx-extension/index.js +0 -131
  185. package/bin/build/provider/mtx-sidecar/index.js +0 -137
  186. package/bin/build/provider/node-cf/index.js +0 -1
  187. package/bin/build/provider/nodejs/index.js +0 -192
  188. package/bin/build/util.js +0 -299
  189. package/bin/cds.js +0 -125
  190. package/bin/deploy/to-hana/cfUtil.js +0 -355
  191. package/bin/deploy/to-hana/gitUtil.js +0 -57
  192. package/bin/deploy/to-hana/hana.js +0 -306
  193. package/bin/deploy/to-hana/hdiDeployUtil.js +0 -153
  194. package/bin/deploy/to-hana/index.js +0 -16
  195. package/bin/deploy/to-hana/mtaUtil.js +0 -170
  196. package/bin/mtx/in-cds.js +0 -17
  197. package/bin/plugins.js +0 -32
  198. package/bin/run.js +0 -24
  199. package/bin/utils/log.js +0 -24
  200. package/bin/version.js +0 -178
  201. package/libx/_runtime/audit/Service.js +0 -222
  202. package/libx/_runtime/audit/generic/personal/access.js +0 -61
  203. package/libx/_runtime/audit/generic/personal/index.js +0 -56
  204. package/libx/_runtime/audit/generic/personal/modification.js +0 -132
  205. package/libx/_runtime/audit/generic/personal/utils.js +0 -186
  206. package/libx/_runtime/audit/utils/log.js +0 -23
  207. package/libx/_runtime/audit/utils/v2.js +0 -176
  208. package/libx/_runtime/db/data-conversion/timestamp.js +0 -9
  209. package/libx/_runtime/db/generic/integrity.js +0 -455
  210. package/srv/audit-log.cds +0 -87
  211. package/srv/mtx.cds +0 -2
  212. package/srv/mtx.js +0 -8
  213. /package/lib/{core → linked}/classes.js +0 -0
  214. /package/lib/{core → linked}/entities.js +0 -0
@@ -1,171 +0,0 @@
1
- const path = require('path')
2
- const cds = require('../../cds')
3
- const BuildTaskHandlerEdmx = require('../buildTaskHandlerEdmx')
4
- const URL = require('url')
5
- const { getProperty, isOldJavaStack, relativePaths } = require('../../util')
6
-
7
- const { ODATA_VERSION_V2, BUILD_OPTION_OUTPUT_MODE, OUTPUT_MODE_RESULT_ONLY, BUILD_TASK_FIORI, BUILD_TASK_JAVA_CF, CDS_CONFIG_PATH_SEP, BUILD_TASK_JAVA } = require('../../constants')
8
-
9
- /**
10
- * With cds 4 service metadata for the UI service binding is no longer created by default.
11
- * For SAP Web IDE Full-Stack compatibility a corresponding metadata.xml is still generated.
12
- * Though, 'fiori' build tasks can still be configured for UI5 mockserver usage - see https://github.wdf.sap.corp/cap/issues/issues/8673
13
- */
14
- class FioriAppModuleBuilder extends BuildTaskHandlerEdmx {
15
- async prepare() {
16
- this.buildOptions.for[BUILD_TASK_FIORI] = this.buildOptions.for[BUILD_TASK_FIORI] || {}
17
-
18
- // cache for later use across multiple FioriAppModuleBuilder instances
19
- const fioriBuildOptions = getProperty(this.buildOptions.for, BUILD_TASK_FIORI)
20
- fioriBuildOptions.appModel = new Map()
21
- fioriBuildOptions.appEdmx = new Map()
22
-
23
- // group tasks that have a common application root folder
24
- const appTaskGroups = new Map()
25
- this.buildOptions.tasks.forEach(task => {
26
- if (task.for === BUILD_TASK_FIORI) {
27
- const appFolder = path.relative(this.buildOptions.root, task.src).split(CDS_CONFIG_PATH_SEP)[0]
28
- appTaskGroups.has(appFolder) ? appTaskGroups.get(appFolder).push(task) : appTaskGroups.set(appFolder, [task])
29
- }
30
- })
31
-
32
- // merge all model references to resolve the model later on
33
- const appModelGroups = new Map()
34
- for (let [appFolder, appTaskGroup] of appTaskGroups.entries()) {
35
- const appModels = new Set()
36
- appTaskGroup.forEach(task => {
37
- if (Array.isArray(task.options.model)) {
38
- task.options.model.forEach(model => appModels.add(model))
39
- }
40
- })
41
- appModelGroups.set(appFolder, appModels)
42
- }
43
-
44
- const originFioriBuildOption = fioriBuildOptions[BUILD_OPTION_OUTPUT_MODE]
45
- fioriBuildOptions[BUILD_OPTION_OUTPUT_MODE] = OUTPUT_MODE_RESULT_ONLY
46
-
47
- try {
48
- const edmxOptions = { version: cds.env.odata?.version }
49
-
50
- if (edmxOptions.version !== ODATA_VERSION_V2) {
51
- const javaTask = this.buildOptions.tasks.find(task => task.for === BUILD_TASK_JAVA_CF || task.for === BUILD_TASK_JAVA)
52
-
53
- if (javaTask
54
- && await isOldJavaStack([javaTask.src, this.buildOptions.root])
55
- && !cds.env.for("cds", this.buildOptions.root, false).odata?.version) {
56
-
57
- // old java stack
58
- // default is now v4 and not v2 anymore, so overwrite with v2 if using default
59
- this.logger.debug("Fiori task is forcing OData v2 for building though the default is v4.")
60
- edmxOptions.version = ODATA_VERSION_V2
61
- }
62
- }
63
-
64
- for (let [appFolder, appModelGroup] of appModelGroups.entries()) {
65
- this.logger.debug(`building module [${appFolder}] using [${this.constructor.name}]`)
66
- const modelPaths = cds.resolve(Array.from(appModelGroup.values()), this.buildOptions)
67
- if (!modelPaths || modelPaths.length === 0) {
68
- continue
69
- }
70
- this.logger._debug && this.logger.debug(`model: ${relativePaths(this.buildOptions.root, modelPaths).join(", ")}`)
71
-
72
- //cache model per fiori app root folder
73
- const options = this.options()
74
- const model = await cds.load(modelPaths, options)
75
- fioriBuildOptions.appModel.set(appFolder, model)
76
-
77
- await this.compileToEdmx(model, null, edmxOptions)
78
-
79
- // cache edmx per fiori app root folder
80
- fioriBuildOptions.appEdmx.set(appFolder, this._result.edmx)
81
- }
82
- } finally {
83
- fioriBuildOptions[BUILD_OPTION_OUTPUT_MODE] = originFioriBuildOption
84
- }
85
- return false
86
- }
87
-
88
- /**
89
- * This version only creates a odata representation for the 'mainService' data source
90
- * as defined by the fiori wizard - everything else is currently not supported.
91
- * Therefore errors are only logged, the build does not fail in case a service
92
- * cannot be resolved based on the defined service URI
93
- */
94
- async build() {
95
- const model = await this.model()
96
- if (!model) {
97
- return
98
- }
99
- await this._writeEdmxToWebapp(this.task.src, this.task.dest)
100
- }
101
-
102
- async _writeEdmxToWebapp(src, dest) {
103
- const manifestPath = path.join(src, 'webapp', 'manifest.json')
104
- let manifest
105
-
106
- try {
107
- manifest = require(manifestPath)
108
- } catch (error) {
109
- this.logger.log(`UI module does not contain a manifest.json [${relativePaths(this.buildOptions.root, manifestPath)}], skipping build`)
110
- return
111
- }
112
-
113
- const mainService = getProperty(manifest, ['sap.app', 'dataSources', 'mainService'])
114
- if (!mainService) {
115
- // no mainService defined - not supported
116
- this.logger._debug && this.logger.debug(`UI module does not have a datasource [mainService], [${relativePaths(this.buildOptions.root, manifestPath)}], skipping build`)
117
- return
118
- }
119
-
120
- const localUri = getProperty(mainService, ['settings', 'localUri'])
121
- const uri = mainService.uri
122
-
123
- if (!localUri || !uri) {
124
- this.logger._debug && this.logger.warn(`local uri setting missing for data source [mainService], [${relativePaths(this.buildOptions.root, manifestPath)}]`)
125
- return
126
- }
127
-
128
- const appFolder = path.relative(this.buildOptions.root, src).split(CDS_CONFIG_PATH_SEP)[0]
129
- const model = this.getBuildOption("appModel").get(appFolder)
130
- if (!model) {
131
- this.logger.error(`failed to load model for service uri ${uri}, data source [mainService]`)
132
- return
133
- }
134
-
135
- const edmx = this._getEdmxForUri(model, appFolder, uri)
136
- if (!edmx) {
137
- this.logger.error(`failed to resolve service definition for service uri ${uri}, data source [mainService]`)
138
- return
139
- }
140
-
141
- if (!this.hasBuildOption(BUILD_OPTION_OUTPUT_MODE, OUTPUT_MODE_RESULT_ONLY)) {
142
- const edmxPath = path.resolve(path.join(dest, 'webapp'), this._strippedUrlPath(localUri))
143
- return this.write(edmx).to(edmxPath)
144
- }
145
- }
146
-
147
- _getEdmxForUri(model, appFolder, uri) {
148
- const uriSegments = this._strippedUrlPath(uri).split('/')
149
-
150
- // one segment of the URI has to match a service name
151
- // NOTE: assumption is that the service definition can be resolved - either by
152
- // - defining corresponding using statement in annotations model or
153
- // - adding the service module folder to the model option
154
- let service = cds.reflect(model).find(service => uriSegments.find(segment => service.name === segment))
155
-
156
- if (service) {
157
- const allServices = this.getBuildOption("appEdmx").get(appFolder)
158
- if (allServices) {
159
- return allServices.get(service.name + ".xml")
160
- }
161
- }
162
- return null
163
- }
164
-
165
- _strippedUrlPath(urlString) {
166
- const url = URL.parse(urlString)
167
- return url.pathname.replace(/^(\/|\\)/, '').replace(/(\/|\\)$/, '') // strip leading and trailing slash or backslash)
168
- }
169
- }
170
-
171
- module.exports = FioriAppModuleBuilder
@@ -1,179 +0,0 @@
1
- const path = require('path')
2
- const parser = require('./migrationtable')
3
- const { BuildError, hasOptionValue } = require('../../util')
4
- const { LOG_MODULE_NAMES } = require('../../constants')
5
- const cds = require('../../cds'), { compiler: cdsc } = cds
6
- const cdscVersion = `-- generated by cds-compiler version ${cdsc.version()}`
7
- const { getArtifactCdsPersistenceName } = cdsc
8
- let logger = cds.log(LOG_MODULE_NAMES)
9
- const ANNO_PERSISTENCE_JOURNAL = '@cds.persistence.journal'
10
-
11
- module.exports = async (model, lastDevVersion, srcPath, options = {}) => {
12
- if (options.logger) {
13
- logger = options.logger
14
- }
15
-
16
- const journalFileNames = _getJournalFileNames(model)
17
- const { definitions, deletions, migrations, afterImage } = _toHdiMigration(model, lastDevVersion, journalFileNames, options)
18
- const definitionResult = []
19
-
20
- for (const { name, suffix, sql } of definitions) {
21
- let definitionEntry = { name, suffix, content: sql }
22
-
23
- if (suffix === '.hdbtable') {
24
- if (journalFileNames.has(name)) {
25
- const migration = migrations.find(migration => migration.name === name)
26
- definitionEntry = await _2migrationtable(srcPath, migration || _emptyMigration(name), sql)
27
- }
28
- }
29
- if (definitionEntry) {
30
- definitionResult.push(definitionEntry)
31
- }
32
- }
33
- return { definitions: definitionResult, deletions, afterImage: _filterJournalArtifacts(afterImage) }
34
- }
35
-
36
- function _toHdiMigration(model, lastDevVersion, journalFileNames, options) {
37
- const result = cdsc.to.hdi.migration(cds.minify(model), options, lastDevVersion);
38
- if (logger._debug) {
39
- logger.debug('cdsc.to.hdi.migration returned')
40
- for (const { name, suffix, sql } of result.definitions) {
41
- if (suffix === '.hdbtable' || suffix === '.hdbmigrationtable') {
42
- if (journalFileNames.has(name)) {
43
- const migration = result.migrations.find(migration => migration.name === name)
44
- logger.debug(`
45
- File ${name + '.hdbmigrationtable'} - ${migration ? migration.changeset.length : 0} new changes
46
- ${sql}
47
- ${migration ? migration.changeset.map(change => change.sql).join('\n') : 'Empty changeset'}
48
- `)
49
- }
50
- }
51
- }
52
- }
53
- return result
54
- }
55
-
56
- /**
57
- * Returns an object providing access to the .hdbmigrationtable file content and its corresponding filename.
58
- *
59
- * @param {String} srcPath Fully qualified path of the directory containing .hdbmigrationtable files
60
- * @param {String} migration the migration descriptor
61
- * @param {String} tableSql SQL TABLE definition
62
- * @returns {Object} Providing access to 'content' and 'fileName'.
63
- */
64
- async function _2migrationtable(srcPath, migration, tableSql) {
65
- let migrationTableModel = null
66
- const file = path.join(srcPath, migration.name + migration.suffix)
67
- try {
68
- migrationTableModel = await parser.read(file)
69
- } catch (e) {
70
- // abort build in order to ensure consistent afterImage model state / hdbmigrationtable file state
71
- throw new BuildError(`${path.relative(process.cwd(), file)}: ${e.message}`)
72
- }
73
-
74
- if (migrationTableModel) {
75
- // adding new changeset if change exist, ignore otherwise
76
- const migrationEntry = _getNewMigrationEntry(migration.changeset, migrationTableModel.versionNumber)
77
- if (migrationEntry) {
78
- const versionNumber = migrationTableModel.versionNumber + 1
79
- const migrationCount = migrationTableModel.migrations.entries.length
80
- const migrations = `${migrationEntry.content}${migrationCount > 0 ? '\n' : ''}${migrationTableModel.migrations.toString()}${migrationCount > 0 ? '\n' : ''}`
81
- return {
82
- name: migration.name,
83
- suffix: migration.suffix,
84
- content: `== version=${versionNumber}\n${tableSql}\n\n${migrations}`,
85
- changed: true,
86
- dropColumns: migrationEntry.dropColumns
87
- }
88
- } else {
89
- // existing migration file version
90
- return { name: migration.name, suffix: migration.suffix, content: migrationTableModel.toString(), changed: false }
91
- }
92
- }
93
- // initial migration file version
94
- return { name: migration.name, suffix: migration.suffix, content: `== version=1\n${tableSql}\n`, changed: true }
95
- }
96
-
97
- function _getNewMigrationEntry(changeset, currentVersion) {
98
- if (changeset && changeset.length > 0) {
99
- const dropColumns = changeset.some(e => e.drop)
100
- const manualChange = changeset.some(e => !e.sql)
101
- const enableDrop = cds.env.hana?.journal?.['enable-drop']
102
- const content = changeset.reduce((acc, e) => {
103
- if (!acc) {
104
- acc = `== migration=${currentVersion + 1}\n`
105
- acc += `${cdscVersion}\n`
106
-
107
- if (dropColumns && enableDrop !== true) {
108
- acc += `>>>>> Manual resolution required - DROP statements causing data loss are disabled by default.
109
- >>>>> You may either:
110
- >>>>> uncomment statements to allow incompatible changes, or
111
- >>>>> refactor statements, e.g. replace DROP/ADD by single RENAME statement
112
- >>>>> After manual resolution delete all lines starting with >>>>>\n`
113
- } else if (manualChange) {
114
- acc += `>>>>> Manual resolution required - insert ALTER statement(s) as described below.
115
- >>>>> After manual resolution delete all lines starting with >>>>>\n`
116
- }
117
- }
118
- if (e.sql) {
119
- if (e.drop && enableDrop !== true) {
120
- acc += `${e.sql.replace(/^/gm, '-- ')}\n`;
121
- } else {
122
- acc += `${e.sql}\n`
123
- }
124
- } else {
125
- acc +=
126
- `>>>>> Insert ALTER statement for: ${e.description}\n`
127
- }
128
- return acc
129
- }, null)
130
- return { dropColumns, content }
131
- }
132
- return null
133
- }
134
-
135
- function _emptyMigration(name) {
136
- return { name, suffix: ".hdbmigrationtable", changeset: [] }
137
- }
138
-
139
- function _getJournalFileNames(model) {
140
- const journalNames = new Set(cds.reflect(model).all(item => {
141
- if (item.kind === 'entity' && item[ANNO_PERSISTENCE_JOURNAL] === true) {
142
- if (item['@cds.persistence.skip'] === true || item['@cds.persistence.exists'] === true) {
143
- logger.warn(`[hdbmigrationtable] annotation @cds.persistence.journal skipped for entity '${item.name}' as persistence exists`)
144
- }
145
- return true
146
- }
147
- return false
148
- }).map(entity => getArtifactCdsPersistenceName(entity.name, 'quoted', model, 'hana')))
149
-
150
- logger._debug && logger.debug(`\n[hdbmigrationtable] found ${journalNames.size} model entities annotated with '@cds.persistence.journal`)
151
- logger._debug && logger.debug(`[hdbmigrationtable] ${[...journalNames].join(', ')}\n`)
152
-
153
- return journalNames
154
- }
155
-
156
- // delete all entities that are not relevant
157
- function _filterJournalArtifacts(csn) {
158
- if (!csn) {
159
- return
160
- }
161
- const dict = csn.definitions
162
- for (const name in dict) {
163
- if (!_isPersistedAsJournalTable(dict[name])) {
164
- delete dict[name]
165
- }
166
- }
167
- // mark CSN as modified by cds build
168
- csn.meta.build = `CDS Build v${cds.version}`
169
- return csn;
170
- }
171
-
172
- // see cds-compiler/lib/model/csnUtils.js#isPersistedAsTable
173
- function _isPersistedAsJournalTable(artifact) {
174
- return artifact.kind === 'entity' && hasOptionValue(artifact['@cds.persistence.journal'], true) &&
175
- !artifact.abstract &&
176
- !hasOptionValue(artifact['@cds.persistence.skip'], true) &&
177
- !hasOptionValue(artifact['@cds.persistence.exists'], true) &&
178
- (!artifact.query && !artifact.projection || hasOptionValue(artifact['@cds.persistence.table'], true))
179
- }