@sap/cds-compiler 3.5.4 → 3.6.2

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 (84) hide show
  1. package/CHANGELOG.md +65 -2
  2. package/bin/cdsc.js +14 -6
  3. package/doc/CHANGELOG_ARCHIVE.md +10 -10
  4. package/doc/CHANGELOG_DEPRECATED.md +2 -2
  5. package/lib/api/main.js +32 -55
  6. package/lib/api/options.js +3 -2
  7. package/lib/api/validate.js +5 -0
  8. package/lib/base/message-registry.js +104 -32
  9. package/lib/base/messages.js +277 -212
  10. package/lib/base/optionProcessorHelper.js +9 -2
  11. package/lib/base/shuffle.js +50 -0
  12. package/lib/checks/actionsFunctions.js +37 -20
  13. package/lib/checks/foreignKeys.js +13 -6
  14. package/lib/checks/nonexpandableStructured.js +1 -2
  15. package/lib/checks/onConditions.js +21 -19
  16. package/lib/checks/parameters.js +1 -1
  17. package/lib/checks/queryNoDbArtifacts.js +2 -0
  18. package/lib/checks/types.js +16 -22
  19. package/lib/compiler/assert-consistency.js +31 -28
  20. package/lib/compiler/builtins.js +20 -4
  21. package/lib/compiler/checks.js +72 -63
  22. package/lib/compiler/define.js +396 -314
  23. package/lib/compiler/extend.js +55 -49
  24. package/lib/compiler/index.js +5 -0
  25. package/lib/compiler/populate.js +28 -11
  26. package/lib/compiler/propagator.js +2 -1
  27. package/lib/compiler/resolve.js +28 -13
  28. package/lib/compiler/shared.js +15 -10
  29. package/lib/compiler/utils.js +7 -7
  30. package/lib/edm/annotations/genericTranslation.js +51 -46
  31. package/lib/edm/annotations/preprocessAnnotations.js +37 -40
  32. package/lib/edm/csn2edm.js +69 -21
  33. package/lib/edm/edm.js +2 -2
  34. package/lib/edm/edmInboundChecks.js +6 -8
  35. package/lib/edm/edmPreprocessor.js +88 -80
  36. package/lib/edm/edmUtils.js +6 -15
  37. package/lib/gen/Dictionary.json +81 -13
  38. package/lib/gen/language.checksum +1 -1
  39. package/lib/gen/language.interp +2 -1
  40. package/lib/gen/languageParser.js +4680 -4484
  41. package/lib/inspect/inspectModelStatistics.js +2 -1
  42. package/lib/inspect/inspectPropagation.js +2 -1
  43. package/lib/json/from-csn.js +131 -78
  44. package/lib/json/to-csn.js +39 -23
  45. package/lib/language/antlrParser.js +0 -3
  46. package/lib/language/docCommentParser.js +7 -3
  47. package/lib/language/errorStrategy.js +3 -2
  48. package/lib/language/genericAntlrParser.js +96 -41
  49. package/lib/language/language.g4 +112 -128
  50. package/lib/language/multiLineStringParser.js +2 -1
  51. package/lib/main.d.ts +115 -2
  52. package/lib/main.js +16 -3
  53. package/lib/model/csnRefs.js +32 -4
  54. package/lib/model/csnUtils.js +109 -179
  55. package/lib/model/enrichCsn.js +13 -8
  56. package/lib/model/revealInternalProperties.js +4 -3
  57. package/lib/optionProcessor.js +22 -3
  58. package/lib/render/manageConstraints.js +11 -15
  59. package/lib/render/toCdl.js +144 -47
  60. package/lib/render/toHdbcds.js +22 -22
  61. package/lib/render/toRename.js +3 -4
  62. package/lib/render/toSql.js +31 -22
  63. package/lib/render/utils/delta.js +3 -1
  64. package/lib/render/utils/sql.js +2 -14
  65. package/lib/transform/db/associations.js +6 -6
  66. package/lib/transform/db/cdsPersistence.js +3 -3
  67. package/lib/transform/db/constraints.js +4 -6
  68. package/lib/transform/db/expansion.js +4 -4
  69. package/lib/transform/db/flattening.js +12 -15
  70. package/lib/transform/db/temporal.js +4 -3
  71. package/lib/transform/db/transformExists.js +13 -7
  72. package/lib/transform/draft/db.js +7 -7
  73. package/lib/transform/forOdataNew.js +15 -4
  74. package/lib/transform/forRelationalDB.js +59 -41
  75. package/lib/transform/odata/toFinalBaseType.js +106 -82
  76. package/lib/transform/odata/typesExposure.js +26 -17
  77. package/lib/transform/odata/utils.js +1 -1
  78. package/lib/transform/parseExpr.js +1 -1
  79. package/lib/transform/transformUtilsNew.js +33 -10
  80. package/lib/transform/translateAssocsToJoins.js +8 -7
  81. package/lib/transform/universalCsn/coreComputed.js +7 -5
  82. package/lib/transform/universalCsn/universalCsnEnricher.js +12 -4
  83. package/lib/utils/timetrace.js +2 -2
  84. package/package.json +1 -2
@@ -47,14 +47,7 @@ function renderStringForHdbcds( str ) {
47
47
  }
48
48
 
49
49
  /**
50
- * Render the CSN model 'model' to CDS source text. One source is created per
51
- * top-level artifact. Return a dictionary of top-level artifacts
52
- * by their names, like this:
53
- * { "foo" : "using XY; context foo {...};",
54
- * "bar::wiz" : "namespace bar::; entity wiz {...};"
55
- * }
56
- *
57
- * FIXME: This comment no longer tells the whole truth
50
+ * Render the CSN model 'model' to CDS source text.
58
51
  *
59
52
  * @param {CSN.Model} csn HANA transformed CSN
60
53
  * @param {CSN.Options} [options] Transformation options
@@ -141,12 +134,11 @@ function toHdbcdsSource( csn, options ) {
141
134
  const hdbconstraint = Object.create(null);
142
135
  forEachDefinition(csn, (art) => {
143
136
  if (art.$tableConstraints && art.$tableConstraints.referential) {
144
- const renderToUppercase = plainNames;
145
137
  const referentialConstraints = {};
146
138
  Object.entries(art.$tableConstraints.referential)
147
139
  .forEach(([ fileName, referentialConstraint ]) => {
148
140
  referentialConstraints[fileName] = renderReferentialConstraint(
149
- referentialConstraint, increaseIndent(createEnv()).indent, renderToUppercase, csn, options
141
+ referentialConstraint, increaseIndent(createEnv()).indent, false, csn, options
150
142
  );
151
143
  });
152
144
  Object.entries(referentialConstraints)
@@ -176,8 +168,8 @@ function toHdbcdsSource( csn, options ) {
176
168
  function sort( obj ) {
177
169
  const keys = Object.keys(obj).sort((a, b) => a.localeCompare(b));
178
170
  const sortedResult = Object.create(null);
179
- for (let i = 0; i < keys.length; i++)
180
- sortedResult[keys[i]] = obj[keys[i]];
171
+ for (const key of keys)
172
+ sortedResult[key] = obj[key];
181
173
 
182
174
  return sortedResult;
183
175
  }
@@ -191,7 +183,7 @@ function toHdbcdsSource( csn, options ) {
191
183
  * @returns {string} The rendered artifact
192
184
  */
193
185
  function renderArtifact( artifactName, art, env ) {
194
- // FIXME: Correctly build the paths during runtime to give better locations
186
+ // We're always a top-level artifact.
195
187
  env.path = [ 'definitions', artifactName ];
196
188
  // Ignore whole artifacts if toHana says so
197
189
  if (art.abstract || hasValidSkipOrExists(art))
@@ -691,8 +683,10 @@ function toHdbcdsSource( csn, options ) {
691
683
  if (path.ref[0].args)
692
684
  result += `(${renderArgs(path.ref[0], ':', env)})`;
693
685
 
694
- if (path.ref[0].where)
695
- result += `[${path.ref[0].cardinality ? (`${path.ref[0].cardinality.max}: `) : ''}${renderExpr(path.ref[0].where, env)}]`;
686
+ if (path.ref[0].where) {
687
+ const cardinality = path.ref[0].cardinality ? (`${path.ref[0].cardinality.max}: `) : '';
688
+ result += `[${cardinality}${renderExpr(path.ref[0].where, env)}]`;
689
+ }
696
690
 
697
691
  // Add any path steps (possibly with parameters and filters) that may follow after that
698
692
  if (path.ref.length > 1)
@@ -959,8 +953,10 @@ function toHdbcdsSource( csn, options ) {
959
953
  if (limit.rows !== undefined)
960
954
  result += `limit ${renderExpr(limit.rows, env)}`;
961
955
 
962
- if (limit.offset !== undefined)
963
- result += `${result !== '' ? `\n${increaseIndent(env).indent}` : ''}offset ${renderExpr(limit.offset, env)}`;
956
+ if (limit.offset !== undefined) {
957
+ const indent = result !== '' ? `\n${increaseIndent(env).indent}` : '';
958
+ result += `${indent}offset ${renderExpr(limit.offset, env)}`;
959
+ }
964
960
 
965
961
  return result;
966
962
  }
@@ -1214,7 +1210,8 @@ function toHdbcdsSource( csn, options ) {
1214
1210
  }
1215
1211
  if (s.where) {
1216
1212
  // Filter, possibly with cardinality
1217
- result += `[${s.cardinality ? (`${s.cardinality.max}: `) : ''}${renderExpr(s.where, env)}]`;
1213
+ const cardinality = s.cardinality ? `${s.cardinality.max}: ` : '';
1214
+ result += `[${cardinality}${renderExpr(s.where, env)}]`;
1218
1215
  }
1219
1216
  return result;
1220
1217
  }
@@ -1371,7 +1368,8 @@ function toHdbcdsSource( csn, options ) {
1371
1368
  * @returns {string} Rendered foreign key
1372
1369
  */
1373
1370
  function renderForeignKey( fKey, env ) {
1374
- return `${renderExpr(fKey, env)}${fKey.as ? (` as ${fKey.as}`) : ''}`;
1371
+ const alias = fKey.as ? (` as ${formatIdentifier(fKey.as)}`) : '';
1372
+ return `${renderExpr(fKey, env)}${alias}`;
1375
1373
  }
1376
1374
 
1377
1375
  /**
@@ -1585,7 +1583,7 @@ function toHdbcdsSource( csn, options ) {
1585
1583
  return '';
1586
1584
  }
1587
1585
  // The top-level artifact's parent would be the namespace (if any)
1588
- const namespace = getNamespace(csn, topLevelName) || '';
1586
+ const namespace = getNamespace(csn, topLevelName);
1589
1587
  if (namespace)
1590
1588
  return `${env.indent}namespace ${quotePathString(namespace)};\n`;
1591
1589
 
@@ -1720,8 +1718,10 @@ function toHdbcdsSource( csn, options ) {
1720
1718
 
1721
1719
  if (hdbcdsNames) {
1722
1720
  const namespace = getNamespace(csn, absName);
1723
- if (namespace)
1724
- return `"${(`${namespace}::${resultingName.substring(namespace.length + 2)}`).replace(/"/g, '""')}"`;
1721
+ if (namespace) {
1722
+ const id = `${namespace}::${resultingName.substring(namespace.length + 2)}`;
1723
+ return `"${id.replace(/"/g, '""')}"`;
1724
+ }
1725
1725
  }
1726
1726
  return `"${resultingName.replace(/"/g, '""')}"`;
1727
1727
  }
@@ -3,7 +3,7 @@
3
3
 
4
4
  const { makeMessageFunction } = require('../base/messages');
5
5
  const { checkCSNVersion } = require('../json/csnVersion');
6
- const { getUtils, forEachDefinition } = require('../model/csnUtils');
6
+ const { getNamespace, forEachDefinition } = require('../model/csnUtils');
7
7
  const { optionProcessor } = require('../optionProcessor');
8
8
  const { isBetaEnabled } = require('../base/model');
9
9
  const { transformForRelationalDBWithCsn } = require('../transform/forRelationalDB');
@@ -34,7 +34,7 @@ function toRename( inputCsn, options ) {
34
34
  const { error, warning, throwWithError } = makeMessageFunction(inputCsn, options, 'to.rename');
35
35
 
36
36
  // Merge options with defaults.
37
- options = Object.assign({ sqlMapping: 'hdbcds' }, options);
37
+ options = Object.assign({ sqlMapping: 'hdbcds', sqlDialect: 'hana' }, options);
38
38
 
39
39
  // Verify options
40
40
  optionProcessor.verifyOptions(options, 'toRename').forEach(complaint => warning(null, null, `${complaint}`));
@@ -53,7 +53,6 @@ function toRename( inputCsn, options ) {
53
53
  });
54
54
 
55
55
  const result = Object.create(null);
56
- const { getNamespaceOfArtifact } = getUtils(csn, false);
57
56
 
58
57
  // Render each artifact on its own
59
58
  for (const artifactName in csn.definitions) {
@@ -122,7 +121,7 @@ function toRename( inputCsn, options ) {
122
121
  if (options.sqlMapping !== 'hdbcds')
123
122
  return name;
124
123
 
125
- const namespaceName = getNamespaceOfArtifact(name);
124
+ const namespaceName = getNamespace(inputCsn, name);
126
125
  if (namespaceName)
127
126
  return `${namespaceName}::${name.substring(namespaceName.length + 1)}`;
128
127
 
@@ -6,6 +6,7 @@ const {
6
6
  hasValidSkipOrExists, isBuiltinType, generatedByCompilerVersion, getNormalizedQuery,
7
7
  forEachDefinition, getResultingName, getVariableReplacement,
8
8
  } = require('../model/csnUtils');
9
+ const { forEach, forEachValue, forEachKey } = require('../utils/objectUtils');
9
10
  const {
10
11
  renderFunc, cdsToSqlTypes, getHanaComment, hasHanaComment,
11
12
  getSqlSnippets, createExpressionRenderer, withoutCast,
@@ -24,7 +25,7 @@ const { isBetaEnabled, isDeprecatedEnabled } = require('../base/model');
24
25
  const { smartFuncId } = require('../sql-identifier');
25
26
  const { sortCsn } = require('../json/to-csn');
26
27
  const { manageConstraints } = require('./manageConstraints');
27
- const { ModelError } = require('../base/error');
28
+ const { ModelError, CompilerAssertion } = require('../base/error');
28
29
 
29
30
 
30
31
  /**
@@ -135,7 +136,7 @@ function toSqlDdl( csn, options ) {
135
136
 
136
137
  // FIXME: Currently requires 'options.forHana', because it can only render HANA-ish SQL dialect
137
138
  if (!options.forHana && !isBetaEnabled(options, 'sqlExtensions'))
138
- throw new Error('toSql can currently only be used with HANA preprocessing');
139
+ throw new CompilerAssertion('toSql can currently only be used with HANA preprocessing');
139
140
 
140
141
  checkCSNVersion(csn, options);
141
142
 
@@ -229,7 +230,7 @@ function toSqlDdl( csn, options ) {
229
230
  sourceString = sourceString.slice('COLUMN '.length);
230
231
  sql[name] = `${options.testMode ? '' : sqlVersionLine}CREATE ${sourceString};`;
231
232
  }
232
- else if (!options.testMode) {
233
+ else if (!options.testMode && options.generatedByComment) {
233
234
  mainResultObj[hdbKind][name] = sqlVersionLine + mainResultObj[hdbKind][name];
234
235
  }
235
236
  }
@@ -237,12 +238,14 @@ function toSqlDdl( csn, options ) {
237
238
  delete mainResultObj[hdbKind];
238
239
  }
239
240
 
240
- // add `ALTER TABLE ADD CONSTRAINT` statements per default for `to.sql` w/ dialect `hana`
241
- if (!options.constraintsInCreateTable && options.src === 'sql' && (options.sqlDialect === 'hana' || options.sqlDialect === 'postgres')) {
241
+ // add `ALTER TABLE ADD CONSTRAINT` statements per default for `to.sql` w/ dialect `hana` / `postgres`
242
+ // TODO `ALTER TABLE ADD CONSTRAINT` statements also for sqlite constraints
243
+ if (!options.constraintsInCreateTable && options.src === 'sql' && (options.sqlDialect === 'hana' || options.sqlDialect === 'postgres' /* || options.sqlDialect === 'sqlite' */)) {
242
244
  const alterStmts = manageConstraints(csn, options);
243
245
 
244
- for ( const constraintName of Object.keys(alterStmts))
246
+ forEachKey(alterStmts, (constraintName) => {
245
247
  sql[constraintName] = `${options.testMode ? '' : sqlVersionLine}${alterStmts[constraintName]}`;
248
+ });
246
249
  mainResultObj.sql = sql;
247
250
  }
248
251
 
@@ -250,7 +253,7 @@ function toSqlDdl( csn, options ) {
250
253
  mainResultObj.sql = sql;
251
254
 
252
255
  for (const name in deletions)
253
- deletions[name] = `${options.testMode ? '' : sqlVersionLine}${deletions[name]}`;
256
+ deletions[name] = `${options.testMode || !options.generatedByComment ? '' : sqlVersionLine}${deletions[name]}`;
254
257
 
255
258
  timetrace.stop('SQL rendering');
256
259
  return mainResultObj;
@@ -506,17 +509,16 @@ function toSqlDdl( csn, options ) {
506
509
  if ( !constraintsAsAlter && art.$tableConstraints && art.$tableConstraints.referential) {
507
510
  const renderReferentialConstraintsAsHdbconstraint = options.src === 'hdi';
508
511
  const referentialConstraints = {};
509
- Object.entries(art.$tableConstraints.referential)
510
- .forEach(([ fileName, referentialConstraint ]) => {
511
- referentialConstraints[fileName] = renderReferentialConstraint(referentialConstraint, childEnv.indent, false, csn, options);
512
- });
512
+ forEach(art.$tableConstraints.referential, ( fileName, referentialConstraint ) => {
513
+ referentialConstraints[fileName] = renderReferentialConstraint(referentialConstraint, childEnv.indent, false, csn, options);
514
+ });
513
515
  if (renderReferentialConstraintsAsHdbconstraint) {
514
- Object.entries(referentialConstraints).forEach(([ fileName, constraint ]) => {
516
+ forEach(referentialConstraints, (fileName, constraint ) => {
515
517
  resultObj.hdbconstraint[fileName] = constraint;
516
518
  });
517
519
  }
518
520
  else {
519
- Object.values(referentialConstraints).forEach((constraint) => {
521
+ forEachValue(referentialConstraints, (constraint) => {
520
522
  result += `,\n${constraint}`;
521
523
  });
522
524
  }
@@ -527,12 +529,14 @@ function toSqlDdl( csn, options ) {
527
529
  const uniqueConstraints = art.$tableConstraints && art.$tableConstraints.unique;
528
530
  for (const cn in uniqueConstraints) {
529
531
  const c = uniqueConstraints[cn];
532
+ const cnName = renderArtifactName(`${artifactName}_${cn}`);
533
+ const refs = c.map(cpath => quoteSqlId(cpath.ref[0])).join(', ');
530
534
  if (options.src === 'hdi') {
531
535
  resultObj.hdbindex[`${artifactName}.${cn}`]
532
- = `UNIQUE INVERTED INDEX ${renderArtifactName(`${artifactName}_${cn}`)} ON ${tableName} (${c.map(cpath => quoteSqlId(cpath.ref[0])).join(', ')})`;
536
+ = `UNIQUE INVERTED INDEX ${cnName} ON ${tableName} (${refs})`;
533
537
  }
534
538
  else {
535
- result += `,\n${childEnv.indent}CONSTRAINT ${renderArtifactName(`${artifactName}_${cn}`)} UNIQUE (${c.map(cpath => quoteSqlId(cpath.ref[0])).join(', ')})`;
539
+ result += `,\n${childEnv.indent}CONSTRAINT ${cnName} UNIQUE (${refs})`;
536
540
  }
537
541
  }
538
542
  result += `${env.indent}\n)`;
@@ -962,8 +966,10 @@ function toSqlDdl( csn, options ) {
962
966
  // CV without parameters is called as simple view
963
967
  result += '()';
964
968
  }
965
- if (path.ref[0].where)
966
- result += `[${path.ref[0].cardinality ? (`${path.ref[0].cardinality.max}: `) : ''}${renderExpr(path.ref[0].where, env)}]`;
969
+ if (path.ref[0].where) {
970
+ const cardinality = path.ref[0].cardinality ? (`${path.ref[0].cardinality.max}: `) : '';
971
+ result += `[${cardinality}${renderExpr(path.ref[0].where, env)}]`;
972
+ }
967
973
 
968
974
  // Add any path steps (possibly with parameters and filters) that may follow after that
969
975
  if (path.ref.length > 1)
@@ -1193,10 +1199,10 @@ function toSqlDdl( csn, options ) {
1193
1199
  }
1194
1200
 
1195
1201
  /**
1196
- * Render a query's LIMIT clause, which may have also have OFFSET.
1202
+ * Render a query's LIMIT clause, which may also have OFFSET.
1197
1203
  *
1198
1204
  * @param {CSN.QueryLimit} limit Limit clause
1199
- * @param {object} env Renderenvironment
1205
+ * @param {object} env Render environment
1200
1206
  * @returns {string} Rendered LIMIT clause
1201
1207
  */
1202
1208
  function renderLimit( limit, env ) {
@@ -1204,8 +1210,10 @@ function toSqlDdl( csn, options ) {
1204
1210
  if (limit.rows !== undefined)
1205
1211
  result += `LIMIT ${renderExpr(limit.rows, env)}`;
1206
1212
 
1207
- if (limit.offset !== undefined)
1208
- result += `${result !== '' ? `\n${env.indent}` : ''}OFFSET ${renderExpr(limit.offset, env)}`;
1213
+ if (limit.offset !== undefined) {
1214
+ const indent = result !== '' ? `\n${env.indent}` : '';
1215
+ result += `${indent}OFFSET ${renderExpr(limit.offset, env)}`;
1216
+ }
1209
1217
 
1210
1218
  return result;
1211
1219
  }
@@ -1547,7 +1555,8 @@ function toSqlDdl( csn, options ) {
1547
1555
  if (s.where) {
1548
1556
  // Filter, possibly with cardinality
1549
1557
  // FIXME: Does SQL understand filter cardinalities?
1550
- result += `[${s.cardinality ? (`${s.cardinality.max}: `) : ''}${renderExpr(s.where, env)}]`;
1558
+ const cardinality = s.cardinality ? (`${s.cardinality.max}: `) : '';
1559
+ result += `[${cardinality}${renderExpr(s.where, env)}]`;
1551
1560
  }
1552
1561
  return result;
1553
1562
  }
@@ -162,7 +162,9 @@ class DeltaRendererPostgres extends DeltaRenderer {
162
162
  * @todo tableName is escaped - we cannot simply add _pkey
163
163
  */
164
164
  dropKey(artifactName) {
165
- return [ `ALTER TABLE ${this.scopedFunctions.renderArtifactName(artifactName)} DROP CONSTRAINT ${this.scopedFunctions.renderArtifactName(`${artifactName}_pkey`)};` ];
165
+ const table = this.scopedFunctions.renderArtifactName(artifactName);
166
+ const pkey = this.scopedFunctions.renderArtifactName(`${artifactName}_pkey`);
167
+ return [ `ALTER TABLE ${table} DROP CONSTRAINT ${pkey};` ];
166
168
  }
167
169
 
168
170
  /**
@@ -19,18 +19,7 @@ const { ModelError } = require('../../base/error');
19
19
  * @returns {string} SQL statement which can be used to create the referential constraint on the db.
20
20
  */
21
21
  function renderReferentialConstraint( constraint, indent, toUpperCase, csn, options, alterConstraint = false ) {
22
- let quoteId;
23
- // for to.hana we can't utilize the sql identifier utils
24
- if (options.transformation === 'hdbcds') {
25
- quoteId = (id) => {
26
- if (options.sqlMapping === 'plain')
27
- return id.replace(/\./g, '_');
28
- return `"${id}"`;
29
- };
30
- }
31
- else {
32
- quoteId = getIdentifierUtils(csn, options).quoteSqlId;
33
- }
22
+ const quoteId = getIdentifierUtils(csn, options).quoteSqlId;
34
23
  if (toUpperCase) {
35
24
  constraint.identifier = constraint.identifier.toUpperCase();
36
25
  constraint.foreignKey = constraint.foreignKey.map(fk => fk.toUpperCase());
@@ -40,8 +29,7 @@ function renderReferentialConstraint( constraint, indent, toUpperCase, csn, opti
40
29
  }
41
30
 
42
31
  const renderAsHdbconstraint = options.transformation === 'hdbcds' ||
43
- options.src === 'hdi' ||
44
- (options.manageConstraints && options.manageConstraints.src === 'hdi');
32
+ options.src === 'hdi';
45
33
 
46
34
  const { sqlMapping, sqlDialect } = options;
47
35
  let result = '';
@@ -3,22 +3,21 @@
3
3
  const {
4
4
  applyTransformationsOnNonDictionary,
5
5
  applyTransformations,
6
- getUtils,
7
6
  } = require('../../model/csnUtils');
8
7
 
9
-
10
8
  /**
11
9
  * In all .elements of entities and views (and their bound actions/functions), create the on-condition for
12
10
  * a managed associations. This needs to happen after the .keys are expanded and the corresponding elements are created.
13
11
  *
14
12
  * @param {CSN.Model} csn
13
+ * @param {object} csnUtils
15
14
  * @param {string} pathDelimiter
16
15
  * @returns {CSN.Model} Return the input csn, with the transformations applied
17
16
  */
18
- function attachOnConditions( csn, pathDelimiter ) {
17
+ function attachOnConditions( csn, csnUtils, pathDelimiter ) {
19
18
  const {
20
19
  isManagedAssociation,
21
- } = getUtils(csn);
20
+ } = csnUtils;
22
21
 
23
22
  const alreadyHandled = new WeakMap();
24
23
  applyTransformations(csn, {
@@ -104,13 +103,14 @@ function attachOnConditions( csn, pathDelimiter ) {
104
103
 
105
104
  /**
106
105
  * @param {CSN.Model} csn
106
+ * @param {object} csnUtils
107
107
  * @param {string} pathDelimiter
108
108
  * @returns {(artifact: CSN.Artifact, artifactName: string) => void} Callback for forEachDefinition
109
109
  */
110
- function getFKAccessFinalizer( csn, pathDelimiter ) {
110
+ function getFKAccessFinalizer( csn, csnUtils, pathDelimiter ) {
111
111
  const {
112
112
  inspectRef,
113
- } = getUtils(csn);
113
+ } = csnUtils;
114
114
 
115
115
  return handleManagedAssocSteps;
116
116
 
@@ -2,7 +2,6 @@
2
2
 
3
3
  const {
4
4
  forEachGeneric, forEachMemberRecursively, hasAnnotationValue, isPersistedOnDatabase,
5
- getUtils,
6
5
  } = require('../../model/csnUtils');
7
6
  const transformUtils = require('../transformUtilsNew');
8
7
 
@@ -37,13 +36,14 @@ function getAnnoProcessor() {
37
36
  * @param {CSN.Options} options
38
37
  * @param {object} messageFunctions
39
38
  * @param {Function} messageFunctions.info
39
+ * @param {object} csnUtils
40
40
  * @returns {(artifact: CSN.Artifact, artifactName: string, prop: string, path: CSN.Path) => void} Callback function for forEachDefinition
41
41
  */
42
- function getAssocToSkippedIgnorer( csn, options, messageFunctions ) {
42
+ function getAssocToSkippedIgnorer( csn, options, messageFunctions, csnUtils ) {
43
43
  const { info } = messageFunctions;
44
44
  const doA2J = !(options.transformation === 'hdbcds' && options.sqlMapping === 'hdbcds');
45
45
 
46
- const { isAssocOrComposition } = getUtils(csn);
46
+ const { isAssocOrComposition } = csnUtils;
47
47
 
48
48
  return ignoreAssociationToSkippedTarget;
49
49
  /**
@@ -4,6 +4,7 @@ const { forEachDefinition } = require('../../base/model');
4
4
  const { applyTransformations, hasAnnotationValue, getResultingName } = require('../../model/csnUtils');
5
5
  const { csnRefs } = require('../../model/csnRefs');
6
6
  const { forEach, forEachKey } = require('../../utils/objectUtils');
7
+ const { CompilerAssertion } = require('../../base/error');
7
8
 
8
9
  const COMPOSITION = 'cds.Composition';
9
10
  const ASSOCIATION = 'cds.Association';
@@ -90,7 +91,7 @@ function createReferentialConstraints( csn, options ) {
90
91
  foreignKeyConstraintForAssociation(up_, [ 'definitions', composition.target, 'elements', upLinkName ], path[path.length - 1]);
91
92
  }
92
93
  else if (!onCondition && composition.keys.length > 0) {
93
- throw new Error('Please debug me, an on-condition was expected here, but only found keys');
94
+ throw new CompilerAssertion('Please debug me, an on-condition was expected here, but only found keys');
94
95
  }
95
96
  }
96
97
 
@@ -120,7 +121,7 @@ function createReferentialConstraints( csn, options ) {
120
121
  attachConstraintsToDependentKeys(dependentKeys, parentKeys, association.target, path[path.length - 1], upLinkFor);
121
122
  }
122
123
  else if (!onCondition && association.keys.length > 0) {
123
- throw new Error('Please debug me, an on-condition was expected here, but only found keys');
124
+ throw new CompilerAssertion('Please debug me, an on-condition was expected here, but only found keys');
124
125
  }
125
126
  }
126
127
 
@@ -377,12 +378,9 @@ function createReferentialConstraints( csn, options ) {
377
378
  * @returns {boolean}
378
379
  */
379
380
  function assertForIntegrityTypeDB() {
380
- if (isAssertIntegrityAnnotationSetTo(RT))
381
- return true;
382
- return false;
381
+ return isAssertIntegrityAnnotationSetTo(RT);
383
382
  }
384
383
 
385
-
386
384
  /**
387
385
  * convenience to check if value of element's @assert.integrity annotation
388
386
  * is the same as a given value
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const {
4
- hasAnnotationValue, getUtils,
4
+ hasAnnotationValue,
5
5
  applyTransformations,
6
6
  setDependencies,
7
7
  walkCsnPath,
@@ -21,10 +21,10 @@ const { forEach } = require('../../utils/objectUtils');
21
21
  * @param {Function} messageFunctions.error
22
22
  * @param {Function} messageFunctions.info
23
23
  * @param {Function} messageFunctions.throwWithAnyError
24
- * @param {object} iterateOptions
24
+ * @param {object} csnUtils
25
+ * @param {object} [iterateOptions]
25
26
  */
26
- function expandStructureReferences( csn, options, pathDelimiter, { error, info, throwWithAnyError }, iterateOptions = {} ) {
27
- const csnUtils = getUtils(csn);
27
+ function expandStructureReferences( csn, options, pathDelimiter, { error, info, throwWithAnyError }, csnUtils, iterateOptions = {} ) {
28
28
  const {
29
29
  isStructured, get$combined, getFinalBaseTypeWithProps,
30
30
  } = csnUtils;
@@ -1,7 +1,6 @@
1
1
  'use strict';
2
2
 
3
3
  const {
4
- getUtils,
5
4
  applyTransformations, applyTransformationsOnNonDictionary,
6
5
  isBuiltinType, cloneCsnNonDict,
7
6
  copyAnnotations, implicitAs, isDeepEqual,
@@ -409,10 +408,11 @@ function flattenElements( csn, options, pathDelimiter, error, iterateOptions = {
409
408
  * @param {Function} error
410
409
  * @param {string} pathDelimiter
411
410
  * @param {boolean} flattenKeyRefs
411
+ * @param {object} csnUtils
412
412
  * @param {object} iterateOptions
413
413
  */
414
- function handleManagedAssociationsAndCreateForeignKeys( csn, options, error, pathDelimiter, flattenKeyRefs, iterateOptions = {} ) {
415
- const { isManagedAssociation, inspectRef, isStructured } = getUtils(csn);
414
+ function handleManagedAssociationsAndCreateForeignKeys( csn, options, error, pathDelimiter, flattenKeyRefs, csnUtils, iterateOptions = {} ) {
415
+ const { isManagedAssociation, inspectRef, isStructured } = csnUtils;
416
416
  const { flattenStructStepsInRef, flattenStructuredElement } = transformUtils.getTransformers(csn, options, pathDelimiter);
417
417
  if (flattenKeyRefs) {
418
418
  applyTransformations(csn, {
@@ -595,7 +595,7 @@ function handleManagedAssociationsAndCreateForeignKeys( csn, options, error, pat
595
595
  Object.entries(dict).forEach(([ elementName, element ]) => {
596
596
  orderedElements.push([ elementName, element ]);
597
597
  const eltPath = path.concat(prop, elementName);
598
- const fks = createForeignKeys(eltPath, element, elementName, csn, options, pathDelimiter);
598
+ const fks = createForeignKeys(csnUtils, eltPath, element, elementName, csn, options, pathDelimiter);
599
599
 
600
600
  // finalize the generated foreign keys
601
601
  const refCount = fks.reduce((acc, fk) => {
@@ -662,6 +662,7 @@ function handleManagedAssociationsAndCreateForeignKeys( csn, options, error, pat
662
662
  *
663
663
  * If element is not a managed association, an empty array is returned
664
664
  *
665
+ * @param {object} csnUtils
665
666
  * @param {Array|object} path CSN path pointing to element or the result of a previous call to inspectRef
666
667
  * @param {CSN.Element} element
667
668
  * @param {string} prefix Element name
@@ -671,12 +672,8 @@ function handleManagedAssociationsAndCreateForeignKeys( csn, options, error, pat
671
672
  * @param {number} lvl
672
673
  * @returns {Array[]} First element of every sub-array is the foreign key name, second is the foreign key definition
673
674
  */
674
- function createForeignKeys( path, element, prefix, csn, options, pathDelimiter, lvl = 0 ) {
675
- const {
676
- effectiveType,
677
- inspectRef,
678
- } = getUtils(csn);
679
-
675
+ function createForeignKeys( csnUtils, path, element, prefix, csn, options, pathDelimiter, lvl = 0 ) {
676
+ const special$self = !csn?.definitions?.$self && '$self';
680
677
  const isInspectRefResult = !Array.isArray(path);
681
678
 
682
679
  let fks = [];
@@ -686,8 +683,8 @@ function createForeignKeys( path, element, prefix, csn, options, pathDelimiter,
686
683
  let finalElement = element;
687
684
  let finalTypeName; // TODO: Find a way to not rely on $path?
688
685
  // TODO: effectiveType's return value is 'path' for the next inspectRef
689
- if (element.type && !isBuiltinType(element.type)) {
690
- const tmpElt = effectiveType(element);
686
+ if (element.type && !isBuiltinType(element.type) && element.type !== special$self) {
687
+ const tmpElt = csnUtils.effectiveType(element);
691
688
  // effective type resolves to structs and enums only but not scalars
692
689
  if (Object.keys(tmpElt).length) {
693
690
  finalElement = tmpElt;
@@ -717,8 +714,8 @@ function createForeignKeys( path, element, prefix, csn, options, pathDelimiter,
717
714
  finalElement.keys.forEach((key, keyIndex) => {
718
715
  const continuePath = getContinuePath([ 'keys', keyIndex ]);
719
716
  const alias = key.as || implicitAs(key.ref);
720
- const result = inspectRef(continuePath);
721
- fks = fks.concat(createForeignKeys(result, result.art, alias, csn, options, pathDelimiter, lvl + 1));
717
+ const result = csnUtils.inspectRef(continuePath);
718
+ fks = fks.concat(createForeignKeys(csnUtils, result, result.art, alias, csn, options, pathDelimiter, lvl + 1));
722
719
  });
723
720
  if (!hasKeys)
724
721
  delete finalElement.keys;
@@ -742,7 +739,7 @@ function createForeignKeys( path, element, prefix, csn, options, pathDelimiter,
742
739
  // Skip already produced foreign keys
743
740
  if (!elem['@odata.foreignKey4']) {
744
741
  const continuePath = getContinuePath([ 'elements', elemName ]);
745
- fks = fks.concat(createForeignKeys(continuePath, elem, elemName, csn, options, pathDelimiter, lvl + 1));
742
+ fks = fks.concat(createForeignKeys(csnUtils, continuePath, elem, elemName, csn, options, pathDelimiter, lvl + 1));
746
743
  }
747
744
  });
748
745
  }
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const {
4
- getUtils, getNormalizedQuery, hasAnnotationValue, forEachMember,
4
+ getNormalizedQuery, hasAnnotationValue, forEachMember,
5
5
  } = require('../../model/csnUtils');
6
6
  const { implicitAs } = require('../../model/csnRefs');
7
7
  const { setProp } = require('../../base/model');
@@ -20,11 +20,12 @@ const validFromString = '@cds.valid.from';
20
20
  * @param {CSN.Model} csn
21
21
  * @param {object} messageFunctions
22
22
  * @param {Function} messageFunctions.info
23
+ * @param {object} csnUtils
23
24
  * @returns {(artifact: CSN.Artifact, artifactName: string) => void} Callback for forEachDefinition applying the where-condition to views.
24
25
  */
25
- function getViewDecorator( csn, messageFunctions ) {
26
+ function getViewDecorator( csn, messageFunctions, csnUtils ) {
26
27
  const { info } = messageFunctions;
27
- const { get$combined } = getUtils(csn);
28
+ const { get$combined } = csnUtils;
28
29
  return addTemporalWhereConditionToView;
29
30
  /**
30
31
  * Add a where condition to views that
@@ -3,7 +3,6 @@
3
3
  const { forAllQueries, forEachDefinition, walkCsnPath } = require('../../model/csnUtils');
4
4
  const { setProp } = require('../../base/model');
5
5
  const { getRealName } = require('../../render/utils/common');
6
- const { csnRefs } = require('../../model/csnRefs');
7
6
  const { ModelError } = require('../../base/error');
8
7
 
9
8
  /**
@@ -47,9 +46,11 @@ const { ModelError } = require('../../base/error');
47
46
  * @param {CSN.Model} csn
48
47
  * @param {CSN.Options} options
49
48
  * @param {Function} error
49
+ * @param {Function} inspectRef
50
+ * @param {Function} initDefinition
51
+ * @param {Function} dropDefinitionCache
50
52
  */
51
- function handleExists( csn, options, error ) {
52
- let { inspectRef } = csnRefs(csn);
53
+ function handleExists( csn, options, error, inspectRef, initDefinition, dropDefinitionCache ) {
53
54
  const generatedExists = new WeakMap();
54
55
  forEachDefinition(csn, (artifact, artifactName) => {
55
56
  if (artifact.projection) // do the same hack we do for the other stuff...
@@ -78,14 +79,19 @@ function handleExists( csn, options, error ) {
78
79
 
79
80
  while (toProcess.length > 0) {
80
81
  const [ queryPath, exprPath ] = toProcess.pop();
82
+ // Re-init caches for this artifact
83
+ dropDefinitionCache(artifact);
84
+ initDefinition(artifact);
81
85
  // leftovers can happen with nested exists - we then need to drill down into the created SELECT
82
86
  // to check for further exists
83
87
  const { result, leftovers } = processExists(queryPath, exprPath);
84
88
  walkCsnPath(csn, exprPath.slice(0, -1))[exprPath[exprPath.length - 1]] = result;
85
- if (leftovers.length > 0)
86
- inspectRef = csnRefs(csn).inspectRef; // Refresh caches - we need to resolve stuff in the newly created subquery
87
- toProcess.push(...leftovers.reverse()); // any leftovers - schedule for further processing
89
+ leftovers.reverse();
90
+ toProcess.push(...leftovers); // any leftovers - schedule for further processing
88
91
  }
92
+ // Make sure we leave csnRefs usable
93
+ dropDefinitionCache(artifact);
94
+ initDefinition(artifact);
89
95
  }
90
96
  }, [ 'definitions', artifactName, 'query' ]);
91
97
  }
@@ -763,7 +769,7 @@ function handleExists( csn, options, error ) {
763
769
  */
764
770
  function remapExistingWhere( target, where ) {
765
771
  return where.map((part) => {
766
- if (part.ref) {
772
+ if (part.ref && part.$scope !== '$magic') {
767
773
  part.ref = [ target, ...part.ref ];
768
774
  return part;
769
775
  }