@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.
Files changed (60) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/bin/cdsc.js +5 -0
  3. package/bin/cdsv2m.js +7 -5
  4. package/doc/CHANGELOG_BETA.md +16 -0
  5. package/lib/api/main.js +68 -47
  6. package/lib/api/options.js +10 -6
  7. package/lib/api/validate.js +1 -1
  8. package/lib/base/message-registry.js +28 -6
  9. package/lib/base/messages.js +18 -13
  10. package/lib/base/model.js +3 -0
  11. package/lib/checks/annotationsOData.js +49 -0
  12. package/lib/checks/validator.js +6 -4
  13. package/lib/compiler/assert-consistency.js +38 -16
  14. package/lib/compiler/builtins.js +10 -49
  15. package/lib/compiler/checks.js +16 -8
  16. package/lib/compiler/cycle-detector.js +1 -4
  17. package/lib/compiler/define.js +4 -1
  18. package/lib/compiler/extend.js +21 -7
  19. package/lib/compiler/generate.js +3 -0
  20. package/lib/compiler/populate.js +5 -1
  21. package/lib/compiler/propagator.js +46 -9
  22. package/lib/compiler/resolve.js +68 -14
  23. package/lib/compiler/shared.js +44 -27
  24. package/lib/compiler/tweak-assocs.js +158 -37
  25. package/lib/compiler/utils.js +9 -0
  26. package/lib/edm/annotations/edmJson.js +35 -61
  27. package/lib/edm/annotations/genericTranslation.js +13 -5
  28. package/lib/edm/annotations/preprocessAnnotations.js +2 -3
  29. package/lib/edm/csn2edm.js +4 -1
  30. package/lib/edm/edmInboundChecks.js +59 -15
  31. package/lib/edm/edmPreprocessor.js +1 -7
  32. package/lib/gen/Dictionary.json +8 -0
  33. package/lib/gen/language.checksum +1 -1
  34. package/lib/gen/language.interp +12 -2
  35. package/lib/gen/languageParser.js +6095 -5195
  36. package/lib/json/from-csn.js +4 -5
  37. package/lib/json/to-csn.js +22 -3
  38. package/lib/language/errorStrategy.js +7 -3
  39. package/lib/language/genericAntlrParser.js +120 -24
  40. package/lib/language/textUtils.js +16 -0
  41. package/lib/model/csnUtils.js +9 -8
  42. package/lib/model/revealInternalProperties.js +5 -2
  43. package/lib/modelCompare/compare.js +10 -4
  44. package/lib/optionProcessor.js +2 -3
  45. package/lib/render/toCdl.js +31 -13
  46. package/lib/render/toHdbcds.js +20 -30
  47. package/lib/render/toSql.js +33 -54
  48. package/lib/render/utils/common.js +24 -6
  49. package/lib/transform/db/applyTransformations.js +59 -2
  50. package/lib/transform/db/backlinks.js +13 -1
  51. package/lib/transform/db/expansion.js +24 -3
  52. package/lib/transform/db/flattening.js +2 -2
  53. package/lib/transform/db/killAnnotations.js +37 -0
  54. package/lib/transform/db/rewriteCalculatedElements.js +46 -6
  55. package/lib/transform/forOdata.js +13 -46
  56. package/lib/transform/forRelationalDB.js +2 -1
  57. package/lib/transform/translateAssocsToJoins.js +13 -4
  58. package/lib/transform/universalCsn/coreComputed.js +1 -1
  59. package/lib/transform/universalCsn/universalCsnEnricher.js +4 -4
  60. 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 from compiler
6
- // v1 to v2. (If our client command processor would have been not as difficult
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
- console.log( `annotate ${name} with @cds.redirection.target: false;`);
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
  }
@@ -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=[]] Option names that should be attached as a fyi
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={}] 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={}] 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={}] 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={}] 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={}] 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={}] 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={}] 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={}] 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={}] 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={}] 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={}] 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={}] 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
- checkCsnFlavor( csn, options, messageFunctions, _name );
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 checkCsnFlavor( csn, options, messageFunctions, module ) {
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
- // TODO: csn.meta?.flavor === 'parsed'; currently used by `@sap/cds` tests.
1006
- messageFunctions.error('api-unsupported-csn-flavor', null, { name: module, option: csn.meta?.flavor },
1007
- 'Module $(NAME) expects a client/inferred CSN, not $(OPTION)');
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
  /**
@@ -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={}] Input options
81
- * @param {FlatOptions} [defaults={}] Default options to apply
82
- * @param {FlatOptions} [hardRequire={}] Hard requirements to enforce
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 = { sqlMapping: 'plain', sqlDialect: 'plain', generatedByComment: true };
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 = { sqlMapping: 'plain', sqlDialect: 'hana', generatedByComment: false };
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) => {
@@ -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: 'Warning' },
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: 'Warning' },
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': 'Artifact $(ART) can\'t be extended with columns, only projections can',
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': 'Expect entity $(ID) to exist for $(ANNO)',
1038
- 'txtarr': 'Expect $(ANNO) shortcut to have a $(NAME) annotation'
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: