@sap/cds 6.5.0 → 6.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -2
- package/README.md +5 -0
- package/apis/services.d.ts +5 -0
- package/bin/build/buildTaskEngine.js +0 -2
- package/bin/build/buildTaskFactory.js +1 -1
- package/bin/build/buildTaskHandler.js +1 -1
- package/bin/build/provider/buildTaskProviderInternal.js +10 -6
- package/bin/build/provider/fiori/index.js +5 -10
- package/bin/build/provider/hana/2migration.js +11 -2
- package/bin/build/provider/hana/index.js +17 -14
- package/bin/build/provider/hana/template/.hdiconfig-hanacloud +137 -0
- package/bin/build/provider/mtx-extension/index.js +18 -1
- package/bin/build/provider/mtx-sidecar/index.js +1 -1
- package/bin/build/util.js +1 -1
- package/bin/cds.js +1 -5
- package/bin/deploy/to-hana/hana.js +10 -3
- package/bin/serve.js +32 -20
- package/lib/auth/jwt-auth.js +4 -4
- package/lib/compile/for/lean_drafts.js +55 -6
- package/lib/dbs/cds-deploy.js +6 -8
- package/lib/index.js +4 -2
- package/lib/req/cds-context.js +3 -3
- package/lib/srv/bindings.js +1 -2
- package/lib/srv/cds-serve.js +2 -1
- package/lib/srv/middlewares/trace.js +31 -15
- package/lib/srv/protocols/odata-v2-proxy.js +8 -8
- package/lib/srv/srv-handlers.js +26 -7
- package/lib/srv/srv-methods.js +2 -2
- package/lib/srv/srv-models.js +3 -3
- package/lib/utils/cds-test.js +7 -5
- package/libx/_runtime/auth/strategies/ias-auth.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/OData.js +6 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +26 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +8 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/readToCQN.js +11 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/utils/PrimitiveValueDecoder.js +8 -8
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/utils/ValueConverter.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/validator/ValueValidator.js +14 -14
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/deserializer/DeserializerFactory.js +1 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/serializer/ResourceJsonSerializer.js +3 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/utils/UriHelper.js +2 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/metaInfo.js +3 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +7 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/stream.js +0 -3
- package/libx/_runtime/cds-services/services/Service.js +8 -19
- package/libx/_runtime/cds-services/services/utils/columns.js +7 -4
- package/libx/_runtime/cds-services/util/assert.js +7 -1
- package/libx/_runtime/common/code-ext/WorkerReq.js +3 -1
- package/libx/_runtime/common/code-ext/execute.js +9 -2
- package/libx/_runtime/common/code-ext/handlers.js +2 -2
- package/libx/_runtime/common/code-ext/worker.js +9 -5
- package/libx/_runtime/common/code-ext/workerQueryExecutor.js +5 -2
- package/libx/_runtime/common/composition/data.js +5 -2
- package/libx/_runtime/common/composition/tree.js +2 -0
- package/libx/_runtime/common/generic/auth/restrict.js +1 -1
- package/libx/_runtime/common/generic/etag.js +3 -1
- package/libx/_runtime/common/generic/input.js +12 -14
- package/libx/_runtime/common/utils/cqn2cqn4sql.js +31 -11
- package/libx/_runtime/common/utils/path.js +0 -1
- package/libx/_runtime/common/utils/search2cqn4sql.js +4 -1
- package/libx/_runtime/common/utils/templateProcessorPathSerializer.js +19 -13
- package/libx/_runtime/db/data-conversion/post-processing.js +1 -1
- package/libx/_runtime/db/expand/expandCQNToJoin.js +5 -3
- package/libx/_runtime/db/expand/rawToExpanded.js +3 -2
- package/libx/_runtime/db/generic/input.js +2 -2
- package/libx/_runtime/db/generic/integrity.js +1 -0
- package/libx/_runtime/db/generic/virtual.js +1 -0
- package/libx/_runtime/db/query/read.js +3 -2
- package/libx/_runtime/fiori/generic/activate.js +3 -1
- package/libx/_runtime/fiori/generic/before.js +1 -0
- package/libx/_runtime/fiori/generic/edit.js +3 -1
- package/libx/_runtime/fiori/generic/new.js +2 -0
- package/libx/_runtime/fiori/generic/patch.js +2 -0
- package/libx/_runtime/fiori/generic/prepare.js +2 -0
- package/libx/_runtime/fiori/generic/read.js +8 -2
- package/libx/_runtime/fiori/generic/readOverDraft.js +2 -0
- package/libx/_runtime/fiori/lean-draft.js +498 -245
- package/libx/_runtime/fiori/utils/delete.js +2 -0
- package/libx/_runtime/messaging/Outbox.js +1 -1
- package/libx/_runtime/messaging/enterprise-messaging-utils/getTenantInfo.js +1 -0
- package/libx/_runtime/messaging/enterprise-messaging.js +2 -6
- package/libx/_runtime/messaging/file-based.js +1 -2
- package/libx/_runtime/messaging/outbox/OutboxRunner.js +1 -1
- package/libx/_runtime/messaging/outbox/utils.js +1 -1
- package/libx/_runtime/messaging/service.js +0 -1
- package/libx/_runtime/remote/Service.js +1 -0
- package/libx/_runtime/sqlite/convertDraftAdminPathExpression.js +19 -3
- package/libx/_runtime/sqlite/customBuilder/CustomExpressionBuilder.js +0 -18
- package/libx/_runtime/sqlite/customBuilder/CustomFunctionBuilder.js +0 -18
- package/libx/_runtime/sqlite/customBuilder/CustomSelectBuilder.js +0 -24
- package/libx/_runtime/sqlite/customBuilder/CustomUpsertBuilder.js +2 -1
- package/libx/_runtime/sqlite/customBuilder/index.js +47 -32
- package/libx/odata/afterburner.js +17 -5
- package/libx/odata/grammar.pegjs +3 -4
- package/libx/odata/index.js +5 -1
- package/libx/odata/parseToCqn.js +3 -3
- package/libx/odata/parser.js +1 -1
- package/libx/odata/utils.js +58 -1
- package/package.json +1 -1
- package/server.js +1 -1
- package/libx/_runtime/sqlite/customBuilder/CustomDeleteBuilder.js +0 -17
- package/libx/_runtime/sqlite/customBuilder/CustomReferenceBuilder.js +0 -11
- package/libx/_runtime/sqlite/customBuilder/CustomUpdateBuilder.js +0 -17
- /package/bin/build/provider/hana/template/{.hdiconfig → .hdiconfig-haas} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,41 @@
|
|
|
4
4
|
- The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
|
5
5
|
- This project adheres to [Semantic Versioning](http://semver.org/).
|
|
6
6
|
|
|
7
|
+
## Version 6.6.0 - 2023-02-27
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Improved error handling for `cds build` if the SaaS base model is missing in an extension project.
|
|
12
|
+
- Support for reliable paging using `$skiptoken`. Can be activated via `cds.query.limit.reliablePaging = true`
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- `cds.serve(ServiceName)` (and `cds serve -s ServiceName`) now exactly serve services with the given names. Previously, all services that ended with the given name were served as well, e.g. `MyServiceName` and `ServiceName`, which might be problematic for applications that bootstrap services one by one.
|
|
17
|
+
- Optimize `@cds.persistence.journal` filtering for `last-dev` CSN file.
|
|
18
|
+
- `process.exit()` is no longer called during server shutdown, so that other/custom exit handlers get a chance to execute.
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- `cds deploy --to hana` no longer calls `cds bind` when `VCAP_SERVICES` is provided, e.g via `default-env.json`.
|
|
23
|
+
- `$search` on an entity without String elements
|
|
24
|
+
- Only elements from type `cds.String` are searchable when combining `$apply` and `$search`
|
|
25
|
+
- Error message for missing database connection in draft case
|
|
26
|
+
- Extensibility with in-memory Sqlite
|
|
27
|
+
- OData adapter error messages
|
|
28
|
+
- Columns in navigation path are now added to the SELECT.columns in new parser
|
|
29
|
+
- Application service calls on draft enabled entities using aliases
|
|
30
|
+
- Custom mtxs build tasks now use the correct default `src` folder value.
|
|
31
|
+
- `cds build` adds a `.hdiconfig` file when creating HANA migration tables if none is existing.
|
|
32
|
+
- UPSERTs using reserved keywords
|
|
33
|
+
- Fix outbound-streaming error handling
|
|
34
|
+
- Rollback transaction if inbound streaming fails
|
|
35
|
+
- Custom database initialization in `db/init.js` now skips the `t0` tenant for multitenant apps.
|
|
36
|
+
- Concurrent etag calculation for UPDATE and DELETE
|
|
37
|
+
- Typings for `cds.delete()`
|
|
38
|
+
- CQN for `not` operator with OData functions
|
|
39
|
+
- Expand on composition of aspect for draft enabled entities
|
|
40
|
+
- Better error messages are provided for errors with HTTP status code `400`, `500` and `501`
|
|
41
|
+
|
|
7
42
|
## Version 6.5.0 - 2023-01-27
|
|
8
43
|
|
|
9
44
|
### Added
|
|
@@ -15,13 +50,13 @@
|
|
|
15
50
|
|
|
16
51
|
- Successive calls to `SELECT.where()` wraps existing clause in brackets if it contains `or`. E.g.
|
|
17
52
|
```js
|
|
18
|
-
SELECT.from `X` .where `x` .or `y` .where `z`
|
|
53
|
+
SELECT.from `X` .where `x` .or `y` .where `z`
|
|
19
54
|
//> SELECT from X where (x or y) and z`
|
|
20
55
|
```
|
|
21
56
|
- `cds build` for HANA now adds an `engines.node` version to the generated `db/package.json`. This will help in the future when runtime environments change their default to some version higher than the one supported by `@sap/hdi-deploy`.
|
|
22
57
|
- `cds build` checks the consistency of built-in models for java projects. An error is logged if some model files could not successfully be resolved indicating that a required npm module might be missing.
|
|
23
58
|
- Status code of draft actions are set in respective handler instead of protocol adapter
|
|
24
|
-
- `cds deploy --dry` no longer loads the `sqlite3` module by mistake. This fixes a regression when building Java projects. As a side effect a file with the name `undefined` was created in the project root folder.
|
|
59
|
+
- `cds deploy --dry` no longer loads the `sqlite3` module by mistake. This fixes a regression when building Java projects. As a side effect a file with the name `undefined` was created in the project root folder.
|
|
25
60
|
- Internal representation of pseudo roles `internal-user` and `system-user`
|
|
26
61
|
|
|
27
62
|
### Fixed
|
|
@@ -57,6 +92,7 @@
|
|
|
57
92
|
- fix view resolving and managed data for UPSERT
|
|
58
93
|
- `cds.linked` supports polymorphic self links like in: `action foo( self: [many] $self, ...)`
|
|
59
94
|
- Error with `@odata.draft.enabled` and `@restrict`
|
|
95
|
+
- Skip mandatory check on navigation properties for write requests
|
|
60
96
|
|
|
61
97
|
## Version 6.4.0 - 2022-12-15
|
|
62
98
|
|
package/README.md
CHANGED
|
@@ -4,5 +4,10 @@ The API package for the [SAP Cloud Application Programming Model (CAP)](https://
|
|
|
4
4
|
|
|
5
5
|
See the [API documentation](https://cap.cloud.sap/docs/node.js/api) for more details.
|
|
6
6
|
|
|
7
|
+
## How to Obtain Support**
|
|
8
|
+
|
|
9
|
+
In case you find a bug, please report an [incident](https://cap.cloud.sap/docs/resources/#reporting-incidents) on SAP Support Portal.
|
|
10
|
+
|
|
7
11
|
## License
|
|
12
|
+
|
|
8
13
|
This package is provided under the terms of the [SAP Developer License Agreement](https://tools.hana.ondemand.com/developer-license-3.1.txt).
|
package/apis/services.d.ts
CHANGED
|
@@ -54,6 +54,11 @@ export class QueryAPI {
|
|
|
54
54
|
(query: Query): Promise<ResultSet | any>
|
|
55
55
|
(query: string, args?: any[] | object): Promise<ResultSet | any>
|
|
56
56
|
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @see [docs](https://cap.cloud.sap/docs/node.js/cds-facade?q=cds.delete)
|
|
60
|
+
*/
|
|
61
|
+
delete<T>(entity: Definition | string, key?: any): DELETE<T>
|
|
57
62
|
|
|
58
63
|
/**
|
|
59
64
|
* @see [docs](https://cap.cloud.sap/docs/node.js/services#srv-run)
|
|
@@ -257,8 +257,6 @@ class BuildTaskEngine {
|
|
|
257
257
|
const files = BuildTaskEngine._getBuildOutput(handlers, buildOptions)
|
|
258
258
|
if (files.length > 0) {
|
|
259
259
|
this.logger.log(`done > wrote output to:\n ${files.join("\n ")}\n`)
|
|
260
|
-
} else {
|
|
261
|
-
this.logger.log('done >')
|
|
262
260
|
}
|
|
263
261
|
}
|
|
264
262
|
|
|
@@ -56,7 +56,7 @@ class BuildTaskFactory {
|
|
|
56
56
|
|
|
57
57
|
async _createTasks(providerFactory) {
|
|
58
58
|
const buildOptions = providerFactory.buildOptions
|
|
59
|
-
this.logger.
|
|
59
|
+
this.logger.debug(`determining build tasks for project [${buildOptions.root}].`)
|
|
60
60
|
|
|
61
61
|
// clearing model cache (details https://github.tools.sap/cap/cds/pull/181) is no longer required
|
|
62
62
|
// because of changes https://github.tools.sap/cap/cds/pull/1121
|
|
@@ -184,7 +184,7 @@ class BuildTaskHandler {
|
|
|
184
184
|
async model() {
|
|
185
185
|
const files = this._resolveModel()
|
|
186
186
|
if (!files || files.length === 0) {
|
|
187
|
-
this._logger.log(
|
|
187
|
+
this._logger.log(`no CDS model found for [${this.task.for}] build task [${this.task.src}] - nothing to be done`)
|
|
188
188
|
return null
|
|
189
189
|
}
|
|
190
190
|
this._logger._debug && this._logger.debug(`model: ${relativePaths(this._buildOptions.root, files).join(", ")}`)
|
|
@@ -63,7 +63,11 @@ class BuildTaskProviderInternal extends BuildTaskProvider {
|
|
|
63
63
|
break
|
|
64
64
|
case BUILD_TASK_MTX_EXTENSION:
|
|
65
65
|
case BUILD_TASK_MTX:
|
|
66
|
-
|
|
66
|
+
if (isStreamlinedMtx()) {
|
|
67
|
+
task.src = task.src || BuildTaskProviderInternal._normalizePath(cds.env.folders.srv)
|
|
68
|
+
} else {
|
|
69
|
+
task.src = task.src || "."
|
|
70
|
+
}
|
|
67
71
|
break
|
|
68
72
|
default:
|
|
69
73
|
throw new Error(`Unknown build task '${task.use || task.for}'`)
|
|
@@ -84,13 +88,13 @@ class BuildTaskProviderInternal extends BuildTaskProvider {
|
|
|
84
88
|
if (Array.isArray(db) && db.length > 0) {
|
|
85
89
|
db = BuildTaskProviderInternal._getModuleFolder(projectPath, db) || null
|
|
86
90
|
if (!db && !addRequiredTasks) { // log once
|
|
87
|
-
this.logger.
|
|
91
|
+
this.logger.debug("No database module found")
|
|
88
92
|
}
|
|
89
93
|
}
|
|
90
94
|
if (Array.isArray(srv) && srv.length > 0) {
|
|
91
95
|
srv = BuildTaskProviderInternal._getModuleFolder(projectPath, srv) || null
|
|
92
96
|
if (!srv && !addRequiredTasks) { // log once
|
|
93
|
-
this.logger.
|
|
97
|
+
this.logger.debug("No service module found")
|
|
94
98
|
}
|
|
95
99
|
}
|
|
96
100
|
// create required build tasks
|
|
@@ -205,7 +209,7 @@ class BuildTaskProviderInternal extends BuildTaskProvider {
|
|
|
205
209
|
|
|
206
210
|
const sidecarPath = path.join(projectPath, MTX_SIDECAR_FOLDER)
|
|
207
211
|
if (!fs.existsSync(sidecarPath)) {
|
|
208
|
-
throw new BuildError(
|
|
212
|
+
throw new BuildError(`MTX sidecar directory '${sidecarPath}' not existing. Custom build task configuration necessary if the folder is named differently.`)
|
|
209
213
|
}
|
|
210
214
|
const sidecarEnv = cds.env.for("cds", sidecarPath)
|
|
211
215
|
if (sidecarEnv.requires["cds.xt.ModelProviderService"]?.kind === "in-sidecar") {
|
|
@@ -213,12 +217,12 @@ class BuildTaskProviderInternal extends BuildTaskProvider {
|
|
|
213
217
|
for: BUILD_TASK_MTX_SIDECAR
|
|
214
218
|
}
|
|
215
219
|
}
|
|
216
|
-
throw new BuildError("
|
|
220
|
+
throw new BuildError("Invalid MTX sidecar configuration - \"cds.xt.ModelProviderService\": \"in-sidecar\" missing.")
|
|
217
221
|
}
|
|
218
222
|
|
|
219
223
|
if (cds.env.requires["cds.xt.ModelProviderService"]?.kind === "in-sidecar") {
|
|
220
224
|
// cds build is executed in sidecar folder
|
|
221
|
-
throw new BuildError("
|
|
225
|
+
throw new BuildError("Invalid working directory. Make sure to execute 'cds build' in CAP project root directory.")
|
|
222
226
|
}
|
|
223
227
|
|
|
224
228
|
this.logger.debug("Nodejs Streamlined MTX app without sidecar")
|
|
@@ -62,10 +62,9 @@ class FioriAppModuleBuilder extends BuildTaskHandlerEdmx {
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
for (let [appFolder, appModelGroup] of appModelGroups.entries()) {
|
|
65
|
-
this.logger.
|
|
65
|
+
this.logger.debug(`building module [${appFolder}] using [${this.constructor.name}]`)
|
|
66
66
|
const modelPaths = cds.resolve(Array.from(appModelGroup.values()), this.buildOptions)
|
|
67
67
|
if (!modelPaths || modelPaths.length === 0) {
|
|
68
|
-
this.logger.log(`no model found`)
|
|
69
68
|
continue
|
|
70
69
|
}
|
|
71
70
|
this.logger._debug && this.logger.debug(`model: ${relativePaths(this.buildOptions.root, modelPaths).join(", ")}`)
|
|
@@ -89,19 +88,15 @@ class FioriAppModuleBuilder extends BuildTaskHandlerEdmx {
|
|
|
89
88
|
/**
|
|
90
89
|
* This version only creates a odata representation for the 'mainService' data source
|
|
91
90
|
* as defined by the fiori wizard - everything else is currently not supported.
|
|
92
|
-
* Therefore errors are only logged, the build does not fail in case a
|
|
91
|
+
* Therefore errors are only logged, the build does not fail in case a service
|
|
93
92
|
* cannot be resolved based on the defined service URI
|
|
94
93
|
*/
|
|
95
94
|
async build() {
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
if (!modelPaths || modelPaths.length === 0) {
|
|
99
|
-
this.logger.log(`no model found`)
|
|
95
|
+
const model = await this.model()
|
|
96
|
+
if (!model) {
|
|
100
97
|
return
|
|
101
98
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
await this._writeEdmxToWebapp(src, dest)
|
|
99
|
+
await this._writeEdmxToWebapp(this.task.src, this.task.dest)
|
|
105
100
|
}
|
|
106
101
|
|
|
107
102
|
async _writeEdmxToWebapp(src, dest) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const path = require('path')
|
|
2
2
|
const parser = require('./migrationtable')
|
|
3
|
-
const { BuildError } = require('../../util')
|
|
3
|
+
const { BuildError, hasOptionValue } = require('../../util')
|
|
4
4
|
const { LOG_MODULE_NAMES } = require('../../constants')
|
|
5
5
|
const cds = require('../../cds'), { compiler: cdsc } = cds
|
|
6
6
|
const cdscVersion = `-- generated by cds-compiler version ${cdsc.version()}`
|
|
@@ -160,7 +160,7 @@ function _filterJournalArtifacts(csn) {
|
|
|
160
160
|
}
|
|
161
161
|
const dict = csn.definitions
|
|
162
162
|
for (const name in dict) {
|
|
163
|
-
if (dict[name]
|
|
163
|
+
if (!_isPersistedAsJournalTable(dict[name])) {
|
|
164
164
|
delete dict[name]
|
|
165
165
|
}
|
|
166
166
|
}
|
|
@@ -168,3 +168,12 @@ function _filterJournalArtifacts(csn) {
|
|
|
168
168
|
csn.meta.build = `CDS Build v${cds.version}`
|
|
169
169
|
return csn;
|
|
170
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
|
+
}
|
|
@@ -338,6 +338,12 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
|
|
|
338
338
|
if (!HanaModuleBuilder._toEqualIgnoreMeta(lastDev, afterImage)) {
|
|
339
339
|
await this.write(afterImage).to(lastDevCsnDir)
|
|
340
340
|
}
|
|
341
|
+
|
|
342
|
+
// add src/.hdiconfig if not existing
|
|
343
|
+
if (!fs.existsSync(path.join(dbSrcDir, '.hdiconfig'))) {
|
|
344
|
+
const template = await HanaModuleBuilder._readTemplateAsJson('.hdiconfig-hanacloud')
|
|
345
|
+
await this.write(template).to(path.join(dbSrcDir, '.hdiconfig'))
|
|
346
|
+
}
|
|
341
347
|
}
|
|
342
348
|
} else {
|
|
343
349
|
throw new BuildError(`Inconsistent CDS compilation results - file ${lastDevCsnFolder} missing`)
|
|
@@ -352,7 +358,7 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
|
|
|
352
358
|
this.logger._debug && this.logger.debug(`skip create [${relativePaths(this.buildOptions.root, packageJson)}], already existing`)
|
|
353
359
|
}
|
|
354
360
|
if (this.isStagingBuild() && !exists) {
|
|
355
|
-
const content = await
|
|
361
|
+
const content = await HanaModuleBuilder._readTemplateAsJson(FILE_NAME_PACKAGE_JSON)
|
|
356
362
|
await this.write(content).to(path.join(this.task.dest, FILE_NAME_PACKAGE_JSON))
|
|
357
363
|
}
|
|
358
364
|
}
|
|
@@ -362,7 +368,7 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
|
|
|
362
368
|
*/
|
|
363
369
|
async _writeHdiConfig(plugins) {
|
|
364
370
|
const hdiConfig = path.join(this.task.options.compileDest, FILE_NAME_HDICONFIG)
|
|
365
|
-
const template = await
|
|
371
|
+
const template = await HanaModuleBuilder._readTemplateAsJson('.hdiconfig-haas')
|
|
366
372
|
let content = {
|
|
367
373
|
'file_suffixes': {}
|
|
368
374
|
}
|
|
@@ -372,7 +378,7 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
|
|
|
372
378
|
}
|
|
373
379
|
}
|
|
374
380
|
if (Object.keys(content['file_suffixes']).length !== plugins.size) {
|
|
375
|
-
this.
|
|
381
|
+
this.pushMessage(`'HANA plugin not found for file suffix [${Array.from(plugins).join(',')}]`)
|
|
376
382
|
}
|
|
377
383
|
// TODO - Be on the save side for now - go for the content use case later on if this works as expected.
|
|
378
384
|
if (cds.env.hana['deploy-format'] === 'hdbtable') {
|
|
@@ -388,7 +394,7 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
|
|
|
388
394
|
async _writeHdiNamespace() {
|
|
389
395
|
// see issue #64 - add .hdinamespace file to prevent HDI from adding gen/ folder to the namespace.
|
|
390
396
|
const hdiNamespace = path.join(this.task.options.compileDest, FILE_NAME_HDINAMESPACE)
|
|
391
|
-
const content = await
|
|
397
|
+
const content = await HanaModuleBuilder._readTemplateAsJson(FILE_NAME_HDINAMESPACE)
|
|
392
398
|
return await this.write(content).to(hdiNamespace)
|
|
393
399
|
}
|
|
394
400
|
|
|
@@ -400,7 +406,7 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
|
|
|
400
406
|
// see issue #64 - add .hdinamespace file to prevent HDI from adding gen/ folder to the namespace.
|
|
401
407
|
const undeployJsonDest = path.join(this.task.dest, FILE_NAME_UNDEPLOY_JSON)
|
|
402
408
|
const undeployJsonSrc = path.join(this.task.src, FILE_NAME_UNDEPLOY_JSON)
|
|
403
|
-
const templateEntries = await
|
|
409
|
+
const templateEntries = await HanaModuleBuilder._readTemplateAsJson(FILE_NAME_UNDEPLOY_JSON)
|
|
404
410
|
let newEntries = []
|
|
405
411
|
if (fs.existsSync(undeployJsonSrc)) {
|
|
406
412
|
newEntries = await JSON.parse((await fs.promises.readFile(undeployJsonSrc, 'utf-8')).toString())
|
|
@@ -423,20 +429,12 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
|
|
|
423
429
|
}
|
|
424
430
|
}
|
|
425
431
|
|
|
426
|
-
async _readTemplateAsJson(template) {
|
|
427
|
-
const templatePath = path.join(__dirname, 'template', template)
|
|
428
|
-
return fs.promises.readFile(templatePath, 'utf-8').then(f => JSON.parse(f.toString()))
|
|
429
|
-
.catch((error) => {
|
|
430
|
-
this.logger.error(`Failed to read template [${templatePath}]`)
|
|
431
|
-
return Promise.reject(error)
|
|
432
|
-
})
|
|
433
|
-
}
|
|
434
432
|
|
|
435
433
|
async _readTypesFromUndeployJson() {
|
|
436
434
|
const result = new Set()
|
|
437
435
|
const file = path.join(this.task.src, "undeploy.json")
|
|
438
436
|
if (fs.existsSync(file)) {
|
|
439
|
-
const undeployList = JSON.parse((await fs.promises.readFile(file)).toString())
|
|
437
|
+
const undeployList = JSON.parse((await fs.promises.readFile(file)).toString(), 'utf-8')
|
|
440
438
|
if (Array.isArray(undeployList)) {
|
|
441
439
|
undeployList.forEach(entry => result.add(path.extname(entry)))
|
|
442
440
|
}
|
|
@@ -466,6 +464,11 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
|
|
|
466
464
|
}
|
|
467
465
|
}
|
|
468
466
|
|
|
467
|
+
static async _readTemplateAsJson(template) {
|
|
468
|
+
const content = await fs.promises.readFile(path.join(__dirname, 'template', template), 'utf-8')
|
|
469
|
+
return JSON.parse(content.toString())
|
|
470
|
+
}
|
|
471
|
+
|
|
469
472
|
static _toEqualIgnoreMeta(csn1, csn2) {
|
|
470
473
|
function toString(csn) {
|
|
471
474
|
return JSON.stringify(csn, (k, v) => {
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
|
|
2
|
+
{
|
|
3
|
+
"file_suffixes": {
|
|
4
|
+
"csv": {
|
|
5
|
+
"plugin_name": "com.sap.hana.di.tabledata.source"
|
|
6
|
+
},
|
|
7
|
+
"hdbafllangprocedure": {
|
|
8
|
+
"plugin_name": "com.sap.hana.di.afllangprocedure"
|
|
9
|
+
},
|
|
10
|
+
"hdbanalyticprivilege": {
|
|
11
|
+
"plugin_name": "com.sap.hana.di.analyticprivilege"
|
|
12
|
+
},
|
|
13
|
+
"hdbcalculationview": {
|
|
14
|
+
"plugin_name": "com.sap.hana.di.calculationview"
|
|
15
|
+
},
|
|
16
|
+
"hdbcollection": {
|
|
17
|
+
"plugin_name": "com.sap.hana.di.collection"
|
|
18
|
+
},
|
|
19
|
+
"hdbconstraint": {
|
|
20
|
+
"plugin_name": "com.sap.hana.di.constraint"
|
|
21
|
+
},
|
|
22
|
+
"hdbdropcreatetable": {
|
|
23
|
+
"plugin_name": "com.sap.hana.di.dropcreatetable"
|
|
24
|
+
},
|
|
25
|
+
"hdbflowgraph": {
|
|
26
|
+
"plugin_name": "com.sap.hana.di.flowgraph"
|
|
27
|
+
},
|
|
28
|
+
"hdbfunction": {
|
|
29
|
+
"plugin_name": "com.sap.hana.di.function"
|
|
30
|
+
},
|
|
31
|
+
"hdbgraphworkspace": {
|
|
32
|
+
"plugin_name": "com.sap.hana.di.graphworkspace"
|
|
33
|
+
},
|
|
34
|
+
"hdbhadoopmrjob": {
|
|
35
|
+
"plugin_name": "com.sap.hana.di.virtualfunctionpackage.hadoop"
|
|
36
|
+
},
|
|
37
|
+
"hdbindex": {
|
|
38
|
+
"plugin_name": "com.sap.hana.di.index"
|
|
39
|
+
},
|
|
40
|
+
"hdblibrary": {
|
|
41
|
+
"plugin_name": "com.sap.hana.di.library"
|
|
42
|
+
},
|
|
43
|
+
"hdbmigrationtable": {
|
|
44
|
+
"plugin_name": "com.sap.hana.di.table.migration"
|
|
45
|
+
},
|
|
46
|
+
"hdbprocedure": {
|
|
47
|
+
"plugin_name": "com.sap.hana.di.procedure"
|
|
48
|
+
},
|
|
49
|
+
"hdbprojectionview": {
|
|
50
|
+
"plugin_name": "com.sap.hana.di.projectionview"
|
|
51
|
+
},
|
|
52
|
+
"hdbprojectionviewconfig": {
|
|
53
|
+
"plugin_name": "com.sap.hana.di.projectionview.config"
|
|
54
|
+
},
|
|
55
|
+
"hdbreptask": {
|
|
56
|
+
"plugin_name": "com.sap.hana.di.reptask"
|
|
57
|
+
},
|
|
58
|
+
"hdbresultcache": {
|
|
59
|
+
"plugin_name": "com.sap.hana.di.resultcache"
|
|
60
|
+
},
|
|
61
|
+
"hdbrole": {
|
|
62
|
+
"plugin_name": "com.sap.hana.di.role"
|
|
63
|
+
},
|
|
64
|
+
"hdbroleconfig": {
|
|
65
|
+
"plugin_name": "com.sap.hana.di.role.config"
|
|
66
|
+
},
|
|
67
|
+
"hdbsearchruleset": {
|
|
68
|
+
"plugin_name": "com.sap.hana.di.searchruleset"
|
|
69
|
+
},
|
|
70
|
+
"hdbsequence": {
|
|
71
|
+
"plugin_name": "com.sap.hana.di.sequence"
|
|
72
|
+
},
|
|
73
|
+
"hdbstatistics": {
|
|
74
|
+
"plugin_name": "com.sap.hana.di.statistics"
|
|
75
|
+
},
|
|
76
|
+
"hdbstructuredprivilege": {
|
|
77
|
+
"plugin_name": "com.sap.hana.di.structuredprivilege"
|
|
78
|
+
},
|
|
79
|
+
"hdbsynonym": {
|
|
80
|
+
"plugin_name": "com.sap.hana.di.synonym"
|
|
81
|
+
},
|
|
82
|
+
"hdbsynonymconfig": {
|
|
83
|
+
"plugin_name": "com.sap.hana.di.synonym.config"
|
|
84
|
+
},
|
|
85
|
+
"hdbsystemversioning": {
|
|
86
|
+
"plugin_name": "com.sap.hana.di.systemversioning"
|
|
87
|
+
},
|
|
88
|
+
"hdbtable": {
|
|
89
|
+
"plugin_name": "com.sap.hana.di.table"
|
|
90
|
+
},
|
|
91
|
+
"hdbtabledata": {
|
|
92
|
+
"plugin_name": "com.sap.hana.di.tabledata"
|
|
93
|
+
},
|
|
94
|
+
"hdbtabletype": {
|
|
95
|
+
"plugin_name": "com.sap.hana.di.tabletype"
|
|
96
|
+
},
|
|
97
|
+
"hdbtrigger": {
|
|
98
|
+
"plugin_name": "com.sap.hana.di.trigger"
|
|
99
|
+
},
|
|
100
|
+
"hdbview": {
|
|
101
|
+
"plugin_name": "com.sap.hana.di.view"
|
|
102
|
+
},
|
|
103
|
+
"hdbvirtualfunction": {
|
|
104
|
+
"plugin_name": "com.sap.hana.di.virtualfunction"
|
|
105
|
+
},
|
|
106
|
+
"hdbvirtualfunctionconfig": {
|
|
107
|
+
"plugin_name": "com.sap.hana.di.virtualfunction.config"
|
|
108
|
+
},
|
|
109
|
+
"hdbvirtualpackagehadoop": {
|
|
110
|
+
"plugin_name": "com.sap.hana.di.virtualpackage.hadoop"
|
|
111
|
+
},
|
|
112
|
+
"hdbvirtualpackagesparksql": {
|
|
113
|
+
"plugin_name": "com.sap.hana.di.virtualpackage.sparksql"
|
|
114
|
+
},
|
|
115
|
+
"hdbvirtualprocedure": {
|
|
116
|
+
"plugin_name": "com.sap.hana.di.virtualprocedure"
|
|
117
|
+
},
|
|
118
|
+
"hdbvirtualprocedureconfig": {
|
|
119
|
+
"plugin_name": "com.sap.hana.di.virtualprocedure.config"
|
|
120
|
+
},
|
|
121
|
+
"hdbvirtualtable": {
|
|
122
|
+
"plugin_name": "com.sap.hana.di.virtualtable"
|
|
123
|
+
},
|
|
124
|
+
"hdbvirtualtableconfig": {
|
|
125
|
+
"plugin_name": "com.sap.hana.di.virtualtable.config"
|
|
126
|
+
},
|
|
127
|
+
"properties": {
|
|
128
|
+
"plugin_name": "com.sap.hana.di.tabledata.properties"
|
|
129
|
+
},
|
|
130
|
+
"tags": {
|
|
131
|
+
"plugin_name": "com.sap.hana.di.tabledata.properties"
|
|
132
|
+
},
|
|
133
|
+
"txt": {
|
|
134
|
+
"plugin_name": "com.sap.hana.di.copyonly"
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -5,6 +5,7 @@ const cds = require('../../cds')
|
|
|
5
5
|
const BuildTaskHandlerInternal = require('../buildTaskHandlerInternal')
|
|
6
6
|
const { FOLDER_GEN } = require('../../constants')
|
|
7
7
|
const ResourcesTarBuilder = require('../mtx/resourcesTarBuilder')
|
|
8
|
+
const { BuildError } = require('../../util')
|
|
8
9
|
|
|
9
10
|
class MtxExtensionModuleBuilder extends BuildTaskHandlerInternal {
|
|
10
11
|
init() {
|
|
@@ -18,7 +19,19 @@ class MtxExtensionModuleBuilder extends BuildTaskHandlerInternal {
|
|
|
18
19
|
const { src, dest } = this.task
|
|
19
20
|
const destExt = path.join(dest, 'ext')
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
const packageJson = path.join(src, 'package.json')
|
|
23
|
+
if (!fs.existsSync(packageJson)) {
|
|
24
|
+
throw new BuildError(`The package.json file is missing`)
|
|
25
|
+
}
|
|
26
|
+
await this.copy(packageJson).to(path.join(destExt, 'package.json'))
|
|
27
|
+
|
|
28
|
+
// validate existence of base model by simply checking existence of appPackage folder
|
|
29
|
+
// cds.resolve might fail for the extension migration use case as no index.csn file exists.
|
|
30
|
+
// A compilation error is thrown anyhow if any base model using statement cannot be resolved.
|
|
31
|
+
const appPackage = MtxExtensionModuleBuilder._getAppPackageName()
|
|
32
|
+
if (!fs.existsSync(path.join(src, 'node_modules', appPackage))) {
|
|
33
|
+
throw new BuildError(`The SaaS application base model '${appPackage}' is missing. Have you run the 'cds pull' command?`)
|
|
34
|
+
}
|
|
22
35
|
|
|
23
36
|
// copy handlers
|
|
24
37
|
const folders = [path.join(src, cds.env.folders.srv, 'handlers')]
|
|
@@ -58,5 +71,9 @@ class MtxExtensionModuleBuilder extends BuildTaskHandlerInternal {
|
|
|
58
71
|
// add all resources contained in the 'ext' folder
|
|
59
72
|
await new ResourcesTarBuilder(this).writeTarFile(path.join(this.task.dest, 'extension.tgz'), destExt)
|
|
60
73
|
}
|
|
74
|
+
|
|
75
|
+
static _getAppPackageName() {
|
|
76
|
+
return cds.env.extends || '_base';
|
|
77
|
+
}
|
|
61
78
|
}
|
|
62
79
|
module.exports = MtxExtensionModuleBuilder
|
|
@@ -59,7 +59,7 @@ class MtxSidecarModuleBuilder extends NodeCfModuleBuilder {
|
|
|
59
59
|
*/
|
|
60
60
|
async _buildMainApp(sidecarEnv) {
|
|
61
61
|
if (sidecarEnv.requires['cds.xt.ModelProviderService']?.kind !== 'in-sidecar') {
|
|
62
|
-
throw new BuildError(
|
|
62
|
+
throw new BuildError('Invalid MTX sidecar configuration - "cds.xt.ModelProviderService": "in-sidecar" missing.')
|
|
63
63
|
}
|
|
64
64
|
let main = sidecarEnv.requires['cds.xt.ModelProviderService']?.root
|
|
65
65
|
const profiles = cds.env.profiles || []
|
package/bin/build/util.js
CHANGED
|
@@ -228,7 +228,7 @@ class BuildError extends BuildMessage {
|
|
|
228
228
|
}
|
|
229
229
|
|
|
230
230
|
toString() {
|
|
231
|
-
return this.message + '\n' + this.messages.map(m => m.toString()).join('\n')
|
|
231
|
+
return this.message + (this.messages.length > 0 ? '\n' + this.messages.map(m => m.toString()).join('\n') : '')
|
|
232
232
|
}
|
|
233
233
|
}
|
|
234
234
|
|
package/bin/cds.js
CHANGED
|
@@ -9,7 +9,6 @@ const cli = { //NOSONAR
|
|
|
9
9
|
|
|
10
10
|
exec (cmd = process.argv[2], ...argv) {
|
|
11
11
|
if (!argv.length) argv = process.argv.slice(3)
|
|
12
|
-
if (process.env.NODE_ENV !== 'test') this.errorHandlers()
|
|
13
12
|
if (cmd in this.Shortcuts) cmd = process.argv[2] = this.Shortcuts[cmd]
|
|
14
13
|
let task = this.load ('./'+cmd)
|
|
15
14
|
if (task && cmd !== 'build') return task.apply (this, this.args(task,argv))
|
|
@@ -59,10 +58,7 @@ const cli = { //NOSONAR
|
|
|
59
58
|
},
|
|
60
59
|
|
|
61
60
|
errorHandlers () {
|
|
62
|
-
|
|
63
|
-
const _exit = (c) => { console.log(); process.exit(c) }
|
|
64
|
-
cds.repl || process.on ('unhandledRejection', _error)
|
|
65
|
-
cds.repl || process.on ('uncaughtException', _error)
|
|
61
|
+
// for compatibility with lkg -> remove after next release of cds-dk
|
|
66
62
|
},
|
|
67
63
|
|
|
68
64
|
get log() { return this.log = require('./utils/log') }
|
|
@@ -71,8 +71,8 @@ class HanaDeployer {
|
|
|
71
71
|
await fs.write(path.join(currentModelFolder, 'undeploy.json'), JSON.stringify(undeployWhitelist, null, 2));
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
const
|
|
75
|
-
if (
|
|
74
|
+
const hasVCAPEnv = Object.keys(vcapEnv).length > 0;
|
|
75
|
+
if (hasVCAPEnv) {
|
|
76
76
|
await fs.mkdir(currentModelFolder, { recursive: true });
|
|
77
77
|
} else {
|
|
78
78
|
const { cfServiceInstanceName, cfServiceInstanceKeyName, serviceKey } =
|
|
@@ -106,7 +106,14 @@ class HanaDeployer {
|
|
|
106
106
|
|
|
107
107
|
await hdiDeployUtil.deploy(currentModelFolder, vcapEnv, hdiOptions);
|
|
108
108
|
|
|
109
|
-
|
|
109
|
+
// let isLoggedInToCF;
|
|
110
|
+
// try {
|
|
111
|
+
// isLoggedInToCF = !!(await cfUtil.getCfTarget());
|
|
112
|
+
// } catch (err) {
|
|
113
|
+
// // valid state: not logged in
|
|
114
|
+
// }
|
|
115
|
+
// if (bindCallback && isLoggedInToCF) {
|
|
116
|
+
if (!hasVCAPEnv && bindCallback) {
|
|
110
117
|
const args = [path.relative(projectPath, buildResult.task.src)];
|
|
111
118
|
const options = { to: `${serviceName}:${serviceKeyName}`, kind: buildResult.task.for }
|
|
112
119
|
await bindCallback(args, options);
|