@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.
- package/CHANGELOG.md +95 -0
- package/apis/cds.d.ts +3 -1
- package/apis/core.d.ts +118 -90
- package/apis/cqn.d.ts +11 -2
- package/apis/internal/inference.d.ts +7 -2
- package/apis/ql.d.ts +49 -11
- package/apis/serve.d.ts +8 -1
- package/apis/services.d.ts +311 -305
- package/bin/build/buildTaskEngine.js +28 -36
- package/bin/build/buildTaskFactory.js +32 -81
- package/bin/build/buildTaskHandler.js +3 -2
- package/bin/build/buildTaskProvider.js +2 -2
- package/bin/build/buildTaskProviderFactory.js +5 -14
- package/bin/build/constants.js +0 -1
- package/bin/build/provider/buildTaskHandlerEdmx.js +7 -6
- package/bin/build/provider/buildTaskHandlerFeatureToggles.js +6 -5
- package/bin/build/provider/buildTaskHandlerInternal.js +9 -30
- package/bin/build/provider/buildTaskProviderInternal.js +70 -58
- package/bin/build/provider/fiori/index.js +6 -5
- package/bin/build/provider/hana/2migration.js +20 -3
- package/bin/build/provider/hana/2tabledata.js +1 -0
- package/bin/build/provider/hana/index.js +40 -17
- package/bin/build/provider/java/index.js +10 -10
- package/bin/build/provider/mtx/index.js +25 -16
- package/bin/build/provider/mtx/resourcesTarBuilder.js +22 -27
- package/bin/build/provider/mtx-extension/index.js +3 -2
- package/bin/build/provider/mtx-sidecar/index.js +16 -15
- package/bin/build/provider/nodejs/index.js +14 -56
- package/bin/build/util.js +56 -16
- package/bin/deploy/to-hana/cfUtil.js +2 -0
- package/bin/deploy/to-hana/gitUtil.js +1 -1
- package/bin/deploy/to-hana/hana.js +45 -38
- package/bin/deploy/to-hana/hdiDeployUtil.js +17 -12
- package/bin/deploy/to-hana/mtaUtil.js +13 -14
- package/bin/mtx/in-cds.js +3 -1
- package/bin/serve.js +1 -1
- package/bin/version.js +2 -1
- package/lib/auth/index.js +17 -15
- package/lib/compile/cds-compile.js +1 -0
- package/lib/compile/cdsc.js +1 -0
- package/lib/compile/etc/_localized.js +2 -2
- package/lib/compile/for/lean_drafts.js +83 -0
- package/lib/compile/for/nodejs.js +1 -0
- package/lib/compile/minify.js +2 -1
- package/lib/compile/to/gql.js +1 -1
- package/lib/compile/to/sql.js +11 -1
- package/lib/core/entities.js +1 -1
- package/lib/core/index.js +9 -9
- package/lib/core/infer.js +1 -0
- package/lib/dbs/cds-deploy.js +97 -41
- package/lib/env/cds-env.js +9 -10
- package/lib/env/cds-requires.js +8 -2
- package/lib/env/defaults.js +0 -4
- package/lib/env/schemas/cds-rc.json +38 -0
- package/lib/ql/SELECT.js +10 -4
- package/lib/srv/bindings.js +1 -1
- package/lib/srv/factory.js +1 -1
- package/lib/srv/middlewares/cds-context.js +0 -2
- package/lib/srv/middlewares/ctx-auth.js +11 -0
- package/lib/srv/middlewares/ctx-model.js +22 -20
- package/lib/srv/middlewares/index.js +7 -9
- package/lib/srv/protocols/_legacy.js +4 -0
- package/lib/srv/protocols/graphql.js +2 -2
- package/lib/srv/protocols/index.js +7 -3
- package/lib/srv/srv-api.js +1 -0
- package/lib/srv/srv-methods.js +1 -1
- package/lib/utils/cds-utils.js +11 -0
- package/lib/utils/data.js +2 -2
- package/lib/utils/inflect.js +13 -12
- package/lib/utils/tar.js +43 -13
- package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +2 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/action.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/create.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/delete.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +1 -15
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/errors/UriSyntaxError.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/UriParser.js +6 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/utils/BufferedWriter.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/validator/ConditionalRequestValidator.js +0 -12
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/oDataConfiguration.js +1 -7
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +4 -0
- package/libx/_runtime/cds-services/services/Service.js +23 -1
- package/libx/_runtime/cds-services/util/assert.js +0 -41
- package/libx/_runtime/common/composition/data.js +5 -1
- package/libx/_runtime/common/generic/auth/utils.js +3 -3
- package/libx/_runtime/common/generic/crud.js +1 -1
- package/libx/_runtime/common/generic/input.js +4 -24
- package/libx/_runtime/common/generic/paging.js +10 -9
- package/libx/_runtime/common/utils/cqn2cqn4sql.js +31 -0
- package/libx/_runtime/common/utils/csn.js +21 -15
- package/libx/_runtime/common/utils/draft.js +2 -1
- package/libx/_runtime/common/utils/resolveView.js +27 -4
- package/libx/_runtime/common/utils/rewriteAsterisks.js +3 -1
- package/libx/_runtime/common/utils/rowUUIDGenerator.js +21 -0
- package/libx/_runtime/common/utils/templateProcessor.js +12 -15
- package/libx/_runtime/common/utils/templateProcessorPathSerializer.js +23 -0
- package/libx/_runtime/db/expand/expandCQNToJoin.js +29 -12
- package/libx/_runtime/db/generic/input.js +7 -13
- package/libx/_runtime/db/sql-builder/InsertBuilder.js +5 -1
- package/libx/_runtime/db/sql-builder/UpsertBuilder.js +24 -0
- package/libx/_runtime/db/sql-builder/annotations.js +6 -3
- package/libx/_runtime/db/sql-builder/index.js +2 -0
- package/libx/_runtime/db/sql-builder/sqlFactory.js +9 -0
- package/libx/_runtime/db/utils/columns.js +4 -2
- package/libx/_runtime/fiori/generic/read.js +1 -12
- package/libx/_runtime/fiori/lean-draft.js +657 -0
- package/libx/_runtime/fiori/utils/handler.js +1 -1
- package/libx/_runtime/hana/Service.js +1 -1
- package/libx/_runtime/hana/execute.js +5 -5
- package/libx/_runtime/hana/pool.js +16 -1
- package/libx/_runtime/messaging/enterprise-messaging-utils/getTenantInfo.js +2 -1
- package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +1 -1
- package/libx/_runtime/messaging/enterprise-messaging.js +2 -3
- package/libx/_runtime/messaging/outbox/utils.js +109 -70
- package/libx/_runtime/messaging/service.js +16 -7
- package/libx/_runtime/remote/Service.js +15 -2
- package/libx/_runtime/remote/utils/client.js +41 -11
- package/libx/_runtime/sqlite/Service.js +4 -1
- package/libx/_runtime/sqlite/convertDraftAdminPathExpression.js +56 -0
- package/libx/_runtime/sqlite/customBuilder/CustomUpsertBuilder.js +41 -0
- package/libx/_runtime/sqlite/customBuilder/index.js +5 -0
- package/libx/_runtime/sqlite/execute.js +1 -1
- package/libx/_runtime/types/api.js +2 -2
- package/libx/rest/RestAdapter.js +15 -13
- package/package.json +1 -1
- 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(
|
|
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 =
|
|
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 =
|
|
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' } =
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
240
|
+
var stats = this._getResourceStatus(entry)
|
|
262
241
|
if (stats.isDirectory()) {
|
|
263
|
-
|
|
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
|
|
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(
|
|
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
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
|
|
76
|
-
let srv = typeof
|
|
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 '${
|
|
123
|
-
!srv && this.logger._debug && this.logger.debug(`project doesn't have a service module '${
|
|
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.
|
|
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 =
|
|
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
|
-
||
|
|
173
|
-
||
|
|
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 (
|
|
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 =
|
|
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.
|
|
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
|
|
192
|
+
this.logger.debug("determining mtx version of nodejs project")
|
|
193
193
|
|
|
194
|
-
if (isStreamlinedMtx(
|
|
195
|
-
if (
|
|
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 =
|
|
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 (
|
|
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.
|
|
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 (
|
|
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.
|
|
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 =
|
|
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
|
|
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:
|
|
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
|
-
&& !
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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[
|
|
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
|
|
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
|
|
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
|
-
|
|
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 !==
|
|
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) ||
|
|
255
|
-
if (!
|
|
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:
|
|
271
|
-
const result =
|
|
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:
|
|
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
|
-
|
|
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.
|
|
333
|
+
await this._validateMigrationTableFiles()
|
|
334
334
|
|
|
335
335
|
// update last development version
|
|
336
336
|
if (afterImage) {
|
|
337
337
|
if (migrationTableFiles.length > 0) {
|
|
338
|
-
|
|
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 (
|
|
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
|
|
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
|