@sap/cds-compiler 2.5.0 → 2.10.4
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 +191 -9
- package/bin/cdsc.js +2 -2
- package/doc/CHANGELOG_BETA.md +33 -3
- package/lib/api/main.js +29 -101
- package/lib/api/options.js +15 -11
- package/lib/api/validate.js +12 -8
- package/lib/backends.js +0 -81
- package/lib/base/keywords.js +32 -2
- package/lib/base/message-registry.js +63 -9
- package/lib/base/messages.js +63 -21
- package/lib/base/model.js +2 -3
- package/lib/checks/defaultValues.js +27 -2
- package/lib/checks/elements.js +1 -6
- package/lib/checks/foreignKeys.js +0 -6
- package/lib/checks/managedWithoutKeys.js +17 -0
- package/lib/checks/nonexpandableStructured.js +38 -0
- package/lib/checks/onConditions.js +9 -45
- package/lib/checks/queryNoDbArtifacts.js +25 -7
- package/lib/checks/selectItems.js +25 -2
- package/lib/checks/types.js +26 -2
- package/lib/checks/unknownMagic.js +38 -0
- package/lib/checks/utils.js +61 -0
- package/lib/checks/validator.js +60 -7
- package/lib/compiler/assert-consistency.js +16 -7
- package/lib/compiler/builtins.js +2 -0
- package/lib/compiler/checks.js +6 -4
- package/lib/compiler/definer.js +99 -42
- package/lib/compiler/index.js +73 -27
- package/lib/compiler/resolver.js +288 -157
- package/lib/compiler/shared.js +31 -11
- package/lib/edm/annotations/genericTranslation.js +182 -186
- package/lib/edm/csn2edm.js +103 -108
- package/lib/edm/edm.js +18 -21
- package/lib/edm/edmPreprocessor.js +361 -114
- package/lib/edm/edmUtils.js +103 -33
- package/lib/gen/Dictionary.json +22 -0
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +12 -1
- package/lib/gen/language.tokens +57 -53
- package/lib/gen/languageLexer.interp +10 -1
- package/lib/gen/languageLexer.js +770 -744
- package/lib/gen/languageLexer.tokens +49 -46
- package/lib/gen/languageParser.js +4713 -4279
- package/lib/json/from-csn.js +103 -45
- package/lib/json/to-csn.js +296 -117
- package/lib/language/antlrParser.js +4 -3
- package/lib/language/errorStrategy.js +1 -0
- package/lib/language/genericAntlrParser.js +21 -12
- package/lib/language/language.g4 +99 -31
- package/lib/main.d.ts +81 -3
- package/lib/main.js +30 -7
- package/lib/model/api.js +78 -0
- package/lib/model/csnRefs.js +329 -142
- package/lib/model/csnUtils.js +235 -58
- package/lib/model/enrichCsn.js +18 -1
- package/lib/model/revealInternalProperties.js +2 -1
- package/lib/modelCompare/compare.js +37 -20
- package/lib/optionProcessor.js +9 -3
- package/lib/render/.eslintrc.json +4 -1
- package/lib/render/DuplicateChecker.js +8 -5
- package/lib/render/toCdl.js +112 -33
- package/lib/render/toHdbcds.js +134 -64
- package/lib/render/toSql.js +91 -38
- package/lib/render/utils/common.js +8 -13
- package/lib/render/utils/sql.js +3 -3
- package/lib/sql-identifier.js +6 -1
- package/lib/transform/db/assertUnique.js +5 -6
- package/lib/transform/db/constraints.js +29 -13
- package/lib/transform/db/draft.js +8 -6
- package/lib/transform/db/expansion.js +582 -0
- package/lib/transform/db/flattening.js +325 -0
- package/lib/transform/db/groupByOrderBy.js +2 -2
- package/lib/transform/db/transformExists.js +284 -63
- package/lib/transform/forHanaNew.js +98 -381
- package/lib/transform/forOdataNew.js +21 -22
- package/lib/transform/localized.js +37 -10
- package/lib/transform/odata/attachPath.js +19 -4
- package/lib/transform/odata/generateForeignKeyElements.js +11 -10
- package/lib/transform/odata/referenceFlattener.js +60 -39
- package/lib/transform/odata/sortByAssociationDependency.js +2 -2
- package/lib/transform/odata/structuralPath.js +72 -0
- package/lib/transform/odata/structureFlattener.js +19 -18
- package/lib/transform/odata/typesExposure.js +22 -12
- package/lib/transform/transformUtilsNew.js +134 -78
- package/lib/transform/translateAssocsToJoins.js +17 -14
- package/lib/transform/universalCsnEnricher.js +67 -0
- package/lib/utils/file.js +0 -11
- package/lib/utils/moduleResolve.js +6 -8
- package/package.json +1 -1
- package/lib/json/walker.js +0 -26
- package/lib/transform/sqlite +0 -0
- package/lib/utils/string.js +0 -17
package/lib/render/toHdbcds.js
CHANGED
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
const {
|
|
4
4
|
getParentNameOf, getLastPartOf, getLastPartOfRef,
|
|
5
5
|
hasValidSkipOrExists, isBuiltinType, generatedByCompilerVersion, getNormalizedQuery,
|
|
6
|
-
getRootArtifactName, getResultingName, getNamespace,
|
|
6
|
+
getRootArtifactName, getResultingName, getNamespace, forEachMember,
|
|
7
7
|
} = require('../model/csnUtils');
|
|
8
8
|
const keywords = require('../base/keywords');
|
|
9
9
|
const {
|
|
10
|
-
renderFunc,
|
|
11
|
-
hasHanaComment, getHanaComment, findElement,
|
|
10
|
+
renderFunc, beautifyExprArray, getRealName, addContextMarkers, addIntermediateContexts, cdsToSqlTypes,
|
|
11
|
+
hasHanaComment, getHanaComment, findElement, funcWithoutParen,
|
|
12
12
|
} = require('./utils/common');
|
|
13
13
|
const {
|
|
14
14
|
renderReferentialConstraint,
|
|
@@ -19,6 +19,8 @@ const { checkCSNVersion } = require('../json/csnVersion');
|
|
|
19
19
|
const { makeMessageFunction } = require('../base/messages');
|
|
20
20
|
const timetrace = require('../utils/timetrace');
|
|
21
21
|
|
|
22
|
+
const { smartId, delimitedId } = require('../sql-identifier');
|
|
23
|
+
|
|
22
24
|
const $PROJECTION = '$projection';
|
|
23
25
|
const $SELF = '$self';
|
|
24
26
|
|
|
@@ -39,8 +41,7 @@ function getEscapedHanaComment(obj) {
|
|
|
39
41
|
* { "foo" : "using XY; context foo {...};",
|
|
40
42
|
* "bar::wiz" : "namespace bar::; entity wiz {...};"
|
|
41
43
|
* }
|
|
42
|
-
*
|
|
43
|
-
* only affects translation of '$self.foo' in paths and ::-ish namespace declarations)
|
|
44
|
+
*
|
|
44
45
|
* FIXME: This comment no longer tells the whole truth
|
|
45
46
|
*
|
|
46
47
|
* @param {CSN.Model} csn HANA transformed CSN
|
|
@@ -49,9 +50,9 @@ function getEscapedHanaComment(obj) {
|
|
|
49
50
|
*/
|
|
50
51
|
function toHdbcdsSource(csn, options) {
|
|
51
52
|
timetrace.start('HDBCDS rendering');
|
|
52
|
-
const plainNames = options.
|
|
53
|
-
const quotedNames = options.
|
|
54
|
-
const hdbcdsNames = options.
|
|
53
|
+
const plainNames = options.sqlMapping === 'plain';
|
|
54
|
+
const quotedNames = options.sqlMapping === 'quoted';
|
|
55
|
+
const hdbcdsNames = options.sqlMapping === 'hdbcds';
|
|
55
56
|
|
|
56
57
|
const {
|
|
57
58
|
info, warning, error, throwWithError,
|
|
@@ -62,7 +63,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
62
63
|
const result = Object.create(null);
|
|
63
64
|
|
|
64
65
|
|
|
65
|
-
const globalDuplicateChecker = new DuplicateChecker(options.
|
|
66
|
+
const globalDuplicateChecker = new DuplicateChecker(options.sqlMapping); // registry for all artifact names and element names
|
|
66
67
|
|
|
67
68
|
const killList = [];
|
|
68
69
|
if (quotedNames)
|
|
@@ -389,7 +390,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
389
390
|
const childEnv = increaseIndent(env);
|
|
390
391
|
const normalizedArtifactName = renderArtifactName(artifactName, env);
|
|
391
392
|
|
|
392
|
-
globalDuplicateChecker.addArtifact(art['@cds.persistence.name'],
|
|
393
|
+
globalDuplicateChecker.addArtifact(art['@cds.persistence.name'], env.path, artifactName);
|
|
393
394
|
|
|
394
395
|
if (hasHanaComment(art, options))
|
|
395
396
|
result += `${env.indent}@Comment: '${getEscapedHanaComment(art)}'\n`;
|
|
@@ -401,7 +402,11 @@ function toHdbcdsSource(csn, options) {
|
|
|
401
402
|
}
|
|
402
403
|
result += ' {\n';
|
|
403
404
|
const duplicateChecker = new DuplicateChecker(); // registry for all artifact names and element names
|
|
404
|
-
duplicateChecker.addArtifact(artifactName,
|
|
405
|
+
duplicateChecker.addArtifact(artifactName, env.path, artifactName);
|
|
406
|
+
childEnv.path = env.path.concat('elements');
|
|
407
|
+
// calculate __aliases which must be used in case an association
|
|
408
|
+
// has the same identifier as it's target
|
|
409
|
+
createTopLevelAliasesForArtifact(artifactName, art, env);
|
|
405
410
|
for (const name in art.elements)
|
|
406
411
|
result += renderElement(name, art.elements[name], childEnv, duplicateChecker);
|
|
407
412
|
|
|
@@ -411,6 +416,33 @@ function toHdbcdsSource(csn, options) {
|
|
|
411
416
|
return result;
|
|
412
417
|
}
|
|
413
418
|
|
|
419
|
+
/**
|
|
420
|
+
* If an association/composition has the same identifier as it's target
|
|
421
|
+
* we must render an "using target as __target" and use the alias to refer to the target
|
|
422
|
+
*
|
|
423
|
+
* @param {string} artName
|
|
424
|
+
* @param {CSN.Artifact} art
|
|
425
|
+
* @param {CdlRenderEnvironment} env
|
|
426
|
+
*/
|
|
427
|
+
function createTopLevelAliasesForArtifact(artName, art, env) {
|
|
428
|
+
forEachMember(art, (element) => {
|
|
429
|
+
if (!element.target)
|
|
430
|
+
return;
|
|
431
|
+
|
|
432
|
+
let alias = element['@cds.persistence.name'];
|
|
433
|
+
if (uppercaseAndUnderscore(element.target) === element['@cds.persistence.name']) {
|
|
434
|
+
alias = createTopLevelAliasName(element['@cds.persistence.name']);
|
|
435
|
+
// calculate new alias if it would conflict with other csn.Artifact
|
|
436
|
+
while (csn.definitions[alias])
|
|
437
|
+
alias = createTopLevelAliasName(alias);
|
|
438
|
+
env.topLevelAliases[element['@cds.persistence.name']] = {
|
|
439
|
+
quotedName: formatIdentifier(element['@cds.persistence.name']),
|
|
440
|
+
quotedAlias: formatIdentifier(alias),
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
|
|
414
446
|
/**
|
|
415
447
|
* Render the 'technical configuration { ... }' section 'tc' of an entity.
|
|
416
448
|
*
|
|
@@ -516,9 +548,9 @@ function toHdbcdsSource(csn, options) {
|
|
|
516
548
|
// Special handling for HANA CDS: Must omit the ':' before anonymous structured types (for historical reasons)
|
|
517
549
|
const omitColon = (!elm.type && elm.elements);
|
|
518
550
|
let result = '';
|
|
519
|
-
const quotedElementName =
|
|
551
|
+
const quotedElementName = formatIdentifier(elementName);
|
|
520
552
|
if (duplicateChecker)
|
|
521
|
-
duplicateChecker.addElement(quotedElementName,
|
|
553
|
+
duplicateChecker.addElement(quotedElementName, env.path, elementName);
|
|
522
554
|
|
|
523
555
|
if (hasHanaComment(elm, options))
|
|
524
556
|
result += `${env.indent}@Comment: '${getEscapedHanaComment(elm)}'\n`;
|
|
@@ -548,7 +580,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
548
580
|
if (source.SELECT || source.SET) {
|
|
549
581
|
let result = `(${renderQuery(source, false, increaseIndent(env))})`;
|
|
550
582
|
if (source.as)
|
|
551
|
-
result += ` as ${
|
|
583
|
+
result += ` as ${formatIdentifier(source.as)}`;
|
|
552
584
|
|
|
553
585
|
return result;
|
|
554
586
|
}
|
|
@@ -598,7 +630,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
598
630
|
|
|
599
631
|
// Even the first step might have parameters and/or a filter
|
|
600
632
|
if (path.ref[0].args)
|
|
601
|
-
result += `(${renderArgs(path.ref[0]
|
|
633
|
+
result += `(${renderArgs(path.ref[0], ':', env)})`;
|
|
602
634
|
|
|
603
635
|
if (path.ref[0].where)
|
|
604
636
|
result += `[${path.ref[0].cardinality ? (`${path.ref[0].cardinality.max}: `) : ''}${renderExpr(path.ref[0].where, env, true, true)}]`;
|
|
@@ -624,14 +656,14 @@ function toHdbcdsSource(csn, options) {
|
|
|
624
656
|
function renderAbsolutePathWithAlias(path, env) {
|
|
625
657
|
let result = renderAbsolutePath(path, env);
|
|
626
658
|
// Take care of aliases - for artifact references, use the resulting name (multi-dot joined with _)
|
|
627
|
-
const implicitAlias = path.ref.length === 0 ? getLastPartOf(getResultingName(csn, options.
|
|
659
|
+
const implicitAlias = path.ref.length === 0 ? getLastPartOf(getResultingName(csn, options.sqlMapping, path.ref[0])) : getLastPartOfRef(path.ref);
|
|
628
660
|
if (path.as) {
|
|
629
661
|
// Source had an alias - render it
|
|
630
|
-
result += ` as ${
|
|
662
|
+
result += ` as ${formatIdentifier(path.as)}`;
|
|
631
663
|
}
|
|
632
|
-
else if (getLastPartOf(result) !==
|
|
664
|
+
else if (getLastPartOf(result) !== formatIdentifier(implicitAlias)) {
|
|
633
665
|
// Render an artificial alias if the result would produce a different one
|
|
634
|
-
result += ` as ${
|
|
666
|
+
result += ` as ${formatIdentifier(implicitAlias)}`;
|
|
635
667
|
}
|
|
636
668
|
return result;
|
|
637
669
|
}
|
|
@@ -653,9 +685,9 @@ function toHdbcdsSource(csn, options) {
|
|
|
653
685
|
const leaf = col.as || col.ref && col.ref[col.ref.length - 1];
|
|
654
686
|
// Render 'null as <alias>' only for database and if element is virtual
|
|
655
687
|
|
|
656
|
-
if (element && element.virtual) {
|
|
688
|
+
if (element && element.virtual || env._artifact.elements[leaf] && env._artifact.elements[leaf].virtual) {
|
|
657
689
|
if (isDeprecatedEnabled(options, 'renderVirtualElements'))
|
|
658
|
-
return `${result}${env.indent}null as ${
|
|
690
|
+
return `${result}${env.indent}null as ${formatIdentifier(leaf)}`;
|
|
659
691
|
}
|
|
660
692
|
else {
|
|
661
693
|
return renderNonVirtualColumn();
|
|
@@ -683,7 +715,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
683
715
|
alias = leaf;
|
|
684
716
|
|
|
685
717
|
if (alias)
|
|
686
|
-
result += ` as ${
|
|
718
|
+
result += ` as ${formatIdentifier(alias)}`;
|
|
687
719
|
|
|
688
720
|
// Explicit type provided for the view element?
|
|
689
721
|
if (col.cast && col.cast.target) {
|
|
@@ -710,7 +742,8 @@ function toHdbcdsSource(csn, options) {
|
|
|
710
742
|
*/
|
|
711
743
|
function renderView(artifactName, art, env) {
|
|
712
744
|
let result = '';
|
|
713
|
-
|
|
745
|
+
const artifactPath = [ 'definitions', artifactName ];
|
|
746
|
+
globalDuplicateChecker.addArtifact(art['@cds.persistence.name'], artifactPath, artifactName);
|
|
714
747
|
|
|
715
748
|
if (hasHanaComment(art, options))
|
|
716
749
|
result += `${env.indent}@Comment: '${getEscapedHanaComment(art)}'\n`;
|
|
@@ -726,7 +759,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
726
759
|
result += ' as ';
|
|
727
760
|
}
|
|
728
761
|
env._artifact = art;
|
|
729
|
-
result += renderQuery(getNormalizedQuery(art).query, true, env,
|
|
762
|
+
result += renderQuery(getNormalizedQuery(art).query, true, env, artifactPath.concat(art.projection ? 'projection' : 'query'), art.elements);
|
|
730
763
|
result += ';\n';
|
|
731
764
|
return result;
|
|
732
765
|
}
|
|
@@ -776,7 +809,6 @@ function toHdbcdsSource(csn, options) {
|
|
|
776
809
|
const childEnv = increaseIndent(env);
|
|
777
810
|
childEnv.currentArtifactName = $PROJECTION; // $self to be replaced by $projection
|
|
778
811
|
result += `select from ${renderViewSource(select.from, env)}`;
|
|
779
|
-
|
|
780
812
|
if (select.mixin) {
|
|
781
813
|
let elems = '';
|
|
782
814
|
for (const name in select.mixin)
|
|
@@ -797,7 +829,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
797
829
|
result += `${env.indent}}`;
|
|
798
830
|
}
|
|
799
831
|
if (select.excluding) {
|
|
800
|
-
result += ` excluding {\n${select.excluding.map(id => `${childEnv.indent}${
|
|
832
|
+
result += ` excluding {\n${select.excluding.map(id => `${childEnv.indent}${formatIdentifier(id)}`).join(',\n')}\n`;
|
|
801
833
|
result += `${env.indent}}`;
|
|
802
834
|
}
|
|
803
835
|
|
|
@@ -895,7 +927,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
895
927
|
function renderParameter(parName, par, env) {
|
|
896
928
|
if (par.notNull === true || par.notNull === false)
|
|
897
929
|
info(null, env.path.concat([ 'params', parName ]), 'Not Null constraints on HDBCDS view parameters are not allowed and are ignored');
|
|
898
|
-
return `${env.indent +
|
|
930
|
+
return `${env.indent + formatParamIdentifier(parName, env.path.concat([ 'params', parName ]))} : ${renderTypeReference(par, env)}`;
|
|
899
931
|
}
|
|
900
932
|
|
|
901
933
|
/**
|
|
@@ -1012,10 +1044,24 @@ function toHdbcdsSource(csn, options) {
|
|
|
1012
1044
|
|
|
1013
1045
|
result += `${renderCardinality(elm.cardinality)} to `;
|
|
1014
1046
|
|
|
1047
|
+
|
|
1015
1048
|
// normal target or named aspect
|
|
1016
1049
|
if (elm.target || elm.targetAspect && typeof elm.targetAspect === 'string') {
|
|
1017
|
-
|
|
1018
|
-
|
|
1050
|
+
// we might have a "using target as __target"
|
|
1051
|
+
const targetArtifact = csn.definitions[elm.target];
|
|
1052
|
+
const targetAlias = env.topLevelAliases[targetArtifact['@cds.persistence.name']];
|
|
1053
|
+
if (targetAlias) {
|
|
1054
|
+
result += targetAlias.quotedAlias;
|
|
1055
|
+
}
|
|
1056
|
+
else {
|
|
1057
|
+
result += plainNames ? renderAbsoluteNamePlain(elm.target || elm.targetAspect, env)
|
|
1058
|
+
: renderAbsoluteNameWithQuotes(elm.target || elm.targetAspect, env);
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
// ON-condition (if any)
|
|
1063
|
+
if (elm.on) {
|
|
1064
|
+
result += ` on ${renderExpr(elm.on, env, true, true)}`;
|
|
1019
1065
|
}
|
|
1020
1066
|
else if (elm.targetAspect && elm.targetAspect.elements) { // anonymous aspect
|
|
1021
1067
|
const childEnv = increaseIndent(env);
|
|
@@ -1027,11 +1073,6 @@ function toHdbcdsSource(csn, options) {
|
|
|
1027
1073
|
}
|
|
1028
1074
|
|
|
1029
1075
|
|
|
1030
|
-
// ON-condition (if any)
|
|
1031
|
-
if (elm.on)
|
|
1032
|
-
result += ` on ${renderExpr(elm.on, env, true, true)}`;
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
1076
|
// Foreign keys (if any, unless we also have an ON_condition (which means we have been transformed from managed to unmanaged)
|
|
1036
1077
|
if (elm.keys && !elm.on)
|
|
1037
1078
|
result += ` { ${Object.keys(elm.keys).map(name => renderForeignKey(elm.keys[name], env)).join(', ')} }`;
|
|
@@ -1087,7 +1128,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
1087
1128
|
function renderExpr(x, env, inline = true, inExpr = false) {
|
|
1088
1129
|
// Compound expression
|
|
1089
1130
|
if (Array.isArray(x))
|
|
1090
|
-
return
|
|
1131
|
+
return beautifyExprArray(x.map(item => renderExpr(item, env, inline, inExpr)));
|
|
1091
1132
|
|
|
1092
1133
|
if (typeof x === 'object' && x !== null) {
|
|
1093
1134
|
if (inExpr && x.cast && x.cast.type)
|
|
@@ -1129,6 +1170,9 @@ function toHdbcdsSource(csn, options) {
|
|
|
1129
1170
|
|
|
1130
1171
|
const regex = RegExp(/^[a-zA-Z][\w#$]*$/, 'g');
|
|
1131
1172
|
const funcName = regex.test(x.func) ? x.func : quoteId(x.func);
|
|
1173
|
+
// we can't quote functions with parens, issue warning if it is a reserved keyword
|
|
1174
|
+
if (!funcWithoutParen(x, 'hana') && keywords.hdbcds.includes(uppercaseAndUnderscore(funcName)))
|
|
1175
|
+
warning(null, x.$location, `The identifier “${uppercaseAndUnderscore(funcName)}“ is a SAP HANA keyword`);
|
|
1132
1176
|
return renderFunc( funcName, x, 'hana', a => renderArgs(a, '=>', env) );
|
|
1133
1177
|
}
|
|
1134
1178
|
// Nested expression
|
|
@@ -1188,11 +1232,11 @@ function toHdbcdsSource(csn, options) {
|
|
|
1188
1232
|
if (x.ref[0] === '$user') {
|
|
1189
1233
|
// FIXME: this is all not enough: we might need an explicit select item alias
|
|
1190
1234
|
if (x.ref[1] === 'id') {
|
|
1191
|
-
if (options.
|
|
1192
|
-
return `'${options.
|
|
1235
|
+
if (options.magicVars && options.magicVars.user && (typeof options.magicVars.user === 'string' || options.magicVars.user instanceof String))
|
|
1236
|
+
return `'${options.magicVars.user}'`;
|
|
1193
1237
|
|
|
1194
|
-
else if ((options.
|
|
1195
|
-
return `'${options.
|
|
1238
|
+
else if ((options.magicVars && options.magicVars.user && options.magicVars.user.id) && (typeof options.magicVars.user.id === 'string' || options.magicVars.user.id instanceof String))
|
|
1239
|
+
return `'${options.magicVars.user.id}'`;
|
|
1196
1240
|
|
|
1197
1241
|
return 'SESSION_CONTEXT(\'APPLICATIONUSER\')';
|
|
1198
1242
|
}
|
|
@@ -1267,7 +1311,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
1267
1311
|
[ $SELF, $PROJECTION, '$session' ].includes(s))
|
|
1268
1312
|
return s;
|
|
1269
1313
|
|
|
1270
|
-
return
|
|
1314
|
+
return formatIdentifier(s);
|
|
1271
1315
|
}
|
|
1272
1316
|
// ID with filters or parameters
|
|
1273
1317
|
else if (typeof s === 'object') {
|
|
@@ -1277,13 +1321,13 @@ function toHdbcdsSource(csn, options) {
|
|
|
1277
1321
|
|
|
1278
1322
|
// Not really a path step but an object-like function call
|
|
1279
1323
|
if (s.func)
|
|
1280
|
-
return `${s.func}(${renderArgs(s
|
|
1324
|
+
return `${s.func}(${renderArgs(s, '=>', env)})`;
|
|
1281
1325
|
|
|
1282
1326
|
// Path step, possibly with view parameters and/or filters
|
|
1283
|
-
let result = `${
|
|
1327
|
+
let result = `${formatIdentifier(s.id)}`;
|
|
1284
1328
|
if (s.args) {
|
|
1285
1329
|
// View parameters
|
|
1286
|
-
result += `(${renderArgs(s
|
|
1330
|
+
result += `(${renderArgs(s, ':', env)})`;
|
|
1287
1331
|
}
|
|
1288
1332
|
if (s.where) {
|
|
1289
1333
|
// Filter, possibly with cardinality
|
|
@@ -1300,19 +1344,21 @@ function toHdbcdsSource(csn, options) {
|
|
|
1300
1344
|
* Render function arguments or view parameters (positional if array, named if object/dict),
|
|
1301
1345
|
* using 'sep' as separator for positional parameters
|
|
1302
1346
|
*
|
|
1303
|
-
* @param {object
|
|
1347
|
+
* @param {object} node with `args` to render
|
|
1304
1348
|
* @param {string} sep Seperator between arguments
|
|
1305
1349
|
* @param {CdlRenderEnvironment} env Environment
|
|
1306
1350
|
* @returns {string} Rendered arguments
|
|
1307
1351
|
*/
|
|
1308
|
-
function renderArgs(
|
|
1352
|
+
function renderArgs(node, sep, env) {
|
|
1353
|
+
const args = node.args ? node.args : {};
|
|
1309
1354
|
// Positional arguments
|
|
1310
1355
|
if (Array.isArray(args))
|
|
1311
1356
|
return args.map(arg => renderExpr(arg, env)).join(', ');
|
|
1312
1357
|
|
|
1313
1358
|
// Named arguments (object/dict)
|
|
1314
1359
|
else if (typeof args === 'object')
|
|
1315
|
-
|
|
1360
|
+
// if this is a function param which is not a reference to the model, we must not quote it
|
|
1361
|
+
return Object.keys(args).map(key => `${node.func ? key : formatIdentifier(key)} ${sep} ${renderExpr(args[key], env)}`).join(', ');
|
|
1316
1362
|
|
|
1317
1363
|
|
|
1318
1364
|
throw new Error(`Unknown args: ${JSON.stringify(args)}`);
|
|
@@ -1405,10 +1451,10 @@ function toHdbcdsSource(csn, options) {
|
|
|
1405
1451
|
function renderAbsoluteNamePlain(absName, env) {
|
|
1406
1452
|
// Add using declaration
|
|
1407
1453
|
env.topLevelAliases[absName] = {
|
|
1408
|
-
quotedName: uppercaseAndUnderscore(absName),
|
|
1409
|
-
quotedAlias: uppercaseAndUnderscore(absName),
|
|
1454
|
+
quotedName: formatIdentifier(uppercaseAndUnderscore(absName)),
|
|
1455
|
+
quotedAlias: formatIdentifier(uppercaseAndUnderscore(absName)),
|
|
1410
1456
|
};
|
|
1411
|
-
return uppercaseAndUnderscore(absName);
|
|
1457
|
+
return formatIdentifier(uppercaseAndUnderscore(absName));
|
|
1412
1458
|
}
|
|
1413
1459
|
|
|
1414
1460
|
/**
|
|
@@ -1493,7 +1539,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
1493
1539
|
function renderUsings(artifactName, env) {
|
|
1494
1540
|
const distinct = {};
|
|
1495
1541
|
Object.keys(env.topLevelAliases)
|
|
1496
|
-
.filter(name =>
|
|
1542
|
+
.filter(name => env.topLevelAliases[name].quotedAlias !== formatIdentifier(uppercaseAndUnderscore(artifactName))) // avoid "using FOO as FOO" in FOO.cds
|
|
1497
1543
|
.forEach((name) => {
|
|
1498
1544
|
distinct[`using ${env.topLevelAliases[name].quotedName} as ${env.topLevelAliases[name].quotedAlias};\n`] = '';
|
|
1499
1545
|
});
|
|
@@ -1564,6 +1610,8 @@ function toHdbcdsSource(csn, options) {
|
|
|
1564
1610
|
topLevelAliases: Object.create(null),
|
|
1565
1611
|
// Current name prefix (including trailing dot if not empty)
|
|
1566
1612
|
namePrefix: '',
|
|
1613
|
+
// CSN path - should at least point to the correct artifact
|
|
1614
|
+
path: [],
|
|
1567
1615
|
};
|
|
1568
1616
|
}
|
|
1569
1617
|
|
|
@@ -1608,7 +1656,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
1608
1656
|
*/
|
|
1609
1657
|
function quoteAbsolutePathString(abspath) {
|
|
1610
1658
|
const namespace = getNamespace(csn, abspath);
|
|
1611
|
-
const resultingName = getResultingName(csn, options.
|
|
1659
|
+
const resultingName = getResultingName(csn, options.sqlMapping, abspath);
|
|
1612
1660
|
|
|
1613
1661
|
if (hdbcdsNames && namespace)
|
|
1614
1662
|
return `${quotePathString(namespace)}::${quotePathString(resultingName.slice(namespace.length + 2))}`;
|
|
@@ -1633,10 +1681,19 @@ function toHdbcdsSource(csn, options) {
|
|
|
1633
1681
|
return id;
|
|
1634
1682
|
|
|
1635
1683
|
|
|
1636
|
-
|
|
1684
|
+
switch (options.forHana.names) {
|
|
1685
|
+
case 'plain':
|
|
1686
|
+
return smartId(id, 'hdbcds');
|
|
1687
|
+
case 'quoted':
|
|
1688
|
+
return delimitedId(id, 'hdbcds');
|
|
1689
|
+
case 'hdbcds':
|
|
1690
|
+
return delimitedId(id, 'hdbcds');
|
|
1691
|
+
default:
|
|
1692
|
+
return null;
|
|
1693
|
+
}
|
|
1637
1694
|
}
|
|
1638
1695
|
|
|
1639
|
-
|
|
1696
|
+
/*
|
|
1640
1697
|
* Return an absolute name 'absname', with '::' inserted if required by naming strategy 'hdbcds', quoted
|
|
1641
1698
|
* as if it was a single identifier (required only for native USINGs)
|
|
1642
1699
|
*
|
|
@@ -1654,21 +1711,34 @@ function toHdbcdsSource(csn, options) {
|
|
|
1654
1711
|
}
|
|
1655
1712
|
|
|
1656
1713
|
/**
|
|
1657
|
-
* Quote or uppercase an identifier 'id', depending on naming strategy
|
|
1714
|
+
* Quote and/or uppercase an identifier 'id', depending on naming strategy
|
|
1658
1715
|
*
|
|
1659
1716
|
* @param {string} id Identifier
|
|
1660
|
-
* @param {CSN.Location} [location] Optional location for the warning.
|
|
1661
1717
|
* @returns {string} Quoted/uppercased id
|
|
1662
1718
|
*/
|
|
1663
|
-
function
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1719
|
+
function formatIdentifier(id) {
|
|
1720
|
+
id = options.forHana.names === 'plain' ? id.toUpperCase() : id;
|
|
1721
|
+
return quoteId(id);
|
|
1722
|
+
}
|
|
1723
|
+
|
|
1724
|
+
/**
|
|
1725
|
+
* Quote or uppercase a parameter identifier 'id', depending on naming strategy
|
|
1726
|
+
* Smart quoting cannot be applied to the parameter identifiers, issue warning instead.
|
|
1727
|
+
*
|
|
1728
|
+
*
|
|
1729
|
+
* @param {string} id Identifier
|
|
1730
|
+
* @param {CSN.Path} [location] Optional location for the warning.
|
|
1731
|
+
* @returns {string} Quoted/uppercased id
|
|
1732
|
+
*/
|
|
1733
|
+
function formatParamIdentifier(id, location) {
|
|
1734
|
+
// Warn if colliding with HANA keyword, but do not quote for plain
|
|
1735
|
+
// --> quoted reserved words as param lead to a weird deployment error
|
|
1736
|
+
if (keywords.hdbcds.includes(uppercaseAndUnderscore(id)))
|
|
1737
|
+
warning(null, location, { id }, 'The identifier $(ID) is a SAP HANA keyword');
|
|
1738
|
+
|
|
1739
|
+
if (plainNames)
|
|
1740
|
+
return uppercaseAndUnderscore(id);
|
|
1669
1741
|
|
|
1670
|
-
return result;
|
|
1671
|
-
}
|
|
1672
1742
|
return quoteId(id);
|
|
1673
1743
|
}
|
|
1674
1744
|
|
|
@@ -1691,7 +1761,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
1691
1761
|
*/
|
|
1692
1762
|
function renderArtifactName(artifactName, env, fallthrough = false) {
|
|
1693
1763
|
if (plainNames && !fallthrough)
|
|
1694
|
-
return uppercaseAndUnderscore(artifactName);
|
|
1764
|
+
return formatIdentifier(uppercaseAndUnderscore(artifactName));
|
|
1695
1765
|
// hdbcds with quoted or hdbcds naming
|
|
1696
1766
|
return env.namePrefix + quoteId(getRealName(csn, artifactName).replace(/\./g, '_'));
|
|
1697
1767
|
}
|