@sap/cds-compiler 4.4.2 → 4.5.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 +58 -0
- package/bin/cdsc.js +5 -0
- package/bin/cdsv2m.js +7 -5
- package/doc/CHANGELOG_BETA.md +16 -0
- package/lib/api/main.js +68 -47
- package/lib/api/options.js +10 -6
- package/lib/api/validate.js +1 -1
- package/lib/base/message-registry.js +28 -6
- package/lib/base/messages.js +18 -13
- package/lib/base/model.js +3 -0
- package/lib/checks/annotationsOData.js +49 -0
- package/lib/checks/validator.js +6 -4
- package/lib/compiler/assert-consistency.js +38 -16
- package/lib/compiler/builtins.js +10 -49
- package/lib/compiler/checks.js +16 -8
- package/lib/compiler/cycle-detector.js +1 -4
- package/lib/compiler/define.js +4 -1
- 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 +68 -14
- package/lib/compiler/shared.js +44 -27
- package/lib/compiler/tweak-assocs.js +158 -37
- package/lib/compiler/utils.js +9 -0
- package/lib/edm/annotations/edmJson.js +35 -61
- package/lib/edm/annotations/genericTranslation.js +13 -5
- package/lib/edm/annotations/preprocessAnnotations.js +2 -3
- package/lib/edm/csn2edm.js +4 -1
- package/lib/edm/edmInboundChecks.js +59 -15
- package/lib/edm/edmPreprocessor.js +1 -7
- package/lib/gen/Dictionary.json +8 -0
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +12 -2
- package/lib/gen/languageParser.js +6095 -5195
- package/lib/json/from-csn.js +4 -5
- package/lib/json/to-csn.js +22 -3
- package/lib/language/errorStrategy.js +7 -3
- package/lib/language/genericAntlrParser.js +120 -24
- package/lib/language/textUtils.js +16 -0
- package/lib/model/csnUtils.js +9 -8
- package/lib/model/revealInternalProperties.js +5 -2
- package/lib/modelCompare/compare.js +10 -4
- package/lib/optionProcessor.js +2 -3
- package/lib/render/toCdl.js +31 -13
- package/lib/render/toHdbcds.js +20 -30
- package/lib/render/toSql.js +33 -54
- package/lib/render/utils/common.js +24 -6
- package/lib/transform/db/applyTransformations.js +59 -2
- package/lib/transform/db/backlinks.js +13 -1
- package/lib/transform/db/expansion.js +24 -3
- package/lib/transform/db/flattening.js +2 -2
- package/lib/transform/db/killAnnotations.js +37 -0
- package/lib/transform/db/rewriteCalculatedElements.js +46 -6
- package/lib/transform/forOdata.js +13 -46
- package/lib/transform/forRelationalDB.js +2 -1
- package/lib/transform/translateAssocsToJoins.js +13 -4
- package/lib/transform/universalCsn/coreComputed.js +1 -1
- package/lib/transform/universalCsn/universalCsnEnricher.js +4 -4
- package/package.json +7 -6
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,50 @@
|
|
|
7
7
|
Note: `beta` fixes, changes and features are usually not listed in this ChangeLog but [here](doc/CHANGELOG_BETA.md).
|
|
8
8
|
The compiler behavior concerning `beta` features can change at any time without notice.
|
|
9
9
|
|
|
10
|
+
## Version 4.5.0 - 2023-12-08
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- parser: `annotate` can now annotate entity parameters, elements and bound actions in one statement.
|
|
15
|
+
- compiler: A single `annotate` statement can now be used to annotate parameters, elements and
|
|
16
|
+
bound actions in one statement.
|
|
17
|
+
- to.edm(x): Key elements of type `cds.UUID` are annotated with `@Core.ComputedDefaultValue` if they are
|
|
18
|
+
defined directly in the entity. Elements of type `cds.UUID` that are defined in a named structured type
|
|
19
|
+
and used to define a key element are not annotated, instead a warning is raised if such elements are
|
|
20
|
+
not annotated with `@Core.ComputedDefaultValue`.
|
|
21
|
+
- to.sql|hdi: Add option `withHanaAssociations` which, for sqlDialect `hana`, allows suppressing
|
|
22
|
+
the generation of the `WITH ASSOCIATIONS`.
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
|
|
26
|
+
- Update OData Vocabulary: 'Common'.
|
|
27
|
+
- api: Reject CSN as input in backends, if it is a CSN in flavor `parsed` with a non-empty `requires` array.
|
|
28
|
+
Reason being that the model is not considered a "full" CSN, as dependencies were not resolved.
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- compiler:
|
|
33
|
+
- Fix false positives of cyclic dependencies for calculated elements.
|
|
34
|
+
- Fix cardinality on source associations when publishing them with a filter (+ different cardinality)
|
|
35
|
+
in a projection. The cardinality was incorrectly changed on the source as well.
|
|
36
|
+
- CDL parser:
|
|
37
|
+
- More numbers that would lose relevant digits due to precision loss are
|
|
38
|
+
stored as strings in CSN (i.e. `{ "literal":"number", "val": "1.0000000000000001" }`).
|
|
39
|
+
- Nested table expressions and queries in the FROM clause (with surrounding parentheses)
|
|
40
|
+
could cause some constructs such as `virtual` to be not properly parsed.
|
|
41
|
+
- to.hdi.migration: Don't drop-create the primary key when only a doc-comment has changed.
|
|
42
|
+
- to.cdl: Fix edge case where `@A.![B#]` was not rendered correctly.
|
|
43
|
+
|
|
44
|
+
### Removed
|
|
45
|
+
|
|
46
|
+
- to.edm(x): Remove option `--odata-open-type` introduced with [4.4.0](#version-440---2023-11-09).
|
|
47
|
+
|
|
48
|
+
## Version 4.4.4 - 2023-11-24
|
|
49
|
+
|
|
50
|
+
### Fixed
|
|
51
|
+
|
|
52
|
+
- to.hdi.migration: Changes in only `doc`-comments should not result in a drop-create of the primary key.
|
|
53
|
+
|
|
10
54
|
## Version 4.4.2 - 2023-11-17
|
|
11
55
|
|
|
12
56
|
### Fixed
|
|
@@ -355,6 +399,20 @@ The compiler behavior concerning `beta` features can change at any time without
|
|
|
355
399
|
are removed, because since - `Entity.myElement` could also be a definition,
|
|
356
400
|
creating ambiguities. This did not work always, anyway.
|
|
357
401
|
|
|
402
|
+
## Version 3.9.12 - 2023-12-06
|
|
403
|
+
|
|
404
|
+
### Fixed
|
|
405
|
+
|
|
406
|
+
- compiler:
|
|
407
|
+
+ SQL function `STDDEV(*)` was not parsable.
|
|
408
|
+
+ Numbers in scientific notation `-1e1` were sometimes not recognized via CSN input.
|
|
409
|
+
- for.odata: Fix crash when using a projection with associations as action parameter type.
|
|
410
|
+
- for.hana: Fix a bug in association to join translation, expect ON condition operand to be a function without arguments.
|
|
411
|
+
- to.edm(x):
|
|
412
|
+
+ Omit `EntitySet` attribute on `Edm.FunctionImport` and `Edm.ActionImport` that return a singleton.
|
|
413
|
+
+ Don't render `Scale: variable` for `cds.Decimal(scale:0)`.
|
|
414
|
+
- to.sql/hdi/hdbcds: consider `having` predicate for `exists` expansion
|
|
415
|
+
|
|
358
416
|
## Version 3.9.10 - 2023-08-25
|
|
359
417
|
|
|
360
418
|
### Fixed
|
package/bin/cdsc.js
CHANGED
|
@@ -419,6 +419,11 @@ function executeCommandLine( command, options, args ) {
|
|
|
419
419
|
// Execute the command line option '--to-sql' and display the results.
|
|
420
420
|
// Return the original model (for chaining)
|
|
421
421
|
function toSql( model ) {
|
|
422
|
+
if (options.withoutHanaAssociations) {
|
|
423
|
+
options.withHanaAssociations = false;
|
|
424
|
+
delete options.withoutHanaAssociations;
|
|
425
|
+
}
|
|
426
|
+
|
|
422
427
|
const csn = options.directBackend ? model : compactModel(model, options);
|
|
423
428
|
if (options.src === 'hdi') {
|
|
424
429
|
if (options.csn) {
|
package/bin/cdsv2m.js
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
'use strict';
|
|
4
4
|
|
|
5
|
-
// Very simple command-line interface to support model migration
|
|
6
|
-
// v1 to v2.
|
|
7
|
-
// as after #2629, we could have a cdsc commend "migrate...)
|
|
5
|
+
// Very simple command-line interface to support model migration
|
|
6
|
+
// from compiler v1 to v2.
|
|
8
7
|
|
|
9
8
|
const commands = {
|
|
10
9
|
ria,
|
|
11
10
|
};
|
|
12
11
|
const compiler = require('../lib/compiler');
|
|
12
|
+
const { smartId } = require('../lib/render/toCdl');
|
|
13
13
|
|
|
14
14
|
const { argv } = process;
|
|
15
15
|
const cmd = commands[argv[2]];
|
|
@@ -42,6 +42,8 @@ function ria() {
|
|
|
42
42
|
annotates[name.slice( 1, -1 )] = true;
|
|
43
43
|
} );
|
|
44
44
|
}
|
|
45
|
-
for (const name in annotates)
|
|
46
|
-
|
|
45
|
+
for (const name in annotates) {
|
|
46
|
+
const escaped = name.split('.').map(part => smartId(part)).join('.');
|
|
47
|
+
console.log(`annotate ${escaped} with @cds.redirection.target: false;`);
|
|
48
|
+
}
|
|
47
49
|
}
|
package/doc/CHANGELOG_BETA.md
CHANGED
|
@@ -8,6 +8,22 @@ Note: `beta` fixes, changes and features are listed in this ChangeLog just for i
|
|
|
8
8
|
The compiler behavior concerning `beta` features can change at any time without notice.
|
|
9
9
|
**Don't use `beta` fixes, changes and features in productive mode.**
|
|
10
10
|
|
|
11
|
+
## Version 4.5.0 - 2023-12-08
|
|
12
|
+
|
|
13
|
+
### Added `odataAnnotationExpressions`
|
|
14
|
+
|
|
15
|
+
This flag allows to use expressions as annotation values, e.g.
|
|
16
|
+
`@anno: (1+2)` and to enable OData specific transformations on those expressions.
|
|
17
|
+
|
|
18
|
+
### Added `tenantVariable`
|
|
19
|
+
|
|
20
|
+
If this beta flag is enabled, variable `$tenant` can be used without explicit replacement value.
|
|
21
|
+
|
|
22
|
+
### Added feature "associations as direct calculated element values"
|
|
23
|
+
|
|
24
|
+
This beta feature does not require a flag. It is now possible to use associations with
|
|
25
|
+
filters as direct values of calculated elements (on-read), e.g. `calc = assoc[ID = 1]`.
|
|
26
|
+
|
|
11
27
|
## Version 4.3.0 - 2023-09-29
|
|
12
28
|
|
|
13
29
|
### Removed `associationDefault`
|
package/lib/api/main.js
CHANGED
|
@@ -19,6 +19,13 @@ 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 edmToCsn = lazyload('../edm/csn2edm');
|
|
25
|
+
const trace = lazyload('./trace');
|
|
26
|
+
|
|
27
|
+
const { forEach, forEachKey } = require('../utils/objectUtils');
|
|
28
|
+
const { checkRemovedDeprecatedFlags } = require('../base/model');
|
|
22
29
|
|
|
23
30
|
/**
|
|
24
31
|
* Return the artifact name for use for the hdbresult object
|
|
@@ -32,13 +39,6 @@ function getFileName( artifactName, csn ) {
|
|
|
32
39
|
return csnUtils.getResultingName(csn, 'quoted', artifactName);
|
|
33
40
|
}
|
|
34
41
|
|
|
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
42
|
const relevantGeneralOptions = [ /* for future generic options */ ];
|
|
43
43
|
const relevantOdataOptions = [ 'sqlMapping', 'odataFormat' ];
|
|
44
44
|
const warnAboutMismatchOdata = [ 'odataVersion' ];
|
|
@@ -50,7 +50,7 @@ const warnAboutMismatchOdata = [ 'odataVersion' ];
|
|
|
50
50
|
* @param {string} transformation Name of the transformation - odata or hana
|
|
51
51
|
* @param {NestedOptions} options Options used for the transformation
|
|
52
52
|
* @param {string[]} relevantOptionNames Option names that are defining characteristics
|
|
53
|
-
* @param {string[]} [optionalOptionNames
|
|
53
|
+
* @param {string[]} [optionalOptionNames] Option names that should be attached as a fyi
|
|
54
54
|
*/
|
|
55
55
|
function attachTransformerCharacteristics( csn, transformation, options,
|
|
56
56
|
relevantOptionNames, optionalOptionNames = [] ) {
|
|
@@ -143,11 +143,11 @@ function odataInternal( csn, internalOptions ) {
|
|
|
143
143
|
* Return a odata-transformed CSN
|
|
144
144
|
*
|
|
145
145
|
* @param {CSN.Model} csn Clean input CSN
|
|
146
|
-
* @param {ODataOptions} [options
|
|
146
|
+
* @param {ODataOptions} [options] Options
|
|
147
147
|
* @returns {oDataCSN} Return an oData-pre-processed CSN
|
|
148
148
|
*/
|
|
149
149
|
function odata( csn, options = {} ) {
|
|
150
|
-
traceApi('for.odata', options);
|
|
150
|
+
trace.traceApi('for.odata', options);
|
|
151
151
|
const internalOptions = prepareOptions.for.odata(options);
|
|
152
152
|
return odataInternal(csn, internalOptions);
|
|
153
153
|
}
|
|
@@ -156,11 +156,11 @@ function odata( csn, options = {} ) {
|
|
|
156
156
|
* Process the given csn back to cdl.
|
|
157
157
|
*
|
|
158
158
|
* @param {object} csn CSN to process
|
|
159
|
-
* @param {object} [options
|
|
159
|
+
* @param {object} [options] Options
|
|
160
160
|
* @returns {object} { model: string, namespace: string }
|
|
161
161
|
*/
|
|
162
162
|
function cdl( csn, options = {} ) {
|
|
163
|
-
traceApi('to.cdl', options);
|
|
163
|
+
trace.traceApi('to.cdl', options);
|
|
164
164
|
const internalOptions = prepareOptions.to.cdl(options);
|
|
165
165
|
return toCdl.csnToCdl(csn, internalOptions);
|
|
166
166
|
}
|
|
@@ -186,7 +186,7 @@ function csnForSql( csn, internalOptions ) {
|
|
|
186
186
|
* Pseudo-public version of csnForSql().
|
|
187
187
|
*
|
|
188
188
|
* @param {CSN.Model} csn Plain input CSN
|
|
189
|
-
* @param {SqlOptions} [options
|
|
189
|
+
* @param {SqlOptions} [options] Options
|
|
190
190
|
* @returns {CSN.Model} CSN transformed like to.sql
|
|
191
191
|
* @private
|
|
192
192
|
*/
|
|
@@ -199,7 +199,7 @@ function forSql( csn, options = {} ) {
|
|
|
199
199
|
* Transform a CSN like to.hdi
|
|
200
200
|
*
|
|
201
201
|
* @param {CSN.Model} csn Plain input CSN
|
|
202
|
-
* @param {HdiOptions} [options
|
|
202
|
+
* @param {HdiOptions} [options] Options
|
|
203
203
|
* @returns {CSN.Model} CSN transformed like to.hdi
|
|
204
204
|
* @private
|
|
205
205
|
*/
|
|
@@ -214,7 +214,7 @@ function forHdi( csn, options = {} ) {
|
|
|
214
214
|
* Transform a CSN like to.hdbcds
|
|
215
215
|
*
|
|
216
216
|
* @param {CSN.Model} csn Plain input CSN
|
|
217
|
-
* @param {HdbcdsOptions} [options
|
|
217
|
+
* @param {HdbcdsOptions} [options] Options
|
|
218
218
|
* @returns {CSN.Model} CSN transformed like to.hdbcds
|
|
219
219
|
* @private
|
|
220
220
|
*/
|
|
@@ -248,11 +248,11 @@ function forEffective( csn, options = {} ) {
|
|
|
248
248
|
* Process the given CSN into SQL.
|
|
249
249
|
*
|
|
250
250
|
* @param {CSN.Model} csn A clean input CSN
|
|
251
|
-
* @param {SqlOptions} [options
|
|
251
|
+
* @param {SqlOptions} [options] Options
|
|
252
252
|
* @returns {SQL[]} Array of SQL statements, tables first, views second
|
|
253
253
|
*/
|
|
254
254
|
function sql( csn, options = {} ) {
|
|
255
|
-
traceApi('to.sql', options);
|
|
255
|
+
trace.traceApi('to.sql', options);
|
|
256
256
|
const internalOptions = prepareOptions.to.sql(options);
|
|
257
257
|
internalOptions.transformation = 'sql';
|
|
258
258
|
|
|
@@ -271,11 +271,11 @@ function sql( csn, options = {} ) {
|
|
|
271
271
|
* Process the given CSN into HDI artifacts.
|
|
272
272
|
*
|
|
273
273
|
* @param {CSN.Model} csn A clean input CSN
|
|
274
|
-
* @param {HdiOptions} [options
|
|
274
|
+
* @param {HdiOptions} [options] Options
|
|
275
275
|
* @returns {HDIArtifacts} { <filename>:<content>, ...}
|
|
276
276
|
*/
|
|
277
277
|
function hdi( csn, options = {} ) {
|
|
278
|
-
traceApi('to.hdi', options);
|
|
278
|
+
trace.traceApi('to.hdi', options);
|
|
279
279
|
const internalOptions = prepareOptions.to.hdi(options);
|
|
280
280
|
|
|
281
281
|
// we need the CSN for view sorting
|
|
@@ -378,7 +378,7 @@ function remapName( key, csn, filter = () => true ) {
|
|
|
378
378
|
* - createsAndAlters: An array of SQL statements to ALTER/CREATE tables/views
|
|
379
379
|
*/
|
|
380
380
|
function sqlMigration( csn, options, beforeImage ) {
|
|
381
|
-
traceApi('to.sql.migration', options);
|
|
381
|
+
trace.traceApi('to.sql.migration', options);
|
|
382
382
|
const internalOptions = prepareOptions.to.sql(options);
|
|
383
383
|
const {
|
|
384
384
|
error, warning, info, throwWithError, message,
|
|
@@ -533,7 +533,7 @@ function sqlMigration( csn, options, beforeImage ) {
|
|
|
533
533
|
* @returns {migration} The migration result
|
|
534
534
|
*/
|
|
535
535
|
function hdiMigration( csn, options, beforeImage ) {
|
|
536
|
-
traceApi('to.hdi.migration', options);
|
|
536
|
+
trace.traceApi('to.hdi.migration', options);
|
|
537
537
|
const internalOptions = prepareOptions.to.hdi(options);
|
|
538
538
|
|
|
539
539
|
// Prepare after-image.
|
|
@@ -614,28 +614,28 @@ sql.migration = sqlMigration;
|
|
|
614
614
|
* Process the given CSN into HDBCDS artifacts.
|
|
615
615
|
*
|
|
616
616
|
* @param {any} csn A clean input CSN
|
|
617
|
-
* @param {HdbcdsOptions} [options
|
|
617
|
+
* @param {HdbcdsOptions} [options] Options
|
|
618
618
|
* @returns {HDBCDS} { <filename>:<content>, ...}
|
|
619
619
|
*/
|
|
620
620
|
function hdbcds( csn, options = {} ) {
|
|
621
|
-
traceApi('to.hdbcds', options);
|
|
621
|
+
trace.traceApi('to.hdbcds', options);
|
|
622
622
|
const internalOptions = prepareOptions.to.hdbcds(options);
|
|
623
623
|
internalOptions.transformation = 'hdbcds';
|
|
624
624
|
|
|
625
625
|
const hanaCsn = forHdbcds(csn, internalOptions);
|
|
626
626
|
|
|
627
|
-
const result = flattenResultStructure(toHdbcdsSource(hanaCsn, internalOptions));
|
|
627
|
+
const result = flattenResultStructure(toHdbcds.toHdbcdsSource(hanaCsn, internalOptions));
|
|
628
628
|
return result;
|
|
629
629
|
}
|
|
630
630
|
/**
|
|
631
631
|
* Generate a edm document for the given service
|
|
632
632
|
*
|
|
633
633
|
* @param {CSN|oDataCSN} csn Clean input CSN or a pre-transformed CSN
|
|
634
|
-
* @param {ODataOptions} [options
|
|
634
|
+
* @param {ODataOptions} [options] Options
|
|
635
635
|
* @returns {edm} The JSON representation of the service
|
|
636
636
|
*/
|
|
637
637
|
function edm( csn, options = {} ) {
|
|
638
|
-
traceApi('to.edm', options);
|
|
638
|
+
trace.traceApi('to.edm', options);
|
|
639
639
|
// If not provided at all, set service to undefined to trigger validation
|
|
640
640
|
const internalOptions = prepareOptions.to.edm(
|
|
641
641
|
// eslint-disable-next-line comma-dangle
|
|
@@ -662,11 +662,11 @@ edm.all = edmall;
|
|
|
662
662
|
* Generate edm documents for all services
|
|
663
663
|
*
|
|
664
664
|
* @param {CSN|oDataCSN} csn Clean input CSN or a pre-transformed CSN
|
|
665
|
-
* @param {ODataOptions} [options
|
|
665
|
+
* @param {ODataOptions} [options] Options
|
|
666
666
|
* @returns {edms} { <service>:<JSON representation>, ...}
|
|
667
667
|
*/
|
|
668
668
|
function edmall( csn, options = {} ) {
|
|
669
|
-
traceApi('to.edm.all', options);
|
|
669
|
+
trace.traceApi('to.edm.all', options);
|
|
670
670
|
const internalOptions = prepareOptions.to.edm(options);
|
|
671
671
|
const { error } = messages.makeMessageFunction(csn, internalOptions, 'for.odata');
|
|
672
672
|
|
|
@@ -693,11 +693,11 @@ function edmall( csn, options = {} ) {
|
|
|
693
693
|
* Generate a edmx document for the given service
|
|
694
694
|
*
|
|
695
695
|
* @param {CSN|oDataCSN} csn Clean input CSN or a pre-transformed CSN
|
|
696
|
-
* @param {ODataOptions} [options
|
|
696
|
+
* @param {ODataOptions} [options] Options
|
|
697
697
|
* @returns {edmx} The XML representation of the service
|
|
698
698
|
*/
|
|
699
699
|
function edmx( csn, options = {} ) {
|
|
700
|
-
traceApi('to.edmx', options);
|
|
700
|
+
trace.traceApi('to.edmx', options);
|
|
701
701
|
// If not provided at all, set service to undefined to trigger validation
|
|
702
702
|
const internalOptions = prepareOptions.to.edmx(
|
|
703
703
|
// eslint-disable-next-line comma-dangle
|
|
@@ -725,11 +725,11 @@ edmx.all = edmxall;
|
|
|
725
725
|
* Generate edmx documents for all services
|
|
726
726
|
*
|
|
727
727
|
* @param {CSN|oDataCSN} csn Clean input CSN or a pre-transformed CSN
|
|
728
|
-
* @param {ODataOptions} [options
|
|
728
|
+
* @param {ODataOptions} [options] Options
|
|
729
729
|
* @returns {edmxs} { <service>:<XML representation>, ...}
|
|
730
730
|
*/
|
|
731
731
|
function edmxall( csn, options = {} ) {
|
|
732
|
-
traceApi('to.edmx.all', options);
|
|
732
|
+
trace.traceApi('to.edmx.all', options);
|
|
733
733
|
const internalOptions = prepareOptions.to.edmx(options);
|
|
734
734
|
|
|
735
735
|
const result = {};
|
|
@@ -763,7 +763,7 @@ function edmxall( csn, options = {} ) {
|
|
|
763
763
|
*/
|
|
764
764
|
function preparedCsnToEdmx( csn, service, options ) {
|
|
765
765
|
timetrace.timetrace.start('EDMX rendering');
|
|
766
|
-
const e = csn2edm(csn, service, options)?.toXML('all');
|
|
766
|
+
const e = edmToCsn.csn2edm(csn, service, options)?.toXML('all');
|
|
767
767
|
timetrace.timetrace.stop('EDMX rendering');
|
|
768
768
|
return { edmx: e };
|
|
769
769
|
}
|
|
@@ -778,7 +778,7 @@ function preparedCsnToEdmx( csn, service, options ) {
|
|
|
778
778
|
*/
|
|
779
779
|
function preparedCsnToEdmxAll( csn, options ) {
|
|
780
780
|
timetrace.timetrace.start('EDMX all rendering');
|
|
781
|
-
const edmxResult = csn2edmAll(csn, options);
|
|
781
|
+
const edmxResult = edmToCsn.csn2edmAll(csn, options);
|
|
782
782
|
for (const service in edmxResult)
|
|
783
783
|
edmxResult[service] = edmxResult[service].toXML('all');
|
|
784
784
|
timetrace.timetrace.stop('EDMX all rendering');
|
|
@@ -798,7 +798,7 @@ function preparedCsnToEdm( csn, service, options ) {
|
|
|
798
798
|
timetrace.timetrace.start('EDM rendering');
|
|
799
799
|
// Override OData version as edm json is always v4
|
|
800
800
|
options.odataVersion = 'v4';
|
|
801
|
-
const e = csn2edm(csn, service, options)?.toJSON();
|
|
801
|
+
const e = edmToCsn.csn2edm(csn, service, options)?.toJSON();
|
|
802
802
|
timetrace.timetrace.stop('EDM rendering');
|
|
803
803
|
return { edmj: e };
|
|
804
804
|
}
|
|
@@ -815,7 +815,7 @@ function preparedCsnToEdmAll( csn, options ) {
|
|
|
815
815
|
timetrace.timetrace.start('EDM all rendering');
|
|
816
816
|
// Override OData version as edm json is always v4
|
|
817
817
|
options.odataVersion = 'v4';
|
|
818
|
-
const edmj = csn2edmAll(csn, options);
|
|
818
|
+
const edmj = edmToCsn.csn2edmAll(csn, options);
|
|
819
819
|
for (const service in edmj)
|
|
820
820
|
edmj[service] = edmj[service].toJSON();
|
|
821
821
|
timetrace.timetrace.stop('EDM all rendering');
|
|
@@ -897,8 +897,7 @@ function publishCsnProcessor( processor, _name ) {
|
|
|
897
897
|
checkRemovedDeprecatedFlags( options, messageFunctions );
|
|
898
898
|
|
|
899
899
|
checkOutdatedOptions( options, messageFunctions );
|
|
900
|
-
|
|
901
|
-
|
|
900
|
+
csn = ensureClientCsn( csn, options, messageFunctions, _name );
|
|
902
901
|
messageFunctions.throwWithError();
|
|
903
902
|
|
|
904
903
|
timetrace.timetrace.start(_name);
|
|
@@ -912,7 +911,7 @@ function publishCsnProcessor( processor, _name ) {
|
|
|
912
911
|
throw err;
|
|
913
912
|
|
|
914
913
|
if (options.testMode && !(err instanceof TypeError) &&
|
|
915
|
-
!(err instanceof ModelError))
|
|
914
|
+
!(err instanceof baseError.ModelError))
|
|
916
915
|
throw err;
|
|
917
916
|
|
|
918
917
|
const { info } = messages.makeMessageFunction( csn, options, 'compile' );
|
|
@@ -981,6 +980,12 @@ function checkOutdatedOptions( options, messageFunctions ) {
|
|
|
981
980
|
* Checks that the given CSN is usable by our backends, e.g. that
|
|
982
981
|
* the CSN is not a gensrc (a.k.a. xtended) for most backends.
|
|
983
982
|
*
|
|
983
|
+
* Returns the input CSN if it is acceptable or compiles the input CSN if it does not
|
|
984
|
+
* have the expected CSN flavor.
|
|
985
|
+
*
|
|
986
|
+
* The compiler does not set any marker in `meta`; we use the umbrella one
|
|
987
|
+
* for easier debugging.
|
|
988
|
+
*
|
|
984
989
|
* For reference, cds-compiler/cds-dk CSN flavor map:
|
|
985
990
|
* - client -> inferred
|
|
986
991
|
* - gensrc -> xtended
|
|
@@ -989,23 +994,39 @@ function checkOutdatedOptions( options, messageFunctions ) {
|
|
|
989
994
|
* If this function becomes more complex (e.g. more module conditions),
|
|
990
995
|
* move it from then generic api wrapper to the individual module.
|
|
991
996
|
*
|
|
992
|
-
* TODO: The compiler does not set any marker in `meta`; we use the umbrella one
|
|
993
|
-
* for easier debugging.
|
|
994
|
-
*
|
|
995
997
|
* @param {CSN.Model} csn User CSN
|
|
996
998
|
* @param {CSN.Options} options User options
|
|
997
999
|
* @param {object} messageFunctions Functions returned by makeMessageFunction()
|
|
998
1000
|
* @param {string} module Backend module, e.g. to.cdl or to.sql
|
|
1001
|
+
* @returns {CSN.Model} CSN that works for backends.
|
|
999
1002
|
*/
|
|
1000
|
-
function
|
|
1003
|
+
function ensureClientCsn( csn, options, messageFunctions, module ) {
|
|
1001
1004
|
if (module === 'to.cdl' || !csn)
|
|
1002
|
-
return; // to.cdl allows every CSN flavor
|
|
1005
|
+
return csn; // to.cdl allows every CSN flavor
|
|
1003
1006
|
|
|
1004
1007
|
if (csn.meta?.flavor === 'xtended') {
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
+
messageFunctions.error('api-unsupported-csn-flavor', null, { name: module, option: csn.meta?.flavor });
|
|
1009
|
+
return csn;
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
// `parsed` CSN is allowed if it can be compiled (i.e. no `requires`).
|
|
1013
|
+
// Still return false, because it's not client CSN. The caller must handle it.
|
|
1014
|
+
if (csn.meta?.flavor === 'parsed') {
|
|
1015
|
+
if (csn.requires?.length > 0) {
|
|
1016
|
+
messageFunctions.error('api-unsupported-csn-flavor', null, {
|
|
1017
|
+
'#': 'parsed-requires',
|
|
1018
|
+
name: module,
|
|
1019
|
+
prop: 'requires',
|
|
1020
|
+
});
|
|
1021
|
+
return csn;
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
// TODO: next line to be replaced by CSN parser call which reads the CSN object once the two API files are merged.
|
|
1025
|
+
const xsn = compiler.recompileX(csn, options);
|
|
1026
|
+
return toCsn.compactModel(xsn);
|
|
1008
1027
|
}
|
|
1028
|
+
|
|
1029
|
+
return csn;
|
|
1009
1030
|
}
|
|
1010
1031
|
|
|
1011
1032
|
/**
|
package/lib/api/options.js
CHANGED
|
@@ -31,6 +31,7 @@ const publicOptionsNewAPI = [
|
|
|
31
31
|
'generatedByComment',
|
|
32
32
|
'betterSqliteSessionVariables',
|
|
33
33
|
'fewerLocalizedViews',
|
|
34
|
+
'withHanaAssociations',
|
|
34
35
|
// ODATA
|
|
35
36
|
'odataOpenapiHints',
|
|
36
37
|
'odataVersion',
|
|
@@ -42,7 +43,6 @@ const publicOptionsNewAPI = [
|
|
|
42
43
|
'odataXServiceRefs',
|
|
43
44
|
'odataV2PartialConstr',
|
|
44
45
|
'odataVocabularies',
|
|
45
|
-
'odataOpenType',
|
|
46
46
|
'service',
|
|
47
47
|
'serviceNames',
|
|
48
48
|
//
|
|
@@ -77,9 +77,9 @@ const overallOptions = publicOptionsNewAPI.concat(privateOptions);
|
|
|
77
77
|
* Apply defaults and make sure that the "hard requirements" are met,
|
|
78
78
|
* i.e. src: sql if to.sql() was called.
|
|
79
79
|
*
|
|
80
|
-
* @param {FlatOptions} [input
|
|
81
|
-
* @param {FlatOptions} [defaults
|
|
82
|
-
* @param {FlatOptions} [hardRequire
|
|
80
|
+
* @param {FlatOptions} [input] Input options
|
|
81
|
+
* @param {FlatOptions} [defaults] Default options to apply
|
|
82
|
+
* @param {FlatOptions} [hardRequire] Hard requirements to enforce
|
|
83
83
|
* @param {object} [customValidators] Custom validations to run instead of defaults
|
|
84
84
|
* @param {string[]} [combinationValidators] Option combinations to validate
|
|
85
85
|
* @param {string} moduleName The called module, e.g. 'for.odata', 'to.hdi'. Needed to initialize the message functions
|
|
@@ -127,14 +127,18 @@ module.exports = {
|
|
|
127
127
|
cdl: options => translateOptions(options, undefined, undefined, undefined, undefined, 'to.cdl'),
|
|
128
128
|
sql: (options) => {
|
|
129
129
|
const hardOptions = { src: 'sql', toSql: true, forHana: true };
|
|
130
|
-
const defaultOptions = {
|
|
130
|
+
const defaultOptions = {
|
|
131
|
+
sqlMapping: 'plain', sqlDialect: 'plain', generatedByComment: true, withHanaAssociations: true,
|
|
132
|
+
};
|
|
131
133
|
const processed = translateOptions(options, defaultOptions, hardOptions, undefined, [ 'sql-dialect-and-naming' ], 'to.sql');
|
|
132
134
|
|
|
133
135
|
return Object.assign({}, processed);
|
|
134
136
|
},
|
|
135
137
|
hdi: (options) => {
|
|
136
138
|
const hardOptions = { src: 'hdi', toSql: true, forHana: true };
|
|
137
|
-
const defaultOptions = {
|
|
139
|
+
const defaultOptions = {
|
|
140
|
+
sqlMapping: 'plain', sqlDialect: 'hana', generatedByComment: false, withHanaAssociations: true,
|
|
141
|
+
};
|
|
138
142
|
return translateOptions(options, defaultOptions, hardOptions, { sqlDialect: generateStringValidator([ 'hana' ]) }, undefined, 'to.hdi');
|
|
139
143
|
},
|
|
140
144
|
hdbcds: (options) => {
|
package/lib/api/validate.js
CHANGED
|
@@ -141,7 +141,7 @@ const allCombinationValidators = {
|
|
|
141
141
|
message.error('api-invalid-combination', null, { '#': 'sql-dialect-and-naming', name: options.sqlDialect, prop: options.sqlMapping });
|
|
142
142
|
},
|
|
143
143
|
'sql-dialect-and-localized': (options, message) => {
|
|
144
|
-
if (options.fewerLocalizedViews && options.sqlDialect === 'hana')
|
|
144
|
+
if (options.fewerLocalizedViews && options.sqlDialect === 'hana' && (options.withHanaAssociations || options.withHanaAssociations === undefined))
|
|
145
145
|
message.error('api-invalid-combination', null, { '#': 'sql-dialect-and-localized', option: 'fewerLocalizedViews', value: 'hana' });
|
|
146
146
|
},
|
|
147
147
|
'beta-no-test': (options, message) => {
|
|
@@ -121,12 +121,12 @@ const centralMessages = {
|
|
|
121
121
|
'ref-undefined-def': { severity: 'Error' },
|
|
122
122
|
'ref-undefined-var': { severity: 'Error' },
|
|
123
123
|
'ref-undefined-element': { severity: 'Error' },
|
|
124
|
-
'anno-undefined-element': { severity: '
|
|
124
|
+
'anno-undefined-element': { severity: 'Error' },
|
|
125
125
|
'ref-unknown-var': { severity: 'Info', errorFor: [ 'to.hdbcds', 'to.sql', 'to.hdi', 'to.rename' ] },
|
|
126
126
|
'ref-obsolete-parameters': { severity: 'Error', configurableFor: 'v4' },
|
|
127
127
|
// does not hurt us, but makes it tedious to detect parameter refs
|
|
128
128
|
'ref-undefined-param': { severity: 'Error' },
|
|
129
|
-
'anno-undefined-param': { severity: '
|
|
129
|
+
'anno-undefined-param': { severity: 'Error' },
|
|
130
130
|
'ref-rejected-on': { severity: 'Error' },
|
|
131
131
|
'ref-expected-element': { severity: 'Error' },
|
|
132
132
|
|
|
@@ -259,6 +259,10 @@ const centralMessageTexts = {
|
|
|
259
259
|
slash: 'Expected directory $(VALUE) in option $(OPTION) to end with $(OTHERVALUE)',
|
|
260
260
|
relative: 'Expected directory $(VALUE) in option $(OPTION) to not start with $(OTHERVALUE)',
|
|
261
261
|
},
|
|
262
|
+
'api-unsupported-csn-flavor': {
|
|
263
|
+
std: 'Module $(NAME) expects a client/inferred CSN, not $(OPTION)',
|
|
264
|
+
'parsed-requires': 'Module $(NAME) expects a client/inferred CSN, or a parsed CSN without dependencies, but found $(PROP) property',
|
|
265
|
+
},
|
|
262
266
|
|
|
263
267
|
'anno-duplicate': {
|
|
264
268
|
std: 'Duplicate assignment with $(ANNO)',
|
|
@@ -281,6 +285,11 @@ const centralMessageTexts = {
|
|
|
281
285
|
view: 'Compiler generated view $(NAME) must not be annotated with $(ANNO) if $(ART) is not skipped',
|
|
282
286
|
},
|
|
283
287
|
|
|
288
|
+
'anno-missing-rewrite': {
|
|
289
|
+
std: 'Assign a value for $(ANNO), the value inherited from $(ART) would contain invalid references like $(ELEMREF)',
|
|
290
|
+
unrelated: 'Assign a value for $(ANNO), the value inherited from $(ART) would contain references like $(ELEMREF) to unrelated elements',
|
|
291
|
+
},
|
|
292
|
+
|
|
284
293
|
'chained-array-of': '"Array of"/"many" must not be chained with another "array of"/"many" inside a service',
|
|
285
294
|
|
|
286
295
|
'check-proper-type-of': {
|
|
@@ -326,6 +335,9 @@ const centralMessageTexts = {
|
|
|
326
335
|
csn: 'Expecting a non-negative integer for property $(PROP)',
|
|
327
336
|
'or-asterisk': 'Expecting a non-negative integer or string $(OP) for property $(PROP)',
|
|
328
337
|
},
|
|
338
|
+
'syntax-ignoring-decimal': {
|
|
339
|
+
std: 'Ignoring decimal places, because an integer was expected'
|
|
340
|
+
},
|
|
329
341
|
'syntax-ignoring-anno': {
|
|
330
342
|
std: 'Annotations can\'t be used in a column with $(CODE)',
|
|
331
343
|
doc: 'Doc comments can\'t be used in a column with $(CODE)',
|
|
@@ -614,6 +626,7 @@ const centralMessageTexts = {
|
|
|
614
626
|
self: 'A reference to an unmanaged association is only valid when compared via $(CODE)',
|
|
615
627
|
expr: 'Associations can\'t be used as values in expressions',
|
|
616
628
|
'expr-comp': 'Compositions can\'t be used as values in expressions',
|
|
629
|
+
'assoc-stored': 'Associations and compositions can\'t be used as values in stored calculated elements',
|
|
617
630
|
cast: 'Casting to an association is not supported',
|
|
618
631
|
|
|
619
632
|
'managed-filter': 'Unexpected managed association $(NAME) in filter expression of $(ID)',
|
|
@@ -649,6 +662,10 @@ const centralMessageTexts = {
|
|
|
649
662
|
|
|
650
663
|
// TODO: Better text ?
|
|
651
664
|
'rewrite-not-supported': 'The ON-condition is not rewritten here - provide an explicit ON-condition',
|
|
665
|
+
'type-unsupported-rewrite': {
|
|
666
|
+
std: 'Rewriting the ON-condition not supported here', // unused: merge with 'rewrite-not-supported'
|
|
667
|
+
'sub-element': 'Rewriting the ON-condition of unmanaged association in sub element is not supported'
|
|
668
|
+
},
|
|
652
669
|
|
|
653
670
|
'type-unexpected-typeof': {
|
|
654
671
|
std: 'Unexpected $(KEYWORD) for the type reference here',
|
|
@@ -837,7 +854,11 @@ const centralMessageTexts = {
|
|
|
837
854
|
},
|
|
838
855
|
// TODO: text variant if the association does not start an entity
|
|
839
856
|
'ref-invalid-source': 'A query source must be an entity or an association',
|
|
840
|
-
'extend-columns':
|
|
857
|
+
'extend-columns': {
|
|
858
|
+
std: 'Artifact $(ART) can\'t be extended with columns, only simple views/projections without JOINs and UNIONs can',
|
|
859
|
+
join: 'Artifact $(ART) can\'t be extended with columns, because it contains a JOIN',
|
|
860
|
+
union: 'Artifact $(ART) can\'t be extended with columns, because it contains a UNION',
|
|
861
|
+
},
|
|
841
862
|
'extend-repeated-intralayer': 'Unstable element order due to repeated extensions in same layer',
|
|
842
863
|
'extend-unexpected-include': 'Can\'t extend $(META) with includes',
|
|
843
864
|
|
|
@@ -1018,6 +1039,7 @@ const centralMessageTexts = {
|
|
|
1018
1039
|
},
|
|
1019
1040
|
'odata-parameter-order': 'Unexpected mandatory after optional parameter',
|
|
1020
1041
|
'odata-key-recursive': 'Unexpected recursive key $(NAME)',
|
|
1042
|
+
'odata-key-uuid-default-anno': 'Expected element of type $(TYPE) to be annotated with $(ANNO) when used as primary key in $(ID)',
|
|
1021
1043
|
// -----------------------------------------------------------------------------------
|
|
1022
1044
|
// All odata-anno MUST have a '$(ANNO)' parameter to indicate error location
|
|
1023
1045
|
// -----------------------------------------------------------------------------------
|
|
@@ -1026,7 +1048,7 @@ const centralMessageTexts = {
|
|
|
1026
1048
|
'odata-anno-preproc': {
|
|
1027
1049
|
'std': 'unused message text',
|
|
1028
1050
|
'nokey': 'Expected target $(NAME) to have a key element for $(ANNO)',
|
|
1029
|
-
'multkeys': 'Expected target $(NAME) to have only one key element',
|
|
1051
|
+
'multkeys': 'Expected target $(NAME) to have only one key element for $(ANNO)',
|
|
1030
1052
|
'vhlnokey': 'Expected value help list entity $(NAME) to have a key element for $(ANNO)',
|
|
1031
1053
|
'vhlmultkeys': 'Expected value help list entity $(NAME) to have only one key element for $(ANNO)',
|
|
1032
1054
|
'notforentity': 'Unexpected usage of $(ANNO) for an entity',
|
|
@@ -1034,8 +1056,8 @@ const centralMessageTexts = {
|
|
|
1034
1056
|
'noassoc': 'Expected association $(ID) to exist for $(ANNO)',
|
|
1035
1057
|
'vallistignored': '$(NAME) is ignored for $(ANNO) as $(CODE) is present',
|
|
1036
1058
|
'notastring': 'Expected value to be a string for $(ANNO)',
|
|
1037
|
-
'notexist': '
|
|
1038
|
-
'txtarr': '
|
|
1059
|
+
'notexist': 'Expected entity $(ID) to exist for $(ANNO)',
|
|
1060
|
+
'txtarr': 'Expected $(ANNO) shortcut to have a $(NAME) annotation'
|
|
1039
1061
|
},
|
|
1040
1062
|
// -----------------------------------------------------------------------------------
|
|
1041
1063
|
// GenericTranslation:
|