@sap/cds-compiler 2.12.0 → 2.15.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 +221 -15
- package/bin/cdsc.js +125 -50
- package/bin/cdsse.js +2 -2
- package/doc/CHANGELOG_BETA.md +13 -6
- package/doc/CHANGELOG_DEPRECATED.md +22 -6
- package/doc/NameResolution.md +21 -16
- package/lib/api/main.js +47 -84
- package/lib/api/options.js +5 -6
- package/lib/api/validate.js +6 -11
- package/lib/backends.js +15 -23
- package/lib/base/dictionaries.js +0 -8
- package/lib/base/error.js +26 -0
- package/lib/base/keywords.js +7 -17
- package/lib/base/location.js +9 -4
- package/lib/base/message-registry.js +114 -18
- package/lib/base/messages.js +101 -90
- package/lib/base/model.js +2 -63
- package/lib/base/optionProcessorHelper.js +177 -123
- package/lib/checks/annotationsOData.js +12 -33
- package/lib/checks/arrayOfs.js +1 -34
- package/lib/checks/cdsPersistence.js +2 -1
- package/lib/checks/enricher.js +17 -1
- package/lib/checks/invalidTarget.js +3 -1
- package/lib/checks/managedWithoutKeys.js +3 -1
- package/lib/checks/selectItems.js +4 -4
- package/lib/checks/sql-snippets.js +27 -26
- package/lib/checks/types.js +1 -1
- package/lib/checks/validator.js +6 -11
- package/lib/compiler/assert-consistency.js +6 -3
- package/lib/compiler/base.js +1 -0
- package/lib/compiler/builtins.js +19 -6
- package/lib/compiler/checks.js +23 -60
- package/lib/compiler/cycle-detector.js +1 -1
- package/lib/compiler/define.js +1151 -0
- package/lib/compiler/extend.js +1000 -0
- package/lib/compiler/finalize-parse-cdl.js +237 -0
- package/lib/compiler/index.js +107 -39
- package/lib/compiler/kick-start.js +190 -0
- package/lib/compiler/moduleLayers.js +4 -4
- package/lib/compiler/populate.js +1227 -0
- package/lib/compiler/propagator.js +114 -46
- package/lib/compiler/resolve.js +1521 -0
- package/lib/compiler/shared.js +126 -65
- package/lib/compiler/tweak-assocs.js +535 -0
- package/lib/compiler/utils.js +197 -33
- package/lib/edm/.eslintrc.json +5 -0
- package/lib/edm/annotations/genericTranslation.js +38 -24
- package/lib/edm/annotations/preprocessAnnotations.js +2 -2
- package/lib/edm/csn2edm.js +219 -100
- package/lib/edm/edm.js +302 -230
- package/lib/edm/edmPreprocessor.js +554 -419
- package/lib/edm/edmUtils.js +138 -44
- package/lib/gen/Dictionary.json +100 -19
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +11 -1
- package/lib/gen/language.tokens +86 -83
- package/lib/gen/languageLexer.interp +10 -1
- package/lib/gen/languageLexer.js +860 -833
- package/lib/gen/languageLexer.tokens +78 -75
- package/lib/gen/languageParser.js +5765 -4480
- package/lib/json/csnVersion.js +10 -11
- package/lib/json/from-csn.js +15 -3
- package/lib/json/to-csn.js +126 -68
- package/lib/language/docCommentParser.js +4 -4
- package/lib/language/genericAntlrParser.js +123 -5
- package/lib/language/language.g4 +355 -156
- package/lib/language/multiLineStringParser.js +5 -5
- package/lib/main.d.ts +486 -59
- package/lib/main.js +41 -9
- package/lib/model/api.js +3 -1
- package/lib/model/csnRefs.js +252 -156
- package/lib/model/csnUtils.js +384 -297
- package/lib/model/enrichCsn.js +71 -29
- package/lib/model/revealInternalProperties.js +29 -8
- package/lib/model/sortViews.js +2 -1
- package/lib/modelCompare/compare.js +23 -18
- package/lib/optionProcessor.js +63 -26
- package/lib/render/manageConstraints.js +35 -32
- package/lib/render/toCdl.js +897 -947
- package/lib/render/toHdbcds.js +205 -257
- package/lib/render/toSql.js +264 -225
- package/lib/render/utils/common.js +136 -25
- package/lib/render/utils/sql.js +4 -3
- package/lib/render/utils/stringEscapes.js +111 -0
- package/lib/sql-identifier.js +1 -1
- package/lib/transform/.eslintrc.json +5 -0
- package/lib/transform/db/.eslintrc.json +3 -1
- package/lib/transform/db/applyTransformations.js +35 -12
- package/lib/transform/db/assertUnique.js +1 -1
- package/lib/transform/db/associations.js +104 -306
- package/lib/transform/db/cdsPersistence.js +2 -2
- package/lib/transform/db/constraints.js +58 -53
- package/lib/transform/db/expansion.js +60 -33
- package/lib/transform/db/flattening.js +582 -104
- package/lib/transform/db/groupByOrderBy.js +3 -1
- package/lib/transform/db/transformExists.js +66 -13
- package/lib/transform/db/views.js +11 -7
- package/lib/transform/draft/.eslintrc.json +38 -0
- package/lib/transform/{db/draft.js → draft/db.js} +6 -5
- package/lib/transform/draft/odata.js +227 -0
- package/lib/transform/forHanaNew.js +109 -208
- package/lib/transform/forOdataNew.js +59 -212
- package/lib/transform/localized.js +46 -26
- package/lib/transform/odata/toFinalBaseType.js +85 -11
- package/lib/transform/odata/typesExposure.js +147 -199
- package/lib/transform/odata/utils.js +2 -2
- package/lib/transform/transformUtilsNew.js +44 -33
- package/lib/transform/translateAssocsToJoins.js +3 -20
- package/lib/transform/universalCsn/.eslintrc.json +36 -0
- package/lib/transform/universalCsn/coreComputed.js +172 -0
- package/lib/transform/universalCsn/universalCsnEnricher.js +737 -0
- package/lib/transform/universalCsn/utils.js +63 -0
- package/lib/utils/moduleResolve.js +13 -6
- package/lib/utils/objectUtils.js +30 -0
- package/package.json +1 -1
- package/share/messages/README.md +26 -0
- package/share/messages/message-explanations.json +2 -1
- package/share/messages/syntax-expected-integer.md +37 -0
- package/lib/compiler/definer.js +0 -2361
- package/lib/compiler/resolver.js +0 -3079
- package/lib/transform/odata/attachPath.js +0 -96
- package/lib/transform/odata/expandStructKeysInAssociations.js +0 -59
- package/lib/transform/odata/generateForeignKeyElements.js +0 -261
- package/lib/transform/odata/referenceFlattener.js +0 -290
- package/lib/transform/odata/sortByAssociationDependency.js +0 -105
- package/lib/transform/odata/structuralPath.js +0 -72
- package/lib/transform/odata/structureFlattener.js +0 -171
- package/lib/transform/universalCsnEnricher.js +0 -237
package/lib/render/toHdbcds.js
CHANGED
|
@@ -7,8 +7,8 @@ const {
|
|
|
7
7
|
} = require('../model/csnUtils');
|
|
8
8
|
const keywords = require('../base/keywords');
|
|
9
9
|
const {
|
|
10
|
-
renderFunc,
|
|
11
|
-
hasHanaComment, getHanaComment,
|
|
10
|
+
renderFunc, getExpressionRenderer, getRealName, addContextMarkers, addIntermediateContexts, cdsToSqlTypes,
|
|
11
|
+
hasHanaComment, getHanaComment, funcWithoutParen, getSqlSnippets,
|
|
12
12
|
} = require('./utils/common');
|
|
13
13
|
const {
|
|
14
14
|
renderReferentialConstraint,
|
|
@@ -20,18 +20,19 @@ const { makeMessageFunction } = require('../base/messages');
|
|
|
20
20
|
const { timetrace } = require('../utils/timetrace');
|
|
21
21
|
|
|
22
22
|
const { smartId, delimitedId } = require('../sql-identifier');
|
|
23
|
+
const { ModelError } = require('../base/error');
|
|
23
24
|
|
|
24
25
|
const $PROJECTION = '$projection';
|
|
25
26
|
const $SELF = '$self';
|
|
26
27
|
|
|
27
28
|
/**
|
|
28
|
-
* Get the comment and in addition escape \n so HANA CDS can handle it.
|
|
29
|
+
* Get the comment and in addition escape \n and `'` so SAP HANA CDS can handle it.
|
|
29
30
|
*
|
|
30
31
|
* @param {CSN.Artifact} obj
|
|
31
32
|
* @returns {string}
|
|
32
33
|
*/
|
|
33
34
|
function getEscapedHanaComment(obj) {
|
|
34
|
-
return getHanaComment(obj).replace(/\n/g, '\\n');
|
|
35
|
+
return getHanaComment(obj).replace(/\n/g, '\\n').replace(/'/g, "''");
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
/**
|
|
@@ -55,9 +56,40 @@ function toHdbcdsSource(csn, options) {
|
|
|
55
56
|
const hdbcdsNames = options.sqlMapping === 'hdbcds';
|
|
56
57
|
|
|
57
58
|
const {
|
|
58
|
-
info, warning, error,
|
|
59
|
+
info, warning, error, throwWithAnyError,
|
|
59
60
|
} = makeMessageFunction(csn, options, 'to.hdbcds');
|
|
60
61
|
|
|
62
|
+
const renderExpr = getExpressionRenderer({
|
|
63
|
+
finalize: x => x,
|
|
64
|
+
explicitTypeCast(x, env) {
|
|
65
|
+
let typeRef = renderTypeReference(x.cast, env);
|
|
66
|
+
|
|
67
|
+
// inside a cast expression, the cds and hana cds types need to be mapped to hana sql types
|
|
68
|
+
const hanaSqlType = cdsToSqlTypes.hana[x.cast.type] || cdsToSqlTypes.standard[x.cast.type];
|
|
69
|
+
if (hanaSqlType) {
|
|
70
|
+
const typeRefWithoutParams = typeRef.substring(0, typeRef.indexOf('(')) || typeRef;
|
|
71
|
+
typeRef = typeRef.replace(typeRefWithoutParams, hanaSqlType);
|
|
72
|
+
}
|
|
73
|
+
return `CAST(${renderExpr(x, env)} AS ${typeRef})`;
|
|
74
|
+
},
|
|
75
|
+
val: renderExpressionLiteral,
|
|
76
|
+
enum: x => `#${x['#']}`,
|
|
77
|
+
ref: renderExpressionRef,
|
|
78
|
+
aliasOnly(x, _env) {
|
|
79
|
+
return x.as;
|
|
80
|
+
},
|
|
81
|
+
windowFunction: renderExpressionFunc,
|
|
82
|
+
func: renderExpressionFunc,
|
|
83
|
+
xpr(x, env) {
|
|
84
|
+
if (this.nestedExpr && !x.cast)
|
|
85
|
+
return `(${renderExpr(x.xpr, env, this.inline, true)})`;
|
|
86
|
+
|
|
87
|
+
return renderExpr(x.xpr, env, this.inline, true);
|
|
88
|
+
},
|
|
89
|
+
SELECT: (x, env) => `(${renderQuery(x, false, increaseIndent(env))})`,
|
|
90
|
+
SET: (x, env) => `${renderQuery(x, false, increaseIndent(env))}`,
|
|
91
|
+
});
|
|
92
|
+
|
|
61
93
|
checkCSNVersion(csn, options);
|
|
62
94
|
|
|
63
95
|
const hdbcdsResult = Object.create(null);
|
|
@@ -116,7 +148,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
116
148
|
|
|
117
149
|
killList.forEach(fn => fn());
|
|
118
150
|
|
|
119
|
-
|
|
151
|
+
throwWithAnyError();
|
|
120
152
|
timetrace.stop();
|
|
121
153
|
return options.testMode ? sort(hdbcdsResult) : hdbcdsResult;
|
|
122
154
|
|
|
@@ -152,7 +184,6 @@ function toHdbcdsSource(csn, options) {
|
|
|
152
184
|
|
|
153
185
|
switch (art.kind) {
|
|
154
186
|
case 'entity':
|
|
155
|
-
case 'view':
|
|
156
187
|
// FIXME: For HANA CDS, we need to replace $self at the beginning of paths in association ON-condition
|
|
157
188
|
// by the full name of the artifact we are rendering (should actually be done by forHana, but that is
|
|
158
189
|
// somewhat difficult because this kind of absolute path is quite unusual). In order not to have to pass
|
|
@@ -177,7 +208,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
177
208
|
case 'event':
|
|
178
209
|
return '';
|
|
179
210
|
default:
|
|
180
|
-
throw new
|
|
211
|
+
throw new ModelError(`Unknown artifact kind: ${art.kind}`);
|
|
181
212
|
}
|
|
182
213
|
}
|
|
183
214
|
|
|
@@ -213,11 +244,11 @@ function toHdbcdsSource(csn, options) {
|
|
|
213
244
|
}
|
|
214
245
|
|
|
215
246
|
/**
|
|
216
|
-
* Check
|
|
247
|
+
* Check whether the given context is the direct parent of the containee.
|
|
217
248
|
*
|
|
218
249
|
* @param {string} containee Name of the contained artifact
|
|
219
250
|
* @param {string} contextName Name of the (grand?)parent context
|
|
220
|
-
* @returns {boolean} True if there is another context
|
|
251
|
+
* @returns {boolean} True if there is another context in between
|
|
221
252
|
*/
|
|
222
253
|
function isContainedInOtherContext(containee, contextName) {
|
|
223
254
|
const parts = containee.split('.');
|
|
@@ -280,7 +311,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
280
311
|
* Render a context or service. Return the resulting source string.
|
|
281
312
|
*
|
|
282
313
|
* If the context is shadowed by another entity, the context itself is not rendered,
|
|
283
|
-
* but any contained (and transitively contained)
|
|
314
|
+
* but any contained (and transitively contained) entities and views are.
|
|
284
315
|
*
|
|
285
316
|
* @param {string} artifactName Name of the context/service
|
|
286
317
|
* @param {CSN.Artifact} art Content of the context/service
|
|
@@ -313,7 +344,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
313
344
|
return `${result + renderedSubArtifacts + env.indent}};\n`;
|
|
314
345
|
}
|
|
315
346
|
/**
|
|
316
|
-
* Check
|
|
347
|
+
* Check whether the given context is shadowed, i.e. part of his name prefix is shared by a
|
|
317
348
|
* non-context/service/namespace definition
|
|
318
349
|
*
|
|
319
350
|
* @param {string} artifactName
|
|
@@ -469,7 +500,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
469
500
|
// in 'tc' that we find and render them all (is it syntactically allowed yet to have more than one?)
|
|
470
501
|
tc = tc.hana;
|
|
471
502
|
if (!tc)
|
|
472
|
-
throw new
|
|
503
|
+
throw new ModelError('Expecting a HANA technical configuration');
|
|
473
504
|
|
|
474
505
|
result += `\n${env.indent}technical ${tc.calculated ? '' : 'hana '}configuration {\n`;
|
|
475
506
|
|
|
@@ -544,7 +575,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
544
575
|
* @param {CSN.Element} elm Content of the element
|
|
545
576
|
* @param {CdlRenderEnvironment} env Environment
|
|
546
577
|
* @param {DuplicateChecker} [duplicateChecker] Utility for detecting duplicates
|
|
547
|
-
* @param {boolean} [isSubElement]
|
|
578
|
+
* @param {boolean} [isSubElement] Whether the given element is a subelement or not - subelements cannot be key!
|
|
548
579
|
* @returns {string} The rendered element
|
|
549
580
|
*/
|
|
550
581
|
function renderElement(elementName, elm, env, duplicateChecker, isSubElement) {
|
|
@@ -628,7 +659,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
628
659
|
function renderAbsolutePath(path, env) {
|
|
629
660
|
// Sanity checks
|
|
630
661
|
if (!path.ref)
|
|
631
|
-
throw new
|
|
662
|
+
throw new ModelError(`Expecting ref in path: ${JSON.stringify(path)}`);
|
|
632
663
|
|
|
633
664
|
|
|
634
665
|
// Determine the absolute name of the first artifact on the path (before any associations or element traversals)
|
|
@@ -687,18 +718,19 @@ function toHdbcdsSource(csn, options) {
|
|
|
687
718
|
* Return the resulting source string (no trailing LF).
|
|
688
719
|
*
|
|
689
720
|
* @param {object} col Column to render
|
|
721
|
+
* @param {CSN.Elements} elements where column exists
|
|
690
722
|
* @param {CdlRenderEnvironment} env Environment
|
|
691
|
-
* @param {CSN.Element} [element] Element (non-enum from subquery possibly) corresponding to the column ref
|
|
692
723
|
* @returns {string} Rendered column
|
|
693
724
|
*/
|
|
694
|
-
function renderViewColumn(col,
|
|
725
|
+
function renderViewColumn(col, elements, env ) {
|
|
695
726
|
// Annotations and column
|
|
696
727
|
let result = '';
|
|
697
728
|
|
|
698
|
-
const leaf = col.as || col.ref && col.ref[col.ref.length - 1];
|
|
699
|
-
|
|
729
|
+
const leaf = col.as || col.ref && col.ref[col.ref.length - 1] || col.func;
|
|
730
|
+
const element = elements[leaf];
|
|
700
731
|
|
|
701
|
-
|
|
732
|
+
// Render 'null as <alias>' only for database and if element is virtual
|
|
733
|
+
if (element && element.virtual) {
|
|
702
734
|
if (isDeprecatedEnabled(options, 'renderVirtualElements'))
|
|
703
735
|
return `${result}${env.indent}null as ${formatIdentifier(leaf)}`;
|
|
704
736
|
}
|
|
@@ -791,7 +823,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
791
823
|
* or 'entity')
|
|
792
824
|
*
|
|
793
825
|
* @param {CSN.Query} query Query object
|
|
794
|
-
* @param {boolean} isLeadingQuery
|
|
826
|
+
* @param {boolean} isLeadingQuery Whether the query is the leading query or not
|
|
795
827
|
* @param {CdlRenderEnvironment} env Environment
|
|
796
828
|
* @param {CSN.Path} [path=[]] CSN path to the query
|
|
797
829
|
* @param {object} [elements] For leading query, the elements of the artifact
|
|
@@ -803,12 +835,12 @@ function toHdbcdsSource(csn, options) {
|
|
|
803
835
|
// Set operator, like UNION, INTERSECT, ...
|
|
804
836
|
if (query.SET) {
|
|
805
837
|
// First arg may be leading query
|
|
806
|
-
result += `(${renderQuery(query.SET.args[0], isLeadingQuery, env, path.concat([ 'SET', 'args', 0 ]), elements)}`;
|
|
838
|
+
result += `(${renderQuery(query.SET.args[0], isLeadingQuery, env, path.concat([ 'SET', 'args', 0 ]), elements || query.SET.elements)}`;
|
|
807
839
|
// FIXME: Clarify if set operators can be n-ary (assuming binary here)
|
|
808
840
|
if (query.SET.op) {
|
|
809
841
|
// Loop over all other arguments, i.e. for A UNION B UNION C UNION D ...
|
|
810
842
|
for (let i = 1; i < query.SET.args.length; i++)
|
|
811
|
-
result += `\n${env.indent}${query.SET.op}${query.SET.all ? ' all' : ''} ${renderQuery(query.SET.args[i], false, env, path.concat([ 'SET', 'args', i ]))}`;
|
|
843
|
+
result += `\n${env.indent}${query.SET.op}${query.SET.all ? ' all' : ''} ${renderQuery(query.SET.args[i], false, env, path.concat([ 'SET', 'args', i ]), elements || query.SET.elements)}`;
|
|
812
844
|
}
|
|
813
845
|
result += ')';
|
|
814
846
|
// Set operation may also have an ORDER BY and LIMIT/OFFSET (in contrast to the ones belonging to
|
|
@@ -823,7 +855,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
823
855
|
}
|
|
824
856
|
// Otherwise must have a SELECT
|
|
825
857
|
else if (!query.SELECT) {
|
|
826
|
-
throw new
|
|
858
|
+
throw new ModelError(`Unexpected query operation ${JSON.stringify(query)}`);
|
|
827
859
|
}
|
|
828
860
|
const select = query.SELECT;
|
|
829
861
|
const childEnv = increaseIndent(env);
|
|
@@ -843,7 +875,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
843
875
|
result += select.distinct ? ' distinct' : '';
|
|
844
876
|
if (select.columns) {
|
|
845
877
|
result += ' {\n';
|
|
846
|
-
result += `${select.columns.map(col => renderViewColumn(col,
|
|
878
|
+
result += `${select.columns.map(col => renderViewColumn(col, elements || select.elements, childEnv))
|
|
847
879
|
.filter(s => s !== '')
|
|
848
880
|
.join(',\n')}\n`;
|
|
849
881
|
result += `${env.indent}}`;
|
|
@@ -870,7 +902,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
870
902
|
alreadyRendered += `${continueIndent(alreadyRendered, env)}where ${renderExpr(select.where, env, true, true)}`;
|
|
871
903
|
|
|
872
904
|
if (select.groupBy)
|
|
873
|
-
alreadyRendered += `${continueIndent(alreadyRendered, env)}group by ${select.groupBy.map(expr => renderExpr(expr, env)).join(', ')}`;
|
|
905
|
+
alreadyRendered += `${continueIndent(alreadyRendered, env)}group by ${select.groupBy.map(expr => renderExpr(expr, env, true, false, true)).join(', ')}`;
|
|
874
906
|
|
|
875
907
|
if (select.having)
|
|
876
908
|
alreadyRendered += `${continueIndent(alreadyRendered, env)}having ${renderExpr(select.having, env, true, true)}`;
|
|
@@ -927,7 +959,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
927
959
|
* @returns {string} Rendered order by
|
|
928
960
|
*/
|
|
929
961
|
function renderOrderByEntry(entry, env) {
|
|
930
|
-
let result = renderExpr(entry, env);
|
|
962
|
+
let result = renderExpr(entry, env, true, false, true);
|
|
931
963
|
if (entry.sort)
|
|
932
964
|
result += ` ${entry.sort}`;
|
|
933
965
|
|
|
@@ -1011,7 +1043,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
1011
1043
|
// Anonymous structured type
|
|
1012
1044
|
if (!elm.type) {
|
|
1013
1045
|
if (!elm.elements)
|
|
1014
|
-
throw new
|
|
1046
|
+
throw new ModelError(`Missing type of: ${JSON.stringify(elm)}`);
|
|
1015
1047
|
|
|
1016
1048
|
result += '{\n';
|
|
1017
1049
|
const childEnv = increaseIndent(env);
|
|
@@ -1109,237 +1141,154 @@ function toHdbcdsSource(csn, options) {
|
|
|
1109
1141
|
}
|
|
1110
1142
|
|
|
1111
1143
|
/**
|
|
1112
|
-
* Render
|
|
1113
|
-
* (no trailing LF, don't indent if inline)
|
|
1144
|
+
* Render a single path step 's' at path position 'idx', which can have filters or parameters or be a function
|
|
1114
1145
|
*
|
|
1115
|
-
* @param {
|
|
1116
|
-
* @param {
|
|
1117
|
-
* @
|
|
1118
|
-
* @param {boolean} [inExpr=false] Whether the expression is already inside another expression
|
|
1119
|
-
* @returns {string} Rendered expression
|
|
1146
|
+
* @param {string|object} s Path step
|
|
1147
|
+
* @param {number} idx Path position
|
|
1148
|
+
* @returns {string} Rendered path step
|
|
1120
1149
|
*/
|
|
1121
|
-
function
|
|
1122
|
-
//
|
|
1123
|
-
if (
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
if (
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1150
|
+
function renderPathStep(s, idx, ref, env, inline) {
|
|
1151
|
+
// Simple id or absolute name
|
|
1152
|
+
if (typeof s === 'string') {
|
|
1153
|
+
// HANA-specific extra magic (should actually be in forHana)
|
|
1154
|
+
// In HANA, we replace leading $self by the absolute name of the current artifact
|
|
1155
|
+
// (see FIXME at renderArtifact)
|
|
1156
|
+
if (idx === 0 && s === $SELF) {
|
|
1157
|
+
// do not produce USING for $projection
|
|
1158
|
+
if (env.currentArtifactName === $PROJECTION)
|
|
1159
|
+
return env.currentArtifactName;
|
|
1160
|
+
|
|
1161
|
+
return plainNames ? renderAbsoluteNamePlain(env.currentArtifactName, env)
|
|
1162
|
+
: renderAbsoluteNameWithQuotes(env.currentArtifactName, env);
|
|
1163
|
+
}
|
|
1164
|
+
// HANA-specific translation of '$now' and '$user'
|
|
1165
|
+
if (s === '$now' && ref.length === 1)
|
|
1166
|
+
return 'CURRENT_TIMESTAMP';
|
|
1131
1167
|
|
|
1132
|
-
|
|
1133
|
-
|
|
1168
|
+
// In first path position, do not quote $projection and magic $-variables like CURRENT_DATE, $now etc.
|
|
1169
|
+
// FIXME: We should rather explicitly recognize quoting somehow
|
|
1134
1170
|
|
|
1171
|
+
// TODO: quote $parameters if it doesn't reference a parameter, this requires knowledge about the kind
|
|
1172
|
+
// Example: both views are correct in HANA CDS
|
|
1173
|
+
// entity E { key id: Integer; }
|
|
1174
|
+
// view EV with parameters P1: Integer as select from E { id, $parameters.P1 };
|
|
1175
|
+
// view EVp as select from E as "$parameters" { "$parameters".id };
|
|
1135
1176
|
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
* @param {object} x Expression
|
|
1140
|
-
* @returns {string} Rendered expression object
|
|
1141
|
-
*/
|
|
1142
|
-
function renderExprObject(x) {
|
|
1143
|
-
if (x.list) {
|
|
1144
|
-
// set "inExpr" to false: treat list elements as new expressions
|
|
1145
|
-
return `(${x.list.map(item => renderExpr(item, env, inline, false)).join(', ')})`;
|
|
1146
|
-
}
|
|
1147
|
-
else if (x.val !== undefined) {
|
|
1148
|
-
return renderExpressionLiteral(x);
|
|
1149
|
-
}
|
|
1150
|
-
// Enum symbol
|
|
1151
|
-
else if (x['#']) {
|
|
1152
|
-
return `#${x['#']}`;
|
|
1153
|
-
}
|
|
1154
|
-
// Reference: Array of path steps, possibly preceded by ':'
|
|
1155
|
-
else if (x.ref) {
|
|
1156
|
-
return renderExpressionRef(x);
|
|
1157
|
-
}
|
|
1158
|
-
// Function call, possibly with args (use '=>' for named args)
|
|
1159
|
-
else if (x.func) {
|
|
1160
|
-
// test for non-regular HANA identifier that needs to be quoted
|
|
1161
|
-
// identifier {letter}({letter_or_digit}|[#$])*
|
|
1162
|
-
// letter [A-Za-z_]
|
|
1163
|
-
// letter_or_digit [A-Za-z_0-9]
|
|
1164
|
-
|
|
1165
|
-
const regex = RegExp(/^[a-zA-Z][\w#$]*$/, 'g');
|
|
1166
|
-
const funcName = regex.test(x.func) ? x.func : quoteId(x.func);
|
|
1167
|
-
// we can't quote functions with parens, issue warning if it is a reserved keyword
|
|
1168
|
-
if (!funcWithoutParen(x, 'hana') && keywords.hdbcds.includes(uppercaseAndUnderscore(funcName)))
|
|
1169
|
-
warning(null, x.$location, `The identifier “${uppercaseAndUnderscore(funcName)}“ is a SAP HANA keyword`);
|
|
1170
|
-
return renderFunc(funcName, x, 'hana', a => renderArgs(a, '=>', env));
|
|
1171
|
-
}
|
|
1172
|
-
// Nested expression
|
|
1173
|
-
else if (x.xpr) {
|
|
1174
|
-
if (inExpr && !x.cast)
|
|
1175
|
-
return `(${renderExpr(x.xpr, env, inline, true)})`;
|
|
1176
|
-
|
|
1177
|
-
return renderExpr(x.xpr, env, inline, true);
|
|
1178
|
-
}
|
|
1179
|
-
// Sub-select
|
|
1180
|
-
else if (x.SELECT) {
|
|
1181
|
-
// renderQuery for SELECT does not bring its own parentheses (because it is also used in renderView)
|
|
1182
|
-
return `(${renderQuery(x, false, increaseIndent(env))})`;
|
|
1183
|
-
}
|
|
1184
|
-
else if (x.SET) {
|
|
1185
|
-
// renderQuery for SET always brings its own parentheses (because it is also used in renderViewSource)
|
|
1186
|
-
return `${renderQuery(x, false, increaseIndent(env))}`;
|
|
1187
|
-
}
|
|
1177
|
+
if (idx === 0 &&
|
|
1178
|
+
[ $SELF, $PROJECTION, '$session' ].includes(s))
|
|
1179
|
+
return s;
|
|
1188
1180
|
|
|
1189
|
-
|
|
1181
|
+
return formatIdentifier(s);
|
|
1190
1182
|
}
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
return `${x.literal}'${x.val}'`;
|
|
1207
|
-
case 'string':
|
|
1208
|
-
return `'${x.val.replace(/'/g, '\'\'')}'`;
|
|
1209
|
-
case 'object':
|
|
1210
|
-
if (x.val === null)
|
|
1211
|
-
return 'null';
|
|
1212
|
-
|
|
1213
|
-
// otherwise fall through to
|
|
1214
|
-
default:
|
|
1215
|
-
throw new Error(`Unknown literal or type: ${JSON.stringify(x)}`);
|
|
1183
|
+
// ID with filters or parameters
|
|
1184
|
+
else if (typeof s === 'object') {
|
|
1185
|
+
// Sanity check
|
|
1186
|
+
if (!s.func && !s.id)
|
|
1187
|
+
throw new ModelError(`Unknown path step object: ${JSON.stringify(s)}`);
|
|
1188
|
+
|
|
1189
|
+
// Not really a path step but an object-like function call
|
|
1190
|
+
if (s.func)
|
|
1191
|
+
return `${s.func}(${renderArgs(s, '=>', env)})`;
|
|
1192
|
+
|
|
1193
|
+
// Path step, possibly with view parameters and/or filters
|
|
1194
|
+
let result = `${formatIdentifier(s.id)}`;
|
|
1195
|
+
if (s.args) {
|
|
1196
|
+
// View parameters
|
|
1197
|
+
result += `(${renderArgs(s, ':', env)})`;
|
|
1216
1198
|
}
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
* @param {object} x Expression with a ref property
|
|
1221
|
-
* @returns {string} Rendered expression
|
|
1222
|
-
* @todo no extra magic with x.param or x.global
|
|
1223
|
-
*/
|
|
1224
|
-
function renderExpressionRef(x) {
|
|
1225
|
-
if (!x.param && !x.global) {
|
|
1226
|
-
const magicReplacement = getVariableReplacement(x.ref, options);
|
|
1227
|
-
if (x.ref[0] === '$user') {
|
|
1228
|
-
if (magicReplacement !== null)
|
|
1229
|
-
return `'${magicReplacement}'`;
|
|
1230
|
-
|
|
1231
|
-
// Keep old way of solving this to remain backwards compatible
|
|
1232
|
-
// FIXME: this is all not enough: we might need an explicit select item alias
|
|
1233
|
-
if (x.ref[1] === 'id') {
|
|
1234
|
-
if (options.magicVars && options.magicVars.user && (typeof options.magicVars.user === 'string' || options.magicVars.user instanceof String))
|
|
1235
|
-
return `'${options.magicVars.user}'`;
|
|
1236
|
-
|
|
1237
|
-
else if ((options.magicVars && options.magicVars.user && options.magicVars.user.id) && (typeof options.magicVars.user.id === 'string' || options.magicVars.user.id instanceof String))
|
|
1238
|
-
return `'${options.magicVars.user.id}'`;
|
|
1239
|
-
|
|
1240
|
-
return 'SESSION_CONTEXT(\'APPLICATIONUSER\')';
|
|
1241
|
-
}
|
|
1242
|
-
else if (x.ref[1] === 'locale') {
|
|
1243
|
-
return 'SESSION_CONTEXT(\'LOCALE\')';
|
|
1244
|
-
}
|
|
1245
|
-
}
|
|
1246
|
-
else if (x.ref[0] === '$at') {
|
|
1247
|
-
if (x.ref[1] === 'from')
|
|
1248
|
-
return 'TO_TIMESTAMP(SESSION_CONTEXT(\'VALID-FROM\'))';
|
|
1249
|
-
|
|
1250
|
-
else if (x.ref[1] === 'to')
|
|
1251
|
-
return 'TO_TIMESTAMP(SESSION_CONTEXT(\'VALID-TO\'))';
|
|
1252
|
-
}
|
|
1253
|
-
else if (x.ref[0] === '$session' && magicReplacement !== null) {
|
|
1254
|
-
return `'${magicReplacement}'`;
|
|
1255
|
-
}
|
|
1199
|
+
if (s.where) {
|
|
1200
|
+
// Filter, possibly with cardinality
|
|
1201
|
+
result += `[${s.cardinality ? (`${s.cardinality.max}: `) : ''}${renderExpr(s.where, env, inline, true)}]`;
|
|
1256
1202
|
}
|
|
1257
|
-
return
|
|
1203
|
+
return result;
|
|
1258
1204
|
}
|
|
1259
1205
|
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
*
|
|
1263
|
-
* @param {string} value Value to cast
|
|
1264
|
-
* @returns {string} Rendered cast()
|
|
1265
|
-
*/
|
|
1266
|
-
function renderExplicitTypeCast(value) {
|
|
1267
|
-
let typeRef = renderTypeReference(expr.cast, env);
|
|
1206
|
+
throw new ModelError(`Unknown path step: ${JSON.stringify(s)}`);
|
|
1207
|
+
}
|
|
1268
1208
|
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1209
|
+
/**
|
|
1210
|
+
* @param {object} x Expression with a val and/or literal property
|
|
1211
|
+
* @returns {string} Rendered expression
|
|
1212
|
+
*/
|
|
1213
|
+
function renderExpressionLiteral(x) {
|
|
1214
|
+
// Literal value, possibly with explicit 'literal' property
|
|
1215
|
+
switch (x.literal || typeof x.val) {
|
|
1216
|
+
case 'number':
|
|
1217
|
+
case 'boolean':
|
|
1218
|
+
case 'null':
|
|
1219
|
+
return x.val;
|
|
1220
|
+
case 'x':
|
|
1221
|
+
case 'date':
|
|
1222
|
+
case 'time':
|
|
1223
|
+
case 'timestamp':
|
|
1224
|
+
return `${x.literal}'${x.val}'`;
|
|
1225
|
+
case 'string':
|
|
1226
|
+
return `'${x.val.replace(/'/g, '\'\'')}'`;
|
|
1227
|
+
case 'object':
|
|
1228
|
+
if (x.val === null)
|
|
1229
|
+
return 'null';
|
|
1230
|
+
|
|
1231
|
+
// otherwise fall through to
|
|
1232
|
+
default:
|
|
1233
|
+
throw new ModelError(`Unknown literal or type: ${JSON.stringify(x)}`);
|
|
1276
1234
|
}
|
|
1235
|
+
}
|
|
1277
1236
|
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
if (env.currentArtifactName === $PROJECTION)
|
|
1294
|
-
return env.currentArtifactName;
|
|
1295
|
-
|
|
1296
|
-
return plainNames ? renderAbsoluteNamePlain(env.currentArtifactName, env)
|
|
1297
|
-
: renderAbsoluteNameWithQuotes(env.currentArtifactName, env);
|
|
1298
|
-
}
|
|
1299
|
-
// HANA-specific translation of '$now' and '$user'
|
|
1300
|
-
if (s === '$now' && ref.length === 1)
|
|
1301
|
-
return 'CURRENT_TIMESTAMP';
|
|
1237
|
+
/**
|
|
1238
|
+
* Render the given expression x - which has a .func property
|
|
1239
|
+
*
|
|
1240
|
+
* @param {object} x
|
|
1241
|
+
* @param {CdlRenderEnvironment} env
|
|
1242
|
+
* @returns {string}
|
|
1243
|
+
*/
|
|
1244
|
+
function renderExpressionFunc(x, env) {
|
|
1245
|
+
const regex = RegExp(/^[a-zA-Z][\w#$]*$/, 'g');
|
|
1246
|
+
const funcName = regex.test(x.func) ? x.func : quoteId(x.func);
|
|
1247
|
+
// we can't quote functions with parens, issue warning if it is a reserved keyword
|
|
1248
|
+
if (!funcWithoutParen(x, 'hana') && keywords.hdbcds.includes(uppercaseAndUnderscore(funcName)))
|
|
1249
|
+
warning(null, x.$location, `The identifier “${uppercaseAndUnderscore(funcName)}“ is a SAP HANA keyword`);
|
|
1250
|
+
return renderFunc(funcName, x, 'hana', a => renderArgs(a, '=>', env));
|
|
1251
|
+
}
|
|
1302
1252
|
|
|
1303
|
-
|
|
1304
|
-
|
|
1253
|
+
/**
|
|
1254
|
+
* @param {object} x Expression with a ref property
|
|
1255
|
+
* @returns {string} Rendered expression
|
|
1256
|
+
* @todo no extra magic with x.param or x.global
|
|
1257
|
+
*/
|
|
1258
|
+
function renderExpressionRef(x, env) {
|
|
1259
|
+
if (!x.param && !x.global) {
|
|
1260
|
+
const magicReplacement = getVariableReplacement(x.ref, options);
|
|
1261
|
+
if (x.ref[0] === '$user') {
|
|
1262
|
+
if (magicReplacement !== null)
|
|
1263
|
+
return `'${magicReplacement}'`;
|
|
1305
1264
|
|
|
1306
|
-
//
|
|
1307
|
-
//
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1265
|
+
// Keep old way of solving this to remain backwards compatible
|
|
1266
|
+
// FIXME: this is all not enough: we might need an explicit select item alias
|
|
1267
|
+
if (x.ref[1] === 'id') {
|
|
1268
|
+
if (options.magicVars && options.magicVars.user && (typeof options.magicVars.user === 'string' || options.magicVars.user instanceof String))
|
|
1269
|
+
return `'${options.magicVars.user}'`;
|
|
1311
1270
|
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
return s;
|
|
1271
|
+
else if ((options.magicVars && options.magicVars.user && options.magicVars.user.id) && (typeof options.magicVars.user.id === 'string' || options.magicVars.user.id instanceof String))
|
|
1272
|
+
return `'${options.magicVars.user.id}'`;
|
|
1315
1273
|
|
|
1316
|
-
|
|
1317
|
-
}
|
|
1318
|
-
// ID with filters or parameters
|
|
1319
|
-
else if (typeof s === 'object') {
|
|
1320
|
-
// Sanity check
|
|
1321
|
-
if (!s.func && !s.id)
|
|
1322
|
-
throw new Error(`Unknown path step object: ${JSON.stringify(s)}`);
|
|
1323
|
-
|
|
1324
|
-
// Not really a path step but an object-like function call
|
|
1325
|
-
if (s.func)
|
|
1326
|
-
return `${s.func}(${renderArgs(s, '=>', env)})`;
|
|
1327
|
-
|
|
1328
|
-
// Path step, possibly with view parameters and/or filters
|
|
1329
|
-
let result = `${formatIdentifier(s.id)}`;
|
|
1330
|
-
if (s.args) {
|
|
1331
|
-
// View parameters
|
|
1332
|
-
result += `(${renderArgs(s, ':', env)})`;
|
|
1274
|
+
return 'SESSION_CONTEXT(\'APPLICATIONUSER\')';
|
|
1333
1275
|
}
|
|
1334
|
-
if (
|
|
1335
|
-
|
|
1336
|
-
result += `[${s.cardinality ? (`${s.cardinality.max}: `) : ''}${renderExpr(s.where, env, inline, true)}]`;
|
|
1276
|
+
else if (x.ref[1] === 'locale') {
|
|
1277
|
+
return 'SESSION_CONTEXT(\'LOCALE\')';
|
|
1337
1278
|
}
|
|
1338
|
-
return result;
|
|
1339
1279
|
}
|
|
1280
|
+
else if (x.ref[0] === '$at') {
|
|
1281
|
+
if (x.ref[1] === 'from')
|
|
1282
|
+
return 'TO_TIMESTAMP(SESSION_CONTEXT(\'VALID-FROM\'))';
|
|
1340
1283
|
|
|
1341
|
-
|
|
1284
|
+
else if (x.ref[1] === 'to')
|
|
1285
|
+
return 'TO_TIMESTAMP(SESSION_CONTEXT(\'VALID-TO\'))';
|
|
1286
|
+
}
|
|
1287
|
+
else if (x.ref[0] === '$session' && magicReplacement !== null) {
|
|
1288
|
+
return `'${magicReplacement}'`;
|
|
1289
|
+
}
|
|
1342
1290
|
}
|
|
1291
|
+
return `${(x.param || x.global) ? ':' : ''}${x.ref.map((step, index) => renderPathStep(step, index, x.ref, env, this.inline)).join('.')}`;
|
|
1343
1292
|
}
|
|
1344
1293
|
|
|
1345
1294
|
/**
|
|
@@ -1347,7 +1296,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
1347
1296
|
* using 'sep' as separator for positional parameters
|
|
1348
1297
|
*
|
|
1349
1298
|
* @param {object} node with `args` to render
|
|
1350
|
-
* @param {string} sep
|
|
1299
|
+
* @param {string} sep Separator between arguments
|
|
1351
1300
|
* @param {CdlRenderEnvironment} env Environment
|
|
1352
1301
|
* @returns {string} Rendered arguments
|
|
1353
1302
|
*/
|
|
@@ -1355,15 +1304,15 @@ function toHdbcdsSource(csn, options) {
|
|
|
1355
1304
|
const args = node.args ? node.args : {};
|
|
1356
1305
|
// Positional arguments
|
|
1357
1306
|
if (Array.isArray(args))
|
|
1358
|
-
return args.map(arg => renderExpr(arg, env)).join(', ');
|
|
1307
|
+
return args.map(arg => renderExpr(arg, env, true, false, true)).join(', ');
|
|
1359
1308
|
|
|
1360
1309
|
// Named arguments (object/dict)
|
|
1361
1310
|
else if (typeof args === 'object')
|
|
1362
1311
|
// if this is a function param which is not a reference to the model, we must not quote it
|
|
1363
|
-
return Object.keys(args).map(key => `${node.func ? key : formatIdentifier(key)} ${sep} ${renderExpr(args[key], env)}`).join(', ');
|
|
1312
|
+
return Object.keys(args).map(key => `${node.func ? key : formatIdentifier(key)} ${sep} ${renderExpr(args[key], env, true, false, true)}`).join(', ');
|
|
1364
1313
|
|
|
1365
1314
|
|
|
1366
|
-
throw new
|
|
1315
|
+
throw new ModelError(`Unknown args: ${JSON.stringify(args)}`);
|
|
1367
1316
|
}
|
|
1368
1317
|
|
|
1369
1318
|
/**
|
|
@@ -1645,7 +1594,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
1645
1594
|
if (plainNames) {
|
|
1646
1595
|
const art = csn.definitions[name];
|
|
1647
1596
|
// For 'plain' naming, take all entities and views, nothing else
|
|
1648
|
-
if (art.kind === 'entity'
|
|
1597
|
+
if (art.kind === 'entity')
|
|
1649
1598
|
result[name] = art;
|
|
1650
1599
|
}
|
|
1651
1600
|
else {
|
|
@@ -1690,7 +1639,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
1690
1639
|
}
|
|
1691
1640
|
|
|
1692
1641
|
/**
|
|
1693
|
-
* Returns a copy of 'env' with increased indentation
|
|
1642
|
+
* Returns a copy of 'env' with increased indentation - also resets the name prefix
|
|
1694
1643
|
*
|
|
1695
1644
|
* @param {CdlRenderEnvironment} env Current environment
|
|
1696
1645
|
* @returns {CdlRenderEnvironment} New environment with increased indent
|
|
@@ -1711,15 +1660,15 @@ function toHdbcdsSource(csn, options) {
|
|
|
1711
1660
|
}
|
|
1712
1661
|
|
|
1713
1662
|
/**
|
|
1714
|
-
* Return an absolute path '
|
|
1663
|
+
* Return an absolute path 'absPath', with '::' inserted if required by naming strategy 'hdbcds',
|
|
1715
1664
|
* with appropriate "-quotes
|
|
1716
1665
|
*
|
|
1717
|
-
* @param {string}
|
|
1666
|
+
* @param {string} absPath Absolute path to quote
|
|
1718
1667
|
* @returns {string} Quoted path
|
|
1719
1668
|
*/
|
|
1720
|
-
function quoteAbsolutePathString(
|
|
1721
|
-
const namespace = getNamespace(csn,
|
|
1722
|
-
const resultingName = getResultingName(csn, options.sqlMapping,
|
|
1669
|
+
function quoteAbsolutePathString(absPath) {
|
|
1670
|
+
const namespace = getNamespace(csn, absPath);
|
|
1671
|
+
const resultingName = getResultingName(csn, options.sqlMapping, absPath);
|
|
1723
1672
|
|
|
1724
1673
|
if (hdbcdsNames && namespace)
|
|
1725
1674
|
return `${quotePathString(namespace)}::${quotePathString(resultingName.slice(namespace.length + 2))}`;
|
|
@@ -1736,14 +1685,13 @@ function toHdbcdsSource(csn, options) {
|
|
|
1736
1685
|
function quoteId(id) {
|
|
1737
1686
|
// Should only ever be called for real IDs (i.e. no dots inside)
|
|
1738
1687
|
if (id.indexOf('.') !== -1)
|
|
1739
|
-
throw new
|
|
1688
|
+
throw new ModelError(`HDBCDS: Tried to quote id with dot: ${id}`);
|
|
1740
1689
|
|
|
1741
1690
|
|
|
1742
|
-
switch (options.
|
|
1691
|
+
switch (options.sqlMapping) {
|
|
1743
1692
|
case 'plain':
|
|
1744
1693
|
return smartId(id, 'hdbcds');
|
|
1745
1694
|
case 'quoted':
|
|
1746
|
-
return delimitedId(id, 'hdbcds');
|
|
1747
1695
|
case 'hdbcds':
|
|
1748
1696
|
return delimitedId(id, 'hdbcds');
|
|
1749
1697
|
default:
|
|
@@ -1752,17 +1700,17 @@ function toHdbcdsSource(csn, options) {
|
|
|
1752
1700
|
}
|
|
1753
1701
|
|
|
1754
1702
|
/*
|
|
1755
|
-
* Return an absolute name '
|
|
1703
|
+
* Return an absolute name 'absName', with '::' inserted if required by naming strategy 'hdbcds', quoted
|
|
1756
1704
|
* as if it was a single identifier (required only for native USINGs)
|
|
1757
1705
|
*
|
|
1758
|
-
* @param {string}
|
|
1759
|
-
* @returns {string} Correctly quoted
|
|
1706
|
+
* @param {string} absName Absolute name
|
|
1707
|
+
* @returns {string} Correctly quoted absName
|
|
1760
1708
|
*/
|
|
1761
|
-
function quoteAbsoluteNameAsId(
|
|
1762
|
-
const resultingName = getResultingName(csn, options.sqlMapping,
|
|
1709
|
+
function quoteAbsoluteNameAsId(absName) {
|
|
1710
|
+
const resultingName = getResultingName(csn, options.sqlMapping, absName);
|
|
1763
1711
|
|
|
1764
1712
|
if (hdbcdsNames) {
|
|
1765
|
-
const namespace = getNamespace(csn,
|
|
1713
|
+
const namespace = getNamespace(csn, absName);
|
|
1766
1714
|
if (namespace)
|
|
1767
1715
|
return `"${(`${namespace}::${resultingName.substring(namespace.length + 2)}`).replace(/"/g, '""')}"`;
|
|
1768
1716
|
}
|
|
@@ -1776,7 +1724,7 @@ function toHdbcdsSource(csn, options) {
|
|
|
1776
1724
|
* @returns {string} Quoted/uppercased id
|
|
1777
1725
|
*/
|
|
1778
1726
|
function formatIdentifier(id) {
|
|
1779
|
-
id =
|
|
1727
|
+
id = plainNames ? id.toUpperCase() : id;
|
|
1780
1728
|
return quoteId(id);
|
|
1781
1729
|
}
|
|
1782
1730
|
|