@sap/cds 6.3.2 → 6.4.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 (128) hide show
  1. package/CHANGELOG.md +95 -0
  2. package/apis/cds.d.ts +3 -1
  3. package/apis/core.d.ts +118 -90
  4. package/apis/cqn.d.ts +11 -2
  5. package/apis/internal/inference.d.ts +7 -2
  6. package/apis/ql.d.ts +49 -11
  7. package/apis/serve.d.ts +8 -1
  8. package/apis/services.d.ts +311 -305
  9. package/bin/build/buildTaskEngine.js +28 -36
  10. package/bin/build/buildTaskFactory.js +32 -81
  11. package/bin/build/buildTaskHandler.js +3 -2
  12. package/bin/build/buildTaskProvider.js +2 -2
  13. package/bin/build/buildTaskProviderFactory.js +5 -14
  14. package/bin/build/constants.js +0 -1
  15. package/bin/build/provider/buildTaskHandlerEdmx.js +7 -6
  16. package/bin/build/provider/buildTaskHandlerFeatureToggles.js +6 -5
  17. package/bin/build/provider/buildTaskHandlerInternal.js +9 -30
  18. package/bin/build/provider/buildTaskProviderInternal.js +70 -58
  19. package/bin/build/provider/fiori/index.js +6 -5
  20. package/bin/build/provider/hana/2migration.js +20 -3
  21. package/bin/build/provider/hana/2tabledata.js +1 -0
  22. package/bin/build/provider/hana/index.js +40 -17
  23. package/bin/build/provider/java/index.js +10 -10
  24. package/bin/build/provider/mtx/index.js +25 -16
  25. package/bin/build/provider/mtx/resourcesTarBuilder.js +22 -27
  26. package/bin/build/provider/mtx-extension/index.js +3 -2
  27. package/bin/build/provider/mtx-sidecar/index.js +16 -15
  28. package/bin/build/provider/nodejs/index.js +14 -56
  29. package/bin/build/util.js +56 -16
  30. package/bin/deploy/to-hana/cfUtil.js +2 -0
  31. package/bin/deploy/to-hana/gitUtil.js +1 -1
  32. package/bin/deploy/to-hana/hana.js +45 -38
  33. package/bin/deploy/to-hana/hdiDeployUtil.js +17 -12
  34. package/bin/deploy/to-hana/mtaUtil.js +13 -14
  35. package/bin/mtx/in-cds.js +3 -1
  36. package/bin/serve.js +1 -1
  37. package/bin/version.js +2 -1
  38. package/lib/auth/index.js +17 -15
  39. package/lib/compile/cds-compile.js +1 -0
  40. package/lib/compile/cdsc.js +1 -0
  41. package/lib/compile/etc/_localized.js +2 -2
  42. package/lib/compile/for/lean_drafts.js +83 -0
  43. package/lib/compile/for/nodejs.js +1 -0
  44. package/lib/compile/minify.js +2 -1
  45. package/lib/compile/to/gql.js +1 -1
  46. package/lib/compile/to/sql.js +11 -1
  47. package/lib/core/entities.js +1 -1
  48. package/lib/core/index.js +9 -9
  49. package/lib/core/infer.js +1 -0
  50. package/lib/dbs/cds-deploy.js +97 -41
  51. package/lib/env/cds-env.js +9 -10
  52. package/lib/env/cds-requires.js +8 -2
  53. package/lib/env/defaults.js +0 -4
  54. package/lib/env/schemas/cds-rc.json +38 -0
  55. package/lib/ql/SELECT.js +10 -4
  56. package/lib/srv/bindings.js +1 -1
  57. package/lib/srv/factory.js +1 -1
  58. package/lib/srv/middlewares/cds-context.js +0 -2
  59. package/lib/srv/middlewares/ctx-auth.js +11 -0
  60. package/lib/srv/middlewares/ctx-model.js +22 -20
  61. package/lib/srv/middlewares/index.js +7 -9
  62. package/lib/srv/protocols/_legacy.js +4 -0
  63. package/lib/srv/protocols/graphql.js +2 -2
  64. package/lib/srv/protocols/index.js +7 -3
  65. package/lib/srv/srv-api.js +1 -0
  66. package/lib/srv/srv-methods.js +1 -1
  67. package/lib/utils/cds-utils.js +11 -0
  68. package/lib/utils/data.js +2 -2
  69. package/lib/utils/inflect.js +13 -12
  70. package/lib/utils/tar.js +43 -13
  71. package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +2 -2
  72. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/action.js +1 -1
  73. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/create.js +1 -1
  74. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/delete.js +1 -1
  75. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +1 -15
  76. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +1 -1
  77. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +1 -1
  78. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/errors/UriSyntaxError.js +1 -1
  79. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/UriParser.js +6 -1
  80. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/utils/BufferedWriter.js +1 -1
  81. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/validator/ConditionalRequestValidator.js +0 -12
  82. package/libx/_runtime/cds-services/adapter/odata-v4/utils/oDataConfiguration.js +1 -7
  83. package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +4 -0
  84. package/libx/_runtime/cds-services/services/Service.js +23 -1
  85. package/libx/_runtime/cds-services/util/assert.js +0 -41
  86. package/libx/_runtime/common/composition/data.js +5 -1
  87. package/libx/_runtime/common/generic/auth/utils.js +3 -3
  88. package/libx/_runtime/common/generic/crud.js +1 -1
  89. package/libx/_runtime/common/generic/input.js +4 -24
  90. package/libx/_runtime/common/generic/paging.js +10 -9
  91. package/libx/_runtime/common/utils/cqn2cqn4sql.js +31 -0
  92. package/libx/_runtime/common/utils/csn.js +21 -15
  93. package/libx/_runtime/common/utils/draft.js +2 -1
  94. package/libx/_runtime/common/utils/resolveView.js +27 -4
  95. package/libx/_runtime/common/utils/rewriteAsterisks.js +3 -1
  96. package/libx/_runtime/common/utils/rowUUIDGenerator.js +21 -0
  97. package/libx/_runtime/common/utils/templateProcessor.js +12 -15
  98. package/libx/_runtime/common/utils/templateProcessorPathSerializer.js +23 -0
  99. package/libx/_runtime/db/expand/expandCQNToJoin.js +29 -12
  100. package/libx/_runtime/db/generic/input.js +7 -13
  101. package/libx/_runtime/db/sql-builder/InsertBuilder.js +5 -1
  102. package/libx/_runtime/db/sql-builder/UpsertBuilder.js +24 -0
  103. package/libx/_runtime/db/sql-builder/annotations.js +6 -3
  104. package/libx/_runtime/db/sql-builder/index.js +2 -0
  105. package/libx/_runtime/db/sql-builder/sqlFactory.js +9 -0
  106. package/libx/_runtime/db/utils/columns.js +4 -2
  107. package/libx/_runtime/fiori/generic/read.js +1 -12
  108. package/libx/_runtime/fiori/lean-draft.js +657 -0
  109. package/libx/_runtime/fiori/utils/handler.js +1 -1
  110. package/libx/_runtime/hana/Service.js +1 -1
  111. package/libx/_runtime/hana/execute.js +5 -5
  112. package/libx/_runtime/hana/pool.js +16 -1
  113. package/libx/_runtime/messaging/enterprise-messaging-utils/getTenantInfo.js +2 -1
  114. package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +1 -1
  115. package/libx/_runtime/messaging/enterprise-messaging.js +2 -3
  116. package/libx/_runtime/messaging/outbox/utils.js +109 -70
  117. package/libx/_runtime/messaging/service.js +16 -7
  118. package/libx/_runtime/remote/Service.js +15 -2
  119. package/libx/_runtime/remote/utils/client.js +41 -11
  120. package/libx/_runtime/sqlite/Service.js +4 -1
  121. package/libx/_runtime/sqlite/convertDraftAdminPathExpression.js +56 -0
  122. package/libx/_runtime/sqlite/customBuilder/CustomUpsertBuilder.js +41 -0
  123. package/libx/_runtime/sqlite/customBuilder/index.js +5 -0
  124. package/libx/_runtime/sqlite/execute.js +1 -1
  125. package/libx/_runtime/types/api.js +2 -2
  126. package/libx/rest/RestAdapter.js +15 -13
  127. package/package.json +1 -1
  128. package/server.js +2 -19
@@ -1,5 +1,6 @@
1
1
  const fs = require('fs')
2
2
  const path = require('path')
3
+ const cds = require('../cds')
3
4
  const BuildTaskHandler = require('../buildTaskHandler')
4
5
  const { hasOptionValue } = require('../util')
5
6
  const { FOLDER_GEN, BUILD_OPTION_OUTPUT_MODE, OUTPUT_MODE_RESULT_ONLY } = require('../constants')
@@ -13,14 +14,6 @@ class BuildTaskHandlerInternal extends BuildTaskHandler {
13
14
  //injected by framework
14
15
  return this._logger;
15
16
  }
16
- /**
17
- * Returns the cds module providing access to the CDS compiler functionality and other framework functionality.
18
- * @returns {object}
19
- */
20
- get cds() {
21
- //injected by framework
22
- return this._cds
23
- }
24
17
  /**
25
18
  * Returns the build options used for this CDS build execution
26
19
  * @returns {object}
@@ -28,13 +21,6 @@ class BuildTaskHandlerInternal extends BuildTaskHandler {
28
21
  get buildOptions() {
29
22
  return this._buildOptions
30
23
  }
31
- /**
32
- * Returns the effective CDS environment used by this CDS build execution.
33
- * @returns {object}
34
- */
35
- get env() {
36
- return this.cds.env
37
- }
38
24
  /**
39
25
  * Custom build handlers are executed before internal handlers in order
40
26
  * ensure and content cannot be overwritten by mistake.
@@ -58,13 +44,6 @@ class BuildTaskHandlerInternal extends BuildTaskHandler {
58
44
  set logger(logger) {
59
45
  super.logger = logger;
60
46
  }
61
- /**
62
- * Used by the framework to initialize the correct cds context.
63
- * @param {object} cds
64
- */
65
- set cds(cds) {
66
- super.cds = cds;
67
- }
68
47
  /**
69
48
  * Sets the build options used for this CDS build execution
70
49
  * @param {object} options
@@ -106,7 +85,7 @@ class BuildTaskHandlerInternal extends BuildTaskHandler {
106
85
  * @param {any=} value
107
86
  */
108
87
  hasCdsEnvOption(qualifiedName, value) {
109
- return hasOptionValue(this.env.get(qualifiedName), value)
88
+ return hasOptionValue(cds.env.get(qualifiedName), value)
110
89
  }
111
90
 
112
91
  /**
@@ -173,7 +152,7 @@ class BuildTaskHandlerInternal extends BuildTaskHandler {
173
152
  cwd: this.buildOptions.root,
174
153
  src: this.task.src === this.task.dest ? this.task.src : this.buildOptions.root
175
154
  }
176
- const csnStr = this.cds.compile.to.json(model, jsonOptions)
155
+ const csnStr = cds.compile.to.json(model, jsonOptions)
177
156
  if (!this.hasBuildOption(BUILD_OPTION_OUTPUT_MODE, OUTPUT_MODE_RESULT_ONLY)) {
178
157
  await this.write(csnStr).to(csnFile)
179
158
  }
@@ -188,7 +167,7 @@ class BuildTaskHandlerInternal extends BuildTaskHandler {
188
167
  async collectLanguageBundles(model, bundleDest) {
189
168
  // collect effective i18n properties...
190
169
  let bundles = {}
191
- const bundleGenerator = this.cds.localize.bundles4(model)
170
+ const bundleGenerator = cds.localize.bundles4(model)
192
171
  if (bundleGenerator && bundleGenerator[Symbol.iterator]) {
193
172
  for (let [locale, bundle] of bundleGenerator) {
194
173
  // fallback bundle has the name ""
@@ -204,7 +183,7 @@ class BuildTaskHandlerInternal extends BuildTaskHandler {
204
183
  bundles = {}
205
184
  }
206
185
  // copied from ../compile/i18n.js
207
- const { file: base = 'i18n' } = this.env.i18n
186
+ const { file: base = 'i18n' } = cds.env.i18n
208
187
  const file = path.join(bundleDest, base + '.json')
209
188
 
210
189
  // bundleDest might be null
@@ -240,7 +219,7 @@ class BuildTaskHandlerInternal extends BuildTaskHandler {
240
219
 
241
220
  static _find(srcDir, filter) {
242
221
  const files = []
243
- BuildTaskHandlerInternal._traverseFileSystem(srcDir, files, filter)
222
+ this._traverseFileSystem(srcDir, files, filter)
244
223
  return files;
245
224
  }
246
225
 
@@ -252,15 +231,15 @@ class BuildTaskHandlerInternal extends BuildTaskHandler {
252
231
  // ignore if not existing
253
232
  }
254
233
  entries.map(subDirEntry => path.join(srcDir, subDirEntry)).forEach((entry) => {
255
- BuildTaskHandlerInternal._handleResource(entry, files, filter)
234
+ this._handleResource(entry, files, filter)
256
235
  })
257
236
  }
258
237
 
259
238
  static _handleResource(entry, files, filter) {
260
239
  if (!filter || filter.call(this, entry)) {
261
- var stats = BuildTaskHandlerInternal._getResourceStatus(entry)
240
+ var stats = this._getResourceStatus(entry)
262
241
  if (stats.isDirectory()) {
263
- BuildTaskHandlerInternal._traverseFileSystem(entry, files, filter)
242
+ this._traverseFileSystem(entry, files, filter)
264
243
  } else if (stats.isFile() || stats.isSymbolicLink()) {
265
244
  files.push(entry)
266
245
  }
@@ -1,24 +1,17 @@
1
1
  const fs = require('fs')
2
2
  const path = require('path')
3
- const { hasJavaNature, getProperty, isStreamlinedMtx, BuildError } = require('../util')
3
+ const cds = require('../cds')
4
+ const { hasJavaNature, getProperty, isStreamlinedMtx, getDefaultModelOptions, BuildError } = require('../util')
4
5
  const BuildTaskProvider = require('../buildTaskProvider')
5
6
 
6
7
  const { FILE_EXT_CDS, BUILD_TASK_HANA, BUILD_TASK_FIORI, BUILD_TASK_JAVA, BUILD_TASK_JAVA_CF, BUILD_TASK_NODEJS, BUILD_TASK_NODE_CF, BUILD_TASK_MTX,
7
- BUILD_TASK_PREFIX, BUILD_TASKS, BUILD_TASK_MTX_SIDECAR, MTX_SIDECAR_FOLDER, BUILD_TASK_MTX_EXTENSION } = require("../constants")
8
+ BUILD_TASK_PREFIX, BUILD_TASKS, BUILD_TASK_MTX_SIDECAR, MTX_SIDECAR_FOLDER, BUILD_TASK_MTX_EXTENSION, CDS_MODEL_EXCLUDE_LIST } = require("../constants")
8
9
 
9
10
  class BuildTaskProviderInternal extends BuildTaskProvider {
10
- constructor(cds, logger) {
11
+ constructor(logger) {
11
12
  super()
12
- this._cds = cds
13
13
  this._logger = logger
14
14
  }
15
-
16
- get cds() {
17
- return this._cds
18
- }
19
- get env() {
20
- return this.cds.env
21
- }
22
15
  get logger() {
23
16
  return this._logger
24
17
  }
@@ -38,42 +31,49 @@ class BuildTaskProviderInternal extends BuildTaskProvider {
38
31
  return this._createTasks(tasks, buildOptions, tasks.length > 0)
39
32
  }
40
33
 
41
- async applyTaskDefaults(task) {
34
+ async applyTaskDefaults(task, buildOptions) {
42
35
  const taskFor = BuildTaskProviderInternal._getForValueFromTask(task)
36
+ const { root: projectPath } = buildOptions
43
37
  task.for = task.for || taskFor
44
38
  task.use = task.use || `${BUILD_TASK_PREFIX}/${taskFor}`
45
39
 
46
- if (!task.src) {
47
- switch (taskFor) {
48
- case BUILD_TASK_HANA:
49
- task.src = BuildTaskProviderInternal._normalizePath(this.env.folders.db)
50
- break
51
- case BUILD_TASK_JAVA:
52
- case BUILD_TASK_JAVA_CF:
53
- case BUILD_TASK_NODEJS:
54
- case BUILD_TASK_NODE_CF:
55
- task.src = BuildTaskProviderInternal._normalizePath(this.env.folders.srv)
56
- break
57
- case BUILD_TASK_FIORI:
58
- task.src = BuildTaskProviderInternal._normalizePath(this.env.folders.app)
59
- break
60
- case BUILD_TASK_MTX_EXTENSION:
61
- case BUILD_TASK_MTX:
62
- task.src = "."
63
- break
64
- case BUILD_TASK_MTX_SIDECAR:
65
- task.src = MTX_SIDECAR_FOLDER
66
- break
67
- default:
68
- throw new Error(`Unknown build task '${task.use || task.for}'`)
69
- }
40
+ switch (taskFor) {
41
+ case BUILD_TASK_HANA:
42
+ task.src = task.src || BuildTaskProviderInternal._normalizePath(cds.env.folders.db)
43
+ break
44
+ case BUILD_TASK_JAVA:
45
+ case BUILD_TASK_JAVA_CF:
46
+ task.src = task.src || BuildTaskProviderInternal._normalizePath(cds.env.folders.srv)
47
+ if (!task.options?.model) {
48
+ BuildTaskProviderInternal._setDefaultModelOptionsForJava(task, projectPath)
49
+ }
50
+ break
51
+ case BUILD_TASK_NODEJS:
52
+ case BUILD_TASK_NODE_CF:
53
+ task.src = task.src || BuildTaskProviderInternal._normalizePath(cds.env.folders.srv)
54
+ break
55
+ case BUILD_TASK_FIORI:
56
+ task.src = task.src || BuildTaskProviderInternal._normalizePath(cds.env.folders.app)
57
+ break
58
+ case BUILD_TASK_MTX_SIDECAR:
59
+ task.src = task.src || MTX_SIDECAR_FOLDER
60
+ if (!task.options?.model && BuildTaskProviderInternal._hasJavaNature(projectPath, cds.env.folders.srv)) {
61
+ BuildTaskProviderInternal._setDefaultModelOptionsForJava(task, projectPath)
62
+ }
63
+ break
64
+ case BUILD_TASK_MTX_EXTENSION:
65
+ case BUILD_TASK_MTX:
66
+ task.src = task.src || "."
67
+ break
68
+ default:
69
+ throw new Error(`Unknown build task '${task.use || task.for}'`)
70
70
  }
71
71
  }
72
72
 
73
73
  async _createTasks(tasks, buildOptions, addRequiredTasks) {
74
74
  const { root: projectPath } = buildOptions
75
- let db = typeof this.env.folders.db === "string" ? [BuildTaskProviderInternal._normalizePath(this.env.folders.db)] : this.env.folders.db
76
- let srv = typeof this.env.folders.srv === "string" ? [BuildTaskProviderInternal._normalizePath(this.env.folders.srv)] : this.env.folders.srv
75
+ let db = typeof cds.env.folders.db === "string" ? [BuildTaskProviderInternal._normalizePath(cds.env.folders.db)] : cds.env.folders.db
76
+ let srv = typeof cds.env.folders.srv === "string" ? [BuildTaskProviderInternal._normalizePath(cds.env.folders.srv)] : cds.env.folders.srv
77
77
 
78
78
  const dbOptions = {
79
79
  model: []
@@ -119,8 +119,8 @@ class BuildTaskProviderInternal extends BuildTaskProvider {
119
119
  }
120
120
  }
121
121
  } else {
122
- !db && this.logger._debug && this.logger.debug(`project doesn't have a database module '${this.env.folders.db}'`)
123
- !srv && this.logger._debug && this.logger.debug(`project doesn't have a service module '${this.env.folders.srv}'`)
122
+ !db && this.logger._debug && this.logger.debug(`project doesn't have a database module '${cds.env.folders.db}'`)
123
+ !srv && this.logger._debug && this.logger.debug(`project doesn't have a service module '${cds.env.folders.srv}'`)
124
124
 
125
125
  // create hana build task
126
126
  const dbTask = this._createDbTask(projectPath, db, dbOptions, buildOptions)
@@ -142,14 +142,14 @@ class BuildTaskProviderInternal extends BuildTaskProvider {
142
142
 
143
143
  _createDbTask(projectPath, src, taskOptions, buildOptions) {
144
144
  this.logger.debug("determining database kind.")
145
- if (!src || BuildTaskProviderInternal._isExtension(this.env)) {
145
+ if (!src || BuildTaskProviderInternal._isMtxExtension()) {
146
146
  return null
147
147
  }
148
148
  let task = null
149
149
  if (this._useHana(projectPath, buildOptions)) {
150
150
  this.logger.debug("found HANA database.")
151
151
  // legacy build supports dest property
152
- const compileDest = this.env.data?.dest
152
+ const compileDest = cds.env.data?.dest
153
153
  if (compileDest) {
154
154
  //../db/src/gen
155
155
  // compileDest is relative to src folder in modular build - resolve correctly
@@ -169,37 +169,37 @@ class BuildTaskProviderInternal extends BuildTaskProvider {
169
169
  _useHana(projectPath, buildOptions) {
170
170
  if (getProperty(buildOptions, "for.hana.skipManifestGeneration") // deprecated fallback for webide fullstack and mtx
171
171
  || getProperty(buildOptions, "for.hana.contentManifest") === false // fallback for webide fullstack and mtx
172
- || this.env.requires.db?.kind === "hana"
173
- || this.env.requires.db?.dialect === "hana") {
172
+ || cds.env.requires.db?.kind === "hana"
173
+ || cds.env.requires.db?.dialect === "hana") {
174
174
 
175
175
  return true
176
176
  }
177
177
  // false if other db has been defined
178
- if (this.env.requires.db?.kind) {
178
+ if (cds.env.requires.db?.kind) {
179
179
  return false
180
180
  }
181
181
  // check whether cds config represents a legacy build system config for which requires.db was not configured
182
182
  // Note: compat layer sets requires.db: {}
183
- const userEnv = this.cds.env.for("cds", projectPath, false)
183
+ const userEnv = cds.env.for("cds", projectPath, false)
184
184
  return userEnv && (userEnv.data?.model || userEnv.service?.model)
185
185
  }
186
186
 
187
187
  _createMtxTask(projectPath, src, dest, tasks) {
188
188
  // MTX build task creation is NOT supported for Java projects
189
- if (tasks.find(task => task.for === BUILD_TASK_JAVA || task.for === BUILD_TASK_JAVA_CF)) {
189
+ if (tasks.some(task => task.for === BUILD_TASK_JAVA || task.for === BUILD_TASK_JAVA_CF)) {
190
190
  return null
191
191
  }
192
- this.logger.debug("determining mtx type for nodejs")
192
+ this.logger.debug("determining mtx version of nodejs project")
193
193
 
194
- if (isStreamlinedMtx(this.cds)) {
195
- if (this.env.requires["cds.xt.ModelProviderService"]?.kind === "rest") { // "cds.xt.ModelProviderService": "from-sidecar"
194
+ if (isStreamlinedMtx()) {
195
+ if (cds.env.requires["cds.xt.ModelProviderService"]?.kind === "rest") { // "cds.xt.ModelProviderService": "from-sidecar"
196
196
  this.logger.debug("Nodejs Streamlined MTX app with sidecar")
197
197
 
198
198
  const sidecarPath = path.join(projectPath, MTX_SIDECAR_FOLDER)
199
199
  if (!fs.existsSync(sidecarPath)) {
200
200
  throw new BuildError("CDS build failed", `MTX sidecar directory '${sidecarPath}' not existing. Custom build task configuration necessary if the folder is named differently.`)
201
201
  }
202
- const sidecarEnv = this.env.for("cds", sidecarPath)
202
+ const sidecarEnv = cds.env.for("cds", sidecarPath)
203
203
  if (sidecarEnv.requires["cds.xt.ModelProviderService"]?.kind === "in-sidecar") {
204
204
  return {
205
205
  for: BUILD_TASK_MTX_SIDECAR
@@ -208,7 +208,7 @@ class BuildTaskProviderInternal extends BuildTaskProvider {
208
208
  throw new BuildError("CDS build failed", 'Invalid MTX sidecar configuration. Make sure to add required service "cds.xt.ModelProviderService": "in-sidecar".')
209
209
  }
210
210
 
211
- if (this.env.requires["cds.xt.ModelProviderService"]?.kind === "in-sidecar") {
211
+ if (cds.env.requires["cds.xt.ModelProviderService"]?.kind === "in-sidecar") {
212
212
  // cds build is executed in sidecar folder
213
213
  throw new BuildError("CDS build failed", "Invalid working directory. Make sure to execute 'cds build' in CAP project root directory.")
214
214
  }
@@ -220,14 +220,14 @@ class BuildTaskProviderInternal extends BuildTaskProvider {
220
220
  }
221
221
  }
222
222
 
223
- if (BuildTaskProviderInternal._isExtension(this.env)) {
223
+ if (BuildTaskProviderInternal._isMtxExtension()) {
224
224
  this.logger.debug("Streamlined MTX extension app")
225
225
  return {
226
226
  for: BUILD_TASK_MTX_EXTENSION
227
227
  }
228
228
  }
229
229
 
230
- if (this.env.requires.multitenancy) {
230
+ if (cds.env.requires.multitenancy) {
231
231
  this.logger.debug("Nodejs Classic MTX app without sidecar")
232
232
  return {
233
233
  src: ".",
@@ -239,7 +239,7 @@ class BuildTaskProviderInternal extends BuildTaskProvider {
239
239
 
240
240
  _createSrvTask(projectPath, src, taskOptions) {
241
241
  this.logger.debug("determining implementation technology")
242
- if (!src || BuildTaskProviderInternal._isExtension(this.env)) {
242
+ if (!src || BuildTaskProviderInternal._isMtxExtension()) {
243
243
  return null
244
244
  }
245
245
  let task = null
@@ -254,7 +254,7 @@ class BuildTaskProviderInternal extends BuildTaskProvider {
254
254
  _createJavaTask(projectPath, src, taskOptions) {
255
255
  this.logger.debug("found implementation technology java")
256
256
  // legacy build supports dest property
257
- const compileDest = this.env.service?.dest
257
+ const compileDest = cds.env.service?.dest
258
258
  if (compileDest) {
259
259
  // compileDest is relative to src folder in modular build - resolve correctly
260
260
  taskOptions.compileDest = path.relative(path.resolve(projectPath, src), path.resolve(projectPath, compileDest))
@@ -275,8 +275,20 @@ class BuildTaskProviderInternal extends BuildTaskProvider {
275
275
  }
276
276
  }
277
277
 
278
- static _isExtension(env) {
279
- return !!env.extends
278
+ static _isMtxExtension() {
279
+ return !!cds.env.extends
280
+ }
281
+
282
+ /**
283
+ * REVISIT: filter model options in order to avoid that the bootstrap service gets added to the application model
284
+ * https://github.tools.sap/cap/issues/issues/12770#issuecomment-1805719
285
+ */
286
+ static _setDefaultModelOptionsForJava(task, projectPath) {
287
+ const defaultModelPaths = new Set(getDefaultModelOptions(projectPath))
288
+ defaultModelPaths.add(task.src)
289
+ CDS_MODEL_EXCLUDE_LIST.forEach(m => defaultModelPaths.delete(m))
290
+ task.options = task.options || {}
291
+ task.options.model = [...defaultModelPaths]
280
292
  }
281
293
 
282
294
  /**
@@ -1,4 +1,5 @@
1
1
  const path = require('path')
2
+ const cds = require('../../cds')
2
3
  const BuildTaskHandlerEdmx = require('../buildTaskHandlerEdmx')
3
4
  const URL = require('url')
4
5
  const { getProperty, isOldJavaStack, relativePaths } = require('../../util')
@@ -44,14 +45,14 @@ class FioriAppModuleBuilder extends BuildTaskHandlerEdmx {
44
45
  fioriBuildOptions[BUILD_OPTION_OUTPUT_MODE] = OUTPUT_MODE_RESULT_ONLY
45
46
 
46
47
  try {
47
- const edmxOptions = { version: this.env.odata?.version }
48
+ const edmxOptions = { version: cds.env.odata?.version }
48
49
 
49
50
  if (edmxOptions.version !== ODATA_VERSION_V2) {
50
51
  const javaTask = this.buildOptions.tasks.find(task => task.for === BUILD_TASK_JAVA_CF || task.for === BUILD_TASK_JAVA)
51
52
 
52
53
  if (javaTask
53
54
  && await isOldJavaStack([javaTask.src, this.buildOptions.root])
54
- && !this.env.for("cds", this.buildOptions.root, false).odata?.version) {
55
+ && !cds.env.for("cds", this.buildOptions.root, false).odata?.version) {
55
56
 
56
57
  // old java stack
57
58
  // default is now v4 and not v2 anymore, so overwrite with v2 if using default
@@ -62,7 +63,7 @@ class FioriAppModuleBuilder extends BuildTaskHandlerEdmx {
62
63
 
63
64
  for (let [appFolder, appModelGroup] of appModelGroups.entries()) {
64
65
  this.logger.log(`building module [${appFolder}] using [${this.constructor.name}]`)
65
- const modelPaths = this.cds.resolve(Array.from(appModelGroup.values()), this.buildOptions)
66
+ const modelPaths = cds.resolve(Array.from(appModelGroup.values()), this.buildOptions)
66
67
  if (!modelPaths || modelPaths.length === 0) {
67
68
  this.logger.log(`no model found`)
68
69
  continue
@@ -71,7 +72,7 @@ class FioriAppModuleBuilder extends BuildTaskHandlerEdmx {
71
72
 
72
73
  //cache model per fiori app root folder
73
74
  const options = this.options()
74
- const model = await this.cds.load(modelPaths, options)
75
+ const model = await cds.load(modelPaths, options)
75
76
  fioriBuildOptions.appModel.set(appFolder, model)
76
77
 
77
78
  await this.compileToEdmx(model, null, edmxOptions)
@@ -155,7 +156,7 @@ class FioriAppModuleBuilder extends BuildTaskHandlerEdmx {
155
156
  // NOTE: assumption is that the service definition can be resolved - either by
156
157
  // - defining corresponding using statement in annotations model or
157
158
  // - adding the service module folder to the model option
158
- let service = this.cds.reflect(model).find(service => uriSegments.find(segment => service.name === segment))
159
+ let service = cds.reflect(model).find(service => uriSegments.find(segment => service.name === segment))
159
160
 
160
161
  if (service) {
161
162
  const allServices = this.getBuildOption("appEdmx").get(appFolder)
@@ -6,6 +6,7 @@ const cds = require('../../cds'), { compiler: cdsc } = cds
6
6
  const cdscVersion = `-- generated by cds-compiler version ${cdsc.version()}`
7
7
  const { getArtifactCdsPersistenceName } = cdsc
8
8
  let logger = cds.log(LOG_MODULE_NAMES)
9
+ const ANNO_PERSISTENCE_JOURNAL = '@cds.persistence.journal'
9
10
 
10
11
  module.exports = async (model, lastDevVersion, srcPath, options = {}) => {
11
12
  if (options.logger) {
@@ -29,7 +30,7 @@ module.exports = async (model, lastDevVersion, srcPath, options = {}) => {
29
30
  definitionResult.push(definitionEntry)
30
31
  }
31
32
  }
32
- return { definitions: definitionResult, deletions, afterImage }
33
+ return { definitions: definitionResult, deletions, afterImage: _filterJournalArtifacts(afterImage) }
33
34
  }
34
35
 
35
36
  function _toHdiMigration(model, lastDevVersion, journalFileNames, options) {
@@ -55,7 +56,7 @@ ${migration ? migration.changeset.map(change => change.sql).join('\n') : 'Empty
55
56
  /**
56
57
  * Returns an object providing access to the .hdbmigrationtable file content and its corresponding filename.
57
58
  *
58
- * @param {String} srcPath Fully quailified path of the directory containing .hdbmigrationtable files
59
+ * @param {String} srcPath Fully qualified path of the directory containing .hdbmigrationtable files
59
60
  * @param {String} migration the migration descriptor
60
61
  * @param {String} tableSql SQL TABLE definition
61
62
  * @returns {Object} Providing access to 'content' and 'fileName'.
@@ -137,7 +138,7 @@ function _emptyMigration(name) {
137
138
 
138
139
  function _getJournalFileNames(model) {
139
140
  const journalNames = new Set(cds.reflect(model).all(item => {
140
- if (item.kind === 'entity' && item['@cds.persistence.journal'] === true) {
141
+ if (item.kind === 'entity' && item[ANNO_PERSISTENCE_JOURNAL] === true) {
141
142
  if (item['@cds.persistence.skip'] === true || item['@cds.persistence.exists'] === true) {
142
143
  logger.warn(`[hdbmigrationtable] annotation @cds.persistence.journal skipped for entity '${item.name}' as persistence exists`)
143
144
  }
@@ -151,3 +152,19 @@ function _getJournalFileNames(model) {
151
152
 
152
153
  return journalNames
153
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 (dict[name][ANNO_PERSISTENCE_JOURNAL] !== true) {
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
+ }
@@ -11,6 +11,7 @@ module.exports = async (model, options = {}) => {
11
11
  logger = options.logger
12
12
  }
13
13
 
14
+ model = cds.minify(model)
14
15
  const baseDir = options.baseDir // where the hdbtabledata will be located, for usage in the file_name path
15
16
  const dirs = Array.isArray(options.dirs) ? options.dirs : _csvDirs(model.$sources.map(path.dirname))
16
17
  if (dirs.length === 0) return [] // nothing to do
@@ -1,5 +1,6 @@
1
1
  const fs = require('fs')
2
2
  const path = require('path')
3
+ const cds = require('../../cds')
3
4
  const BuildTaskHandlerInternal = require('../buildTaskHandlerInternal')
4
5
  const { OUTPUT_MODE_RESULT_ONLY, BUILD_OPTION_OUTPUT_MODE, SKIP_HDBTABLEDATA_GENERATION, SKIP_PACKAGE_JSON_GENERATION,
5
6
  CONTENT_PACKAGE_JSON, CONTENT_HDBTABLEDATA, CSV_FILE_DETECTION, CONTENT_ENV, CONTENT_DEFAULT_ENV_JSON, CONTENT_NODE_MODULES } = require('../../constants')
@@ -99,22 +100,21 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
99
100
  * @param {Object} model
100
101
  */
101
102
  async _copyResourcesExt(src, dest, model) {
102
- const resources = Object.keys(await this.cds.deploy.resources(model))
103
+ const resources = Object.keys(await cds.deploy.resources(model)).reverse() // reverse to get reuse resources first and app resources last
103
104
  const csvPath = path.join(src, "data")
104
105
  // determine subfolder name used by the application for backward compatibility
105
106
  const csvFolder = resources.some(res => res && res.startsWith(csvPath)) ? "data" : "csv"
106
107
 
107
108
  // 1. copy csv files into 'src/gen/data' or 'src/gen/csv' subfolder
108
- const promises = []
109
109
  const dbSrc = path.join(src, 'src')
110
110
 
111
- resources.forEach(res => {
111
+ // await each copy as order is important - reuse resources first and app resources last
112
+ for (const res of resources) {
112
113
  // do not duplicate resources that are already contained in db/src/**
113
114
  if (res && /\.csv$/.test(res) && !res.startsWith(dbSrc)) {
114
- promises.push(this.copy(res).to(path.join(this.task.options.compileDest, csvFolder, path.basename(res))))
115
+ await this.copy(res).to(path.join(this.task.options.compileDest, csvFolder, path.basename(res)))
115
116
  }
116
- })
117
- await Promise.all(promises)
117
+ }
118
118
 
119
119
  // 2. staging build: copy files except *.cds, .env, default-env.json, ./node_modules/**
120
120
  if (this.isStagingBuild()) {
@@ -156,7 +156,7 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
156
156
  if (fs.statSync(entry).isDirectory()) {
157
157
  return !/(\/|\\)node_modules(\/|\\)?$/.test(entry)
158
158
  }
159
- return (!regex.test(entry) && entry !== this.env.build.outputfile) ||
159
+ return (!regex.test(entry) && entry !== cds.env.build.outputfile) ||
160
160
  (regexData.test(entry) && !entry.startsWith(dbCsvDir) && !entry.startsWith(dbDataDir))
161
161
  })
162
162
  }
@@ -251,8 +251,8 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
251
251
  const pluginTypes = new Set([...REQUIRED_PLUGIN_TYPES, ...undeployTypes])
252
252
 
253
253
  // compile to old format (.hdbcds) or new format (.hdbtable / .hdbview)
254
- const format = this.getBuildOption(DEPLOY_FORMAT) || this.env.requires.db?.[DEPLOY_FORMAT] || this.env.hana?.[DEPLOY_FORMAT]
255
- if (!this.cds.compile.to[format]) {
254
+ const format = this.getBuildOption(DEPLOY_FORMAT) || cds.env.requires.db?.[DEPLOY_FORMAT] || cds.env.hana?.[DEPLOY_FORMAT]
255
+ if (!cds.compile.to[format]) {
256
256
  return Promise.reject(new Error(`Invalid deploy-format defined: ${format}`))
257
257
  }
258
258
 
@@ -267,8 +267,8 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
267
267
  async _compileToHdb(model, pluginTypes, format) {
268
268
  const relDest = path.relative(this.task.dest, this.task.options.compileDest)
269
269
  // enforces sqlNames option for compiler in tests
270
- const options = { ...this.options(), sql_mapping: this.env.sql.names }
271
- const result = this.cds.compile.to[format](model, options)
270
+ const options = { ...this.options(), sql_mapping: cds.env.sql.names }
271
+ const result = cds.compile.to[format](model, options)
272
272
  const promises = []
273
273
 
274
274
  for (const [content, key] of result) {
@@ -297,7 +297,7 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
297
297
  lastDev = JSON.parse((await fs.promises.readFile(lastDevCsnDir, 'utf-8')).toString())
298
298
  }
299
299
  // enforces sqlNames option for compiler in tests, pass options from cds env, ensures that the correct format is taken
300
- const options = { ...this.options(), logger: this.logger, sql_mapping: this.env.sql.names, "deploy-format": format }
300
+ const options = { ...this.options(), logger: this.logger, sql_mapping: cds.env.sql.names, "deploy-format": format }
301
301
 
302
302
  const compilationResult = await to_hdbmigration(model, lastDev, dbSrcDir, options)
303
303
  const definitions = compilationResult.definitions
@@ -324,18 +324,20 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
324
324
  if (suffix === FILE_EXT_HDBTABLE) {
325
325
  // issue an error in case a .hdbmigrationtable file already exists
326
326
  if (fs.existsSync(path.join(dbSrcDir, name + FILE_EXT_HDBMIGRATIONTABLE))) {
327
- this.pushMessage(`Multiple files exist defining the same HANA artifact - [${path.join(relDbSrcDir, name + FILE_EXT_HDBMIGRATIONTABLE)}, ${path.join(relDbDestDir, file)}].\nEither annotate the model entity using @cds.persistence.journal or undeploy the file [${path.join('src', name + FILE_EXT_HDBMIGRATIONTABLE)}] using an undeploy.json file.`, ERROR)
327
+ throw new BuildError(`Multiple files exist defining the same HANA artifact - [${path.join(relDbSrcDir, name + FILE_EXT_HDBMIGRATIONTABLE)}, ${path.join(relDbDestDir, file)}].\nEither annotate the model entity using @cds.persistence.journal or undeploy the file [${path.join('src', name + FILE_EXT_HDBMIGRATIONTABLE)}] using an undeploy.json file.`)
328
328
  }
329
329
  }
330
330
  }
331
331
  }
332
332
  await Promise.all(promises)
333
- await this._validateHdbmigrationtables()
333
+ await this._validateMigrationTableFiles()
334
334
 
335
335
  // update last development version
336
336
  if (afterImage) {
337
337
  if (migrationTableFiles.length > 0) {
338
- await this.write(afterImage).to(lastDevCsnDir)
338
+ if (!HanaModuleBuilder._toEqualIgnoreMeta(lastDev, afterImage)) {
339
+ await this.write(afterImage).to(lastDevCsnDir)
340
+ }
339
341
  }
340
342
  } else {
341
343
  throw new BuildError(`Inconsistent CDS compilation results - file ${lastDevCsnFolder} missing`)
@@ -373,7 +375,7 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
373
375
  this.logger.error(`'HANA plugin not found for file suffix [${Array.from(plugins).join(',')}]`)
374
376
  }
375
377
  // TODO - Be on the save side for now - go for the content use case later on if this works as expected.
376
- if (this.env.hana['deploy-format'] === 'hdbtable') {
378
+ if (cds.env.hana['deploy-format'] === 'hdbtable') {
377
379
  await this.write(content).to(hdiConfig)
378
380
  } else {
379
381
  await this.write(template).to(hdiConfig)
@@ -442,7 +444,7 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
442
444
  return result
443
445
  }
444
446
 
445
- async _validateHdbmigrationtables() {
447
+ async _validateMigrationTableFiles() {
446
448
  const dbSrcDir = path.join(this.task.src, "src")
447
449
  const migrationTableFiles = BuildTaskHandlerInternal._find(dbSrcDir, (res) => {
448
450
  return fs.statSync(res).isFile() && path.extname(res) === FILE_EXT_HDBMIGRATIONTABLE
@@ -463,5 +465,26 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
463
465
  }))
464
466
  }
465
467
  }
468
+
469
+ static _toEqualIgnoreMeta(csn1, csn2) {
470
+ function toString(csn) {
471
+ return JSON.stringify(csn, (k, v) => {
472
+ if (v?.creator) {
473
+ // make sure it's the compiler meta tag
474
+ if (k === 'meta' && v.creator?.startsWith('CDS Compiler'))
475
+ return
476
+ }
477
+ return v
478
+ })
479
+ }
480
+
481
+ if (csn1 === csn2) {
482
+ return true
483
+ }
484
+ if (!csn1 || !csn2) {
485
+ return false
486
+ }
487
+ return toString(csn1) === toString(csn2)
488
+ }
466
489
  }
467
490
  module.exports = HanaModuleBuilder