@sap/cds-compiler 4.4.4 → 4.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 +88 -0
- package/bin/cdsc.js +18 -11
- package/bin/cdsv2m.js +7 -5
- package/doc/CHANGELOG_BETA.md +22 -0
- package/lib/api/main.js +306 -144
- package/lib/api/options.js +18 -6
- package/lib/api/validate.js +1 -1
- package/lib/base/message-registry.js +45 -10
- package/lib/base/messages.js +33 -16
- package/lib/base/model.js +4 -0
- package/lib/base/optionProcessorHelper.js +45 -176
- package/lib/checks/annotationsOData.js +49 -0
- package/lib/checks/elements.js +32 -34
- package/lib/checks/enricher.js +39 -3
- package/lib/checks/validator.js +8 -7
- package/lib/compiler/assert-consistency.js +40 -17
- package/lib/compiler/builtins.js +30 -53
- package/lib/compiler/checks.js +46 -14
- package/lib/compiler/cycle-detector.js +1 -4
- package/lib/compiler/define.js +35 -10
- package/lib/compiler/extend.js +21 -7
- package/lib/compiler/generate.js +3 -0
- package/lib/compiler/populate.js +5 -1
- package/lib/compiler/propagator.js +46 -9
- package/lib/compiler/resolve.js +94 -35
- package/lib/compiler/shared.js +60 -33
- package/lib/compiler/tweak-assocs.js +188 -92
- package/lib/compiler/utils.js +11 -1
- package/lib/edm/annotations/edmJson.js +41 -66
- package/lib/edm/annotations/genericTranslation.js +27 -9
- package/lib/edm/annotations/preprocessAnnotations.js +2 -3
- package/lib/edm/csn2edm.js +28 -11
- package/lib/edm/edmInboundChecks.js +58 -15
- package/lib/edm/edmPreprocessor.js +12 -16
- package/lib/edm/edmUtils.js +5 -2
- package/lib/gen/Dictionary.json +10 -0
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +15 -2
- package/lib/gen/language.tokens +1 -0
- package/lib/gen/languageParser.js +6557 -5618
- package/lib/json/from-csn.js +4 -5
- package/lib/json/to-csn.js +29 -4
- package/lib/language/antlrParser.js +19 -1
- package/lib/language/errorStrategy.js +28 -7
- package/lib/language/genericAntlrParser.js +118 -24
- package/lib/language/textUtils.js +16 -0
- package/lib/main.d.ts +28 -3
- package/lib/main.js +3 -0
- package/lib/model/csnRefs.js +4 -1
- package/lib/model/csnUtils.js +20 -14
- package/lib/model/revealInternalProperties.js +5 -2
- package/lib/optionProcessor.js +23 -22
- package/lib/render/manageConstraints.js +13 -29
- package/lib/render/toCdl.js +47 -26
- package/lib/render/toHdbcds.js +63 -42
- package/lib/render/toRename.js +6 -10
- package/lib/render/toSql.js +71 -117
- package/lib/render/utils/common.js +41 -6
- package/lib/transform/.eslintrc.json +9 -1
- package/lib/transform/addTenantFields.js +228 -0
- package/lib/transform/db/applyTransformations.js +57 -4
- package/lib/transform/db/assertUnique.js +4 -4
- package/lib/transform/db/backlinks.js +13 -1
- package/lib/transform/db/cdsPersistence.js +1 -1
- package/lib/transform/db/expansion.js +24 -3
- package/lib/transform/db/flattening.js +70 -71
- package/lib/transform/db/killAnnotations.js +37 -0
- package/lib/transform/db/rewriteCalculatedElements.js +46 -6
- package/lib/transform/db/temporal.js +1 -1
- package/lib/transform/draft/db.js +2 -16
- package/lib/transform/draft/odata.js +3 -3
- package/lib/transform/effective/associations.js +3 -5
- package/lib/transform/effective/main.js +6 -9
- package/lib/transform/forOdata.js +26 -55
- package/lib/transform/forRelationalDB.js +38 -18
- package/lib/transform/odata/toFinalBaseType.js +3 -3
- package/lib/transform/odata/typesExposure.js +14 -5
- package/lib/transform/transformUtils.js +47 -34
- package/lib/transform/translateAssocsToJoins.js +45 -11
- package/lib/transform/universalCsn/coreComputed.js +1 -1
- package/lib/transform/universalCsn/universalCsnEnricher.js +4 -4
- package/package.json +7 -6
package/lib/api/main.js
CHANGED
|
@@ -19,6 +19,14 @@ const timetrace = lazyload('../utils/timetrace');
|
|
|
19
19
|
const forRelationalDB = lazyload('../transform/forRelationalDB');
|
|
20
20
|
const sqlUtils = lazyload('../render/utils/sql');
|
|
21
21
|
const effective = lazyload('../transform/effective/main');
|
|
22
|
+
const toHdbcds = lazyload('../render/toHdbcds');
|
|
23
|
+
const baseError = lazyload('../base/error');
|
|
24
|
+
const csnToEdm = lazyload('../edm/csn2edm');
|
|
25
|
+
const trace = lazyload('./trace');
|
|
26
|
+
|
|
27
|
+
const { forEach, forEachKey } = require('../utils/objectUtils');
|
|
28
|
+
const { checkRemovedDeprecatedFlags } = require('../base/model');
|
|
29
|
+
const { makeMessageFunction } = require('../base/messages');
|
|
22
30
|
|
|
23
31
|
/**
|
|
24
32
|
* Return the artifact name for use for the hdbresult object
|
|
@@ -32,13 +40,6 @@ function getFileName( artifactName, csn ) {
|
|
|
32
40
|
return csnUtils.getResultingName(csn, 'quoted', artifactName);
|
|
33
41
|
}
|
|
34
42
|
|
|
35
|
-
const { toHdbcdsSource } = require('../render/toHdbcds');
|
|
36
|
-
const { ModelError } = require('../base/error');
|
|
37
|
-
const { forEach, forEachKey } = require('../utils/objectUtils');
|
|
38
|
-
const { checkRemovedDeprecatedFlags } = require('../base/model');
|
|
39
|
-
const { csn2edm, csn2edmAll } = require('../edm/csn2edm');
|
|
40
|
-
const { traceApi } = require('./trace');
|
|
41
|
-
|
|
42
43
|
const relevantGeneralOptions = [ /* for future generic options */ ];
|
|
43
44
|
const relevantOdataOptions = [ 'sqlMapping', 'odataFormat' ];
|
|
44
45
|
const warnAboutMismatchOdata = [ 'odataVersion' ];
|
|
@@ -50,7 +51,7 @@ const warnAboutMismatchOdata = [ 'odataVersion' ];
|
|
|
50
51
|
* @param {string} transformation Name of the transformation - odata or hana
|
|
51
52
|
* @param {NestedOptions} options Options used for the transformation
|
|
52
53
|
* @param {string[]} relevantOptionNames Option names that are defining characteristics
|
|
53
|
-
* @param {string[]} [optionalOptionNames
|
|
54
|
+
* @param {string[]} [optionalOptionNames] Option names that should be attached as a fyi
|
|
54
55
|
*/
|
|
55
56
|
function attachTransformerCharacteristics( csn, transformation, options,
|
|
56
57
|
relevantOptionNames, optionalOptionNames = [] ) {
|
|
@@ -86,17 +87,19 @@ function attachTransformerCharacteristics( csn, transformation, options,
|
|
|
86
87
|
* @param {NestedOptions} options Options used for the transformation - scanned top-level
|
|
87
88
|
* @param {string[]} relevantOptionNames Option names that are defining characteristics
|
|
88
89
|
* @param {string[]} warnAboutMismatch Option names to warn about, but not error on
|
|
89
|
-
* @param {
|
|
90
|
+
* @param {object} messageFunctions Message functions such as `error()`, `info()`, …
|
|
90
91
|
*/
|
|
91
|
-
function checkPreTransformedCsn( csn, options,
|
|
92
|
-
|
|
92
|
+
function checkPreTransformedCsn( csn, options,
|
|
93
|
+
relevantOptionNames, warnAboutMismatch,
|
|
94
|
+
messageFunctions ) {
|
|
95
|
+
if (!csn.meta?.options) {
|
|
93
96
|
// Not able to check
|
|
94
97
|
return;
|
|
95
98
|
}
|
|
96
|
-
const { error, warning, throwWithAnyError } =
|
|
99
|
+
const { error, warning, throwWithAnyError } = messageFunctions;
|
|
97
100
|
|
|
98
101
|
for (const name of relevantOptionNames ) {
|
|
99
|
-
if (options[name] !== csn.meta.options
|
|
102
|
+
if (options[name] !== csn.meta.options[name]) {
|
|
100
103
|
error('api-invalid-option-preprocessed', null, { prop: name, value: options[name], othervalue: csn.meta.options[name] },
|
|
101
104
|
'Expected pre-processed CSN to have option $(PROP) set to $(VALUE). Found: $(OTHERVALUE)');
|
|
102
105
|
}
|
|
@@ -130,11 +133,13 @@ function isPreTransformed( csn, transformation ) {
|
|
|
130
133
|
*
|
|
131
134
|
* @param {CSN.Model} csn Clean input CSN
|
|
132
135
|
* @param {object} internalOptions processed options
|
|
136
|
+
* @param {object} messageFunctions Message functions such as `error()`, `info()`, …
|
|
133
137
|
* @returns {object} Return an oData-pre-processed CSN
|
|
134
138
|
*/
|
|
135
|
-
function odataInternal( csn, internalOptions ) {
|
|
139
|
+
function odataInternal( csn, internalOptions, messageFunctions ) {
|
|
136
140
|
internalOptions.transformation = 'odata';
|
|
137
|
-
const oDataCsn = forOdataNew.transform4odataWithCsn(csn, internalOptions);
|
|
141
|
+
const oDataCsn = forOdataNew.transform4odataWithCsn(csn, internalOptions, messageFunctions);
|
|
142
|
+
messageFunctions.setModel(oDataCsn);
|
|
138
143
|
attachTransformerCharacteristics(oDataCsn, 'odata', internalOptions, relevantOdataOptions, warnAboutMismatchOdata);
|
|
139
144
|
return oDataCsn;
|
|
140
145
|
}
|
|
@@ -143,26 +148,28 @@ function odataInternal( csn, internalOptions ) {
|
|
|
143
148
|
* Return a odata-transformed CSN
|
|
144
149
|
*
|
|
145
150
|
* @param {CSN.Model} csn Clean input CSN
|
|
146
|
-
* @param {ODataOptions}
|
|
151
|
+
* @param {ODataOptions} options Options
|
|
152
|
+
* @param {object} messageFunctions Message functions such as `error()`, `info()`, …
|
|
147
153
|
* @returns {oDataCSN} Return an oData-pre-processed CSN
|
|
148
154
|
*/
|
|
149
|
-
function odata( csn, options
|
|
150
|
-
traceApi('for.odata', options);
|
|
155
|
+
function odata( csn, options, messageFunctions ) {
|
|
156
|
+
trace.traceApi('for.odata', options);
|
|
151
157
|
const internalOptions = prepareOptions.for.odata(options);
|
|
152
|
-
return odataInternal(csn, internalOptions);
|
|
158
|
+
return odataInternal(csn, internalOptions, messageFunctions);
|
|
153
159
|
}
|
|
154
160
|
|
|
155
161
|
/**
|
|
156
162
|
* Process the given csn back to cdl.
|
|
157
163
|
*
|
|
158
164
|
* @param {object} csn CSN to process
|
|
159
|
-
* @param {object}
|
|
165
|
+
* @param {object} options Options
|
|
166
|
+
* @param {object} messageFunctions Message functions such as `error()`, `info()`, …
|
|
160
167
|
* @returns {object} { model: string, namespace: string }
|
|
161
168
|
*/
|
|
162
|
-
function cdl( csn, options
|
|
163
|
-
traceApi('to.cdl', options);
|
|
169
|
+
function cdl( csn, options, messageFunctions ) {
|
|
170
|
+
trace.traceApi('to.cdl', options);
|
|
164
171
|
const internalOptions = prepareOptions.to.cdl(options);
|
|
165
|
-
return toCdl.csnToCdl(csn, internalOptions);
|
|
172
|
+
return toCdl.csnToCdl(csn, internalOptions, messageFunctions);
|
|
166
173
|
}
|
|
167
174
|
|
|
168
175
|
/**
|
|
@@ -171,13 +178,15 @@ function cdl( csn, options = {} ) {
|
|
|
171
178
|
*
|
|
172
179
|
* @param {CSN.Model} csn Plain input CSN
|
|
173
180
|
* @param {SqlOptions} internalOptions Options
|
|
181
|
+
* @param {object} messageFunctions Message functions such as `error()`, `info()`, …
|
|
174
182
|
* @returns {CSN.Model} CSN transformed like to.sql
|
|
175
183
|
* @private
|
|
176
184
|
*/
|
|
177
|
-
function csnForSql( csn, internalOptions ) {
|
|
185
|
+
function csnForSql( csn, internalOptions, messageFunctions ) {
|
|
178
186
|
internalOptions.transformation = 'sql';
|
|
179
|
-
const transformedCsn = forRelationalDB.transformForRelationalDBWithCsn(
|
|
180
|
-
|
|
187
|
+
const transformedCsn = forRelationalDB.transformForRelationalDBWithCsn(
|
|
188
|
+
csn, internalOptions, messageFunctions
|
|
189
|
+
);
|
|
181
190
|
return internalOptions.testMode ? toCsn.sortCsn(transformedCsn, internalOptions) : transformedCsn;
|
|
182
191
|
}
|
|
183
192
|
|
|
@@ -186,44 +195,48 @@ function csnForSql( csn, internalOptions ) {
|
|
|
186
195
|
* Pseudo-public version of csnForSql().
|
|
187
196
|
*
|
|
188
197
|
* @param {CSN.Model} csn Plain input CSN
|
|
189
|
-
* @param {SqlOptions}
|
|
198
|
+
* @param {SqlOptions} options Options
|
|
199
|
+
* @param {object} messageFunctions Message functions such as `error()`, `info()`, …
|
|
190
200
|
* @returns {CSN.Model} CSN transformed like to.sql
|
|
191
201
|
* @private
|
|
192
202
|
*/
|
|
193
|
-
function forSql( csn, options
|
|
203
|
+
function forSql( csn, options, messageFunctions ) {
|
|
194
204
|
const internalOptions = prepareOptions.to.sql(options);
|
|
195
|
-
return csnForSql(csn, internalOptions);
|
|
205
|
+
return csnForSql(csn, internalOptions, messageFunctions);
|
|
196
206
|
}
|
|
197
207
|
|
|
198
208
|
/**
|
|
199
209
|
* Transform a CSN like to.hdi
|
|
200
210
|
*
|
|
201
211
|
* @param {CSN.Model} csn Plain input CSN
|
|
202
|
-
* @param {HdiOptions}
|
|
212
|
+
* @param {HdiOptions} options Options
|
|
213
|
+
* @param {object} messageFunctions Message functions such as `error()`, `info()`, …
|
|
203
214
|
* @returns {CSN.Model} CSN transformed like to.hdi
|
|
204
215
|
* @private
|
|
205
216
|
*/
|
|
206
|
-
function forHdi( csn, options
|
|
217
|
+
function forHdi( csn, options, messageFunctions ) {
|
|
207
218
|
const internalOptions = prepareOptions.to.hdi(options);
|
|
208
219
|
internalOptions.transformation = 'sql';
|
|
209
|
-
const transformedCsn = forRelationalDB.transformForRelationalDBWithCsn(
|
|
210
|
-
|
|
220
|
+
const transformedCsn = forRelationalDB.transformForRelationalDBWithCsn(
|
|
221
|
+
csn, internalOptions, messageFunctions
|
|
222
|
+
);
|
|
211
223
|
return internalOptions.testMode ? toCsn.sortCsn(transformedCsn, internalOptions) : transformedCsn;
|
|
212
224
|
}
|
|
213
225
|
/**
|
|
214
226
|
* Transform a CSN like to.hdbcds
|
|
215
227
|
*
|
|
216
228
|
* @param {CSN.Model} csn Plain input CSN
|
|
217
|
-
* @param {HdbcdsOptions}
|
|
229
|
+
* @param {HdbcdsOptions} options Options
|
|
230
|
+
* @param {object} messageFunctions Message functions such as `error()`, `info()`, …
|
|
218
231
|
* @returns {CSN.Model} CSN transformed like to.hdbcds
|
|
219
232
|
* @private
|
|
220
233
|
*/
|
|
221
|
-
function forHdbcds( csn, options
|
|
234
|
+
function forHdbcds( csn, options, messageFunctions ) {
|
|
222
235
|
const internalOptions = prepareOptions.to.hdbcds(options);
|
|
223
236
|
internalOptions.transformation = 'hdbcds';
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
237
|
+
const hanaCsn = forRelationalDB.transformForRelationalDBWithCsn(
|
|
238
|
+
csn, internalOptions, messageFunctions
|
|
239
|
+
);
|
|
227
240
|
return internalOptions.testMode ? toCsn.sortCsn(hanaCsn, internalOptions) : hanaCsn;
|
|
228
241
|
}
|
|
229
242
|
|
|
@@ -231,16 +244,16 @@ function forHdbcds( csn, options = {} ) {
|
|
|
231
244
|
* Effective CSN transformation
|
|
232
245
|
*
|
|
233
246
|
* @param {CSN.Model} csn Plain input CSN
|
|
234
|
-
* @param {EffectiveCsnOptions}
|
|
247
|
+
* @param {EffectiveCsnOptions} options Options
|
|
248
|
+
* @param {object} messageFunctions Message functions such as `error()`, `info()`, …
|
|
235
249
|
* @returns {CSN.Model} CSN transformed
|
|
236
250
|
* @private
|
|
237
251
|
*/
|
|
238
|
-
function forEffective( csn, options
|
|
252
|
+
function forEffective( csn, options, messageFunctions ) {
|
|
239
253
|
const internalOptions = prepareOptions.to.sql(options);
|
|
240
254
|
internalOptions.transformation = 'effective';
|
|
241
255
|
|
|
242
|
-
const eCsn = effective.effectiveCsn(csn, internalOptions);
|
|
243
|
-
|
|
256
|
+
const eCsn = effective.effectiveCsn(csn, internalOptions, messageFunctions);
|
|
244
257
|
return internalOptions.testMode ? toCsn.sortCsn(eCsn, internalOptions) : eCsn;
|
|
245
258
|
}
|
|
246
259
|
|
|
@@ -248,17 +261,19 @@ function forEffective( csn, options = {} ) {
|
|
|
248
261
|
* Process the given CSN into SQL.
|
|
249
262
|
*
|
|
250
263
|
* @param {CSN.Model} csn A clean input CSN
|
|
251
|
-
* @param {SqlOptions}
|
|
264
|
+
* @param {SqlOptions} options Options
|
|
265
|
+
* @param {object} messageFunctions Message functions such as `error()`, `info()`, …
|
|
252
266
|
* @returns {SQL[]} Array of SQL statements, tables first, views second
|
|
253
267
|
*/
|
|
254
|
-
function sql( csn, options
|
|
255
|
-
traceApi('to.sql', options);
|
|
268
|
+
function sql( csn, options, messageFunctions ) {
|
|
269
|
+
trace.traceApi('to.sql', options);
|
|
256
270
|
const internalOptions = prepareOptions.to.sql(options);
|
|
257
271
|
internalOptions.transformation = 'sql';
|
|
258
272
|
|
|
259
273
|
// we need the CSN for view sorting
|
|
260
|
-
const transformedCsn = csnForSql(csn, internalOptions);
|
|
261
|
-
|
|
274
|
+
const transformedCsn = csnForSql(csn, internalOptions, messageFunctions);
|
|
275
|
+
messageFunctions.setModel(transformedCsn);
|
|
276
|
+
const sqls = toSql.toSqlDdl(transformedCsn, internalOptions, messageFunctions);
|
|
262
277
|
|
|
263
278
|
const result = sortViews({ csn: transformedCsn, sql: sqls.sql });
|
|
264
279
|
return [
|
|
@@ -271,16 +286,18 @@ function sql( csn, options = {} ) {
|
|
|
271
286
|
* Process the given CSN into HDI artifacts.
|
|
272
287
|
*
|
|
273
288
|
* @param {CSN.Model} csn A clean input CSN
|
|
274
|
-
* @param {HdiOptions}
|
|
289
|
+
* @param {HdiOptions} options Options
|
|
290
|
+
* @param {object} messageFunctions Message functions such as `error()`, `info()`, …
|
|
275
291
|
* @returns {HDIArtifacts} { <filename>:<content>, ...}
|
|
276
292
|
*/
|
|
277
|
-
function hdi( csn, options
|
|
278
|
-
traceApi('to.hdi', options);
|
|
293
|
+
function hdi( csn, options, messageFunctions ) {
|
|
294
|
+
trace.traceApi('to.hdi', options);
|
|
279
295
|
const internalOptions = prepareOptions.to.hdi(options);
|
|
280
296
|
|
|
281
297
|
// we need the CSN for view sorting
|
|
282
|
-
const sqlCSN = forHdi(csn, options);
|
|
283
|
-
|
|
298
|
+
const sqlCSN = forHdi(csn, options, messageFunctions);
|
|
299
|
+
messageFunctions.setModel(sqlCSN);
|
|
300
|
+
const sqls = toSql.toSqlDdl(sqlCSN, internalOptions, messageFunctions);
|
|
284
301
|
|
|
285
302
|
if (internalOptions.testMode) {
|
|
286
303
|
// All this mapping is needed because sortViews crossmatches
|
|
@@ -370,6 +387,7 @@ function remapName( key, csn, filter = () => true ) {
|
|
|
370
387
|
*
|
|
371
388
|
* @param {CSN.Model} csn A clean input CSN representing the desired "after-image"
|
|
372
389
|
* @param {HdiOptions} options Options
|
|
390
|
+
* @param {object} messageFunctions Message functions such as `error()`, `info()`, …
|
|
373
391
|
* @param {CSN.Model} beforeImage A db-transformed CSN representing the "before-image", or null in case no such image
|
|
374
392
|
* is known, i.e. for the very first migration step.
|
|
375
393
|
* @returns {object} An object with three properties:
|
|
@@ -377,27 +395,23 @@ function remapName( key, csn, filter = () => true ) {
|
|
|
377
395
|
* - drops: An array of SQL statements to drop views/tables
|
|
378
396
|
* - createsAndAlters: An array of SQL statements to ALTER/CREATE tables/views
|
|
379
397
|
*/
|
|
380
|
-
function sqlMigration( csn, options, beforeImage ) {
|
|
381
|
-
traceApi('to.sql.migration', options);
|
|
398
|
+
function sqlMigration( csn, options, messageFunctions, beforeImage ) {
|
|
399
|
+
trace.traceApi('to.sql.migration', options);
|
|
382
400
|
const internalOptions = prepareOptions.to.sql(options);
|
|
383
|
-
const {
|
|
384
|
-
error, warning, info, throwWithError, message,
|
|
385
|
-
} = messages.makeMessageFunction(csn, internalOptions, 'to.sql.migration');
|
|
401
|
+
const { error, throwWithError } = messageFunctions;
|
|
386
402
|
|
|
387
403
|
// Prepare after-image.
|
|
388
|
-
|
|
389
|
-
|
|
404
|
+
let afterImage = csnForSql(csn, internalOptions, messageFunctions);
|
|
405
|
+
if (internalOptions.filterCsn)
|
|
406
|
+
afterImage = diffFilter.csn(afterImage);
|
|
390
407
|
// Compare both images.
|
|
391
408
|
const diff = modelCompare.compareModels(beforeImage || afterImage, afterImage, internalOptions);
|
|
409
|
+
messageFunctions.setModel(diff);
|
|
392
410
|
const diffFilterObj = diffFilter[internalOptions.sqlDialect];
|
|
393
411
|
|
|
394
412
|
if (diffFilterObj) {
|
|
395
|
-
diff.extensions = diff.extensions.filter(ex => diffFilterObj.extension(ex,
|
|
396
|
-
|
|
397
|
-
}));
|
|
398
|
-
diff.migrations.forEach(migration => diffFilterObj.migration(migration, {
|
|
399
|
-
error, warning, info, throwWithError, message,
|
|
400
|
-
}));
|
|
413
|
+
diff.extensions = diff.extensions.filter(ex => diffFilterObj.extension(ex, messageFunctions));
|
|
414
|
+
diff.migrations.forEach(migration => diffFilterObj.migration(migration, messageFunctions));
|
|
401
415
|
Object.entries(diff.deletions).forEach(entry => diffFilterObj.deletion(entry, error));
|
|
402
416
|
diff.changedPrimaryKeys = diff.changedPrimaryKeys
|
|
403
417
|
.filter(an => diffFilterObj.changedPrimaryKeys(an));
|
|
@@ -475,7 +489,7 @@ function sqlMigration( csn, options, beforeImage ) {
|
|
|
475
489
|
const {
|
|
476
490
|
// eslint-disable-next-line no-unused-vars
|
|
477
491
|
deletions, constraintDeletions, migrations, constraints, ...hdbkinds
|
|
478
|
-
} = toSql.toSqlDdl(diff, internalOptions);
|
|
492
|
+
} = toSql.toSqlDdl(diff, internalOptions, messageFunctions);
|
|
479
493
|
|
|
480
494
|
cleanup.forEach(fn => fn());
|
|
481
495
|
// TODO: Handle `ADD CONSTRAINT` etc!
|
|
@@ -528,18 +542,20 @@ function sqlMigration( csn, options, beforeImage ) {
|
|
|
528
542
|
*
|
|
529
543
|
* @param {CSN.Model} csn A clean input CSN representing the desired "after-image"
|
|
530
544
|
* @param {HdiOptions} options Options
|
|
545
|
+
* @param {object} messageFunctions Message functions such as `error()`, `info()`, …
|
|
531
546
|
* @param {CSN.Model} beforeImage A HANA-transformed CSN representing the "before-image", or null in case no such image
|
|
532
547
|
* is known, i.e. for the very first migration step
|
|
533
548
|
* @returns {migration} The migration result
|
|
534
549
|
*/
|
|
535
|
-
function hdiMigration( csn, options, beforeImage ) {
|
|
536
|
-
traceApi('to.hdi.migration', options);
|
|
550
|
+
function hdiMigration( csn, options, messageFunctions, beforeImage ) {
|
|
551
|
+
trace.traceApi('to.hdi.migration', options);
|
|
537
552
|
const internalOptions = prepareOptions.to.hdi(options);
|
|
538
553
|
|
|
539
554
|
// Prepare after-image.
|
|
540
|
-
const afterImage = forHdi(csn, options);
|
|
555
|
+
const afterImage = forHdi(csn, options, messageFunctions);
|
|
541
556
|
|
|
542
557
|
const diff = modelCompare.compareModels(beforeImage || afterImage, afterImage, internalOptions);
|
|
558
|
+
messageFunctions.setModel(diff);
|
|
543
559
|
|
|
544
560
|
// Convert the diff to SQL.
|
|
545
561
|
if (!internalOptions.beta)
|
|
@@ -551,7 +567,7 @@ function hdiMigration( csn, options, beforeImage ) {
|
|
|
551
567
|
const {
|
|
552
568
|
// eslint-disable-next-line no-unused-vars
|
|
553
569
|
deletions, migrations, constraintDeletions, ...hdbkinds
|
|
554
|
-
} = toSql.toSqlDdl(diff, internalOptions);
|
|
570
|
+
} = toSql.toSqlDdl(diff, internalOptions, messageFunctions);
|
|
555
571
|
|
|
556
572
|
return {
|
|
557
573
|
afterImage,
|
|
@@ -614,29 +630,31 @@ sql.migration = sqlMigration;
|
|
|
614
630
|
* Process the given CSN into HDBCDS artifacts.
|
|
615
631
|
*
|
|
616
632
|
* @param {any} csn A clean input CSN
|
|
617
|
-
* @param {HdbcdsOptions}
|
|
633
|
+
* @param {HdbcdsOptions} options Options
|
|
634
|
+
* @param {object} messageFunctions Message functions such as `error()`, `info()`, …
|
|
618
635
|
* @returns {HDBCDS} { <filename>:<content>, ...}
|
|
619
636
|
*/
|
|
620
|
-
function hdbcds( csn, options
|
|
621
|
-
traceApi('to.hdbcds', options);
|
|
637
|
+
function hdbcds( csn, options, messageFunctions ) {
|
|
638
|
+
trace.traceApi('to.hdbcds', options);
|
|
622
639
|
const internalOptions = prepareOptions.to.hdbcds(options);
|
|
623
640
|
internalOptions.transformation = 'hdbcds';
|
|
624
641
|
|
|
625
|
-
const hanaCsn = forHdbcds(csn, internalOptions);
|
|
626
|
-
|
|
627
|
-
const result =
|
|
628
|
-
return result;
|
|
642
|
+
const hanaCsn = forHdbcds(csn, internalOptions, messageFunctions);
|
|
643
|
+
messageFunctions.setModel(hanaCsn);
|
|
644
|
+
const result = toHdbcds.toHdbcdsSource(hanaCsn, internalOptions, messageFunctions);
|
|
645
|
+
return flattenResultStructure(result);
|
|
629
646
|
}
|
|
630
647
|
/**
|
|
631
|
-
* Generate
|
|
648
|
+
* Generate an edm document for the given service
|
|
632
649
|
*
|
|
633
650
|
* @param {CSN|oDataCSN} csn Clean input CSN or a pre-transformed CSN
|
|
634
|
-
* @param {ODataOptions}
|
|
651
|
+
* @param {ODataOptions} options Options
|
|
652
|
+
* @param {object} messageFunctions Message functions such as `error()`, `info()`, …
|
|
635
653
|
* @returns {edm} The JSON representation of the service
|
|
636
654
|
*/
|
|
637
|
-
function edm( csn, options
|
|
638
|
-
traceApi('to.edm', options);
|
|
639
|
-
// If not provided at all, set service to undefined to trigger validation
|
|
655
|
+
function edm( csn, options, messageFunctions ) {
|
|
656
|
+
trace.traceApi('to.edm', options);
|
|
657
|
+
// If not provided at all, set service to 'undefined' to trigger validation
|
|
640
658
|
const internalOptions = prepareOptions.to.edm(
|
|
641
659
|
// eslint-disable-next-line comma-dangle
|
|
642
660
|
options.service ? options : Object.assign({ service: undefined }, options)
|
|
@@ -646,12 +664,14 @@ function edm( csn, options = {} ) {
|
|
|
646
664
|
|
|
647
665
|
let servicesEdmj;
|
|
648
666
|
if (isPreTransformed(csn, 'odata')) {
|
|
649
|
-
checkPreTransformedCsn(csn, internalOptions, relevantOdataOptions,
|
|
650
|
-
|
|
667
|
+
checkPreTransformedCsn(csn, internalOptions, relevantOdataOptions,
|
|
668
|
+
warnAboutMismatchOdata, messageFunctions);
|
|
669
|
+
servicesEdmj = preparedCsnToEdm(csn, service, internalOptions, messageFunctions);
|
|
651
670
|
}
|
|
652
671
|
else {
|
|
653
|
-
const oDataCsn = odataInternal(csn, internalOptions);
|
|
654
|
-
|
|
672
|
+
const oDataCsn = odataInternal(csn, internalOptions, messageFunctions);
|
|
673
|
+
messageFunctions.setModel(oDataCsn);
|
|
674
|
+
servicesEdmj = preparedCsnToEdm(oDataCsn, service, internalOptions, messageFunctions);
|
|
655
675
|
}
|
|
656
676
|
return servicesEdmj.edmj;
|
|
657
677
|
}
|
|
@@ -662,13 +682,14 @@ edm.all = edmall;
|
|
|
662
682
|
* Generate edm documents for all services
|
|
663
683
|
*
|
|
664
684
|
* @param {CSN|oDataCSN} csn Clean input CSN or a pre-transformed CSN
|
|
665
|
-
* @param {ODataOptions}
|
|
685
|
+
* @param {ODataOptions} options Options
|
|
686
|
+
* @param {object} messageFunctions Message functions such as `error()`, `info()`, …
|
|
666
687
|
* @returns {edms} { <service>:<JSON representation>, ...}
|
|
667
688
|
*/
|
|
668
|
-
function edmall( csn, options
|
|
669
|
-
traceApi('to.edm.all', options);
|
|
689
|
+
function edmall( csn, options, messageFunctions ) {
|
|
690
|
+
trace.traceApi('to.edm.all', options);
|
|
670
691
|
const internalOptions = prepareOptions.to.edm(options);
|
|
671
|
-
const { error } =
|
|
692
|
+
const { error } = messageFunctions;
|
|
672
693
|
|
|
673
694
|
if (internalOptions.odataVersion === 'v2')
|
|
674
695
|
error(null, null, {}, 'OData JSON output is not available for OData V2');
|
|
@@ -676,13 +697,16 @@ function edmall( csn, options = {} ) {
|
|
|
676
697
|
const result = {};
|
|
677
698
|
let oDataCsn = csn;
|
|
678
699
|
|
|
679
|
-
if (isPreTransformed(csn, 'odata'))
|
|
680
|
-
checkPreTransformedCsn(csn, internalOptions, relevantOdataOptions,
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
700
|
+
if (isPreTransformed(csn, 'odata')) {
|
|
701
|
+
checkPreTransformedCsn(csn, internalOptions, relevantOdataOptions,
|
|
702
|
+
warnAboutMismatchOdata, messageFunctions);
|
|
703
|
+
}
|
|
704
|
+
else {
|
|
705
|
+
oDataCsn = odataInternal(csn, internalOptions, messageFunctions);
|
|
706
|
+
}
|
|
684
707
|
|
|
685
|
-
|
|
708
|
+
messageFunctions.setModel(oDataCsn);
|
|
709
|
+
const servicesJson = preparedCsnToEdmAll(oDataCsn, internalOptions, messageFunctions);
|
|
686
710
|
const services = servicesJson.edmj;
|
|
687
711
|
for (const serviceName in services)
|
|
688
712
|
result[serviceName] = services[serviceName];
|
|
@@ -690,15 +714,16 @@ function edmall( csn, options = {} ) {
|
|
|
690
714
|
return result;
|
|
691
715
|
}
|
|
692
716
|
/**
|
|
693
|
-
* Generate
|
|
717
|
+
* Generate an edmx document for the given service
|
|
694
718
|
*
|
|
695
719
|
* @param {CSN|oDataCSN} csn Clean input CSN or a pre-transformed CSN
|
|
696
|
-
* @param {ODataOptions}
|
|
720
|
+
* @param {ODataOptions} options Options
|
|
721
|
+
* @param {object} messageFunctions Message functions such as `error()`, `info()`, …
|
|
697
722
|
* @returns {edmx} The XML representation of the service
|
|
698
723
|
*/
|
|
699
|
-
function edmx( csn, options
|
|
700
|
-
traceApi('to.edmx', options);
|
|
701
|
-
// If not provided at all, set service to undefined to trigger validation
|
|
724
|
+
function edmx( csn, options, messageFunctions ) {
|
|
725
|
+
trace.traceApi('to.edmx', options);
|
|
726
|
+
// If not provided at all, set service to 'undefined' to trigger validation
|
|
702
727
|
const internalOptions = prepareOptions.to.edmx(
|
|
703
728
|
// eslint-disable-next-line comma-dangle
|
|
704
729
|
options.service ? options : Object.assign({ service: undefined }, options)
|
|
@@ -708,12 +733,14 @@ function edmx( csn, options = {} ) {
|
|
|
708
733
|
|
|
709
734
|
let services;
|
|
710
735
|
if (isPreTransformed(csn, 'odata')) {
|
|
711
|
-
checkPreTransformedCsn(csn, internalOptions, relevantOdataOptions,
|
|
712
|
-
|
|
736
|
+
checkPreTransformedCsn(csn, internalOptions, relevantOdataOptions,
|
|
737
|
+
warnAboutMismatchOdata, messageFunctions);
|
|
738
|
+
services = preparedCsnToEdmx(csn, service, internalOptions, messageFunctions);
|
|
713
739
|
}
|
|
714
740
|
else {
|
|
715
|
-
const oDataCsn = odataInternal(csn, internalOptions);
|
|
716
|
-
|
|
741
|
+
const oDataCsn = odataInternal(csn, internalOptions, messageFunctions);
|
|
742
|
+
messageFunctions.setModel(oDataCsn);
|
|
743
|
+
services = preparedCsnToEdmx(oDataCsn, service, internalOptions, messageFunctions);
|
|
717
744
|
}
|
|
718
745
|
|
|
719
746
|
return services.edmx;
|
|
@@ -725,23 +752,27 @@ edmx.all = edmxall;
|
|
|
725
752
|
* Generate edmx documents for all services
|
|
726
753
|
*
|
|
727
754
|
* @param {CSN|oDataCSN} csn Clean input CSN or a pre-transformed CSN
|
|
728
|
-
* @param {ODataOptions}
|
|
755
|
+
* @param {ODataOptions} options Options
|
|
756
|
+
* @param {object} messageFunctions Message functions such as `error()`, `info()`, …
|
|
729
757
|
* @returns {edmxs} { <service>:<XML representation>, ...}
|
|
730
758
|
*/
|
|
731
|
-
function edmxall( csn, options
|
|
732
|
-
traceApi('to.edmx.all', options);
|
|
759
|
+
function edmxall( csn, options, messageFunctions ) {
|
|
760
|
+
trace.traceApi('to.edmx.all', options);
|
|
733
761
|
const internalOptions = prepareOptions.to.edmx(options);
|
|
734
762
|
|
|
735
763
|
const result = {};
|
|
736
764
|
let oDataCsn = csn;
|
|
737
765
|
|
|
738
|
-
if (isPreTransformed(csn, 'odata'))
|
|
739
|
-
checkPreTransformedCsn(csn, internalOptions, relevantOdataOptions,
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
766
|
+
if (isPreTransformed(csn, 'odata')) {
|
|
767
|
+
checkPreTransformedCsn(csn, internalOptions, relevantOdataOptions,
|
|
768
|
+
warnAboutMismatchOdata, messageFunctions);
|
|
769
|
+
}
|
|
770
|
+
else {
|
|
771
|
+
oDataCsn = odataInternal(csn, internalOptions, messageFunctions);
|
|
772
|
+
}
|
|
743
773
|
|
|
744
|
-
|
|
774
|
+
messageFunctions.setModel(oDataCsn);
|
|
775
|
+
const servicesEdmx = preparedCsnToEdmxAll(oDataCsn, internalOptions, messageFunctions);
|
|
745
776
|
const services = servicesEdmx.edmx;
|
|
746
777
|
// Create annotations and metadata once per service
|
|
747
778
|
for (const serviceName in services) {
|
|
@@ -752,6 +783,97 @@ function edmxall( csn, options = {} ) {
|
|
|
752
783
|
return result;
|
|
753
784
|
}
|
|
754
785
|
|
|
786
|
+
/**
|
|
787
|
+
* Generate an EDM document for the given service in XML and JSON representation
|
|
788
|
+
* If odataVersion is not 'v4', then no JSON is rendered
|
|
789
|
+
*
|
|
790
|
+
* @param {CSN|oDataCSN} csn Clean input CSN or a pre-transformed CSN
|
|
791
|
+
* @param {ODataOptions} [options={}] Options
|
|
792
|
+
* @param {object} messageFunctions Message functions such as `error()`, `info()`, …
|
|
793
|
+
* @returns {object} { <protocol> : { <ServiceName>: { edmx: <XML representation>, edm: <JSON representation> } } }
|
|
794
|
+
*/
|
|
795
|
+
// @ts-ignore
|
|
796
|
+
function odata2( csn, options = {}, messageFunctions ) {
|
|
797
|
+
trace.traceApi('to.odata', options);
|
|
798
|
+
// If not provided at all, set service to undefined to trigger validation
|
|
799
|
+
const internalOptions = prepareOptions.to.odata(
|
|
800
|
+
// eslint-disable-next-line comma-dangle
|
|
801
|
+
options.service ? options : Object.assign({ service: undefined }, options)
|
|
802
|
+
);
|
|
803
|
+
|
|
804
|
+
const { service } = options;
|
|
805
|
+
|
|
806
|
+
let oDataCsn = csn;
|
|
807
|
+
if (isPreTransformed(csn, 'odata')) {
|
|
808
|
+
checkPreTransformedCsn(csn, internalOptions, relevantOdataOptions,
|
|
809
|
+
warnAboutMismatchOdata, messageFunctions);
|
|
810
|
+
}
|
|
811
|
+
else {
|
|
812
|
+
oDataCsn = odataInternal(csn, internalOptions, messageFunctions);
|
|
813
|
+
messageFunctions.setModel(oDataCsn);
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
const edmIR = csnToEdm.csn2edm(oDataCsn, service, internalOptions, messageFunctions);
|
|
817
|
+
|
|
818
|
+
|
|
819
|
+
const version = internalOptions.odataVersion;
|
|
820
|
+
const result = { [version]: { [service]: {} } };
|
|
821
|
+
|
|
822
|
+
if (edmIR) {
|
|
823
|
+
result[version][service].edmx = edmIR.toXML();
|
|
824
|
+
if (version === 'v4')
|
|
825
|
+
result[version][service].edm = edmIR.toJSON();
|
|
826
|
+
}
|
|
827
|
+
return result;
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
odata2.all = odataall;
|
|
831
|
+
|
|
832
|
+
/**
|
|
833
|
+
* Generate EDM documents for all services in XML and JSON representation
|
|
834
|
+
* If odataVersion is not 'v4', then no JSON is rendered
|
|
835
|
+
*
|
|
836
|
+
* @param {CSN|oDataCSN} csn Clean input CSN or a pre-transformed CSN
|
|
837
|
+
* @param {ODataOptions} [options={}] Options
|
|
838
|
+
* @param {object} messageFunctions Message functions such as `error()`, `info()`, …
|
|
839
|
+
* @returns {object} { <protocol>: { <serviceName>: { edmx: <XML representation>, edm: <JSON representation> } } }
|
|
840
|
+
*/
|
|
841
|
+
// @ts-ignore
|
|
842
|
+
function odataall( csn, options = {}, messageFunctions ) {
|
|
843
|
+
trace.traceApi('to.odata.all', options);
|
|
844
|
+
const internalOptions = prepareOptions.to.odata(options);
|
|
845
|
+
const { error } = messageFunctions;
|
|
846
|
+
|
|
847
|
+
if (internalOptions.odataVersion === 'v2')
|
|
848
|
+
error(null, null, {}, 'OData JSON output is not available for OData V2');
|
|
849
|
+
|
|
850
|
+
let oDataCsn = csn;
|
|
851
|
+
if (isPreTransformed(csn, 'odata')) {
|
|
852
|
+
checkPreTransformedCsn(csn, internalOptions, relevantOdataOptions,
|
|
853
|
+
warnAboutMismatchOdata, messageFunctions);
|
|
854
|
+
}
|
|
855
|
+
else {
|
|
856
|
+
oDataCsn = odataInternal(csn, internalOptions, messageFunctions);
|
|
857
|
+
messageFunctions.setModel(oDataCsn);
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
const edmIR = csnToEdm.csn2edmAll(oDataCsn, internalOptions, undefined, messageFunctions);
|
|
861
|
+
|
|
862
|
+
const version = internalOptions.odataVersion;
|
|
863
|
+
|
|
864
|
+
const result = {};
|
|
865
|
+
result[version] = {};
|
|
866
|
+
|
|
867
|
+
if (edmIR) {
|
|
868
|
+
for (const serviceName in edmIR) {
|
|
869
|
+
result[version][serviceName] = { edmx: edmIR[serviceName].toXML() };
|
|
870
|
+
if (internalOptions.odataVersion === 'v4')
|
|
871
|
+
result[version][serviceName].edm = edmIR[serviceName].toJSON();
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
return result;
|
|
875
|
+
}
|
|
876
|
+
|
|
755
877
|
/**
|
|
756
878
|
* Generate edmx for given 'service' based on 'csn' (new-style compact, already prepared for OData)
|
|
757
879
|
* using 'options'
|
|
@@ -759,11 +881,12 @@ function edmxall( csn, options = {} ) {
|
|
|
759
881
|
* @param {CSN.Model} csn Input CSN model. Must be OData transformed CSN.
|
|
760
882
|
* @param {string} service Service name to use. If you want all services, use preparedCsnToEdmxAll()
|
|
761
883
|
* @param {ODataOptions} options OData / EDMX specific options.
|
|
884
|
+
* @param {object} messageFunctions Message functions such as `error()`, `info()`, …
|
|
762
885
|
* @returns {object} Rendered EDMX string for the given service.
|
|
763
886
|
*/
|
|
764
|
-
function preparedCsnToEdmx( csn, service, options ) {
|
|
887
|
+
function preparedCsnToEdmx( csn, service, options, messageFunctions ) {
|
|
765
888
|
timetrace.timetrace.start('EDMX rendering');
|
|
766
|
-
const e = csn2edm(csn, service, options)?.toXML('all');
|
|
889
|
+
const e = csnToEdm.csn2edm(csn, service, options, messageFunctions)?.toXML('all');
|
|
767
890
|
timetrace.timetrace.stop('EDMX rendering');
|
|
768
891
|
return { edmx: e };
|
|
769
892
|
}
|
|
@@ -774,11 +897,12 @@ function preparedCsnToEdmx( csn, service, options ) {
|
|
|
774
897
|
*
|
|
775
898
|
* @param {CSN.Model} csn Input CSN model. Must be OData transformed CSN.
|
|
776
899
|
* @param {ODataOptions} options OData / EDMX specific options.
|
|
900
|
+
* @param {object} messageFunctions Message functions such as `error()`, `info()`, …
|
|
777
901
|
* @returns {object} Dictionary of rendered EDMX strings for each service.
|
|
778
902
|
*/
|
|
779
|
-
function preparedCsnToEdmxAll( csn, options ) {
|
|
903
|
+
function preparedCsnToEdmxAll( csn, options, messageFunctions ) {
|
|
780
904
|
timetrace.timetrace.start('EDMX all rendering');
|
|
781
|
-
const edmxResult = csn2edmAll(csn, options);
|
|
905
|
+
const edmxResult = csnToEdm.csn2edmAll(csn, options, undefined, messageFunctions);
|
|
782
906
|
for (const service in edmxResult)
|
|
783
907
|
edmxResult[service] = edmxResult[service].toXML('all');
|
|
784
908
|
timetrace.timetrace.stop('EDMX all rendering');
|
|
@@ -792,13 +916,14 @@ function preparedCsnToEdmxAll( csn, options ) {
|
|
|
792
916
|
* @param {CSN.Model} csn Input CSN model. Must be OData transformed CSN.
|
|
793
917
|
* @param {string} service Service name for which EDMX should be rendered.
|
|
794
918
|
* @param {ODataOptions} options OData / EDMX specific options.
|
|
919
|
+
* @param {object} [messageFunctions] Message functions such as `error()`, `info()`, …
|
|
795
920
|
* @returns {object} Rendered EDM JSON object for of the given service.
|
|
796
921
|
*/
|
|
797
|
-
function preparedCsnToEdm( csn, service, options ) {
|
|
922
|
+
function preparedCsnToEdm( csn, service, options, messageFunctions ) {
|
|
798
923
|
timetrace.timetrace.start('EDM rendering');
|
|
799
924
|
// Override OData version as edm json is always v4
|
|
800
925
|
options.odataVersion = 'v4';
|
|
801
|
-
const e = csn2edm(csn, service, options)?.toJSON();
|
|
926
|
+
const e = csnToEdm.csn2edm(csn, service, options, messageFunctions)?.toJSON();
|
|
802
927
|
timetrace.timetrace.stop('EDM rendering');
|
|
803
928
|
return { edmj: e };
|
|
804
929
|
}
|
|
@@ -809,13 +934,14 @@ function preparedCsnToEdm( csn, service, options ) {
|
|
|
809
934
|
*
|
|
810
935
|
* @param {CSN.Model} csn Input CSN model. Must be OData transformed CSN.
|
|
811
936
|
* @param {ODataOptions} options OData / EDMX specific options.
|
|
937
|
+
* @param {object} [messageFunctions] Message functions such as `error()`, `info()`, …
|
|
812
938
|
* @returns {object} Dictionary of rendered EDM JSON objects for each service.
|
|
813
939
|
*/
|
|
814
|
-
function preparedCsnToEdmAll( csn, options ) {
|
|
940
|
+
function preparedCsnToEdmAll( csn, options, messageFunctions ) {
|
|
815
941
|
timetrace.timetrace.start('EDM all rendering');
|
|
816
942
|
// Override OData version as edm json is always v4
|
|
817
943
|
options.odataVersion = 'v4';
|
|
818
|
-
const edmj = csn2edmAll(csn, options);
|
|
944
|
+
const edmj = csnToEdm.csn2edmAll(csn, options, undefined, messageFunctions);
|
|
819
945
|
for (const service in edmj)
|
|
820
946
|
edmj[service] = edmj[service].toJSON();
|
|
821
947
|
timetrace.timetrace.stop('EDM all rendering');
|
|
@@ -855,14 +981,21 @@ module.exports = {
|
|
|
855
981
|
hdbcds: publishCsnProcessor(hdbcds, 'to.hdbcds'),
|
|
856
982
|
edm: publishCsnProcessor(edm, 'to.edm'),
|
|
857
983
|
edmx: publishCsnProcessor(edmx, 'to.edmx'),
|
|
984
|
+
odata2: publishCsnProcessor(odata2, 'to.odata'),
|
|
858
985
|
/** Internal only */
|
|
859
986
|
for_sql: publishCsnProcessor(forSql, 'for.sql'),
|
|
860
987
|
for_hdi: publishCsnProcessor(forHdi, 'for.hdi'),
|
|
861
988
|
for_hdbcds: publishCsnProcessor(forHdbcds, 'for.hdbcds'),
|
|
862
989
|
for_effective: publishCsnProcessor(forEffective, 'for.effective'),
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
990
|
+
|
|
991
|
+
/* Deprecated, will be removed in cds-compiler@v5 */ // TODO(v5): Remove
|
|
992
|
+
preparedCsnToEdmx(csn, service, options) {
|
|
993
|
+
preparedCsnToEdmx(csn, service, options, makeMessageFunction( csn, options, 'to.edmx' ));
|
|
994
|
+
},
|
|
995
|
+
/* Deprecated, will be removed in cds-compiler@v5 */ // TODO(v5): Remove
|
|
996
|
+
preparedCsnToEdm(csn, service, options) {
|
|
997
|
+
preparedCsnToEdm(csn, service, options, makeMessageFunction( csn, options, 'to.edm' ));
|
|
998
|
+
},
|
|
866
999
|
};
|
|
867
1000
|
|
|
868
1001
|
|
|
@@ -891,18 +1024,19 @@ function publishCsnProcessor( processor, _name ) {
|
|
|
891
1024
|
* @returns {any} What ever the processor returns
|
|
892
1025
|
*/
|
|
893
1026
|
function api( csn, options = {}, ...args ) {
|
|
1027
|
+
const originalMessageLength = options.messages?.length;
|
|
894
1028
|
try {
|
|
895
|
-
const messageFunctions = messages.makeMessageFunction(csn, options,
|
|
1029
|
+
const messageFunctions = messages.makeMessageFunction(csn, options, _name);
|
|
896
1030
|
if (options.deprecated)
|
|
897
1031
|
checkRemovedDeprecatedFlags( options, messageFunctions );
|
|
898
1032
|
|
|
899
1033
|
checkOutdatedOptions( options, messageFunctions );
|
|
900
|
-
|
|
901
|
-
|
|
1034
|
+
csn = ensureClientCsn( csn, options, messageFunctions, _name );
|
|
902
1035
|
messageFunctions.throwWithError();
|
|
1036
|
+
messageFunctions.setModel(csn);
|
|
903
1037
|
|
|
904
1038
|
timetrace.timetrace.start(_name);
|
|
905
|
-
const result = processor( csn, options, ...args );
|
|
1039
|
+
const result = processor( csn, options, messageFunctions, ...args );
|
|
906
1040
|
timetrace.timetrace.stop(_name);
|
|
907
1041
|
return result;
|
|
908
1042
|
}
|
|
@@ -912,20 +1046,27 @@ function publishCsnProcessor( processor, _name ) {
|
|
|
912
1046
|
throw err;
|
|
913
1047
|
|
|
914
1048
|
if (options.testMode && !(err instanceof TypeError) &&
|
|
915
|
-
!(err instanceof ModelError))
|
|
1049
|
+
!(err instanceof baseError.ModelError))
|
|
916
1050
|
throw err;
|
|
917
1051
|
|
|
918
|
-
|
|
919
|
-
|
|
1052
|
+
// Reset messages to what we had before the backend crashed.
|
|
1053
|
+
// Backends may report the same issues again after compilation.
|
|
1054
|
+
if (originalMessageLength !== undefined)
|
|
1055
|
+
options.messages.length = originalMessageLength;
|
|
1056
|
+
|
|
1057
|
+
const messageFunctions = messages.makeMessageFunction( csn, options, _name );
|
|
1058
|
+
const recompileMsg = messageFunctions.info( 'api-recompiled-csn', location.emptyLocation('csn.json'), {},
|
|
1059
|
+
'CSN input had to be recompiled' );
|
|
920
1060
|
if (options.internalMsg || options.testMode)
|
|
921
|
-
|
|
1061
|
+
recompileMsg.error = err; // Attach original error;
|
|
922
1062
|
if (options.testMode) // Attach recompilation reason in testMode
|
|
923
|
-
|
|
1063
|
+
recompileMsg.message += `\n ↳ cause: ${ err.message }`;
|
|
924
1064
|
|
|
925
1065
|
// next line to be replaced by CSN parser call which reads the CSN object
|
|
926
1066
|
const xsn = compiler.recompileX(csn, options);
|
|
927
1067
|
const recompiledCsn = toCsn.compactModel(xsn);
|
|
928
|
-
|
|
1068
|
+
messageFunctions.setModel(recompiledCsn);
|
|
1069
|
+
return processor( recompiledCsn, options, messageFunctions, ...args );
|
|
929
1070
|
}
|
|
930
1071
|
}
|
|
931
1072
|
}
|
|
@@ -946,7 +1087,6 @@ function checkOutdatedOptions( options, messageFunctions ) {
|
|
|
946
1087
|
if (options.messages?.some(m => m.messageId === 'api-invalid-option' || m.messageId === 'api-invalid-variable-replacement'))
|
|
947
1088
|
return;
|
|
948
1089
|
|
|
949
|
-
|
|
950
1090
|
for (const name of oldBackendOptionNames) {
|
|
951
1091
|
if (typeof options[name] === 'object') // may be a boolean due to internal options
|
|
952
1092
|
messageFunctions.error('api-invalid-option', null, { '#': 'deprecated', name });
|
|
@@ -981,6 +1121,12 @@ function checkOutdatedOptions( options, messageFunctions ) {
|
|
|
981
1121
|
* Checks that the given CSN is usable by our backends, e.g. that
|
|
982
1122
|
* the CSN is not a gensrc (a.k.a. xtended) for most backends.
|
|
983
1123
|
*
|
|
1124
|
+
* Returns the input CSN if it is acceptable or compiles the input CSN if it does not
|
|
1125
|
+
* have the expected CSN flavor.
|
|
1126
|
+
*
|
|
1127
|
+
* The compiler does not set any marker in `meta`; we use the umbrella one
|
|
1128
|
+
* for easier debugging.
|
|
1129
|
+
*
|
|
984
1130
|
* For reference, cds-compiler/cds-dk CSN flavor map:
|
|
985
1131
|
* - client -> inferred
|
|
986
1132
|
* - gensrc -> xtended
|
|
@@ -989,23 +1135,39 @@ function checkOutdatedOptions( options, messageFunctions ) {
|
|
|
989
1135
|
* If this function becomes more complex (e.g. more module conditions),
|
|
990
1136
|
* move it from then generic api wrapper to the individual module.
|
|
991
1137
|
*
|
|
992
|
-
* TODO: The compiler does not set any marker in `meta`; we use the umbrella one
|
|
993
|
-
* for easier debugging.
|
|
994
|
-
*
|
|
995
1138
|
* @param {CSN.Model} csn User CSN
|
|
996
1139
|
* @param {CSN.Options} options User options
|
|
997
1140
|
* @param {object} messageFunctions Functions returned by makeMessageFunction()
|
|
998
1141
|
* @param {string} module Backend module, e.g. to.cdl or to.sql
|
|
1142
|
+
* @returns {CSN.Model} CSN that works for backends.
|
|
999
1143
|
*/
|
|
1000
|
-
function
|
|
1144
|
+
function ensureClientCsn( csn, options, messageFunctions, module ) {
|
|
1001
1145
|
if (module === 'to.cdl' || !csn)
|
|
1002
|
-
return; // to.cdl allows every CSN flavor
|
|
1146
|
+
return csn; // to.cdl allows every CSN flavor
|
|
1003
1147
|
|
|
1004
1148
|
if (csn.meta?.flavor === 'xtended') {
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
'Module $(NAME) expects a client/inferred CSN, not $(OPTION)');
|
|
1149
|
+
messageFunctions.error('api-unsupported-csn-flavor', null, { name: module, option: csn.meta?.flavor });
|
|
1150
|
+
return csn;
|
|
1008
1151
|
}
|
|
1152
|
+
|
|
1153
|
+
// `parsed` CSN is allowed if it can be compiled (i.e. no `requires`).
|
|
1154
|
+
// Still return false, because it's not client CSN. The caller must handle it.
|
|
1155
|
+
if (csn.meta?.flavor === 'parsed') {
|
|
1156
|
+
if (csn.requires?.length > 0) {
|
|
1157
|
+
messageFunctions.error('api-unsupported-csn-flavor', null, {
|
|
1158
|
+
'#': 'parsed-requires',
|
|
1159
|
+
name: module,
|
|
1160
|
+
prop: 'requires',
|
|
1161
|
+
});
|
|
1162
|
+
return csn;
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
// TODO: next line to be replaced by CSN parser call which reads the CSN object once the two API files are merged.
|
|
1166
|
+
const xsn = compiler.recompileX(csn, options);
|
|
1167
|
+
return toCsn.compactModel(xsn);
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
return csn;
|
|
1009
1171
|
}
|
|
1010
1172
|
|
|
1011
1173
|
/**
|