@sap/cds-compiler 2.13.8 → 3.0.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 (127) hide show
  1. package/CHANGELOG.md +155 -1594
  2. package/bin/cdsc.js +144 -66
  3. package/doc/CHANGELOG_ARCHIVE.md +1592 -0
  4. package/doc/CHANGELOG_BETA.md +3 -4
  5. package/doc/CHANGELOG_DEPRECATED.md +35 -1
  6. package/doc/{DeprecatedOptions.md → DeprecatedOptions_v2.md} +3 -1
  7. package/doc/Versioning.md +20 -1
  8. package/lib/api/.eslintrc.json +2 -2
  9. package/lib/api/main.js +237 -122
  10. package/lib/api/options.js +17 -88
  11. package/lib/api/validate.js +12 -16
  12. package/lib/base/keywords.js +216 -109
  13. package/lib/base/message-registry.js +152 -37
  14. package/lib/base/messages.js +145 -83
  15. package/lib/base/model.js +44 -2
  16. package/lib/base/optionProcessorHelper.js +19 -0
  17. package/lib/checks/actionsFunctions.js +7 -5
  18. package/lib/checks/annotationsOData.js +11 -32
  19. package/lib/checks/arrayOfs.js +1 -34
  20. package/lib/checks/cdsPersistence.js +1 -0
  21. package/lib/checks/elements.js +6 -6
  22. package/lib/checks/invalidTarget.js +1 -1
  23. package/lib/checks/nonexpandableStructured.js +1 -1
  24. package/lib/checks/queryNoDbArtifacts.js +2 -1
  25. package/lib/checks/selectItems.js +5 -1
  26. package/lib/checks/types.js +4 -2
  27. package/lib/checks/utils.js +2 -2
  28. package/lib/checks/validator.js +4 -5
  29. package/lib/compiler/assert-consistency.js +16 -10
  30. package/lib/compiler/base.js +1 -0
  31. package/lib/compiler/builtins.js +98 -9
  32. package/lib/compiler/checks.js +22 -70
  33. package/lib/compiler/define.js +61 -13
  34. package/lib/compiler/extend.js +79 -14
  35. package/lib/compiler/finalize-parse-cdl.js +46 -29
  36. package/lib/compiler/index.js +100 -37
  37. package/lib/compiler/moduleLayers.js +7 -0
  38. package/lib/compiler/populate.js +19 -18
  39. package/lib/compiler/propagator.js +7 -4
  40. package/lib/compiler/resolve.js +297 -234
  41. package/lib/compiler/shared.js +107 -102
  42. package/lib/compiler/tweak-assocs.js +16 -11
  43. package/lib/compiler/utils.js +5 -0
  44. package/lib/edm/annotations/genericTranslation.js +93 -21
  45. package/lib/edm/csn2edm.js +230 -115
  46. package/lib/edm/edm.js +305 -226
  47. package/lib/edm/edmPreprocessor.js +509 -438
  48. package/lib/edm/edmUtils.js +31 -45
  49. package/lib/gen/Dictionary.json +98 -22
  50. package/lib/gen/language.checksum +1 -1
  51. package/lib/gen/language.interp +10 -30
  52. package/lib/gen/language.tokens +105 -114
  53. package/lib/gen/languageLexer.interp +1 -34
  54. package/lib/gen/languageLexer.js +889 -1007
  55. package/lib/gen/languageLexer.tokens +95 -106
  56. package/lib/gen/languageParser.js +20786 -22199
  57. package/lib/json/csnVersion.js +10 -11
  58. package/lib/json/from-csn.js +59 -51
  59. package/lib/json/to-csn.js +10 -10
  60. package/lib/language/antlrParser.js +2 -2
  61. package/lib/language/docCommentParser.js +62 -39
  62. package/lib/language/errorStrategy.js +52 -40
  63. package/lib/language/genericAntlrParser.js +348 -229
  64. package/lib/language/language.g4 +629 -653
  65. package/lib/language/multiLineStringParser.js +14 -42
  66. package/lib/language/textUtils.js +44 -0
  67. package/lib/main.d.ts +46 -43
  68. package/lib/main.js +108 -79
  69. package/lib/model/csnRefs.js +34 -7
  70. package/lib/model/csnUtils.js +337 -332
  71. package/lib/model/enrichCsn.js +1 -0
  72. package/lib/model/revealInternalProperties.js +30 -10
  73. package/lib/model/sortViews.js +32 -31
  74. package/lib/modelCompare/compare.js +6 -6
  75. package/lib/optionProcessor.js +73 -46
  76. package/lib/render/.eslintrc.json +1 -1
  77. package/lib/render/DuplicateChecker.js +4 -7
  78. package/lib/render/manageConstraints.js +70 -2
  79. package/lib/render/toCdl.js +1042 -882
  80. package/lib/render/toHdbcds.js +195 -245
  81. package/lib/render/toRename.js +44 -22
  82. package/lib/render/toSql.js +225 -241
  83. package/lib/render/utils/common.js +145 -15
  84. package/lib/render/utils/sql.js +20 -19
  85. package/lib/sql-identifier.js +6 -0
  86. package/lib/transform/db/.eslintrc.json +4 -3
  87. package/lib/transform/db/associations.js +2 -2
  88. package/lib/transform/db/cdsPersistence.js +5 -15
  89. package/lib/transform/db/constraints.js +4 -2
  90. package/lib/transform/db/expansion.js +22 -16
  91. package/lib/transform/db/flattening.js +109 -80
  92. package/lib/transform/db/transformExists.js +7 -7
  93. package/lib/transform/db/views.js +9 -6
  94. package/lib/transform/draft/.eslintrc.json +2 -2
  95. package/lib/transform/draft/db.js +6 -6
  96. package/lib/transform/draft/odata.js +6 -7
  97. package/lib/transform/forHanaNew.js +62 -48
  98. package/lib/transform/forOdataNew.js +49 -50
  99. package/lib/transform/localized.js +31 -20
  100. package/lib/transform/odata/toFinalBaseType.js +16 -14
  101. package/lib/transform/odata/typesExposure.js +146 -198
  102. package/lib/transform/odata/utils.js +1 -38
  103. package/lib/transform/transformUtilsNew.js +67 -84
  104. package/lib/transform/translateAssocsToJoins.js +7 -3
  105. package/lib/transform/universalCsn/.eslintrc.json +2 -2
  106. package/lib/transform/universalCsn/coreComputed.js +16 -9
  107. package/lib/transform/universalCsn/universalCsnEnricher.js +60 -10
  108. package/lib/utils/file.js +3 -3
  109. package/lib/utils/moduleResolve.js +13 -6
  110. package/lib/utils/timetrace.js +20 -21
  111. package/package.json +35 -4
  112. package/share/messages/message-explanations.json +2 -1
  113. package/share/messages/syntax-expected-integer.md +37 -0
  114. package/doc/ApiMigration.md +0 -237
  115. package/doc/CommandLineMigration.md +0 -58
  116. package/doc/ErrorMessages.md +0 -175
  117. package/doc/FioriAnnotations.md +0 -94
  118. package/doc/ODataTransformation.md +0 -273
  119. package/lib/backends.js +0 -529
  120. package/lib/fix_antlr4-8_warning.js +0 -56
  121. package/lib/transform/odata/attachPath.js +0 -96
  122. package/lib/transform/odata/expandStructKeysInAssociations.js +0 -59
  123. package/lib/transform/odata/generateForeignKeyElements.js +0 -261
  124. package/lib/transform/odata/referenceFlattener.js +0 -296
  125. package/lib/transform/odata/sortByAssociationDependency.js +0 -105
  126. package/lib/transform/odata/structuralPath.js +0 -72
  127. package/lib/transform/odata/structureFlattener.js +0 -171
@@ -152,6 +152,7 @@ function enrichCsn( csn, options = {} ) {
152
152
  else { // targetAspect, target
153
153
  csnPath.push( prop );
154
154
  dictionary( ref, 'elements', ref.elements );
155
+ _cache_debug( ref );
155
156
  csnPath.pop();
156
157
  }
157
158
  // } catch (e) {
@@ -14,6 +14,7 @@
14
14
  const msg = require('../base/messages');
15
15
 
16
16
  const $inferred = Symbol.for('cds.$inferred');
17
+ const $location = Symbol.for('cds.$location');
17
18
 
18
19
  class NOT_A_DICTIONARY {} // used for consol.log display
19
20
 
@@ -36,7 +37,7 @@ const kindsRepresentedAsLinks = {
36
37
  // represent table alias in from / join-args property as link:
37
38
  $tableAlias: tableAliasAsLink,
38
39
  // represent "navigation elemens" in _combined as links:
39
- $navElement: (art, parent) => art._parent && parent !== art._parent.elements,
40
+ $navElement: (art, parent) => art._parent && parent !== art._parent.elements && art._parent.kind !== 'aspect',
40
41
  // represent mixin in $tableAliases as link:
41
42
  mixin: tableAliasAsLink,
42
43
  // represent $projection as link, as it is just another search name for $self:
@@ -96,6 +97,7 @@ function revealInternalProperties( model, nameOrPath ) {
96
97
  _annotate: reveal,
97
98
  _deps: dependencyInfo,
98
99
  _status: primOrString, // is a string anyway
100
+ $annotations: as => as.map( $annotation ),
99
101
  $messageFunctions: () => '‹some functions›',
100
102
  }
101
103
  unique_id = 1;
@@ -129,7 +131,7 @@ function revealInternalProperties( model, nameOrPath ) {
129
131
 
130
132
  path = path.split('/');
131
133
  if (path.length === 1) {
132
- return reveal( xsn.definitions[path] );
134
+ return reveal( xsn.definitions[path] || xsn.vocabularies && xsn.vocabularies[path] );
133
135
  }
134
136
 
135
137
  // with the code below, we might miss the right transformer function
@@ -149,7 +151,7 @@ function revealInternalProperties( model, nameOrPath ) {
149
151
 
150
152
  function shortenName( node, parent ) {
151
153
  const name = reveal( node, parent );
152
- if (name && typeof name === 'object' && name.absolute) {
154
+ if (name && typeof name === 'object' && name.absolute && node.kind) {
153
155
  const text = artifactIdentifier( parent );
154
156
  delete name.absolute;
155
157
  delete name.select;
@@ -178,11 +180,20 @@ function revealInternalProperties( model, nameOrPath ) {
178
180
  return r;
179
181
  }
180
182
 
183
+ function $annotation( anno ) { // property for cds-lsp
184
+ const { name, $flatten } = anno.value || anno;
185
+ const value = ($flatten)
186
+ ? { name: reveal( name ), $flatten: $flatten.map( $annotation ) }
187
+ : `@${name?.absolute}`;
188
+ return { value, location: locationString( anno.location || anno.name.location ) };
189
+ }
190
+
181
191
  function columns( nodes, query ) {
182
192
  // If we will have specified elements, we need another test to see columns in --parse-cdl
183
- return nodes && nodes.map( c => (c._parent && c._parent.elements)
184
- ? artifactIdentifier( c, query )
185
- : reveal( c, nodes ) );
193
+ return nodes && array( nodes,
194
+ c => (c._parent && c._parent.elements)
195
+ ? artifactIdentifier( c, query )
196
+ : reveal( c, nodes ) );
186
197
  }
187
198
 
188
199
  function elements( dict, parent ) {
@@ -215,7 +226,7 @@ function revealInternalProperties( model, nameOrPath ) {
215
226
  if (!node || typeof node !== 'object')
216
227
  return primOrString( node );
217
228
  if (Array.isArray(node)) // with args
218
- return node.map( n => reveal( n, node ) );
229
+ return array( node, reveal );
219
230
  // Make unexpected prototype visible with node-10+:
220
231
  const r = Object.create( Object.getPrototypeOf(node)
221
232
  ? NOT_A_DICTIONARY.prototype
@@ -225,6 +236,8 @@ function revealInternalProperties( model, nameOrPath ) {
225
236
  }
226
237
  if (node[$inferred] && !node['[$inferred]'])
227
238
  r['[$inferred]'] = node[$inferred];
239
+ if (node[$location] && !node['[$location]'])
240
+ r['[$location]'] = locationString( node[$location] );
228
241
  return r;
229
242
  }
230
243
 
@@ -239,7 +252,7 @@ function revealInternalProperties( model, nameOrPath ) {
239
252
  if (node == null || typeof node !== 'object' )
240
253
  return primOrString( node );
241
254
  if (Array.isArray(node))
242
- return node.map( n => revealNonEnum( n, node ) );
255
+ return array( node, revealNonEnum );
243
256
 
244
257
  if (Object.getPrototypeOf( node ))
245
258
  return artifactIdentifier( node, parent );
@@ -250,7 +263,7 @@ function revealInternalProperties( model, nameOrPath ) {
250
263
  if (node == null || typeof node !== 'object' )
251
264
  return node
252
265
  if (Array.isArray(node))
253
- return node.map( n => reveal( n, node, name ) );
266
+ return array( node, n => reveal( n, node, name ) );
254
267
 
255
268
  const asLinkTest = kindsRepresentedAsLinks[ node.kind ];
256
269
  if (asLinkTest && asLinkTest( node, parent, name ))
@@ -280,6 +293,13 @@ function revealInternalProperties( model, nameOrPath ) {
280
293
  }
281
294
  }
282
295
 
296
+ function array( node, fn ) {
297
+ const r = node.map( n => fn( n, node ) );
298
+ if (node[$location])
299
+ r.push( { $location: locationString( node[$location] ) } );
300
+ return r;
301
+ }
302
+
283
303
  function artifactIdentifier( node, parent ) {
284
304
  if (Array.isArray(node))
285
305
  return node.map( a => artifactIdentifier( a, node ) );
@@ -335,7 +355,7 @@ function primOrString( node ) {
335
355
  if (node == null || typeof node !== 'object')
336
356
  return node
337
357
  if (Array.isArray(node))
338
- return node.map( primOrString );
358
+ return array( node, primOrString );
339
359
  if (Object.getPrototypeOf( node ))
340
360
  return '' + node;
341
361
  else
@@ -21,7 +21,7 @@ const { ModelError } = require("../base/error");
21
21
  */
22
22
  function sortTopologically(csn, _dependents, _dependencies){
23
23
  const layers = [];
24
- let { zero, nonZero } = calculateDepth(Object.entries(csn.definitions));
24
+ let { zero, nonZero } = _calculateDepth(Object.entries(csn.definitions), _dependents, _dependencies);
25
25
  while (zero.length !== 0){
26
26
  const currentLayer = [];
27
27
  zero.forEach(([artifactName, artifact]) => {
@@ -34,46 +34,46 @@ function sortTopologically(csn, _dependents, _dependencies){
34
34
  }
35
35
  });
36
36
  layers.push(currentLayer);
37
- ({zero, nonZero} = findWithXPointers(nonZero, 0));
37
+ ({zero, nonZero} = _findWithXPointers(nonZero, 0, _dependents, _dependencies));
38
38
  }
39
39
 
40
40
  return { layers, leftover: nonZero };
41
+ }
41
42
 
42
- function calculateDepth(definitionsArray) {
43
- const zero = [];
44
- const nonZero = [];
43
+ function _calculateDepth(definitionsArray, _dependents, _dependencies) {
44
+ const zero = [];
45
+ const nonZero = [];
45
46
 
46
- definitionsArray.forEach(([artifactName, artifact]) => {
47
- if(artifact[_dependencies]) {
48
- artifact.$pointers = artifact[_dependencies].size;
49
- nonZero.push([artifactName, artifact]);
50
- } else {
51
- artifact.$pointers = 0;
52
- zero.push([artifactName, artifact]);
53
- }
54
- });
55
- return {
56
- zero,
57
- nonZero
47
+ definitionsArray.forEach(([artifactName, artifact]) => {
48
+ if(artifact[_dependencies]) {
49
+ artifact.$pointers = artifact[_dependencies].size;
50
+ nonZero.push([artifactName, artifact]);
51
+ } else {
52
+ artifact.$pointers = 0;
53
+ zero.push([artifactName, artifact]);
58
54
  }
55
+ });
56
+ return {
57
+ zero,
58
+ nonZero
59
59
  }
60
+ }
60
61
 
61
- function findWithXPointers(definitionsArray, x=0){
62
- const zero = [];
63
- const nonZero = [];
64
-
65
- definitionsArray.forEach(([artifactName, artifact]) => {
66
- if(artifact.$pointers !== undefined && artifact.$pointers === x) {
67
- zero.push([artifactName, artifact]);
68
- } else {
69
- nonZero.push([artifactName, artifact]);
70
- }
71
- });
62
+ function _findWithXPointers(definitionsArray, x, _dependents, _dependencies){
63
+ const zero = [];
64
+ const nonZero = [];
72
65
 
73
- return {
74
- zero,
75
- nonZero
66
+ definitionsArray.forEach(([artifactName, artifact]) => {
67
+ if(artifact.$pointers !== undefined && artifact.$pointers === x) {
68
+ zero.push([artifactName, artifact]);
69
+ } else {
70
+ nonZero.push([artifactName, artifact]);
76
71
  }
72
+ });
73
+
74
+ return {
75
+ zero,
76
+ nonZero
77
77
  }
78
78
  }
79
79
 
@@ -83,6 +83,7 @@ function sortTopologically(csn, _dependents, _dependencies){
83
83
  * be run beforehand to resolve association usages.
84
84
  *
85
85
  * @param {object} sql Map of <object name>: "CREATE STATEMENT"
86
+ * @param {CSN.Model} csn
86
87
  *
87
88
  * @returns {{name: string, sql: string}[]} Sorted array of artifact name / "CREATE STATEMENTS" pairs
88
89
  *
@@ -45,19 +45,19 @@ function validateCsnVersions(beforeModel, afterModel, options) {
45
45
  let afterVersionParts = afterVersion && afterVersion.split('.');
46
46
 
47
47
  if (!beforeVersionParts || beforeVersionParts.length < 2) {
48
- const { error, throwWithError } = makeMessageFunction(beforeModel, options, 'modelCompare');
48
+ const { error, throwWithAnyError } = makeMessageFunction(beforeModel, options, 'modelCompare');
49
49
  error(null, null, `Invalid CSN version: ${beforeVersion}`);
50
- throwWithError();
50
+ throwWithAnyError();
51
51
  }
52
52
  if (!afterVersionParts || afterVersionParts.length < 2) {
53
- const { error, throwWithError } = makeMessageFunction(afterModel, options, 'modelCompare');
53
+ const { error, throwWithAnyError } = makeMessageFunction(afterModel, options, 'modelCompare');
54
54
  error(null, null, `Invalid CSN version: ${afterVersion}`);
55
- throwWithError();
55
+ throwWithAnyError();
56
56
  }
57
57
  if (beforeVersionParts[0] > afterVersionParts[0] && !(options && options.allowCsnDowngrade)) {
58
- const { error, throwWithError } = makeMessageFunction(afterModel, options, 'modelCompare');
58
+ const { error, throwWithAnyError } = makeMessageFunction(afterModel, options, 'modelCompare');
59
59
  error(null, null, `Incompatible CSN versions: ${afterVersion} is a major downgrade from ${beforeVersion}. Is @sap/cds-compiler version ${require('../../package.json').version} outdated?`);
60
- throwWithError();
60
+ throwWithAnyError();
61
61
  }
62
62
  }
63
63
 
@@ -11,7 +11,9 @@ const optionProcessor = createOptionProcessor();
11
11
  optionProcessor
12
12
  .option('-h, --help')
13
13
  .option('-v, --version')
14
+ .option(' --options <file>')
14
15
  .option('-w, --warning <level>', ['0', '1', '2', '3'])
16
+ .option(' --quiet')
15
17
  .option(' --show-message-id')
16
18
  .option(' --no-message-context')
17
19
  .option(' --color <mode>', ['auto', 'always', 'never'])
@@ -22,18 +24,16 @@ optionProcessor
22
24
  .option(' --trace-parser')
23
25
  .option(' --trace-parser-amb')
24
26
  .option(' --trace-fs')
27
+ .option(' --error <id-list>')
28
+ .option(' --warn <id-list>')
29
+ .option(' --info <id-list>')
30
+ .option(' --debug <id-list>')
25
31
  .option('-E, --enrich-csn')
26
32
  .option('-R, --raw-output <name>')
27
33
  .option(' --internal-msg')
28
34
  .option(' --beta-mode')
29
35
  .option(' --beta <list>')
30
- .option(' --integrity-not-validated')
31
- .option(' --integrity-not-enforced')
32
- .option(' --assert-integrity <mode>', [ 'true', 'false', 'individual' ])
33
- .option(' --assert-integrity-type <type>', [ 'RT', 'DB' ], { ignoreCase: true })
34
- .option(' --constraints-in-create-table')
35
36
  .option(' --deprecated <list>')
36
- .option(' --hana-flavor')
37
37
  .option(' --direct-backend')
38
38
  .option(' --parse-only')
39
39
  .option(' --fallback-parser <type>', ['cdl', 'csn', 'csn!'])
@@ -59,17 +59,21 @@ optionProcessor
59
59
  General options
60
60
  -h, --help Show this help text
61
61
  -v, --version Display version number and exit
62
+ --quiet Don't emit anything, neither results nor messages.
62
63
  -w, --warning <level> Show messages up to <level>
63
64
  0: Error
64
65
  1: Warnings
65
66
  2: (default) Info
66
67
  3: Debug
68
+ --options <file> Use the given JSON file as input options.
69
+ The key 'cdsc' of 'cds' is used. If not present 'cdsc' is used.
70
+ Otherwise, the JSON as-is is used as options.
67
71
  --show-message-id Show message ID in error, warning and info messages
68
72
  --no-message-context Print messages as single lines without code context (useful for
69
- redirecting output to other processes). Default is to print human
73
+ redirecting output to other processes). Default is to print human-
70
74
  readable text similar to Rust's compiler with a code excerpt.
71
75
  --color <mode> Use colors for warnings. Modes are:
72
- auto: (default) Detect color support of the tty.
76
+ auto: (default) Detect color support of the TTY.
73
77
  always:
74
78
  never:
75
79
  -o, --out <dir> Place generated files in directory <dir>, default is "-" for <stdout>
@@ -87,6 +91,13 @@ optionProcessor
87
91
  --trace-parser-amb Trace parser ambiguities
88
92
  --trace-fs Trace file system access caused by "using from"
89
93
 
94
+ Severity options
95
+ Use these options to reclassify messages. Option argument is a comma separated list of message IDs.
96
+ --error <id-list> IDs that should be reclassified to errors.
97
+ --warn <id-list> IDs that should be reclassified to warnings.
98
+ --info <id-list> IDs that should be reclassified to info messages.
99
+ --debug <id-list> IDs that should be reclassified to debug messages.
100
+
90
101
  Internal options (for testing only, may be changed/removed at any time)
91
102
  -E, --enrich-csn Show non-enumerable CSN properties and locations of references
92
103
  -R, --raw-output <name> Write XSN for definition "name" and error output to <stdout>,
@@ -95,37 +106,12 @@ optionProcessor
95
106
  --beta-mode Enable all unsupported, incomplete (beta) features
96
107
  --beta <list> Comma separated list of unsupported, incomplete (beta) features to use.
97
108
  Valid values are:
98
- addTextsLanguageAssoc
99
109
  hanaAssocRealCardinality
100
110
  mapAssocToJoinCardinality
101
111
  ignoreAssocPublishingInUnion
102
- --integrity-not-enforced If this option is supplied, referential constraints are NOT ENFORCED.
103
- This option is also applied to result of "cdsc manageConstraints"
104
- --integrity-not-validated If this option is supplied, referential constraints are NOT VALIDATED.
105
- This option is also applied to result of "cdsc manageConstraints"
106
- --assert-integrity <mode> Turn DB constraints on/off:
107
- true : (default) Constraints will be generated for all associations if
108
- the assert-integrity-type is set to DB
109
- false : No constraints will be generated
110
- individual : Constraints will be generated for selected associations
111
- --assert-integrity-type <type> Specifies how the referential integrity checks should be performed:
112
- RT : (default) No database constraint for an association
113
- if not explicitly demanded via annotation
114
- DB : Create database constraints for associations
115
- --constraints-in-create-table If set, the foreign key constraints will be rendered as
116
- part of the "CREATE TABLE" statements rather than as separate
117
- "ALTER TABLE ADD CONSTRAINT" statements
118
112
  --deprecated <list> Comma separated list of deprecated options.
119
113
  Valid values are:
120
- noElementsExpansion
121
- v1KeysForTemporal
122
- parensAsStrings
123
- projectionAsQuery
124
- renderVirtualElements
125
- unmanagedUpInComponent
126
- createLocalizedViews
127
- redirectInSubQueries
128
- --hana-flavor Compile with backward compatibility for HANA CDS (incomplete)
114
+ eagerPersistenceForGeneratedEntities
129
115
  --parse-only Stop compilation after parsing and write result to <stdout>
130
116
  --fallback-parser <type> If the language cannot be deduced by the file's extensions, use this
131
117
  parser as a fallback. Valid values are:
@@ -169,6 +155,10 @@ optionProcessor.command('H, toHana')
169
155
  .option('-u, --user <user>')
170
156
  .option('-s, --src')
171
157
  .option('-c, --csn')
158
+ .option(' --integrity-not-validated')
159
+ .option(' --integrity-not-enforced')
160
+ .option(' --assert-integrity <mode>', ['true', 'false', 'individual'])
161
+ .option(' --assert-integrity-type <type>', ['RT', 'DB'], { ignoreCase: true })
172
162
  .help(`
173
163
  Usage: cdsc toHana [options] <files...>
174
164
 
@@ -192,11 +182,22 @@ optionProcessor.command('H, toHana')
192
182
  -u, --user <user> Value for the "$user" variable
193
183
  -s, --src (default) Generate HANA CDS source files "<artifact>.hdbcds"
194
184
  -c, --csn Generate "hana_csn.json" with HANA-preprocessed model
185
+ --integrity-not-enforced If this option is supplied, referential constraints are NOT ENFORCED.
186
+ --integrity-not-validated If this option is supplied, referential constraints are NOT VALIDATED.
187
+ --assert-integrity <mode> Turn DB constraints on/off:
188
+ true : (default) Constraints will be generated for all associations if
189
+ the assert-integrity-type is set to DB
190
+ false : No constraints will be generated
191
+ individual : Constraints will be generated for selected associations
192
+ --assert-integrity-type <type> Specifies how the referential integrity checks should be performed:
193
+ RT : (default) No database constraint for an association
194
+ if not explicitly demanded via annotation
195
+ DB : Create database constraints for associations
195
196
  `);
196
197
 
197
198
  optionProcessor.command('O, toOdata')
198
199
  .option('-h, --help')
199
- .option('-v, --version <version>', ['v2', 'v4', 'v4x'])
200
+ .option('-v, --odata-version <version>', ['v2', 'v4', 'v4x'])
200
201
  .option('-x, --xml')
201
202
  .option('-j, --json')
202
203
  .option(' --odata-containment')
@@ -207,6 +208,7 @@ optionProcessor.command('O, toOdata')
207
208
  .option('-c, --csn')
208
209
  .option('-f, --odata-format <format>', ['flat', 'structured'])
209
210
  .option('-n, --names <style>', ['plain', 'quoted', 'hdbcds'])
211
+ .option('-s, --service-names <list>')
210
212
  .help(`
211
213
  Usage: cdsc toOdata [options] <files...>
212
214
 
@@ -214,10 +216,10 @@ optionProcessor.command('O, toOdata')
214
216
 
215
217
  Options
216
218
  -h, --help Show this help text
217
- -v, --version <version> ODATA version
218
- v2: ODATA V2
219
- v4: (default) ODATA V4
220
- v4x: { version: 'v4', odataContainment:true, format:'structured' }
219
+ -v, --odata-version <version> ODATA version
220
+ v2: ODATA V2
221
+ v4: (default) ODATA V4
222
+ v4x: { version: 'v4', odataContainment:true, format:'structured' }
221
223
  -x, --xml (default) Generate XML output (separate or combined)
222
224
  -j, --json Generate JSON output as "<svc>.json" (not available for v2)
223
225
  -c, --csn Generate "odata_csn.json" with ODATA-preprocessed model
@@ -237,6 +239,8 @@ optionProcessor.command('O, toOdata')
237
239
  but element names flattened with underscores
238
240
  hdbcds : Names as HANA CDS would generate them from the same CDS
239
241
  source (like "quoted", but using element names with dots)
242
+ -s, --service-names <list> List of comma-separated service names to be rendered
243
+ (default) empty, all services are rendered
240
244
  `);
241
245
 
242
246
  optionProcessor.command('C, toCdl')
@@ -255,11 +259,16 @@ optionProcessor.command('Q, toSql')
255
259
  .option('-n, --names <style>', ['plain', 'quoted', 'hdbcds'])
256
260
  .option(' --render-virtual')
257
261
  .option(' --joinfk')
258
- .option('-d, --dialect <dialect>', ['hana', 'sqlite', 'plain'])
262
+ .option('-d, --dialect <dialect>', ['hana', 'sqlite', 'plain', 'postgres'])
259
263
  .option('-u, --user <user>')
260
264
  .option('-l, --locale <locale>')
261
265
  .option('-s, --src <style>', ['sql', 'hdi'])
262
266
  .option('-c, --csn')
267
+ .option(' --integrity-not-validated')
268
+ .option(' --integrity-not-enforced')
269
+ .option(' --assert-integrity <mode>', ['true', 'false', 'individual'])
270
+ .option(' --assert-integrity-type <type>', ['RT', 'DB'], { ignoreCase: true })
271
+ .option(' --constraints-in-create-table')
263
272
  .help(`
264
273
  Usage: cdsc toSql [options] <files...>
265
274
 
@@ -281,9 +290,10 @@ optionProcessor.command('Q, toSql')
281
290
  --render-virtual Render virtual elements in views and draft tables
282
291
  --joinfk Create JOINs for foreign key accesses
283
292
  -d, --dialect <dialect> SQL dialect to be generated:
284
- plain : (default) Common SQL - no assumptions about DB restrictions
285
- hana : SQL with HANA specific language features
286
- sqlite : Common SQL for sqlite
293
+ plain : (default) Common SQL - no assumptions about DB restrictions
294
+ hana : SQL with HANA specific language features
295
+ sqlite : Common SQL for sqlite
296
+ postgres : Common SQL for postgres - beta-feature
287
297
  -u, --user <user> Value for the "$user" variable
288
298
  -l, --locale <locale> Value for the "$user.locale" variable in "sqlite"/"plain" dialect
289
299
  -s, --src <style> Generate SQL source files as <artifact>.<suffix>
@@ -292,6 +302,20 @@ optionProcessor.command('Q, toSql')
292
302
  the HDI plugin name. Can only be used in combination with
293
303
  "hana" dialect.
294
304
  -c, --csn Generate "sql_csn.json" with SQL-preprocessed model
305
+ --integrity-not-enforced If this option is supplied, referential constraints are NOT ENFORCED.
306
+ --integrity-not-validated If this option is supplied, referential constraints are NOT VALIDATED.
307
+ --assert-integrity <mode> Turn DB constraints on/off:
308
+ true : (default) Constraints will be generated for all associations if
309
+ the assert-integrity-type is set to DB
310
+ false : No constraints will be generated
311
+ individual : Constraints will be generated for selected associations
312
+ --assert-integrity-type <type> Specifies how the referential integrity checks should be performed:
313
+ RT : (default) No database constraint for an association
314
+ if not explicitly demanded via annotation
315
+ DB : Create database constraints for associations
316
+ --constraints-in-create-table If set, the foreign key constraints will be rendered as
317
+ part of the "CREATE TABLE" statements rather than as separate
318
+ "ALTER TABLE ADD CONSTRAINT" statements
295
319
  `);
296
320
 
297
321
  optionProcessor.command('toRename')
@@ -322,13 +346,14 @@ optionProcessor.command('manageConstraints')
322
346
  .option(' --drop')
323
347
  .option(' --alter')
324
348
  .option(' --violations')
349
+ .option(' --integrity-not-validated')
350
+ .option(' --integrity-not-enforced')
325
351
  .help(`
326
352
  Usage: cdsc manageConstraints [options] <files...>
327
353
 
328
354
  (internal, subject to change): Generate SQL DDL ALTER TABLE statements to add / modify
329
- referential constraints on an existing model.
330
- Combine with options "--integrity-not-enforced" and "--integrity-not-validated"
331
- to switch off foreign key constraint enforcement / validation.
355
+ referential constraints on an existing model. This can also be used to
356
+ generate SELECT statements which list all referential integrity violations.
332
357
 
333
358
  Options
334
359
  -h, --help Display this help text
@@ -348,6 +373,8 @@ optionProcessor.command('manageConstraints')
348
373
  --alter Generate "ALTER TABLE <table> ALTER CONSTRAINT <constraint>" statements
349
374
  --violations Generates SELECT statements which can be used to list
350
375
  referential integrity violations on the existing data
376
+ --integrity-not-enforced If this option is supplied, referential constraints are NOT ENFORCED.
377
+ --integrity-not-validated If this option is supplied, referential constraints are NOT VALIDATED.
351
378
  `);
352
379
 
353
380
  optionProcessor.command('toCsn')
@@ -16,6 +16,6 @@
16
16
  "no-shadow": "warn"
17
17
  },
18
18
  "env": {
19
- "es6": true
19
+ "es2020": true
20
20
  }
21
21
  }
@@ -2,12 +2,14 @@
2
2
  * Usage: Create an instance to process artifacts which should be checked for collision.
3
3
  * First call addArtifact to specify the current artifact,
4
4
  * then call addElement to register the elements of the current artifact.
5
- * Finally call the "done" function to check for duplicates.
6
- * In addition the internal structures will be reinitialized to enable reuse of the instance.
5
+ * Finally, call the "done" function to check for duplicates.
6
+ * In addition, the internal structures will be reinitialized to enable reuse of the instance.
7
7
  */
8
8
 
9
9
  'use strict';
10
10
 
11
+ const { forEach } = require('../utils/objectUtils');
12
+
11
13
  /**
12
14
  * database name - uppercase if not quoted
13
15
  *
@@ -121,9 +123,4 @@ class DuplicateChecker {
121
123
  }
122
124
  }
123
125
 
124
- function forEach(obj, callback) {
125
- for (const key in obj)
126
- callback(key, obj[key]);
127
- }
128
-
129
126
  module.exports = DuplicateChecker;
@@ -6,11 +6,78 @@ const {
6
6
  getResultingName,
7
7
  } = require('../model/csnUtils');
8
8
  const { forEach } = require('../utils/objectUtils');
9
+ const { makeMessageFunction } = require('../base/messages');
10
+ const { optionProcessor } = require('../optionProcessor');
11
+ const { transformForHanaWithCsn } = require('../transform/forHanaNew');
9
12
 
10
13
  const {
11
14
  renderReferentialConstraint, getIdentifierUtils,
12
15
  } = require('./utils/sql');
13
16
 
17
+ /**
18
+ * Used only by `cdsc manageConstraints`.
19
+ * Not part of our API, yet.
20
+ *
21
+ * @param {CSN.Model} csn
22
+ * @param {CSN.Options} options
23
+ */
24
+ function alterConstraintsWithCsn(csn, options) {
25
+ const { error } = makeMessageFunction(csn, options, 'manageConstraints');
26
+
27
+ const {
28
+ drop, alter, names, src, violations,
29
+ } = options.manageConstraints || {};
30
+
31
+ if (drop && alter)
32
+ error(null, null, 'Option “--drop” can\'t be combined with “--alter”');
33
+
34
+ options.sqlDialect = 'hana';
35
+ options.sqlMapping = names || 'plain';
36
+
37
+ // Of course we want the database constraints
38
+ options.assertIntegrityType = 'DB';
39
+
40
+ const transformedOptions = _transformSqlOptions(csn, options);
41
+ const forSqlCsn = transformForHanaWithCsn(csn, transformedOptions, 'to.sql');
42
+
43
+ if (violations && src && src !== 'sql')
44
+ error(null, null, `Option “--violations“ can't be combined with source style “${src}“`);
45
+
46
+ let intermediateResult;
47
+ if (violations)
48
+ intermediateResult = listReferentialIntegrityViolations(forSqlCsn, transformedOptions);
49
+ else
50
+ intermediateResult = manageConstraints(forSqlCsn, transformedOptions);
51
+
52
+ return intermediateResult;
53
+ }
54
+
55
+ function _transformSqlOptions(model, options) {
56
+ // Merge options with defaults.
57
+ options = Object.assign({ sqlMapping: 'plain', sqlDialect: 'plain' }, options);
58
+ options.toSql = true;
59
+
60
+ if (!options.src && !options.csn)
61
+ options.src = 'sql';
62
+
63
+ const { warning, error } = makeMessageFunction(model, options, 'to.sql');
64
+
65
+ optionProcessor.verifyOptions(options, 'toSql', true)
66
+ .forEach(complaint => warning(null, null, `${complaint}`));
67
+
68
+ if (options.sqlDialect !== 'hana') {
69
+ // CDXCORE-465, 'quoted' and 'hdbcds' are to be used in combination with dialect 'hana' only
70
+ if (options.sqlMapping === 'quoted' || options.sqlMapping === 'hdbcds')
71
+ error(null, null, `Option "{ sqlDialect: '${options.sqlDialect}' }" can't be combined with "{ sqlMapping: '${options.sqlMapping}' }"`);
72
+
73
+ // No non-HANA SQL for HDI
74
+ if (options.src === 'hdi')
75
+ error(null, null, `Option "{ sqlDialect: '${options.sqlDialect}' }" can't be used for HDI"`);
76
+ }
77
+
78
+ return options;
79
+ }
80
+
14
81
  /**
15
82
  * This render middleware can be used to generate SQL DDL ALTER TABLE <table> ALTER / ADD / DROP CONSTRAINT <constraint> statements for a given CDL model.
16
83
  * Moreover, it can be used to generate .hdbconstraint artifacts.
@@ -38,7 +105,7 @@ function manageConstraints(csn, options) {
38
105
  return;
39
106
  }
40
107
  let alterTableStatement = '';
41
- alterTableStatement += `${indent}ALTER TABLE ${quoteSqlId(getResultingName(csn, options.toSql.names, constraint.dependentTable))}`;
108
+ alterTableStatement += `${indent}ALTER TABLE ${quoteSqlId(getResultingName(csn, options.sqlMapping, constraint.dependentTable))}`;
42
109
  if (renderAlterConstraintStatement)
43
110
  alterTableStatement += `\n${indent}ALTER ${renderedConstraint};`;
44
111
  else if (drop)
@@ -172,7 +239,7 @@ function listReferentialIntegrityViolations(csn, options) {
172
239
  }
173
240
 
174
241
  function quoteAndGetResultingName(id) {
175
- return quoteSqlId(getResultingName(csn, options.toSql.names, id));
242
+ return quoteSqlId(getResultingName(csn, options.sqlMapping, id));
176
243
  }
177
244
 
178
245
  return resultArtifacts;
@@ -192,6 +259,7 @@ function getListOfAllConstraints(csn) {
192
259
  }
193
260
 
194
261
  module.exports = {
262
+ alterConstraintsWithCsn,
195
263
  manageConstraints,
196
264
  listReferentialIntegrityViolations,
197
265
  };