@sap/cds 6.8.4 → 7.0.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 (217) hide show
  1. package/CHANGELOG.md +66 -4
  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 +3 -3
  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 +2 -2
  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/protocols/odata-v4.js +9 -4
  45. package/lib/srv/srv-api.js +9 -3
  46. package/lib/srv/srv-dispatch.js +12 -9
  47. package/lib/srv/srv-models.js +4 -21
  48. package/lib/srv/srv-tx.js +15 -12
  49. package/lib/utils/cds-test.js +14 -9
  50. package/lib/utils/cds-utils.js +2 -12
  51. package/lib/utils/check-version.js +17 -0
  52. package/{bin/build → lib/utils}/csv-reader.js +23 -24
  53. package/libx/_runtime/auth/index.js +27 -23
  54. package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +15 -72
  55. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/create.js +1 -1
  56. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +0 -2
  57. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +33 -63
  58. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +14 -18
  59. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +15 -5
  60. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +5 -4
  61. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/readToCQN.js +37 -40
  62. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/updateToCQN.js +7 -1
  63. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/utils.js +101 -38
  64. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/errors/AbstractError.js +5 -1
  65. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/UriTokenizer.js +5 -8
  66. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/utils/ValueConverter.js +2 -1
  67. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/deserializer/ResourceJsonDeserializer.js +9 -8
  68. package/libx/_runtime/cds-services/adapter/odata-v4/to.js +1 -1
  69. package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +15 -11
  70. package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +4 -0
  71. package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +5 -2
  72. package/libx/_runtime/cds-services/adapter/odata-v4/utils/stream.js +1 -123
  73. package/libx/_runtime/cds-services/services/Service.js +79 -107
  74. package/libx/_runtime/cds-services/services/utils/columns.js +23 -19
  75. package/libx/_runtime/cds-services/services/utils/compareJson.js +11 -1
  76. package/libx/_runtime/cds-services/services/utils/differ.js +7 -2
  77. package/libx/_runtime/cds-services/util/assert.js +65 -2
  78. package/libx/_runtime/common/composition/data.js +1 -0
  79. package/libx/_runtime/common/generic/auth/expand.js +1 -1
  80. package/libx/_runtime/common/generic/auth/restrict.js +5 -10
  81. package/libx/_runtime/common/generic/auth/restrictions.js +40 -0
  82. package/libx/_runtime/common/generic/auth/utils.js +1 -2
  83. package/libx/_runtime/common/generic/crud.js +32 -16
  84. package/libx/_runtime/common/generic/etag.js +133 -104
  85. package/libx/_runtime/common/generic/input.js +6 -21
  86. package/libx/_runtime/common/generic/put.js +1 -1
  87. package/libx/_runtime/common/generic/stream.js +52 -0
  88. package/libx/_runtime/common/generic/temporal.js +25 -8
  89. package/libx/_runtime/common/i18n/messages.properties +0 -2
  90. package/libx/_runtime/common/utils/cqn.js +1 -1
  91. package/libx/_runtime/common/utils/cqn2cqn4sql.js +5 -2
  92. package/libx/_runtime/common/utils/csn.js +0 -51
  93. package/libx/_runtime/common/utils/etag.js +30 -0
  94. package/libx/_runtime/common/utils/keys.js +1 -1
  95. package/libx/_runtime/common/utils/normalizeTimestamp.js +25 -0
  96. package/libx/_runtime/common/utils/path.js +1 -1
  97. package/libx/_runtime/common/utils/resolveView.js +2 -1
  98. package/libx/_runtime/common/utils/rewriteAsterisks.js +6 -4
  99. package/libx/_runtime/common/utils/search2cqn4sql.js +12 -16
  100. package/libx/_runtime/common/utils/stream.js +140 -0
  101. package/libx/_runtime/common/utils/streamProp.js +29 -12
  102. package/libx/_runtime/common/utils/templateProcessorPathSerializer.js +0 -2
  103. package/libx/_runtime/db/generic/index.js +0 -2
  104. package/libx/_runtime/db/query/delete.js +2 -2
  105. package/libx/_runtime/db/query/insert.js +2 -2
  106. package/libx/_runtime/db/query/read.js +2 -2
  107. package/libx/_runtime/db/query/run.js +2 -2
  108. package/libx/_runtime/db/query/update.js +2 -2
  109. package/libx/_runtime/db/sql-builder/BaseBuilder.js +0 -6
  110. package/libx/_runtime/db/sql-builder/ExpressionBuilder.js +23 -12
  111. package/libx/_runtime/db/sql-builder/FunctionBuilder.js +18 -6
  112. package/libx/_runtime/db/sql-builder/InsertBuilder.js +1 -0
  113. package/libx/_runtime/db/sql-builder/SelectBuilder.js +3 -7
  114. package/libx/_runtime/db/sql-builder/UpsertBuilder.js +1 -0
  115. package/libx/_runtime/db/utils/normalizeTimeData.js +7 -3
  116. package/libx/_runtime/fiori/draft.js +2 -0
  117. package/libx/_runtime/fiori/generic/activate.js +8 -9
  118. package/libx/_runtime/fiori/generic/before.js +30 -20
  119. package/libx/_runtime/fiori/generic/cancel.js +5 -3
  120. package/libx/_runtime/fiori/generic/delete.js +5 -3
  121. package/libx/_runtime/fiori/generic/edit.js +7 -7
  122. package/libx/_runtime/fiori/generic/index.js +10 -16
  123. package/libx/_runtime/fiori/generic/new.js +5 -3
  124. package/libx/_runtime/fiori/generic/patch.js +11 -8
  125. package/libx/_runtime/fiori/generic/prepare.js +13 -6
  126. package/libx/_runtime/fiori/generic/read.js +12 -6
  127. package/libx/_runtime/fiori/lean-draft.js +207 -152
  128. package/libx/_runtime/fiori/utils/delete.js +10 -5
  129. package/libx/_runtime/fiori/utils/req.js +17 -5
  130. package/libx/_runtime/fiori/utils/stream.js +36 -0
  131. package/libx/_runtime/hana/Service.js +12 -9
  132. package/libx/_runtime/hana/conversion.js +10 -15
  133. package/libx/_runtime/hana/driver.js +2 -0
  134. package/libx/_runtime/hana/execute.js +28 -6
  135. package/libx/_runtime/hana/pool.js +36 -122
  136. package/libx/_runtime/hana/search2cqn4sql.js +34 -36
  137. package/libx/_runtime/messaging/enterprise-messaging-utils/getTenantInfo.js +2 -6
  138. package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +3 -1
  139. package/libx/_runtime/messaging/enterprise-messaging.js +10 -58
  140. package/libx/_runtime/messaging/outbox/utils.js +1 -1
  141. package/libx/_runtime/remote/Service.js +20 -1
  142. package/libx/_runtime/remote/utils/client.js +3 -5
  143. package/libx/_runtime/sqlite/Service.js +4 -6
  144. package/libx/_runtime/sqlite/conversion.js +3 -13
  145. package/libx/_runtime/sqlite/customBuilder/CustomFunctionBuilder.js +9 -6
  146. package/libx/_runtime/sqlite/customBuilder/CustomUpsertBuilder.js +6 -1
  147. package/libx/_runtime/sqlite/execute.js +5 -16
  148. package/libx/odata/afterburner.js +22 -6
  149. package/libx/odata/grammar.pegjs +6 -1
  150. package/libx/odata/parser.js +1 -1
  151. package/libx/rest/RestAdapter.js +16 -9
  152. package/libx/rest/RestRequest.js +1 -1
  153. package/libx/rest/middleware/input.js +2 -1
  154. package/libx/rest/middleware/operation.js +1 -0
  155. package/libx/rest/middleware/parse.js +3 -2
  156. package/libx/rest/middleware/payload.js +9 -8
  157. package/libx/rest/middleware/read.js +1 -0
  158. package/package.json +9 -16
  159. package/server.js +1 -1
  160. package/app/fiori/preview.js +0 -270
  161. package/app/fiori/routes.js +0 -59
  162. package/bin/build/buildTaskEngine.js +0 -360
  163. package/bin/build/buildTaskFactory.js +0 -283
  164. package/bin/build/buildTaskHandler.js +0 -241
  165. package/bin/build/buildTaskProvider.js +0 -22
  166. package/bin/build/buildTaskProviderFactory.js +0 -175
  167. package/bin/build/cds.js +0 -5
  168. package/bin/build/constants.js +0 -66
  169. package/bin/build/index.js +0 -58
  170. package/bin/build/provider/buildTaskHandlerEdmx.js +0 -82
  171. package/bin/build/provider/buildTaskHandlerFeatureToggles.js +0 -131
  172. package/bin/build/provider/buildTaskHandlerInternal.js +0 -254
  173. package/bin/build/provider/buildTaskProviderInternal.js +0 -383
  174. package/bin/build/provider/fiori/index.js +0 -171
  175. package/bin/build/provider/hana/2migration.js +0 -179
  176. package/bin/build/provider/hana/index.js +0 -505
  177. package/bin/build/provider/hana/migrationtable.js +0 -472
  178. package/bin/build/provider/hana/template/.hdiconfig-haas +0 -163
  179. package/bin/build/provider/hana/template/.hdiconfig-hanacloud +0 -137
  180. package/bin/build/provider/hana/template/.hdinamespace +0 -4
  181. package/bin/build/provider/hana/template/package.json +0 -12
  182. package/bin/build/provider/hana/template/undeploy.json +0 -5
  183. package/bin/build/provider/java/index.js +0 -111
  184. package/bin/build/provider/java-cf/index.js +0 -1
  185. package/bin/build/provider/mtx/index.js +0 -268
  186. package/bin/build/provider/mtx/resourcesTarBuilder.js +0 -95
  187. package/bin/build/provider/mtx-extension/index.js +0 -131
  188. package/bin/build/provider/mtx-sidecar/index.js +0 -137
  189. package/bin/build/provider/node-cf/index.js +0 -1
  190. package/bin/build/provider/nodejs/index.js +0 -192
  191. package/bin/build/util.js +0 -299
  192. package/bin/cds.js +0 -125
  193. package/bin/deploy/to-hana/cfUtil.js +0 -355
  194. package/bin/deploy/to-hana/gitUtil.js +0 -57
  195. package/bin/deploy/to-hana/hana.js +0 -306
  196. package/bin/deploy/to-hana/hdiDeployUtil.js +0 -153
  197. package/bin/deploy/to-hana/index.js +0 -16
  198. package/bin/deploy/to-hana/mtaUtil.js +0 -170
  199. package/bin/mtx/in-cds.js +0 -17
  200. package/bin/plugins.js +0 -32
  201. package/bin/run.js +0 -24
  202. package/bin/utils/log.js +0 -24
  203. package/bin/version.js +0 -178
  204. package/libx/_runtime/audit/Service.js +0 -222
  205. package/libx/_runtime/audit/generic/personal/access.js +0 -61
  206. package/libx/_runtime/audit/generic/personal/index.js +0 -56
  207. package/libx/_runtime/audit/generic/personal/modification.js +0 -132
  208. package/libx/_runtime/audit/generic/personal/utils.js +0 -186
  209. package/libx/_runtime/audit/utils/log.js +0 -23
  210. package/libx/_runtime/audit/utils/v2.js +0 -176
  211. package/libx/_runtime/db/data-conversion/timestamp.js +0 -9
  212. package/libx/_runtime/db/generic/integrity.js +0 -455
  213. package/srv/audit-log.cds +0 -87
  214. package/srv/mtx.cds +0 -2
  215. package/srv/mtx.js +0 -8
  216. /package/lib/{core → linked}/classes.js +0 -0
  217. /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
- }