@sap/cds-compiler 4.5.0 → 4.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 (65) hide show
  1. package/CHANGELOG.md +50 -7
  2. package/bin/cdsc.js +13 -11
  3. package/doc/CHANGELOG_BETA.md +6 -0
  4. package/lib/api/main.js +256 -115
  5. package/lib/api/options.js +8 -0
  6. package/lib/base/message-registry.js +17 -4
  7. package/lib/base/messages.js +15 -3
  8. package/lib/base/model.js +1 -0
  9. package/lib/base/optionProcessorHelper.js +45 -176
  10. package/lib/checks/elements.js +32 -34
  11. package/lib/checks/enricher.js +39 -3
  12. package/lib/checks/validator.js +2 -3
  13. package/lib/compiler/assert-consistency.js +2 -1
  14. package/lib/compiler/builtins.js +20 -4
  15. package/lib/compiler/checks.js +30 -6
  16. package/lib/compiler/define.js +31 -9
  17. package/lib/compiler/populate.js +5 -1
  18. package/lib/compiler/resolve.js +26 -21
  19. package/lib/compiler/shared.js +19 -9
  20. package/lib/compiler/tweak-assocs.js +82 -107
  21. package/lib/compiler/utils.js +2 -1
  22. package/lib/edm/annotations/edmJson.js +23 -22
  23. package/lib/edm/annotations/genericTranslation.js +14 -4
  24. package/lib/edm/csn2edm.js +24 -10
  25. package/lib/edm/edmInboundChecks.js +1 -2
  26. package/lib/edm/edmPreprocessor.js +11 -9
  27. package/lib/edm/edmUtils.js +5 -2
  28. package/lib/gen/Dictionary.json +3 -1
  29. package/lib/gen/language.checksum +1 -1
  30. package/lib/gen/language.interp +4 -1
  31. package/lib/gen/language.tokens +1 -0
  32. package/lib/gen/languageParser.js +5253 -5214
  33. package/lib/json/to-csn.js +7 -1
  34. package/lib/language/antlrParser.js +19 -1
  35. package/lib/language/errorStrategy.js +21 -4
  36. package/lib/language/genericAntlrParser.js +9 -11
  37. package/lib/main.d.ts +28 -3
  38. package/lib/main.js +3 -0
  39. package/lib/model/csnRefs.js +4 -1
  40. package/lib/model/csnUtils.js +12 -7
  41. package/lib/optionProcessor.js +21 -19
  42. package/lib/render/manageConstraints.js +13 -29
  43. package/lib/render/toCdl.js +18 -15
  44. package/lib/render/toHdbcds.js +59 -28
  45. package/lib/render/toRename.js +6 -10
  46. package/lib/render/toSql.js +57 -82
  47. package/lib/render/utils/common.js +17 -0
  48. package/lib/transform/.eslintrc.json +9 -1
  49. package/lib/transform/addTenantFields.js +228 -0
  50. package/lib/transform/db/applyTransformations.js +27 -31
  51. package/lib/transform/db/assertUnique.js +4 -4
  52. package/lib/transform/db/cdsPersistence.js +1 -1
  53. package/lib/transform/db/flattening.js +68 -69
  54. package/lib/transform/db/temporal.js +1 -1
  55. package/lib/transform/draft/db.js +2 -16
  56. package/lib/transform/draft/odata.js +3 -3
  57. package/lib/transform/effective/associations.js +3 -5
  58. package/lib/transform/effective/main.js +6 -9
  59. package/lib/transform/forOdata.js +13 -9
  60. package/lib/transform/forRelationalDB.js +36 -17
  61. package/lib/transform/odata/toFinalBaseType.js +3 -3
  62. package/lib/transform/odata/typesExposure.js +14 -5
  63. package/lib/transform/transformUtils.js +47 -34
  64. package/lib/transform/translateAssocsToJoins.js +33 -8
  65. package/package.json +2 -2
@@ -4,13 +4,14 @@ const {
4
4
  getLastPartOf, getLastPartOfRef,
5
5
  hasValidSkipOrExists, isBuiltinType, generatedByCompilerVersion, getNormalizedQuery,
6
6
  getRootArtifactName, getResultingName, getNamespace, forEachMember, getVariableReplacement, hasAnnotationValue,
7
- pathName,
7
+ pathName, isMagicVariable,
8
8
  } = require('../model/csnUtils');
9
9
  const keywords = require('../base/keywords');
10
10
  const {
11
11
  renderFunc, createExpressionRenderer, getRealName, addContextMarkers, addIntermediateContexts,
12
12
  hasHanaComment, getHanaComment, funcWithoutParen, getSqlSnippets,
13
13
  cdsToSqlTypes, cdsToHdbcdsTypes, withoutCast, variableForDialect,
14
+ isVariableReplacementRequired,
14
15
  } = require('./utils/common');
15
16
  const {
16
17
  renderReferentialConstraint,
@@ -18,11 +19,11 @@ const {
18
19
  const DuplicateChecker = require('./DuplicateChecker');
19
20
  const { isDeprecatedEnabled, forEachDefinition } = require('../base/model');
20
21
  const { checkCSNVersion } = require('../json/csnVersion');
21
- const { makeMessageFunction } = require('../base/messages');
22
22
  const { timetrace } = require('../utils/timetrace');
23
23
 
24
24
  const { smartId, delimitedId } = require('../sql-identifier');
25
25
  const { ModelError, CompilerAssertion } = require('../base/error');
26
+ const { pathId } = require('../model/csnRefs');
26
27
 
27
28
  const $PROJECTION = '$projection';
28
29
  const $SELF = '$self';
@@ -90,9 +91,10 @@ function renderStringForHdbcds( str ) {
90
91
  *
91
92
  * @param {CSN.Model} csn HANA transformed CSN
92
93
  * @param {CSN.Options} [options] Transformation options
94
+ * @param {object} messageFunctions Message functions such as `error()`, `info()`, …
93
95
  * @returns {object} Dictionary of filename: content
94
96
  */
95
- function toHdbcdsSource( csn, options ) {
97
+ function toHdbcdsSource( csn, options, messageFunctions ) {
96
98
  timetrace.start('HDBCDS rendering');
97
99
  const plainNames = options.sqlMapping === 'plain';
98
100
  const quotedNames = options.sqlMapping === 'quoted';
@@ -100,7 +102,13 @@ function toHdbcdsSource( csn, options ) {
100
102
 
101
103
  const {
102
104
  info, warning, error, throwWithAnyError, message,
103
- } = makeMessageFunction(csn, options, 'to.hdbcds');
105
+ } = messageFunctions;
106
+ if (options.tenantAsColumn) {
107
+ error('api-unexpected-option', null, { option: 'tenantAsColumn', module: 'to.hdbcds' });
108
+ throwWithAnyError();
109
+ }
110
+
111
+ const reportedMissingReplacements = Object.create(null);
104
112
 
105
113
  const exprRenderer = createExpressionRenderer({
106
114
  finalize: x => x,
@@ -733,7 +741,7 @@ function toHdbcdsSource( csn, options ) {
733
741
 
734
742
  // Add any path steps (possibly with parameters and filters) that may follow after that
735
743
  if (path.ref.length > 1)
736
- result += `.${renderExpr({ ref: path.ref.slice(1) }, env)}`;
744
+ result += `.${renderTypeRef({ ref: path.ref.slice(1) }, env)}`;
737
745
 
738
746
  return result;
739
747
  }
@@ -1310,40 +1318,63 @@ function toHdbcdsSource( csn, options ) {
1310
1318
  return renderFunc(funcName, x, 'hana', a => renderArgs(a, '=>', this.env));
1311
1319
  }
1312
1320
 
1321
+
1313
1322
  /**
1323
+ * Render a magic variable. Values are determined in following order:
1324
+ * 1. User defined replacement in options.variableReplacements
1325
+ * 2. Predefined fallback values
1326
+ * 3. Rendering of the variable as a string (i.e. its name) + warning
1327
+ *
1328
+ * @param {CSN.Path} ref
1329
+ * @param {object} env
1330
+ * @return {string}
1331
+ */
1332
+ function renderMagicVariable( ref, env ) {
1333
+ const magicReplacement = getVariableReplacement(ref, options);
1334
+ if (magicReplacement !== null)
1335
+ return renderStringForHdbcds(magicReplacement);
1336
+
1337
+ const name = pathName(ref);
1338
+ const result = variableForDialect(options, name);
1339
+ if (result)
1340
+ return result;
1341
+
1342
+ if (isVariableReplacementRequired(name)) {
1343
+ reportedMissingReplacements[name] = true;
1344
+ error('ref-undefined-var', env.path, { '#': 'value', id: name, option: 'variableReplacements' });
1345
+ }
1346
+ else if (!reportedMissingReplacements[name]) {
1347
+ reportedMissingReplacements[name] = true;
1348
+ warning('ref-unsupported-variable', env.path, { name, option: 'variableReplacements' },
1349
+ 'Variable $(NAME) is not supported. Use option $(OPTION) to specify a value for $(NAME)');
1350
+ }
1351
+
1352
+ return renderStringForHdbcds(name);
1353
+ }
1354
+
1355
+ /**
1356
+ * Must not be used for type refs, as something like `$user` will be interpreted as a magic
1357
+ * variable and not definition name.
1358
+ *
1314
1359
  * @param {object} x Expression with a ref property
1315
1360
  * @returns {string} Rendered expression
1316
1361
  * @todo no extra magic with x.param
1317
1362
  */
1318
1363
  function renderExpressionRef( x ) {
1319
- if (!x.param) {
1320
- const magicReplacement = getVariableReplacement(x.ref, options);
1321
- if (x.ref[0] === '$user' || x.ref[0] === '$tenant') {
1322
- if (magicReplacement !== null)
1323
- return renderStringForHdbcds(magicReplacement);
1324
-
1325
- const name = pathName(x.ref);
1326
- const result = variableForDialect(options, name);
1327
- // Invalid second path step doesn't cause a return
1328
- if (result)
1329
- return result;
1330
- }
1331
- else if (x.ref[0] === '$at' || x.ref[0] === '$valid' || x.ref[0] === '$now') {
1332
- const name = pathName(x.ref);
1333
- const result = variableForDialect(options, name);
1334
- // Invalid second path step doesn't cause a return
1335
- if (result)
1336
- return result;
1337
- }
1338
- else if (x.ref[0] === '$session' && magicReplacement !== null) {
1339
- return renderStringForHdbcds(magicReplacement);
1340
- }
1341
- }
1364
+ if (!x.param && isMagicVariable(pathId(x.ref[0])))
1365
+ return renderMagicVariable(x.ref, this.env);
1366
+
1342
1367
  const prefix = x.param ? ':' : '';
1343
1368
  const ref = x.ref.map((step, index) => renderPathStep(step, index, this.env.withSubPath([ 'ref', index ]))).join('.');
1344
1369
  return `${prefix}${ref}`;
1345
1370
  }
1346
1371
 
1372
+ function renderTypeRef( x, env ) {
1373
+ const prefix = x.param ? ':' : '';
1374
+ const ref = x.ref.map((step, index) => renderPathStep(step, index, env.withSubPath([ 'ref', index ]))).join('.');
1375
+ return `${prefix}${ref}`;
1376
+ }
1377
+
1347
1378
  /**
1348
1379
  * Render function arguments or view parameters (positional if array, named if object/dict),
1349
1380
  * using 'sep' as separator for positional parameters
@@ -1,10 +1,8 @@
1
1
 
2
2
  'use strict';
3
3
 
4
- const { makeMessageFunction } = require('../base/messages');
5
4
  const { checkCSNVersion } = require('../json/csnVersion');
6
5
  const { forEachDefinition } = require('../model/csnUtils');
7
- const { optionProcessor } = require('../optionProcessor');
8
6
  const { transformForRelationalDBWithCsn } = require('../transform/forRelationalDB');
9
7
  const { getIdentifierUtils } = require('./utils/sql');
10
8
 
@@ -25,25 +23,23 @@ const { getIdentifierUtils } = require('./utils/sql');
25
23
  * @todo clarify input parameters
26
24
  * @param {CSN.Model} inputCsn CSN?
27
25
  * @param {CSN.Options} options Transformation options
26
+ * @param {object} messageFunctions
28
27
  * @returns {object} A dictionary of name: rename statement
29
28
  */
30
- function toRename( inputCsn, options ) {
31
- const { warning, throwWithError } = makeMessageFunction(inputCsn, options, 'to.rename');
29
+ function toRename( inputCsn, options, messageFunctions ) {
30
+ const { warning, throwWithError } = messageFunctions;
32
31
 
33
32
  // Merge options with defaults.
33
+ // TODO: Use api/options.js if this ever becomes an official API.
34
34
  options = Object.assign({ sqlMapping: 'hdbcds', sqlDialect: 'hana' }, options);
35
-
36
- // Verify options
37
- optionProcessor.verifyOptions(options, 'toRename')
38
- // eslint-disable-next-line cds-compiler/message-template-string
39
- .forEach(complaint => warning(null, null, `${complaint}`));
40
35
  checkCSNVersion(inputCsn, options);
41
36
 
42
37
  // Let users know that this is internal
43
38
  warning(null, null, 'Generation of SQL rename statements is a beta feature and might change in the future');
44
39
 
45
40
  // FIXME: Currently, 'toRename' implies transformation for HANA (transferring the options to forRelationalDB)
46
- const csn = transformForRelationalDBWithCsn(inputCsn, options, 'to.rename');
41
+ const csn = transformForRelationalDBWithCsn(inputCsn, options, messageFunctions);
42
+ messageFunctions.setModel(csn);
47
43
  const hdbcdsOrQuotedIdentifiers = getIdentifierUtils(csn, options);
48
44
  const plainIdentifiers = getIdentifierUtils(csn, { sqlDialect: 'hana', sqlMapping: 'plain' });
49
45
 
@@ -4,13 +4,14 @@
4
4
  const {
5
5
  getLastPartOf, getLastPartOfRef,
6
6
  hasValidSkipOrExists, isBuiltinType, generatedByCompilerVersion, getNormalizedQuery,
7
- forEachDefinition, getResultingName, getVariableReplacement, pathName,
7
+ forEachDefinition, getResultingName,
8
+ getVariableReplacement, isMagicVariable, pathName,
8
9
  } = require('../model/csnUtils');
9
10
  const { forEach, forEachValue, forEachKey } = require('../utils/objectUtils');
10
11
  const {
11
12
  renderFunc, cdsToSqlTypes, getHanaComment, hasHanaComment,
12
13
  getSqlSnippets, createExpressionRenderer, withoutCast,
13
- variableForDialect,
14
+ variableForDialect, isVariableReplacementRequired,
14
15
  } = require('./utils/common');
15
16
  const {
16
17
  getDeltaRenderer,
@@ -20,7 +21,6 @@ const {
20
21
  } = require('./utils/sql');
21
22
  const DuplicateChecker = require('./DuplicateChecker');
22
23
  const { checkCSNVersion } = require('../json/csnVersion');
23
- const { makeMessageFunction } = require('../base/messages');
24
24
  const { timetrace } = require('../utils/timetrace');
25
25
  const { isBetaEnabled, isDeprecatedEnabled } = require('../base/model');
26
26
  const { smartFuncId } = require('../sql-identifier');
@@ -28,6 +28,7 @@ const { sortCsn } = require('../json/to-csn');
28
28
  const { manageConstraints, manageConstraint } = require('./manageConstraints');
29
29
  const { renderUniqueConstraintString, renderUniqueConstraintDrop, renderUniqueConstraintAdd } = require('./utils/unique');
30
30
  const { ModelError, CompilerAssertion } = require('../base/error');
31
+ const { pathId } = require('../model/csnRefs');
31
32
 
32
33
  class SqlRenderEnvironment {
33
34
  indent = '';
@@ -99,13 +100,14 @@ class SqlRenderEnvironment {
99
100
  *
100
101
  * @param {CSN.Model} csn HANA transformed CSN
101
102
  * @param {CSN.Options} options Transformation options
103
+ * @param {object} messageFunctions Message functions such as `error()`, `info()`, …
102
104
  * @returns {object} Dictionary of artifact-type:artifacts, where artifacts is a dictionary of name:content
103
105
  */
104
- function toSqlDdl( csn, options ) {
106
+ function toSqlDdl( csn, options, messageFunctions ) {
105
107
  timetrace.start('SQL rendering');
106
108
  const {
107
109
  error, warning, info, throwWithAnyError,
108
- } = makeMessageFunction(csn, options, 'to.sql');
110
+ } = messageFunctions;
109
111
  const { quoteSqlId, prepareIdentifier, renderArtifactName } = getIdentifierUtils(csn, options);
110
112
  const reportedMissingReplacements = Object.create(null);
111
113
 
@@ -771,6 +773,10 @@ function toSqlDdl( csn, options ) {
771
773
  let result = '';
772
774
  if (elm.target) {
773
775
  result += env.indent;
776
+ const on = (!options.tenantAsColumn || elm.target['@cds.tenant.independent'])
777
+ ? elm.on
778
+ : [ { ref: [ 'tenant' ] }, '=', { ref: [ elementName, 'tenant' ] },
779
+ 'and', { xpr: elm.on } ];
774
780
  if (elm.cardinality) {
775
781
  if (isBetaEnabled(options, 'hanaAssocRealCardinality') && elm.cardinality.src && elm.cardinality.src === 1)
776
782
  result += 'ONE TO ';
@@ -787,7 +793,7 @@ function toSqlDdl( csn, options ) {
787
793
  }
788
794
  result += ' JOIN ';
789
795
  result += `${renderArtifactName(elm.target)} AS ${quoteSqlId(elementName)} ON (`;
790
- result += `${renderExpr(elm.on, env.withSubPath([ 'on' ]))})`;
796
+ result += `${renderExpr(on, env.withSubPath([ 'on' ]))})`;
791
797
  }
792
798
  return result;
793
799
  }
@@ -1046,7 +1052,7 @@ function toSqlDdl( csn, options ) {
1046
1052
 
1047
1053
  // Add any path steps (possibly with parameters and filters) that may follow after that
1048
1054
  if (path.ref.length > 1)
1049
- result += `${sep}${renderExpr({ ref: path.ref.slice(1) }, env)}`;
1055
+ result += `${sep}${renderTypeRef({ ref: path.ref.slice(1) }, env)}`;
1050
1056
 
1051
1057
  return result;
1052
1058
  }
@@ -1469,52 +1475,54 @@ function toSqlDdl( csn, options ) {
1469
1475
  }
1470
1476
  }
1471
1477
 
1478
+
1472
1479
  /**
1473
- * @param {object} x
1480
+ * Render a magic variable. Values are determined in following order:
1481
+ * 1. User defined replacement in options.variableReplacements
1482
+ * 2. Predefined fallback values
1483
+ * 3. Rendering of the variable as a string (i.e. its name) + warning
1484
+ *
1485
+ * @param {CSN.Path} ref
1474
1486
  * @param {object} env
1475
1487
  * @return {string}
1476
1488
  */
1477
- function renderExpressionRef( x, env ) {
1478
- if (!x.param) {
1479
- const magicReplacement = getVariableReplacement(x.ref, options);
1489
+ function renderMagicVariable( ref, env ) {
1490
+ const magicReplacement = getVariableReplacement(ref, options);
1491
+ if (magicReplacement !== null)
1492
+ return renderStringForSql(magicReplacement, options.sqlDialect);
1480
1493
 
1481
- if (x.ref[0] === '$user') {
1482
- if (magicReplacement !== null)
1483
- return renderStringForSql(magicReplacement, options.sqlDialect);
1494
+ const name = pathName(ref);
1495
+ const result = variableForDialect(options, name);
1496
+ if (result)
1497
+ return result;
1484
1498
 
1485
- const result = render$user(x);
1486
- // Invalid second path step doesn't cause a return
1487
- if (result)
1488
- return result;
1489
- }
1490
- else if (x.ref[0] === '$tenant') {
1491
- if (magicReplacement !== null)
1492
- return renderStringForSql(magicReplacement, options.sqlDialect);
1493
-
1494
- const name = pathName(x.ref);
1495
- const result = variableForDialect(options, name);
1496
- if (result)
1497
- return result;
1498
- }
1499
- else if (x.ref[0] === '$at' || x.ref[0] === '$valid') {
1500
- const result = render$at(x);
1501
- // Invalid second path step doesn't cause a return
1502
- if (result)
1503
- return result;
1504
- }
1505
- else if (x.ref[0] === '$session' && magicReplacement !== null) {
1506
- return renderStringForSql(magicReplacement, options.sqlDialect);
1507
- }
1508
- else if (x.ref[0] === '$now') {
1509
- const name = pathName(x.ref);
1510
- const result = variableForDialect(options, name);
1511
- if (result)
1512
- return result;
1513
- return quoteSqlId(x.ref[0]);
1514
- }
1499
+ if (isVariableReplacementRequired(name)) {
1500
+ reportedMissingReplacements[name] = true;
1501
+ error('ref-undefined-var', env.path, { '#': 'value', id: name, option: 'variableReplacements' });
1502
+ }
1503
+ else if (!reportedMissingReplacements[name]) {
1504
+ reportedMissingReplacements[name] = true;
1505
+ warning('ref-unsupported-variable', env.path, { name, option: 'variableReplacements' },
1506
+ 'Variable $(NAME) is not supported. Use option $(OPTION) to specify a value for $(NAME)');
1515
1507
  }
1508
+
1509
+ return renderStringForSql(name, options.sqlDialect);
1510
+ }
1511
+
1512
+ /**
1513
+ * Must not be used for type refs, as something like `$user` will be interpreted as a magic
1514
+ * variable and not definition name.
1515
+ *
1516
+ * @param {object} x
1517
+ * @param {object} env
1518
+ * @return {string}
1519
+ */
1520
+ function renderExpressionRef( x, env ) {
1521
+ if (!x.param && isMagicVariable(pathId(x.ref[0])))
1522
+ return renderMagicVariable(x.ref, env);
1523
+
1516
1524
  // FIXME: We currently cannot distinguish whether '$parameters' was quoted or not - we
1517
- // assume that it was not if the path has length 2 (
1525
+ // assume that it was not if the path has length 2
1518
1526
  if (firstPathStepId(x.ref) === '$parameters' && x.ref.length === 2) {
1519
1527
  // Parameters must be uppercased and unquoted in SQL
1520
1528
  return `:${x.ref[1].toUpperCase()}`;
@@ -1527,43 +1535,10 @@ function toSqlDdl( csn, options ) {
1527
1535
  .join('.');
1528
1536
  }
1529
1537
 
1530
- /**
1531
- * @param {object} x
1532
- * @returns {string|null} Null in case of an invalid second path step
1533
- */
1534
- function render$user( x ) {
1535
- if (x.ref.length > 2 || typeof x.ref[1] !== 'string')
1536
- return null; // `$user` can only have two path steps
1537
-
1538
- const name = pathName(x.ref);
1539
- const result = variableForDialect(options, name);
1540
- if (result)
1541
- return result;
1542
-
1543
- if (!reportedMissingReplacements[name]) {
1544
- reportedMissingReplacements[name] = true;
1545
- warning('ref-unsupported-variable', null, { name, option: 'variableReplacements' },
1546
- 'Variable $(NAME) is not supported. Use option $(OPTION) to specify a value for $(NAME)');
1547
- }
1548
- return `'${name}'`;
1549
- }
1550
-
1551
- /**
1552
- * @param {object} x
1553
- * @returns {string|null} Null in case of an invalid second path step
1554
- */
1555
- function render$at( x ) {
1556
- if (x.ref.length > 2 || typeof x.ref[1] !== 'string')
1557
- return null; // `$at` can only have two path steps
1558
-
1559
- const name = pathName(x.ref);
1560
- const config = variableForDialect(options, name);
1561
- if (config)
1562
- return config;
1563
-
1564
- if (options.testMode)
1565
- throw new CompilerAssertion(`render$at: unhandled sqlDialect '${options.sqlDialect}' when rendering ${x.ref.join('.')}`);
1566
- return null;
1538
+ function renderTypeRef( x, env ) {
1539
+ const prefix = x.param ? ':' : '';
1540
+ const ref = x.ref.map((step, index) => renderPathStep(step, index, env.withSubPath([ 'ref', index ]))).join('.');
1541
+ return `${prefix}${ref}`;
1567
1542
  }
1568
1543
 
1569
1544
  /**
@@ -262,12 +262,14 @@ const cdsToSqlTypes = {
262
262
  'cds.UUID': 'NVARCHAR', // changed to cds.String earlier
263
263
  'cds.hana.ST_POINT': 'CHAR', // CHAR is implicit fallback used in toSql - make it explicit here
264
264
  'cds.hana.ST_GEOMETRY': 'CHAR', // CHAR is implicit fallback used in toSql - make it explicit here
265
+ 'cds.Vector': 'NVARCHAR', // Not supported; see #11725
265
266
  },
266
267
  hana: {
267
268
  'cds.hana.SMALLDECIMAL': 'SMALLDECIMAL',
268
269
  'cds.DateTime': 'SECONDDATE',
269
270
  'cds.hana.ST_POINT': 'ST_POINT',
270
271
  'cds.hana.ST_GEOMETRY': 'ST_GEOMETRY',
272
+ 'cds.Vector': 'REAL_VECTOR', // FIXME: test me
271
273
  },
272
274
  sqlite: {
273
275
  'cds.Date': 'DATE_TEXT',
@@ -277,6 +279,7 @@ const cdsToSqlTypes = {
277
279
  'cds.Binary': 'BINARY_BLOB',
278
280
  'cds.hana.BINARY': 'BINARY_BLOB',
279
281
  'cds.hana.SMALLDECIMAL': 'SMALLDECIMAL',
282
+ 'cds.Vector': 'BINARY_BLOB', // Not supported; see #11725
280
283
  },
281
284
  plain: {
282
285
  'cds.Binary': 'VARBINARY',
@@ -298,6 +301,7 @@ const cdsToSqlTypes = {
298
301
  'cds.Binary': 'BYTEA',
299
302
  'cds.Double': 'FLOAT8',
300
303
  'cds.UInt8': 'INTEGER', // Not equivalent
304
+ 'cds.Vector': 'VARCHAR', // Not supported; see #11725
301
305
  },
302
306
  };
303
307
 
@@ -425,6 +429,18 @@ function variableForDialect( options, variable ) {
425
429
  return variablesToSql[dialect]?.[variable] || variablesToSql.fallback[variable] || null;
426
430
  }
427
431
 
432
+ /**
433
+ * Whether a replacement is required for the given variable (e.g. '$user.id').
434
+ * Some variables such as `$user.id` are not required to have replacement values, even if
435
+ * there is no proper fallback via `variableForDialect(…)` (for example in sqlDialect 'plain').
436
+ *
437
+ * @param {string} name
438
+ * @return {boolean}
439
+ */
440
+ function isVariableReplacementRequired( name ) {
441
+ const notRequired = [ '$user.id', '$user.locale', '$tenant' ];
442
+ return !notRequired.includes(name);
443
+ }
428
444
 
429
445
  /**
430
446
  * Get the element matching the column
@@ -708,6 +724,7 @@ module.exports = {
708
724
  cdsToSqlTypes,
709
725
  cdsToHdbcdsTypes,
710
726
  variableForDialect,
727
+ isVariableReplacementRequired,
711
728
  hasHanaComment,
712
729
  getHanaComment,
713
730
  findElement,
@@ -1,5 +1,13 @@
1
1
  {
2
2
  "rules": {
3
3
  "no-shadow": "off"
4
- }
4
+ },
5
+ "overrides": [
6
+ {
7
+ "files": [
8
+ "addTenantFields.js"
9
+ ],
10
+ "extends": "../../.eslintrc-ydkjsi.json"
11
+ }
12
+ ]
5
13
  }