@sap/cds 6.8.4 → 7.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +66 -4
- package/README.md +0 -1
- package/bin/cds-serve.js +50 -3
- package/bin/deploy/to-hana.js +1 -0
- package/bin/serve.js +16 -20
- package/lib/auth/basic-auth.js +6 -4
- package/lib/auth/index.js +4 -3
- package/lib/auth/jwt-auth.js +2 -5
- package/lib/compile/cds-compile.js +34 -89
- package/lib/compile/cdsc.js +11 -0
- package/lib/compile/etc/properties.js +2 -2
- package/lib/compile/for/lean_drafts.js +36 -69
- package/lib/compile/for/nodejs.js +2 -1
- package/lib/compile/load.js +3 -3
- package/lib/compile/minify.js +2 -0
- package/lib/compile/to/csn.js +74 -0
- package/{bin/build/provider/hana/2tabledata.js → lib/compile/to/hdbtabledata.js} +4 -6
- package/lib/compile/to/json.js +1 -1
- package/lib/compile/to/sql.js +8 -6
- package/lib/dbs/cds-deploy.js +174 -114
- package/lib/env/cds-env.js +64 -79
- package/lib/env/cds-requires.js +11 -28
- package/lib/env/defaults.js +13 -3
- package/lib/env/plugins.js +1 -12
- package/lib/env/presets.js +25 -21
- package/lib/index.js +121 -147
- package/lib/{core/reflect.js → linked/models.js} +2 -2
- package/lib/{core/infer.js → linked/queries.js} +2 -0
- package/lib/{core/index.js → linked/types.js} +2 -1
- package/lib/log/cds-error.js +13 -7
- package/lib/log/format/cf.js +1 -1
- package/lib/plugins.js +49 -0
- package/lib/ql/Query.js +0 -9
- package/lib/ql/STREAM.js +0 -1
- package/lib/req/context.js +2 -7
- package/lib/req/request.js +6 -2
- package/lib/req/response.js +23 -10
- package/lib/srv/middlewares/ctx-model.js +2 -2
- package/lib/srv/middlewares/errors.js +1 -1
- package/lib/srv/protocols/_legacy.js +1 -0
- package/lib/srv/protocols/graphql.js +7 -16
- package/lib/srv/protocols/index.js +59 -45
- package/lib/srv/protocols/odata-v2-proxy.js +2 -70
- package/lib/srv/protocols/odata-v4.js +9 -4
- package/lib/srv/srv-api.js +9 -3
- package/lib/srv/srv-dispatch.js +12 -9
- package/lib/srv/srv-models.js +4 -21
- package/lib/srv/srv-tx.js +15 -12
- package/lib/utils/cds-test.js +14 -9
- package/lib/utils/cds-utils.js +2 -12
- package/lib/utils/check-version.js +17 -0
- package/{bin/build → lib/utils}/csv-reader.js +23 -24
- package/libx/_runtime/auth/index.js +27 -23
- package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +15 -72
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/create.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +0 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +33 -63
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +14 -18
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +15 -5
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +5 -4
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/readToCQN.js +37 -40
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/updateToCQN.js +7 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/utils.js +101 -38
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/errors/AbstractError.js +5 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/UriTokenizer.js +5 -8
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/utils/ValueConverter.js +2 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/deserializer/ResourceJsonDeserializer.js +9 -8
- package/libx/_runtime/cds-services/adapter/odata-v4/to.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +15 -11
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +4 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +5 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/stream.js +1 -123
- package/libx/_runtime/cds-services/services/Service.js +79 -107
- package/libx/_runtime/cds-services/services/utils/columns.js +23 -19
- package/libx/_runtime/cds-services/services/utils/compareJson.js +11 -1
- package/libx/_runtime/cds-services/services/utils/differ.js +7 -2
- package/libx/_runtime/cds-services/util/assert.js +65 -2
- package/libx/_runtime/common/composition/data.js +1 -0
- package/libx/_runtime/common/generic/auth/expand.js +1 -1
- package/libx/_runtime/common/generic/auth/restrict.js +5 -10
- package/libx/_runtime/common/generic/auth/restrictions.js +40 -0
- package/libx/_runtime/common/generic/auth/utils.js +1 -2
- package/libx/_runtime/common/generic/crud.js +32 -16
- package/libx/_runtime/common/generic/etag.js +133 -104
- package/libx/_runtime/common/generic/input.js +6 -21
- package/libx/_runtime/common/generic/put.js +1 -1
- package/libx/_runtime/common/generic/stream.js +52 -0
- package/libx/_runtime/common/generic/temporal.js +25 -8
- package/libx/_runtime/common/i18n/messages.properties +0 -2
- package/libx/_runtime/common/utils/cqn.js +1 -1
- package/libx/_runtime/common/utils/cqn2cqn4sql.js +5 -2
- package/libx/_runtime/common/utils/csn.js +0 -51
- package/libx/_runtime/common/utils/etag.js +30 -0
- package/libx/_runtime/common/utils/keys.js +1 -1
- package/libx/_runtime/common/utils/normalizeTimestamp.js +25 -0
- package/libx/_runtime/common/utils/path.js +1 -1
- package/libx/_runtime/common/utils/resolveView.js +2 -1
- package/libx/_runtime/common/utils/rewriteAsterisks.js +6 -4
- package/libx/_runtime/common/utils/search2cqn4sql.js +12 -16
- package/libx/_runtime/common/utils/stream.js +140 -0
- package/libx/_runtime/common/utils/streamProp.js +29 -12
- package/libx/_runtime/common/utils/templateProcessorPathSerializer.js +0 -2
- package/libx/_runtime/db/generic/index.js +0 -2
- package/libx/_runtime/db/query/delete.js +2 -2
- package/libx/_runtime/db/query/insert.js +2 -2
- package/libx/_runtime/db/query/read.js +2 -2
- package/libx/_runtime/db/query/run.js +2 -2
- package/libx/_runtime/db/query/update.js +2 -2
- package/libx/_runtime/db/sql-builder/BaseBuilder.js +0 -6
- package/libx/_runtime/db/sql-builder/ExpressionBuilder.js +23 -12
- package/libx/_runtime/db/sql-builder/FunctionBuilder.js +18 -6
- package/libx/_runtime/db/sql-builder/InsertBuilder.js +1 -0
- package/libx/_runtime/db/sql-builder/SelectBuilder.js +3 -7
- package/libx/_runtime/db/sql-builder/UpsertBuilder.js +1 -0
- package/libx/_runtime/db/utils/normalizeTimeData.js +7 -3
- package/libx/_runtime/fiori/draft.js +2 -0
- package/libx/_runtime/fiori/generic/activate.js +8 -9
- package/libx/_runtime/fiori/generic/before.js +30 -20
- package/libx/_runtime/fiori/generic/cancel.js +5 -3
- package/libx/_runtime/fiori/generic/delete.js +5 -3
- package/libx/_runtime/fiori/generic/edit.js +7 -7
- package/libx/_runtime/fiori/generic/index.js +10 -16
- package/libx/_runtime/fiori/generic/new.js +5 -3
- package/libx/_runtime/fiori/generic/patch.js +11 -8
- package/libx/_runtime/fiori/generic/prepare.js +13 -6
- package/libx/_runtime/fiori/generic/read.js +12 -6
- package/libx/_runtime/fiori/lean-draft.js +207 -152
- package/libx/_runtime/fiori/utils/delete.js +10 -5
- package/libx/_runtime/fiori/utils/req.js +17 -5
- package/libx/_runtime/fiori/utils/stream.js +36 -0
- package/libx/_runtime/hana/Service.js +12 -9
- package/libx/_runtime/hana/conversion.js +10 -15
- package/libx/_runtime/hana/driver.js +2 -0
- package/libx/_runtime/hana/execute.js +28 -6
- package/libx/_runtime/hana/pool.js +36 -122
- package/libx/_runtime/hana/search2cqn4sql.js +34 -36
- package/libx/_runtime/messaging/enterprise-messaging-utils/getTenantInfo.js +2 -6
- package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +3 -1
- package/libx/_runtime/messaging/enterprise-messaging.js +10 -58
- package/libx/_runtime/messaging/outbox/utils.js +1 -1
- package/libx/_runtime/remote/Service.js +20 -1
- package/libx/_runtime/remote/utils/client.js +3 -5
- package/libx/_runtime/sqlite/Service.js +4 -6
- package/libx/_runtime/sqlite/conversion.js +3 -13
- package/libx/_runtime/sqlite/customBuilder/CustomFunctionBuilder.js +9 -6
- package/libx/_runtime/sqlite/customBuilder/CustomUpsertBuilder.js +6 -1
- package/libx/_runtime/sqlite/execute.js +5 -16
- package/libx/odata/afterburner.js +22 -6
- package/libx/odata/grammar.pegjs +6 -1
- package/libx/odata/parser.js +1 -1
- package/libx/rest/RestAdapter.js +16 -9
- package/libx/rest/RestRequest.js +1 -1
- package/libx/rest/middleware/input.js +2 -1
- package/libx/rest/middleware/operation.js +1 -0
- package/libx/rest/middleware/parse.js +3 -2
- package/libx/rest/middleware/payload.js +9 -8
- package/libx/rest/middleware/read.js +1 -0
- package/package.json +9 -16
- package/server.js +1 -1
- package/app/fiori/preview.js +0 -270
- package/app/fiori/routes.js +0 -59
- package/bin/build/buildTaskEngine.js +0 -360
- package/bin/build/buildTaskFactory.js +0 -283
- package/bin/build/buildTaskHandler.js +0 -241
- package/bin/build/buildTaskProvider.js +0 -22
- package/bin/build/buildTaskProviderFactory.js +0 -175
- package/bin/build/cds.js +0 -5
- package/bin/build/constants.js +0 -66
- package/bin/build/index.js +0 -58
- package/bin/build/provider/buildTaskHandlerEdmx.js +0 -82
- package/bin/build/provider/buildTaskHandlerFeatureToggles.js +0 -131
- package/bin/build/provider/buildTaskHandlerInternal.js +0 -254
- package/bin/build/provider/buildTaskProviderInternal.js +0 -383
- package/bin/build/provider/fiori/index.js +0 -171
- package/bin/build/provider/hana/2migration.js +0 -179
- package/bin/build/provider/hana/index.js +0 -505
- package/bin/build/provider/hana/migrationtable.js +0 -472
- package/bin/build/provider/hana/template/.hdiconfig-haas +0 -163
- package/bin/build/provider/hana/template/.hdiconfig-hanacloud +0 -137
- package/bin/build/provider/hana/template/.hdinamespace +0 -4
- package/bin/build/provider/hana/template/package.json +0 -12
- package/bin/build/provider/hana/template/undeploy.json +0 -5
- package/bin/build/provider/java/index.js +0 -111
- package/bin/build/provider/java-cf/index.js +0 -1
- package/bin/build/provider/mtx/index.js +0 -268
- package/bin/build/provider/mtx/resourcesTarBuilder.js +0 -95
- package/bin/build/provider/mtx-extension/index.js +0 -131
- package/bin/build/provider/mtx-sidecar/index.js +0 -137
- package/bin/build/provider/node-cf/index.js +0 -1
- package/bin/build/provider/nodejs/index.js +0 -192
- package/bin/build/util.js +0 -299
- package/bin/cds.js +0 -125
- package/bin/deploy/to-hana/cfUtil.js +0 -355
- package/bin/deploy/to-hana/gitUtil.js +0 -57
- package/bin/deploy/to-hana/hana.js +0 -306
- package/bin/deploy/to-hana/hdiDeployUtil.js +0 -153
- package/bin/deploy/to-hana/index.js +0 -16
- package/bin/deploy/to-hana/mtaUtil.js +0 -170
- package/bin/mtx/in-cds.js +0 -17
- package/bin/plugins.js +0 -32
- package/bin/run.js +0 -24
- package/bin/utils/log.js +0 -24
- package/bin/version.js +0 -178
- package/libx/_runtime/audit/Service.js +0 -222
- package/libx/_runtime/audit/generic/personal/access.js +0 -61
- package/libx/_runtime/audit/generic/personal/index.js +0 -56
- package/libx/_runtime/audit/generic/personal/modification.js +0 -132
- package/libx/_runtime/audit/generic/personal/utils.js +0 -186
- package/libx/_runtime/audit/utils/log.js +0 -23
- package/libx/_runtime/audit/utils/v2.js +0 -176
- package/libx/_runtime/db/data-conversion/timestamp.js +0 -9
- package/libx/_runtime/db/generic/integrity.js +0 -455
- package/srv/audit-log.cds +0 -87
- package/srv/mtx.cds +0 -2
- package/srv/mtx.js +0 -8
- /package/lib/{core → linked}/classes.js +0 -0
- /package/lib/{core → linked}/entities.js +0 -0
|
@@ -1,505 +0,0 @@
|
|
|
1
|
-
const fs = require('fs')
|
|
2
|
-
const path = require('path')
|
|
3
|
-
const cds = require('../../cds')
|
|
4
|
-
const BuildTaskHandlerInternal = require('../buildTaskHandlerInternal')
|
|
5
|
-
const { OUTPUT_MODE_RESULT_ONLY, BUILD_OPTION_OUTPUT_MODE, SKIP_HDBTABLEDATA_GENERATION, SKIP_PACKAGE_JSON_GENERATION,
|
|
6
|
-
CONTENT_PACKAGE_JSON, CONTENT_HDBTABLEDATA, CSV_FILE_DETECTION, CONTENT_ENV, CONTENT_DEFAULT_ENV_JSON, CONTENT_NODE_MODULES } = require('../../constants')
|
|
7
|
-
const { BuildError, relativePaths } = require('../../util')
|
|
8
|
-
const CSV = require('../../csv-reader')
|
|
9
|
-
const to_hdbmigration = require('./2migration')
|
|
10
|
-
const to_hdbtabledata = require('./2tabledata')
|
|
11
|
-
const { ERROR, WARNING } = require('../../buildTaskHandler')
|
|
12
|
-
|
|
13
|
-
const DEFAULT_COMPILE_DEST_FOLDER = path.normalize("src/gen")
|
|
14
|
-
|
|
15
|
-
const FILE_EXT_CSV = ".csv"
|
|
16
|
-
const FILE_EXT_HDBTABLEDATA = ".hdbtabledata"
|
|
17
|
-
const FILE_EXT_HDBTABLE = ".hdbtable"
|
|
18
|
-
const FILE_EXT_HDBMIGRATIONTABLE = ".hdbmigrationtable"
|
|
19
|
-
|
|
20
|
-
const FILE_NAME_HDICONFIG = ".hdiconfig"
|
|
21
|
-
const FILE_NAME_HDINAMESPACE = ".hdinamespace"
|
|
22
|
-
const FILE_NAME_PACKAGE_JSON = "package.json"
|
|
23
|
-
const PATH_LAST_DEV_CSN = "last-dev/csn.json"
|
|
24
|
-
const FILE_NAME_UNDEPLOY_JSON = "undeploy.json"
|
|
25
|
-
|
|
26
|
-
const DEPLOY_FORMAT = "deploy-format"
|
|
27
|
-
|
|
28
|
-
// add well-known types supported by HANA Cloud Edition - see also https://github.wdf.sap.corp/cap/issues/issues/8056
|
|
29
|
-
const REQUIRED_PLUGIN_TYPES = [FILE_EXT_CSV, FILE_EXT_HDBTABLEDATA, FILE_EXT_HDBTABLE, ".hdbview", ".hdbindex", ".hdbconstraint"]
|
|
30
|
-
class HanaModuleBuilder extends BuildTaskHandlerInternal {
|
|
31
|
-
init() {
|
|
32
|
-
this._result = {
|
|
33
|
-
dest: this.task.dest,
|
|
34
|
-
hana: []
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// set unified option values in order to easy access later on
|
|
38
|
-
// default value: true
|
|
39
|
-
this.task.options[CONTENT_PACKAGE_JSON] = !this.hasBuildOption(CONTENT_PACKAGE_JSON, false) && !this.hasBuildOption(SKIP_PACKAGE_JSON_GENERATION, true) ? true : false
|
|
40
|
-
this.task.options[CONTENT_HDBTABLEDATA] = !this.hasBuildOption(CONTENT_HDBTABLEDATA, false) && !this.hasBuildOption(SKIP_HDBTABLEDATA_GENERATION, true) ? true : false
|
|
41
|
-
this.task.options[CSV_FILE_DETECTION] = !this.hasBuildOption(CSV_FILE_DETECTION, false) ? true : false
|
|
42
|
-
|
|
43
|
-
// default value: false
|
|
44
|
-
this.task.options[CONTENT_NODE_MODULES] = this.hasBuildOption(CONTENT_NODE_MODULES, true) ? true : false
|
|
45
|
-
this.task.options[CONTENT_ENV] = this.hasBuildOption(CONTENT_ENV, true) ? true : false
|
|
46
|
-
this.task.options[CONTENT_DEFAULT_ENV_JSON] = this.hasBuildOption(CONTENT_DEFAULT_ENV_JSON, true) ? true : false
|
|
47
|
-
|
|
48
|
-
this.task.options.compileDest = path.resolve(this.task.dest, this.task.options.compileDest || DEFAULT_COMPILE_DEST_FOLDER)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
async build() {
|
|
52
|
-
const { src, dest } = this.task
|
|
53
|
-
const model = await this.model()
|
|
54
|
-
if (!model) {
|
|
55
|
-
return this._result
|
|
56
|
-
}
|
|
57
|
-
const plugins = await this._compileToHana(model)
|
|
58
|
-
|
|
59
|
-
if (!this.hasBuildOption(BUILD_OPTION_OUTPUT_MODE, OUTPUT_MODE_RESULT_ONLY)) {
|
|
60
|
-
if (this.hasBuildOption(CSV_FILE_DETECTION, false)) {
|
|
61
|
-
await this._copyResources(src, dest)
|
|
62
|
-
} else {
|
|
63
|
-
await this._copyResourcesExt(src, dest, model)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
await this._writeHdiConfig(plugins)
|
|
67
|
-
await this._writeHdiNamespace()
|
|
68
|
-
|
|
69
|
-
// TODO disabled as this contradicts the MTX domain concept which allows partial app deployments
|
|
70
|
-
//await this._writeUndeployJson()
|
|
71
|
-
|
|
72
|
-
if (this.hasBuildOption(CONTENT_HDBTABLEDATA, true)) {
|
|
73
|
-
await this._compileToHdbtabledata(model, dest)
|
|
74
|
-
}
|
|
75
|
-
if (this.hasBuildOption(CONTENT_PACKAGE_JSON, true)) {
|
|
76
|
-
await this._writePackageJson()
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
return this._result
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Deletes any content that has been created in folder '#this.task.dest/src/gen' by inplace mode.
|
|
84
|
-
* <br>
|
|
85
|
-
* Note: Content created in staging build will be deleted by the #BuildTaskEngine itself.
|
|
86
|
-
*/
|
|
87
|
-
async clean() {
|
|
88
|
-
if (this.isStagingBuild()) {
|
|
89
|
-
return super.clean()
|
|
90
|
-
}
|
|
91
|
-
return fs.promises.rm(this.task.options.compileDest, { force: true, recursive: true })
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Copies all files located at <src> (except HANA artifacts not contained in <db>/src/**) to the folder <dest>.
|
|
96
|
-
* '*.csv' files are read based on the corresponding CDS model file location and copied as flat list into folder '<dest>/src/gen>'.
|
|
97
|
-
*
|
|
98
|
-
* @param {string} src
|
|
99
|
-
* @param {string} dest
|
|
100
|
-
* @param {Object} model
|
|
101
|
-
*/
|
|
102
|
-
async _copyResourcesExt(src, dest, model) {
|
|
103
|
-
const resources = Object.keys(await cds.deploy.resources(model)).reverse() // reverse to get reuse resources first and app resources last
|
|
104
|
-
const csvPath = path.join(src, "data")
|
|
105
|
-
// determine subfolder name used by the application for backward compatibility
|
|
106
|
-
const csvFolder = resources.some(res => res && res.startsWith(csvPath)) ? "data" : "csv"
|
|
107
|
-
|
|
108
|
-
// 1. copy csv files into 'src/gen/data' or 'src/gen/csv' subfolder
|
|
109
|
-
const dbSrc = path.join(src, 'src')
|
|
110
|
-
|
|
111
|
-
// await each copy as order is important - reuse resources first and app resources last
|
|
112
|
-
for (const res of resources) {
|
|
113
|
-
// do not duplicate resources that are already contained in db/src/**
|
|
114
|
-
if (res && /\.csv$/.test(res) && !res.startsWith(dbSrc)) {
|
|
115
|
-
await this.copy(res).to(path.join(this.task.options.compileDest, csvFolder, path.basename(res)))
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// 2. staging build: copy files except *.cds, .env, default-env.json, ./node_modules/**
|
|
120
|
-
if (this.isStagingBuild()) {
|
|
121
|
-
let blockList = "\\.cds$|\\.csv$|\\.hdbtabledata$"
|
|
122
|
-
blockList += this.hasBuildOption(CONTENT_ENV, false) ? "|\\.env($|\\..*$)" : ""
|
|
123
|
-
blockList += this.hasBuildOption(CONTENT_DEFAULT_ENV_JSON, false) ? "|default-env\\.json$" : ""
|
|
124
|
-
blockList = new RegExp(blockList)
|
|
125
|
-
|
|
126
|
-
await this.copyNativeContent(src, dest, (entry) => {
|
|
127
|
-
if (entry.startsWith(dbSrc)) {
|
|
128
|
-
// entire native content
|
|
129
|
-
return true
|
|
130
|
-
}
|
|
131
|
-
if (fs.statSync(entry).isDirectory()) {
|
|
132
|
-
return !/(\/|\\)node_modules(\/|\\)?$/.test(entry) || this.hasBuildOption(CONTENT_NODE_MODULES, true)
|
|
133
|
-
}
|
|
134
|
-
return !blockList.test(entry)
|
|
135
|
-
})
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Copies the entire content of the db module located in the given <src> folder to the folder <dest>.
|
|
141
|
-
* '*.csv' and '*.hdbtabledata' files located in a subfolder 'data' or 'csv' will be copied to '<dest>/src/gen/data>'||'<dest>/src/gen/csv>'
|
|
142
|
-
*
|
|
143
|
-
* @param {string} src
|
|
144
|
-
* @param {string} dest
|
|
145
|
-
*/
|
|
146
|
-
async _copyResources(src, dest) {
|
|
147
|
-
const dbCsvDir = path.join(src, "csv")
|
|
148
|
-
const dbDataDir = path.join(src, "data")
|
|
149
|
-
const csvDirs = [dbCsvDir, dbDataDir]
|
|
150
|
-
const regexData = RegExp('\\.csv$|\\.hdbtabledata$')
|
|
151
|
-
|
|
152
|
-
if (this.isStagingBuild()) {
|
|
153
|
-
const regex = RegExp('\\.cds$|\\.csv$|\\.hdbtabledata$')
|
|
154
|
-
|
|
155
|
-
await this.copyNativeContent(src, dest, (entry) => {
|
|
156
|
-
if (fs.statSync(entry).isDirectory()) {
|
|
157
|
-
return !/(\/|\\)node_modules(\/|\\)?$/.test(entry)
|
|
158
|
-
}
|
|
159
|
-
return (!regex.test(entry) && entry !== cds.env.build.outputfile) ||
|
|
160
|
-
(regexData.test(entry) && !entry.startsWith(dbCsvDir) && !entry.startsWith(dbDataDir))
|
|
161
|
-
})
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// handle *.csv and *.hdbtabledata located in '<dbSrc>/data' and '<dbSrc>/csv' folder
|
|
165
|
-
const allFiles = csvDirs.reduce((acc, csvDir) => {
|
|
166
|
-
return acc.concat(BuildTaskHandlerInternal._find(csvDir, (entry) => {
|
|
167
|
-
if (fs.statSync(entry).isDirectory()) {
|
|
168
|
-
return false
|
|
169
|
-
}
|
|
170
|
-
return regexData.test(entry)
|
|
171
|
-
}))
|
|
172
|
-
}, [])
|
|
173
|
-
|
|
174
|
-
return Promise.all(allFiles.map((file) => {
|
|
175
|
-
return this.copy(file).to(path.join(this.task.options.compileDest, path.relative(src, file)))
|
|
176
|
-
}))
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Generates *.hdbtabledata files in folder '#this.task.dest/src/gen' from *.csv files located in '#this.task.dest/src/**' folder.
|
|
181
|
-
* The generated *.hdbtabledata files will link to their *.csv counterparts using relative links. The *.csv files have either
|
|
182
|
-
* already been defined in the 'src' folder or they have been copied to '#this.task.dest/src/gen/**' folder if they have been
|
|
183
|
-
* created outside 'src' folder. If custom *.hdbtabledata files are found nothing is generated for this particular folder.
|
|
184
|
-
* <br>
|
|
185
|
-
* Note: *.csv and *.hdbtabledata need to be copied to '#this.task.dest/src/gen**' if required before this method is called.
|
|
186
|
-
* In inplace mode dest folder is refering to src folder.
|
|
187
|
-
*
|
|
188
|
-
* @param {object} model compiled csn
|
|
189
|
-
*/
|
|
190
|
-
async _compileToHdbtabledata(model, dest) { //NOSONAR
|
|
191
|
-
const tabledataDirs = new Set()
|
|
192
|
-
const destSrcDir = path.join(dest, "src")
|
|
193
|
-
|
|
194
|
-
const allCsvFiles = BuildTaskHandlerInternal._find(destSrcDir, (entry) => {
|
|
195
|
-
if (fs.statSync(entry).isDirectory()) {
|
|
196
|
-
return true
|
|
197
|
-
}
|
|
198
|
-
if (/\.hdbtabledata$/.test(entry)) {
|
|
199
|
-
tabledataDirs.add(path.dirname(entry))
|
|
200
|
-
}
|
|
201
|
-
return /\.csv$/.test(entry)
|
|
202
|
-
})
|
|
203
|
-
if (allCsvFiles.length > 0) {
|
|
204
|
-
const csvDirs = allCsvFiles.map(path.dirname).reduce((dirs, dir) => {
|
|
205
|
-
if (!tabledataDirs.has(dir) && !dirs.includes(dir)) { // exclude any dir where a tabledata is present
|
|
206
|
-
dirs.push(dir)
|
|
207
|
-
}
|
|
208
|
-
return dirs
|
|
209
|
-
}, [])
|
|
210
|
-
|
|
211
|
-
// ODM csv data comes with license comments, so strip these
|
|
212
|
-
if (!this.hasBuildOption("stripCsvComments", false)) {
|
|
213
|
-
await this._stripCsvComments(allCsvFiles)
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
const promises = []
|
|
217
|
-
const relDest = path.relative(this.task.dest, this.task.options.compileDest)
|
|
218
|
-
const options = { ...this.options(), logger: this.logger, dirs: csvDirs, baseDir: this.task.options.compileDest }
|
|
219
|
-
const tableDatas = await to_hdbtabledata(model, options)
|
|
220
|
-
|
|
221
|
-
for (let [tableData, { file, csvFolder }] of tableDatas) {
|
|
222
|
-
// create .hdbtabledata side-by-side if .csv is contained in 'src/gen/**' subfolder
|
|
223
|
-
// otherwise create in 'src/gen'
|
|
224
|
-
let tableDataPath = csvFolder.startsWith(this.task.options.compileDest) ? csvFolder : this.task.options.compileDest
|
|
225
|
-
tableDataPath = path.join(tableDataPath, file)
|
|
226
|
-
this._result.hana.push(path.join(relDest, file))
|
|
227
|
-
promises.push(this.write(tableData).to(tableDataPath))
|
|
228
|
-
}
|
|
229
|
-
await Promise.all(promises)
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
async _stripCsvComments(csvFiles) {
|
|
234
|
-
// Note: modification of csv files is only allowed for files located in the compile destination folder,
|
|
235
|
-
// meaning having their origin location at db/data/* or db/csv/*
|
|
236
|
-
for (const file of csvFiles) {
|
|
237
|
-
if (this.isStagingBuild() || file.startsWith(this.task.options.compileDest)) {
|
|
238
|
-
await CSV.stripComments(file)
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/**
|
|
244
|
-
* Creates the hana artifacts from the given csn model and writes the files to the folder '<dest>/src/gen'.
|
|
245
|
-
*
|
|
246
|
-
* @param {object} model The compiled csn model
|
|
247
|
-
*/
|
|
248
|
-
async _compileToHana(model) {
|
|
249
|
-
// see CAP issue #6222
|
|
250
|
-
const undeployTypes = await this._readTypesFromUndeployJson()
|
|
251
|
-
const pluginTypes = new Set([...REQUIRED_PLUGIN_TYPES, ...undeployTypes])
|
|
252
|
-
|
|
253
|
-
// compile to old format (.hdbcds) or new format (.hdbtable / .hdbview)
|
|
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
|
-
return Promise.reject(new Error(`Invalid deploy-format defined: ${format}`))
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
if (this.hasCdsEnvOption('features.journal', false) || format === 'hdbcds') {
|
|
260
|
-
await this._compileToHdb(model, pluginTypes, format)
|
|
261
|
-
} else {
|
|
262
|
-
await this._compileToHdbmigration(model, pluginTypes, format)
|
|
263
|
-
}
|
|
264
|
-
return pluginTypes
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
async _compileToHdb(model, pluginTypes, format) {
|
|
268
|
-
const relDest = path.relative(this.task.dest, this.task.options.compileDest)
|
|
269
|
-
// enforces sqlNames option for compiler in tests
|
|
270
|
-
const options = { ...this.options(), sql_mapping: cds.env.sql.names }
|
|
271
|
-
const result = cds.compile.to[format](model, options)
|
|
272
|
-
const promises = []
|
|
273
|
-
|
|
274
|
-
for (const [content, key] of result) {
|
|
275
|
-
pluginTypes.add(key.suffix || path.extname(key.file))
|
|
276
|
-
const file = key.file ? key.file : key.name + key.suffix
|
|
277
|
-
this._result.hana.push(path.join(relDest, file))
|
|
278
|
-
if (!this.hasBuildOption(BUILD_OPTION_OUTPUT_MODE, OUTPUT_MODE_RESULT_ONLY)) {
|
|
279
|
-
promises.push(this.write(content).to(path.join(this.task.options.compileDest, file)))
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
await Promise.all(promises)
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
async _compileToHdbmigration(model, pluginTypes, format) {
|
|
286
|
-
const relDestDir = path.relative(this.task.dest, this.task.options.compileDest)
|
|
287
|
-
const relDbDestDir = path.relative(this.buildOptions.root, this.task.options.compileDest)
|
|
288
|
-
const dbSrcDir = path.join(this.task.src, "src")
|
|
289
|
-
const relDbSrcDir = path.relative(this.buildOptions.root, dbSrcDir)
|
|
290
|
-
const lastDevCsnFolder = PATH_LAST_DEV_CSN
|
|
291
|
-
const lastDevCsnDir = path.join(this.task.src, lastDevCsnFolder)
|
|
292
|
-
let lastDev = null
|
|
293
|
-
const promises = []
|
|
294
|
-
const migrationTableFiles = []
|
|
295
|
-
|
|
296
|
-
if (fs.existsSync(lastDevCsnDir)) {
|
|
297
|
-
lastDev = JSON.parse((await fs.promises.readFile(lastDevCsnDir, 'utf-8')).toString())
|
|
298
|
-
}
|
|
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: cds.env.sql.names, "deploy-format": format }
|
|
301
|
-
|
|
302
|
-
const compilationResult = await to_hdbmigration(model, lastDev, dbSrcDir, options)
|
|
303
|
-
const definitions = compilationResult.definitions
|
|
304
|
-
const afterImage = compilationResult.afterImage
|
|
305
|
-
|
|
306
|
-
for (const { name, suffix, content, changed } of definitions) {
|
|
307
|
-
pluginTypes.add(suffix)
|
|
308
|
-
const file = name + suffix
|
|
309
|
-
if (suffix === FILE_EXT_HDBMIGRATIONTABLE) {
|
|
310
|
-
migrationTableFiles.push(path.join(relDbSrcDir, file))
|
|
311
|
-
if (changed) {
|
|
312
|
-
this._result.hana.push(path.join("src", file))
|
|
313
|
-
if (!this.hasBuildOption(BUILD_OPTION_OUTPUT_MODE, OUTPUT_MODE_RESULT_ONLY)) {
|
|
314
|
-
promises.push(this.write(content).to(path.join(dbSrcDir, file)))
|
|
315
|
-
}
|
|
316
|
-
} else {
|
|
317
|
-
this.logger._debug && this.logger.debug(`no change, keep existing ${file}`)
|
|
318
|
-
}
|
|
319
|
-
} else {
|
|
320
|
-
this._result.hana.push(path.join(relDestDir, file))
|
|
321
|
-
if (!this.hasBuildOption(BUILD_OPTION_OUTPUT_MODE, OUTPUT_MODE_RESULT_ONLY)) {
|
|
322
|
-
promises.push(this.write(content).to(path.join(this.task.options.compileDest, file)))
|
|
323
|
-
}
|
|
324
|
-
if (suffix === FILE_EXT_HDBTABLE) {
|
|
325
|
-
// issue an error in case a .hdbmigrationtable file already exists
|
|
326
|
-
if (fs.existsSync(path.join(dbSrcDir, name + FILE_EXT_HDBMIGRATIONTABLE))) {
|
|
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
|
-
}
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
await Promise.all(promises)
|
|
333
|
-
await this._validateMigrationTableFiles()
|
|
334
|
-
|
|
335
|
-
// update last development version
|
|
336
|
-
if (afterImage) {
|
|
337
|
-
if (migrationTableFiles.length > 0) {
|
|
338
|
-
if (!HanaModuleBuilder._toEqualIgnoreMeta(lastDev, afterImage)) {
|
|
339
|
-
await this.write(afterImage).to(lastDevCsnDir)
|
|
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
|
-
}
|
|
347
|
-
}
|
|
348
|
-
} else {
|
|
349
|
-
throw new BuildError(`Inconsistent CDS compilation results - file ${lastDevCsnFolder} missing`)
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
async _writePackageJson() {
|
|
354
|
-
const packageJson = path.join(this.task.src, "package.json")
|
|
355
|
-
const exists = fs.existsSync(packageJson)
|
|
356
|
-
|
|
357
|
-
if (exists) {
|
|
358
|
-
this.logger._debug && this.logger.debug(`skip create [${relativePaths(this.buildOptions.root, packageJson)}], already existing`)
|
|
359
|
-
}
|
|
360
|
-
if (this.isStagingBuild() && !exists) {
|
|
361
|
-
const content = await HanaModuleBuilder._readTemplateAsJson(FILE_NAME_PACKAGE_JSON)
|
|
362
|
-
await this.write(content).to(path.join(this.task.dest, FILE_NAME_PACKAGE_JSON))
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
/**
|
|
367
|
-
* Create .hdiconfig file in <dest>src/gen folder of db module.
|
|
368
|
-
*/
|
|
369
|
-
async _writeHdiConfig(plugins) {
|
|
370
|
-
const hdiConfig = path.join(this.task.options.compileDest, FILE_NAME_HDICONFIG)
|
|
371
|
-
const template = await HanaModuleBuilder._readTemplateAsJson('.hdiconfig-haas')
|
|
372
|
-
let content = {
|
|
373
|
-
'file_suffixes': {}
|
|
374
|
-
}
|
|
375
|
-
for (const key in template['file_suffixes']) {
|
|
376
|
-
if (plugins.has('.' + key)) {
|
|
377
|
-
content['file_suffixes'][key] = template['file_suffixes'][key]
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
if (Object.keys(content['file_suffixes']).length !== plugins.size) {
|
|
381
|
-
this.pushMessage(`'HANA database plugin not found for file suffix [${Array.from(plugins).join(',')}]`)
|
|
382
|
-
}
|
|
383
|
-
// TODO - Be on the save side for now - go for the content use case later on if this works as expected.
|
|
384
|
-
if (cds.env.hana['deploy-format'] === 'hdbtable') {
|
|
385
|
-
await this.write(content).to(hdiConfig)
|
|
386
|
-
} else {
|
|
387
|
-
await this.write(template).to(hdiConfig)
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
/**
|
|
392
|
-
* Create .hdinamespace file in <dest>src/gen folder of db module.
|
|
393
|
-
*/
|
|
394
|
-
async _writeHdiNamespace() {
|
|
395
|
-
// see issue #64 - add .hdinamespace file to prevent HDI from adding gen/ folder to the namespace.
|
|
396
|
-
const hdiNamespace = path.join(this.task.options.compileDest, FILE_NAME_HDINAMESPACE)
|
|
397
|
-
const content = await HanaModuleBuilder._readTemplateAsJson(FILE_NAME_HDINAMESPACE)
|
|
398
|
-
return await this.write(content).to(hdiNamespace)
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
/**
|
|
402
|
-
* Create undeploy.json file in <dest> folder of db module.
|
|
403
|
-
*/
|
|
404
|
-
async _writeUndeployJson() {
|
|
405
|
-
if (this.isStagingBuild()) {
|
|
406
|
-
// see issue #64 - add .hdinamespace file to prevent HDI from adding gen/ folder to the namespace.
|
|
407
|
-
const undeployJsonDest = path.join(this.task.dest, FILE_NAME_UNDEPLOY_JSON)
|
|
408
|
-
const undeployJsonSrc = path.join(this.task.src, FILE_NAME_UNDEPLOY_JSON)
|
|
409
|
-
const templateEntries = await HanaModuleBuilder._readTemplateAsJson(FILE_NAME_UNDEPLOY_JSON)
|
|
410
|
-
let newEntries = []
|
|
411
|
-
if (fs.existsSync(undeployJsonSrc)) {
|
|
412
|
-
newEntries = await JSON.parse((await fs.promises.readFile(undeployJsonSrc, 'utf-8')).toString())
|
|
413
|
-
newEntries = Array.isArray(newEntries) ? newEntries : []
|
|
414
|
-
templateEntries.forEach(entry => {
|
|
415
|
-
if (!newEntries.includes(entry)) {
|
|
416
|
-
newEntries.push(entry)
|
|
417
|
-
}
|
|
418
|
-
})
|
|
419
|
-
} else {
|
|
420
|
-
newEntries = templateEntries
|
|
421
|
-
}
|
|
422
|
-
// formatted output
|
|
423
|
-
let content = '[\n'
|
|
424
|
-
for (let i = 0; i < newEntries.length; i++) {
|
|
425
|
-
content += ` "${newEntries[i]}"${i + 1 < newEntries.length ? ',' : ''}\n`
|
|
426
|
-
}
|
|
427
|
-
content += ']'
|
|
428
|
-
await this.write(content).to(undeployJsonDest)
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
async _readTypesFromUndeployJson() {
|
|
434
|
-
const result = new Set()
|
|
435
|
-
const file = path.join(this.task.src, "undeploy.json")
|
|
436
|
-
|
|
437
|
-
if (fs.existsSync(file)) {
|
|
438
|
-
const undeployList = JSON.parse((await fs.promises.readFile(file)).toString(), 'utf-8')
|
|
439
|
-
if (Array.isArray(undeployList)) {
|
|
440
|
-
const hdiconfig = await HanaModuleBuilder._readTemplateAsJson('.hdiconfig-haas')
|
|
441
|
-
const keys = new Set(Object.keys(hdiconfig['file_suffixes']).map(key => '.' + key))
|
|
442
|
-
undeployList.forEach(entry => {
|
|
443
|
-
const extName = path.extname(entry)
|
|
444
|
-
if (extName && !result.has(extName)) {
|
|
445
|
-
if (keys.has(extName)) {
|
|
446
|
-
result.add(extName)
|
|
447
|
-
} else {
|
|
448
|
-
this.pushMessage(`Ignoring invalid entry '${entry}' in undeploy.json file`, WARNING)
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
})
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
return result
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
async _validateMigrationTableFiles() {
|
|
458
|
-
const dbSrcDir = path.join(this.task.src, "src")
|
|
459
|
-
const migrationTableFiles = BuildTaskHandlerInternal._find(dbSrcDir, (res) => {
|
|
460
|
-
return fs.statSync(res).isFile() && path.extname(res) === FILE_EXT_HDBMIGRATIONTABLE
|
|
461
|
-
})
|
|
462
|
-
if (migrationTableFiles.length > 0) {
|
|
463
|
-
const parser = require('./migrationtable')
|
|
464
|
-
|
|
465
|
-
await Promise.all(migrationTableFiles.map(async file => {
|
|
466
|
-
try {
|
|
467
|
-
const tableModel = await parser.read(file)
|
|
468
|
-
if (/^>>>>>/m.test(tableModel.migrations.toString())) {
|
|
469
|
-
// as this is not a build error, we do not abort cds build, instead only log as error
|
|
470
|
-
this.pushMessage(`Current model changes require manual resolution. See migration file ${path.relative(this.buildOptions.root, file)} for further details.`, ERROR)
|
|
471
|
-
}
|
|
472
|
-
} catch (e) {
|
|
473
|
-
throw new Error(`${path.relative(this.buildOptions.root, file)}: ${e.toString()}`, ERROR)
|
|
474
|
-
}
|
|
475
|
-
}))
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
static async _readTemplateAsJson(template) {
|
|
480
|
-
const content = await fs.promises.readFile(path.join(__dirname, 'template', template), 'utf-8')
|
|
481
|
-
return JSON.parse(content.toString())
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
static _toEqualIgnoreMeta(csn1, csn2) {
|
|
485
|
-
function toString(csn) {
|
|
486
|
-
return JSON.stringify(csn, (k, v) => {
|
|
487
|
-
if (v?.creator) {
|
|
488
|
-
// make sure it's the compiler meta tag
|
|
489
|
-
if (k === 'meta' && v.creator?.startsWith('CDS Compiler'))
|
|
490
|
-
return
|
|
491
|
-
}
|
|
492
|
-
return v
|
|
493
|
-
})
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
if (csn1 === csn2) {
|
|
497
|
-
return true
|
|
498
|
-
}
|
|
499
|
-
if (!csn1 || !csn2) {
|
|
500
|
-
return false
|
|
501
|
-
}
|
|
502
|
-
return toString(csn1) === toString(csn2)
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
module.exports = HanaModuleBuilder
|