@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.
- package/CHANGELOG.md +50 -7
- package/bin/cdsc.js +13 -11
- package/doc/CHANGELOG_BETA.md +6 -0
- package/lib/api/main.js +256 -115
- package/lib/api/options.js +8 -0
- package/lib/base/message-registry.js +17 -4
- package/lib/base/messages.js +15 -3
- package/lib/base/model.js +1 -0
- package/lib/base/optionProcessorHelper.js +45 -176
- package/lib/checks/elements.js +32 -34
- package/lib/checks/enricher.js +39 -3
- package/lib/checks/validator.js +2 -3
- package/lib/compiler/assert-consistency.js +2 -1
- package/lib/compiler/builtins.js +20 -4
- package/lib/compiler/checks.js +30 -6
- package/lib/compiler/define.js +31 -9
- package/lib/compiler/populate.js +5 -1
- package/lib/compiler/resolve.js +26 -21
- package/lib/compiler/shared.js +19 -9
- package/lib/compiler/tweak-assocs.js +82 -107
- package/lib/compiler/utils.js +2 -1
- package/lib/edm/annotations/edmJson.js +23 -22
- package/lib/edm/annotations/genericTranslation.js +14 -4
- package/lib/edm/csn2edm.js +24 -10
- package/lib/edm/edmInboundChecks.js +1 -2
- package/lib/edm/edmPreprocessor.js +11 -9
- package/lib/edm/edmUtils.js +5 -2
- package/lib/gen/Dictionary.json +3 -1
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +4 -1
- package/lib/gen/language.tokens +1 -0
- package/lib/gen/languageParser.js +5253 -5214
- package/lib/json/to-csn.js +7 -1
- package/lib/language/antlrParser.js +19 -1
- package/lib/language/errorStrategy.js +21 -4
- package/lib/language/genericAntlrParser.js +9 -11
- package/lib/main.d.ts +28 -3
- package/lib/main.js +3 -0
- package/lib/model/csnRefs.js +4 -1
- package/lib/model/csnUtils.js +12 -7
- package/lib/optionProcessor.js +21 -19
- package/lib/render/manageConstraints.js +13 -29
- package/lib/render/toCdl.js +18 -15
- package/lib/render/toHdbcds.js +59 -28
- package/lib/render/toRename.js +6 -10
- package/lib/render/toSql.js +57 -82
- package/lib/render/utils/common.js +17 -0
- package/lib/transform/.eslintrc.json +9 -1
- package/lib/transform/addTenantFields.js +228 -0
- package/lib/transform/db/applyTransformations.js +27 -31
- package/lib/transform/db/assertUnique.js +4 -4
- package/lib/transform/db/cdsPersistence.js +1 -1
- package/lib/transform/db/flattening.js +68 -69
- package/lib/transform/db/temporal.js +1 -1
- package/lib/transform/draft/db.js +2 -16
- package/lib/transform/draft/odata.js +3 -3
- package/lib/transform/effective/associations.js +3 -5
- package/lib/transform/effective/main.js +6 -9
- package/lib/transform/forOdata.js +13 -9
- package/lib/transform/forRelationalDB.js +36 -17
- package/lib/transform/odata/toFinalBaseType.js +3 -3
- package/lib/transform/odata/typesExposure.js +14 -5
- package/lib/transform/transformUtils.js +47 -34
- package/lib/transform/translateAssocsToJoins.js +33 -8
- package/package.json +2 -2
package/lib/render/toHdbcds.js
CHANGED
|
@@ -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
|
-
} =
|
|
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 += `.${
|
|
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
|
-
|
|
1321
|
-
|
|
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
|
package/lib/render/toRename.js
CHANGED
|
@@ -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 } =
|
|
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,
|
|
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
|
|
package/lib/render/toSql.js
CHANGED
|
@@ -4,13 +4,14 @@
|
|
|
4
4
|
const {
|
|
5
5
|
getLastPartOf, getLastPartOfRef,
|
|
6
6
|
hasValidSkipOrExists, isBuiltinType, generatedByCompilerVersion, getNormalizedQuery,
|
|
7
|
-
forEachDefinition, getResultingName,
|
|
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
|
-
} =
|
|
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(
|
|
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}${
|
|
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
|
-
*
|
|
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
|
|
1478
|
-
|
|
1479
|
-
|
|
1489
|
+
function renderMagicVariable( ref, env ) {
|
|
1490
|
+
const magicReplacement = getVariableReplacement(ref, options);
|
|
1491
|
+
if (magicReplacement !== null)
|
|
1492
|
+
return renderStringForSql(magicReplacement, options.sqlDialect);
|
|
1480
1493
|
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1494
|
+
const name = pathName(ref);
|
|
1495
|
+
const result = variableForDialect(options, name);
|
|
1496
|
+
if (result)
|
|
1497
|
+
return result;
|
|
1484
1498
|
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
1532
|
-
|
|
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,
|