@sap/cds-compiler 2.11.4 → 2.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +58 -1
- package/bin/cds_update_identifiers.js +7 -7
- package/bin/cdsc.js +9 -10
- package/doc/CHANGELOG_ARCHIVE.md +1 -1
- package/doc/CHANGELOG_BETA.md +12 -0
- package/lib/api/main.js +2 -0
- package/lib/api/options.js +2 -2
- package/lib/base/message-registry.js +31 -2
- package/lib/base/model.js +1 -0
- package/lib/base/optionProcessorHelper.js +97 -69
- package/lib/checks/.eslintrc.json +2 -0
- package/lib/checks/actionsFunctions.js +2 -1
- package/lib/checks/foreignKeys.js +4 -4
- package/lib/checks/managedInType.js +4 -4
- package/lib/checks/queryNoDbArtifacts.js +1 -3
- package/lib/checks/sql-snippets.js +93 -0
- package/lib/checks/validator.js +8 -0
- package/lib/compiler/assert-consistency.js +5 -3
- package/lib/compiler/base.js +0 -1
- package/lib/compiler/checks.js +32 -9
- package/lib/compiler/definer.js +25 -4
- package/lib/compiler/index.js +1 -1
- package/lib/compiler/propagator.js +3 -2
- package/lib/compiler/resolver.js +97 -6
- package/lib/compiler/shared.js +12 -1
- package/lib/compiler/utils.js +7 -0
- package/lib/edm/annotations/genericTranslation.js +34 -17
- package/lib/edm/annotations/preprocessAnnotations.js +1 -1
- package/lib/edm/csn2edm.js +1 -1
- package/lib/edm/edm.js +8 -8
- package/lib/edm/edmPreprocessor.js +30 -23
- package/lib/edm/edmUtils.js +11 -12
- package/lib/gen/Dictionary.json +82 -40
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +3 -1
- package/lib/gen/language.tokens +15 -14
- package/lib/gen/languageLexer.interp +9 -1
- package/lib/gen/languageLexer.js +830 -779
- package/lib/gen/languageLexer.tokens +7 -6
- package/lib/gen/languageParser.js +2401 -2282
- package/lib/json/from-csn.js +47 -16
- package/lib/json/to-csn.js +17 -5
- package/lib/language/antlrParser.js +3 -3
- package/lib/language/docCommentParser.js +1 -1
- package/lib/language/genericAntlrParser.js +68 -51
- package/lib/language/language.g4 +128 -74
- package/lib/language/multiLineStringParser.js +536 -0
- package/lib/main.d.ts +5 -3
- package/lib/main.js +3 -2
- package/lib/model/csnRefs.js +116 -68
- package/lib/model/csnUtils.js +40 -48
- package/lib/model/enrichCsn.js +30 -14
- package/lib/optionProcessor.js +3 -3
- package/lib/render/DuplicateChecker.js +1 -1
- package/lib/render/manageConstraints.js +1 -1
- package/lib/render/toCdl.js +193 -79
- package/lib/render/toHdbcds.js +179 -95
- package/lib/render/toRename.js +7 -10
- package/lib/render/toSql.js +57 -40
- package/lib/render/utils/common.js +24 -5
- package/lib/render/utils/sql.js +6 -4
- package/lib/transform/braceExpression.js +4 -2
- package/lib/transform/db/associations.js +389 -0
- package/lib/transform/db/cdsPersistence.js +150 -0
- package/lib/transform/db/constraints.js +6 -4
- package/lib/transform/db/draft.js +3 -2
- package/lib/transform/db/expansion.js +4 -5
- package/lib/transform/db/flattening.js +5 -6
- package/lib/transform/db/temporal.js +236 -0
- package/lib/transform/db/transformExists.js +36 -23
- package/lib/transform/forHanaNew.js +35 -626
- package/lib/transform/forOdataNew.js +5 -4
- package/lib/transform/localized.js +3 -14
- package/lib/transform/odata/generateForeignKeyElements.js +2 -2
- package/lib/transform/transformUtilsNew.js +13 -13
- package/lib/transform/translateAssocsToJoins.js +8 -8
- package/lib/transform/universalCsnEnricher.js +217 -47
- package/lib/utils/file.js +2 -1
- package/lib/utils/timetrace.js +8 -2
- package/package.json +1 -1
package/lib/render/toHdbcds.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const {
|
|
4
|
-
|
|
4
|
+
getLastPartOf, getLastPartOfRef,
|
|
5
5
|
hasValidSkipOrExists, isBuiltinType, generatedByCompilerVersion, getNormalizedQuery,
|
|
6
|
-
getRootArtifactName, getResultingName, getNamespace, forEachMember, getVariableReplacement,
|
|
6
|
+
getRootArtifactName, getResultingName, getNamespace, forEachMember, getVariableReplacement, hasAnnotationValue,
|
|
7
7
|
} = require('../model/csnUtils');
|
|
8
8
|
const keywords = require('../base/keywords');
|
|
9
9
|
const {
|
|
10
10
|
renderFunc, beautifyExprArray, getRealName, addContextMarkers, addIntermediateContexts, cdsToSqlTypes,
|
|
11
|
-
hasHanaComment, getHanaComment, findElement, funcWithoutParen,
|
|
11
|
+
hasHanaComment, getHanaComment, findElement, funcWithoutParen, getSqlSnippets,
|
|
12
12
|
} = require('./utils/common');
|
|
13
13
|
const {
|
|
14
14
|
renderReferentialConstraint,
|
|
@@ -60,8 +60,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
60
60
|
|
|
61
61
|
checkCSNVersion(csn, options);
|
|
62
62
|
|
|
63
|
-
const
|
|
64
|
-
|
|
63
|
+
const hdbcdsResult = Object.create(null);
|
|
65
64
|
|
|
66
65
|
const globalDuplicateChecker = new DuplicateChecker(options.sqlMapping); // registry for all artifact names and element names
|
|
67
66
|
|
|
@@ -100,17 +99,17 @@ function toHdbcdsSource(csn, options) {
|
|
|
100
99
|
Object.entries(art.$tableConstraints.referential)
|
|
101
100
|
.forEach(([ fileName, referentialConstraint ]) => {
|
|
102
101
|
referentialConstraints[fileName] = renderReferentialConstraint(
|
|
103
|
-
referentialConstraint, '', renderToUppercase, csn, options
|
|
102
|
+
referentialConstraint, '', renderToUppercase, csn, options
|
|
104
103
|
);
|
|
105
104
|
});
|
|
106
105
|
Object.entries(referentialConstraints)
|
|
107
|
-
.forEach(
|
|
106
|
+
.forEach(([ fileName, constraint ]) => {
|
|
108
107
|
hdbconstraint[fileName] = constraint;
|
|
109
108
|
});
|
|
110
109
|
}
|
|
111
110
|
});
|
|
112
|
-
|
|
113
|
-
|
|
111
|
+
hdbcdsResult.hdbcds = hdbcds;
|
|
112
|
+
hdbcdsResult.hdbconstraint = hdbconstraint;
|
|
114
113
|
|
|
115
114
|
if (globalDuplicateChecker)
|
|
116
115
|
globalDuplicateChecker.check(error, options); // perform duplicates check
|
|
@@ -119,7 +118,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
119
118
|
|
|
120
119
|
throwWithError();
|
|
121
120
|
timetrace.stop();
|
|
122
|
-
return options.testMode ? sort(
|
|
121
|
+
return options.testMode ? sort(hdbcdsResult) : hdbcdsResult;
|
|
123
122
|
|
|
124
123
|
/**
|
|
125
124
|
* Sort the given object alphabetically
|
|
@@ -224,7 +223,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
224
223
|
const parts = containee.split('.');
|
|
225
224
|
const prefixLength = contextName.split('.').length;
|
|
226
225
|
|
|
227
|
-
for (let i = parts.length - 1; i > prefixLength; i--
|
|
226
|
+
for (let i = parts.length - 1; i > prefixLength; i--) {
|
|
228
227
|
const prefix = parts.slice(0, i).join('.');
|
|
229
228
|
const art = csn.definitions[prefix];
|
|
230
229
|
if (art && (art.kind === 'context' || art.kind === 'service'))
|
|
@@ -291,7 +290,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
291
290
|
function renderContext(artifactName, art, env, isShadowed) {
|
|
292
291
|
let result = '';
|
|
293
292
|
if (!isShadowed)
|
|
294
|
-
isShadowed = contextIsShadowed(artifactName
|
|
293
|
+
isShadowed = contextIsShadowed(artifactName);
|
|
295
294
|
if (isShadowed) {
|
|
296
295
|
const subArtifacts = getSubArtifacts(artifactName);
|
|
297
296
|
for (const name in subArtifacts)
|
|
@@ -318,10 +317,9 @@ function toHdbcdsSource(csn, options) {
|
|
|
318
317
|
* non-context/service/namespace definition
|
|
319
318
|
*
|
|
320
319
|
* @param {string} artifactName
|
|
321
|
-
* @param {CSN.Model} csn
|
|
322
320
|
* @returns {boolean}
|
|
323
321
|
*/
|
|
324
|
-
function contextIsShadowed(artifactName
|
|
322
|
+
function contextIsShadowed(artifactName) {
|
|
325
323
|
if (artifactName.indexOf('.') === -1)
|
|
326
324
|
return false;
|
|
327
325
|
|
|
@@ -395,6 +393,12 @@ function toHdbcdsSource(csn, options) {
|
|
|
395
393
|
if (hasHanaComment(art, options))
|
|
396
394
|
result += `${env.indent}@Comment: '${getEscapedHanaComment(art)}'\n`;
|
|
397
395
|
|
|
396
|
+
// tables can have @sql.prepend and @sql.append
|
|
397
|
+
const { front, back } = getSqlSnippets(options, art);
|
|
398
|
+
|
|
399
|
+
if (front) // attach @sql.prepend after adding @Comment annotation
|
|
400
|
+
result += front;
|
|
401
|
+
|
|
398
402
|
result += `${env.indent + (art.abstract ? 'abstract ' : '')}entity ${normalizedArtifactName}`;
|
|
399
403
|
if (art.includes) {
|
|
400
404
|
// Includes are never flattened (don't exist in HANA)
|
|
@@ -412,8 +416,12 @@ function toHdbcdsSource(csn, options) {
|
|
|
412
416
|
|
|
413
417
|
duplicateChecker.check(error);
|
|
414
418
|
result += `${env.indent}}`;
|
|
415
|
-
result += `${renderTechnicalConfiguration(art.technicalConfig, env)}
|
|
416
|
-
|
|
419
|
+
result += `${renderTechnicalConfiguration(art.technicalConfig, env)}`;
|
|
420
|
+
|
|
421
|
+
if (back)
|
|
422
|
+
result += back;
|
|
423
|
+
|
|
424
|
+
return `${result};\n`;
|
|
417
425
|
}
|
|
418
426
|
|
|
419
427
|
/**
|
|
@@ -429,9 +437,8 @@ function toHdbcdsSource(csn, options) {
|
|
|
429
437
|
if (!element.target)
|
|
430
438
|
return;
|
|
431
439
|
|
|
432
|
-
let alias = element['@cds.persistence.name'];
|
|
433
440
|
if (uppercaseAndUnderscore(element.target) === element['@cds.persistence.name']) {
|
|
434
|
-
alias = createTopLevelAliasName(element['@cds.persistence.name']);
|
|
441
|
+
let alias = createTopLevelAliasName(element['@cds.persistence.name']);
|
|
435
442
|
// calculate new alias if it would conflict with other csn.Artifact
|
|
436
443
|
while (csn.definitions[alias])
|
|
437
444
|
alias = createTopLevelAliasName(alias);
|
|
@@ -556,13 +563,19 @@ function toHdbcdsSource(csn, options) {
|
|
|
556
563
|
result += `${env.indent}@Comment: '${getEscapedHanaComment(elm)}'\n`;
|
|
557
564
|
|
|
558
565
|
result += env.indent + (elm.key && !isSubElement ? 'key ' : '') +
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
566
|
+
(elm.masked ? 'masked ' : '') +
|
|
567
|
+
quotedElementName + (omitColon ? ' ' : ' : ') +
|
|
568
|
+
renderTypeReference(elm, env) +
|
|
569
|
+
renderNullability(elm);
|
|
563
570
|
if (elm.default)
|
|
564
571
|
result += ` default ${renderExpr(elm.default, env)}`;
|
|
565
572
|
|
|
573
|
+
// (table) elements can only have a @sql.append
|
|
574
|
+
const { back } = getSqlSnippets(options, elm);
|
|
575
|
+
|
|
576
|
+
if (back)
|
|
577
|
+
result += back;
|
|
578
|
+
|
|
566
579
|
return `${result};\n`;
|
|
567
580
|
}
|
|
568
581
|
|
|
@@ -760,7 +773,14 @@ function toHdbcdsSource(csn, options) {
|
|
|
760
773
|
}
|
|
761
774
|
env._artifact = art;
|
|
762
775
|
result += renderQuery(getNormalizedQuery(art).query, true, env, artifactPath.concat(art.projection ? 'projection' : 'query'), art.elements);
|
|
776
|
+
|
|
777
|
+
// views can only have a @sql.append
|
|
778
|
+
const { back } = getSqlSnippets(options, art);
|
|
779
|
+
if (back)
|
|
780
|
+
result += back;
|
|
781
|
+
|
|
763
782
|
result += ';\n';
|
|
783
|
+
|
|
764
784
|
return result;
|
|
765
785
|
}
|
|
766
786
|
|
|
@@ -829,72 +849,73 @@ function toHdbcdsSource(csn, options) {
|
|
|
829
849
|
result += `${env.indent}}`;
|
|
830
850
|
}
|
|
831
851
|
if (select.excluding) {
|
|
832
|
-
|
|
852
|
+
const excludingList = select.excluding.map(id => `${childEnv.indent}${formatIdentifier(id)}`).join(',\n');
|
|
853
|
+
result += ` excluding {\n${excludingList}\n`;
|
|
833
854
|
result += `${env.indent}}`;
|
|
834
855
|
}
|
|
835
856
|
|
|
836
|
-
return renderSelectProperties(select, result);
|
|
837
|
-
|
|
838
|
-
/**
|
|
839
|
-
* Render WHERE, GROUP BY, HAVING, ORDER BY and LIMIT clause
|
|
840
|
-
*
|
|
841
|
-
* @param {CSN.QuerySelect} select
|
|
842
|
-
* @param {string} alreadyRendered The query as it has been rendered so far
|
|
843
|
-
* @returns {string} The query with WHERE etc. added
|
|
844
|
-
*/
|
|
845
|
-
function renderSelectProperties(select, alreadyRendered) {
|
|
846
|
-
if (select.where)
|
|
847
|
-
alreadyRendered += `${continueIndent(alreadyRendered, env)}where ${renderExpr(select.where, env, true, true)}`;
|
|
857
|
+
return renderSelectProperties(select, result, env);
|
|
858
|
+
}
|
|
848
859
|
|
|
849
|
-
|
|
850
|
-
|
|
860
|
+
/**
|
|
861
|
+
* Render WHERE, GROUP BY, HAVING, ORDER BY and LIMIT clause
|
|
862
|
+
*
|
|
863
|
+
* @param {CSN.QuerySelect} select
|
|
864
|
+
* @param {string} alreadyRendered The query as it has been rendered so far
|
|
865
|
+
* @param {CdlRenderEnvironment} env Environment
|
|
866
|
+
* @returns {string} The query with WHERE etc. added
|
|
867
|
+
*/
|
|
868
|
+
function renderSelectProperties(select, alreadyRendered, env) {
|
|
869
|
+
if (select.where)
|
|
870
|
+
alreadyRendered += `${continueIndent(alreadyRendered, env)}where ${renderExpr(select.where, env, true, true)}`;
|
|
851
871
|
|
|
852
|
-
|
|
853
|
-
|
|
872
|
+
if (select.groupBy)
|
|
873
|
+
alreadyRendered += `${continueIndent(alreadyRendered, env)}group by ${select.groupBy.map(expr => renderExpr(expr, env)).join(', ')}`;
|
|
854
874
|
|
|
855
|
-
|
|
856
|
-
|
|
875
|
+
if (select.having)
|
|
876
|
+
alreadyRendered += `${continueIndent(alreadyRendered, env)}having ${renderExpr(select.having, env, true, true)}`;
|
|
857
877
|
|
|
858
|
-
|
|
859
|
-
|
|
878
|
+
if (select.orderBy)
|
|
879
|
+
alreadyRendered += `${continueIndent(alreadyRendered, env)}order by ${select.orderBy.map(entry => renderOrderByEntry(entry, env)).join(', ')}`;
|
|
860
880
|
|
|
861
|
-
|
|
862
|
-
|
|
881
|
+
if (select.limit)
|
|
882
|
+
alreadyRendered += `${continueIndent(alreadyRendered, env)}${renderLimit(select.limit, env)}`;
|
|
863
883
|
|
|
884
|
+
return alreadyRendered;
|
|
885
|
+
}
|
|
864
886
|
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
}
|
|
877
|
-
// Otherwise, start new line and indent normally
|
|
878
|
-
return `\n${increaseIndent(env).indent}`;
|
|
887
|
+
/**
|
|
888
|
+
* Utility function to make sure that we continue with the same indentation in WHERE, GROUP BY, ... after a closing curly brace and beyond
|
|
889
|
+
*
|
|
890
|
+
* @param {string} result Result of a previous render step
|
|
891
|
+
* @param {CdlRenderEnvironment} env Environment
|
|
892
|
+
* @returns {string} String to join with
|
|
893
|
+
*/
|
|
894
|
+
function continueIndent(result, env) {
|
|
895
|
+
if (result.endsWith('}') || result.endsWith('})')) {
|
|
896
|
+
// The preceding clause ended with '}', just append after that
|
|
897
|
+
return ' ';
|
|
879
898
|
}
|
|
899
|
+
// Otherwise, start new line and indent normally
|
|
900
|
+
return `\n${increaseIndent(env).indent}`;
|
|
901
|
+
}
|
|
880
902
|
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
903
|
+
/**
|
|
904
|
+
* Render a query's LIMIT clause, which may have also have OFFSET.
|
|
905
|
+
*
|
|
906
|
+
* @param {CSN.QueryLimit} limit CSN limit clause
|
|
907
|
+
* @param {CdlRenderEnvironment} env Environment
|
|
908
|
+
* @returns {string} Rendered limit clause
|
|
909
|
+
*/
|
|
910
|
+
function renderLimit(limit, env) {
|
|
911
|
+
let result = '';
|
|
912
|
+
if (limit.rows !== undefined)
|
|
913
|
+
result += `limit ${renderExpr(limit.rows, env)}`;
|
|
892
914
|
|
|
893
|
-
|
|
894
|
-
|
|
915
|
+
if (limit.offset !== undefined)
|
|
916
|
+
result += `${result !== '' ? `\n${increaseIndent(env).indent}` : ''}offset ${renderExpr(limit.offset, env)}`;
|
|
895
917
|
|
|
896
|
-
|
|
897
|
-
}
|
|
918
|
+
return result;
|
|
898
919
|
}
|
|
899
920
|
|
|
900
921
|
/**
|
|
@@ -943,7 +964,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
943
964
|
if (art.kind === 'aspect' || art.kind === 'type' && !hdbcdsNames || art.kind === 'type' && hdbcdsNames && !art.elements)
|
|
944
965
|
return '';
|
|
945
966
|
let result = '';
|
|
946
|
-
result += `${env.indent + (art.kind
|
|
967
|
+
result += `${env.indent + (art.kind)} ${renderArtifactName(artifactName, env, true)}`;
|
|
947
968
|
if (art.includes) {
|
|
948
969
|
// Includes are never flattened (don't exist in HANA)
|
|
949
970
|
result += ` : ${art.includes.map(name => renderAbsoluteNameWithQuotes(name, env)).join(', ')}`;
|
|
@@ -968,7 +989,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
968
989
|
* Render a reference to a type used by 'elm' (named or inline)
|
|
969
990
|
* Allow suppressing enum-rendering - used in columns for example
|
|
970
991
|
*
|
|
971
|
-
* @param {
|
|
992
|
+
* @param {object} elm Element using the type reference
|
|
972
993
|
* @param {CdlRenderEnvironment} env Environment
|
|
973
994
|
* @returns {string} Rendered type reference
|
|
974
995
|
*/
|
|
@@ -1091,33 +1112,34 @@ function toHdbcdsSource(csn, options) {
|
|
|
1091
1112
|
* Render an expression (including paths and values) or condition 'x'.
|
|
1092
1113
|
* (no trailing LF, don't indent if inline)
|
|
1093
1114
|
*
|
|
1094
|
-
* @param {any}
|
|
1115
|
+
* @param {any} expr Expression to render
|
|
1095
1116
|
* @param {CdlRenderEnvironment} env Environment
|
|
1096
|
-
* @param {boolean} [inline=true]
|
|
1117
|
+
* @param {boolean} [inline=true] Whether to render inline
|
|
1097
1118
|
* @param {boolean} [inExpr=false] Whether the expression is already inside another expression
|
|
1098
1119
|
* @returns {string} Rendered expression
|
|
1099
1120
|
*/
|
|
1100
|
-
function renderExpr(
|
|
1121
|
+
function renderExpr(expr, env, inline = true, inExpr = false) {
|
|
1101
1122
|
// Compound expression
|
|
1102
|
-
if (Array.isArray(
|
|
1103
|
-
return beautifyExprArray(
|
|
1123
|
+
if (Array.isArray(expr))
|
|
1124
|
+
return beautifyExprArray(expr.map(item => renderExpr(item, env, inline, inExpr)));
|
|
1104
1125
|
|
|
1105
|
-
if (typeof
|
|
1106
|
-
if (inExpr &&
|
|
1107
|
-
return renderExplicitTypeCast(renderExprObject());
|
|
1108
|
-
return renderExprObject();
|
|
1126
|
+
if (typeof expr === 'object' && expr !== null) {
|
|
1127
|
+
if (inExpr && expr.cast && expr.cast.type)
|
|
1128
|
+
return renderExplicitTypeCast(renderExprObject(expr));
|
|
1129
|
+
return renderExprObject(expr);
|
|
1109
1130
|
}
|
|
1110
1131
|
|
|
1111
1132
|
// Not a literal value but part of an operator, function etc - just leave as it is
|
|
1112
|
-
return
|
|
1133
|
+
return expr;
|
|
1113
1134
|
|
|
1114
1135
|
|
|
1115
1136
|
/**
|
|
1116
1137
|
* Various special cases represented as objects
|
|
1117
1138
|
*
|
|
1139
|
+
* @param {object} x Expression
|
|
1118
1140
|
* @returns {string} Rendered expression object
|
|
1119
1141
|
*/
|
|
1120
|
-
function renderExprObject() {
|
|
1142
|
+
function renderExprObject(x) {
|
|
1121
1143
|
if (x.list) {
|
|
1122
1144
|
// set "inExpr" to false: treat list elements as new expressions
|
|
1123
1145
|
return `(${x.list.map(item => renderExpr(item, env, inline, false)).join(', ')})`;
|
|
@@ -1145,7 +1167,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
1145
1167
|
// we can't quote functions with parens, issue warning if it is a reserved keyword
|
|
1146
1168
|
if (!funcWithoutParen(x, 'hana') && keywords.hdbcds.includes(uppercaseAndUnderscore(funcName)))
|
|
1147
1169
|
warning(null, x.$location, `The identifier “${uppercaseAndUnderscore(funcName)}“ is a SAP HANA keyword`);
|
|
1148
|
-
return renderFunc(
|
|
1170
|
+
return renderFunc(funcName, x, 'hana', a => renderArgs(a, '=>', env));
|
|
1149
1171
|
}
|
|
1150
1172
|
// Nested expression
|
|
1151
1173
|
else if (x.xpr) {
|
|
@@ -1242,10 +1264,10 @@ function toHdbcdsSource(csn, options) {
|
|
|
1242
1264
|
* @returns {string} Rendered cast()
|
|
1243
1265
|
*/
|
|
1244
1266
|
function renderExplicitTypeCast(value) {
|
|
1245
|
-
let typeRef = renderTypeReference(
|
|
1267
|
+
let typeRef = renderTypeReference(expr.cast, env);
|
|
1246
1268
|
|
|
1247
1269
|
// inside a cast expression, the cds and hana cds types need to be mapped to hana sql types
|
|
1248
|
-
const hanaSqlType = cdsToSqlTypes.hana[
|
|
1270
|
+
const hanaSqlType = cdsToSqlTypes.hana[expr.cast.type] || cdsToSqlTypes.standard[expr.cast.type];
|
|
1249
1271
|
if (hanaSqlType) {
|
|
1250
1272
|
const typeRefWithoutParams = typeRef.substring(0, typeRef.indexOf('(')) || typeRef;
|
|
1251
1273
|
typeRef = typeRef.replace(typeRefWithoutParams, hanaSqlType);
|
|
@@ -1521,9 +1543,70 @@ function toHdbcdsSource(csn, options) {
|
|
|
1521
1543
|
Object.keys(env.topLevelAliases)
|
|
1522
1544
|
.filter(name => env.topLevelAliases[name].quotedAlias !== formatIdentifier(uppercaseAndUnderscore(artifactName))) // avoid "using FOO as FOO" in FOO.cds
|
|
1523
1545
|
.forEach((name) => {
|
|
1546
|
+
const nativeObjectExists = csn.definitions[name] && hasAnnotationValue(csn.definitions[name], '@cds.persistence.exists');
|
|
1547
|
+
if (!plainNames && nativeObjectExists)
|
|
1548
|
+
checkForNameClashesWithNativeObject(name);
|
|
1524
1549
|
distinct[`using ${env.topLevelAliases[name].quotedName} as ${env.topLevelAliases[name].quotedAlias};\n`] = '';
|
|
1525
1550
|
});
|
|
1551
|
+
/**
|
|
1552
|
+
* If we generate a `using <native object> from <bar>` clause,
|
|
1553
|
+
* we warn if we generate a SAP HANA CDS artifact which would hide the
|
|
1554
|
+
* native DB object from being found by the SAP HANA CDS compiler
|
|
1555
|
+
* see cap/cds-compiler#8269 for details
|
|
1556
|
+
* @param {string} name of the native db object
|
|
1557
|
+
*/
|
|
1558
|
+
function checkForNameClashesWithNativeObject(name) {
|
|
1559
|
+
const possibleShadowName = getNamePrefix(env.topLevelAliases[name].quotedName);
|
|
1560
|
+
const mightBeShadowedBy = csn.definitions[possibleShadowName];
|
|
1561
|
+
if (mightBeShadowedBy) {
|
|
1562
|
+
const artifactWillBeRendered = isArtifactRendered(mightBeShadowedBy, possibleShadowName);
|
|
1563
|
+
// only warn if actually rendered to HANA CDS
|
|
1564
|
+
if (artifactWillBeRendered)
|
|
1565
|
+
warning('anno-hidden-exists', [ 'definitions', name ], { name: possibleShadowName }, 'Native database object is hidden by a definition starting with $(NAME)');
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1569
|
+
function isArtifactRendered(art, artName) {
|
|
1570
|
+
const isHanaCdsContext = art.kind === 'service' || art.kind === 'context';
|
|
1571
|
+
if (isHanaCdsContext)
|
|
1572
|
+
return isContextRendered(artName);
|
|
1573
|
+
if ([ 'action', 'function', 'event' ].includes(art.kind) || options.sqlMapping !== 'hdbcds' && art.kind === 'type')
|
|
1574
|
+
return false;
|
|
1575
|
+
return !(hasAnnotationValue(art, '@cds.persistence.exists') || hasAnnotationValue(art, '@cds.persistence.skip'));
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1578
|
+
/**
|
|
1579
|
+
* Check if there is at least one entity which will be rendered as SAP HANA CDS entity
|
|
1580
|
+
* inside the given context (or in its sub-contexts).
|
|
1581
|
+
* Or in other words: If the context will be rendered as a SAP HANA CDS context in the end.
|
|
1582
|
+
*
|
|
1583
|
+
* @param {string} contextName
|
|
1584
|
+
* @returns {boolean} true if a context/service will be rendered as a SAP HANA CDS context.
|
|
1585
|
+
*/
|
|
1586
|
+
function isContextRendered(contextName) {
|
|
1587
|
+
const subArtifacts = getSubArtifacts(contextName);
|
|
1588
|
+
return Object.entries(subArtifacts).some(([ artName, art ]) => {
|
|
1589
|
+
if (art.kind === 'context')
|
|
1590
|
+
return isContextRendered(`${contextName}.${artName}`);
|
|
1591
|
+
return isArtifactRendered(art, artName);
|
|
1592
|
+
});
|
|
1593
|
+
}
|
|
1526
1594
|
|
|
1595
|
+
/**
|
|
1596
|
+
* @param {string} usingName the string which appears in the `using <string> from ..` including the quotes
|
|
1597
|
+
* @returns the prefix of the `using` name.
|
|
1598
|
+
* @example
|
|
1599
|
+
* "com.sap.foo.native.object" --> com
|
|
1600
|
+
* "com.sap.foo::native.object" --> com.sap.foo.native
|
|
1601
|
+
*/
|
|
1602
|
+
function getNamePrefix(usingName) {
|
|
1603
|
+
usingName = usingName.replace(/"/g, '');
|
|
1604
|
+
if (usingName.indexOf('::') !== -1) {
|
|
1605
|
+
const parts = usingName.split('::');
|
|
1606
|
+
return `${parts[0]}.${parts[1].split('.')[0]}`;
|
|
1607
|
+
}
|
|
1608
|
+
return usingName.split('.')[0];
|
|
1609
|
+
}
|
|
1527
1610
|
return Object.keys(distinct).join('');
|
|
1528
1611
|
}
|
|
1529
1612
|
|
|
@@ -1676,13 +1759,14 @@ function toHdbcdsSource(csn, options) {
|
|
|
1676
1759
|
* @returns {string} Correctly quoted absname
|
|
1677
1760
|
*/
|
|
1678
1761
|
function quoteAbsoluteNameAsId(absname) {
|
|
1762
|
+
const resultingName = getResultingName(csn, options.sqlMapping, absname);
|
|
1763
|
+
|
|
1679
1764
|
if (hdbcdsNames) {
|
|
1680
|
-
const
|
|
1681
|
-
const namespace = getParentNameOf(topLevelName);
|
|
1765
|
+
const namespace = getNamespace(csn, absname);
|
|
1682
1766
|
if (namespace)
|
|
1683
|
-
return `"${(`${namespace}::${
|
|
1767
|
+
return `"${(`${namespace}::${resultingName.substring(namespace.length + 2)}`).replace(/"/g, '""')}"`;
|
|
1684
1768
|
}
|
|
1685
|
-
return `"${
|
|
1769
|
+
return `"${resultingName.replace(/"/g, '""')}"`;
|
|
1686
1770
|
}
|
|
1687
1771
|
|
|
1688
1772
|
/**
|
|
@@ -1737,7 +1821,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
1737
1821
|
function renderArtifactName(artifactName, env, fallthrough = false) {
|
|
1738
1822
|
if (plainNames && !fallthrough)
|
|
1739
1823
|
return formatIdentifier(uppercaseAndUnderscore(artifactName));
|
|
1740
|
-
|
|
1824
|
+
// hdbcds with quoted or hdbcds naming
|
|
1741
1825
|
return env.namePrefix + quoteId(getRealName(csn, artifactName).replace(/\./g, '_'));
|
|
1742
1826
|
}
|
|
1743
1827
|
|
package/lib/render/toRename.js
CHANGED
|
@@ -70,22 +70,19 @@ function toRenameDdl(csn, options) {
|
|
|
70
70
|
|
|
71
71
|
resultStr += Object.keys(art.elements).map((name) => {
|
|
72
72
|
const e = art.elements[name];
|
|
73
|
-
let
|
|
73
|
+
let str = '';
|
|
74
74
|
|
|
75
75
|
const beforeColumnName = quoteSqlId(name);
|
|
76
76
|
const afterColumnName = plainSqlId(name);
|
|
77
77
|
|
|
78
78
|
if (!e._ignore) {
|
|
79
|
-
if (e.target)
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
resultStr += ' ';
|
|
85
|
-
result = ` EXEC 'RENAME COLUMN ${afterTableName}.${beforeColumnName} TO ${afterColumnName}';\n`;
|
|
86
|
-
}
|
|
79
|
+
if (e.target)
|
|
80
|
+
str = ` EXEC 'ALTER TABLE ${afterTableName} DROP ASSOCIATION ${beforeColumnName}';\n`;
|
|
81
|
+
|
|
82
|
+
else if (beforeColumnName !== afterColumnName)
|
|
83
|
+
str = ` EXEC 'RENAME COLUMN ${afterTableName}.${beforeColumnName} TO ${afterColumnName}';\n`;
|
|
87
84
|
}
|
|
88
|
-
return
|
|
85
|
+
return str;
|
|
89
86
|
}).join('');
|
|
90
87
|
}
|
|
91
88
|
return resultStr;
|