@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/toSql.js
CHANGED
|
@@ -8,6 +8,7 @@ const {
|
|
|
8
8
|
} = require('../model/csnUtils');
|
|
9
9
|
const {
|
|
10
10
|
renderFunc, beautifyExprArray, cdsToSqlTypes, getHanaComment, hasHanaComment,
|
|
11
|
+
getSqlSnippets,
|
|
11
12
|
} = require('./utils/common');
|
|
12
13
|
const {
|
|
13
14
|
renderReferentialConstraint, getIdentifierUtils,
|
|
@@ -186,10 +187,10 @@ function toSqlDdl(csn, options) {
|
|
|
186
187
|
checkCSNVersion(csn, options);
|
|
187
188
|
|
|
188
189
|
// The final result in hdb-kind-specific form, without leading CREATE, without trailing newlines
|
|
189
|
-
// (note that the order here is relevant for transmission into '
|
|
190
|
+
// (note that the order here is relevant for transmission into 'mainResultObj.sql' below and that
|
|
190
191
|
// the attribute names must be the HDI plugin names for --src hdi)
|
|
191
192
|
// The result object may have a `sql` dictionary for `toSql`.
|
|
192
|
-
const
|
|
193
|
+
const mainResultObj = {
|
|
193
194
|
hdbtabletype: Object.create(null),
|
|
194
195
|
hdbtable: Object.create(null),
|
|
195
196
|
hdbindex: Object.create(null),
|
|
@@ -215,12 +216,12 @@ function toSqlDdl(csn, options) {
|
|
|
215
216
|
// Current indentation string
|
|
216
217
|
indent: '',
|
|
217
218
|
};
|
|
218
|
-
renderArtifactInto(artifactName, artifact,
|
|
219
|
+
renderArtifactInto(artifactName, artifact, mainResultObj, env);
|
|
219
220
|
});
|
|
220
221
|
|
|
221
222
|
// Render each deleted artifact
|
|
222
223
|
for (const artifactName in csn.deletions)
|
|
223
|
-
renderArtifactDeletionInto(artifactName, csn.deletions[artifactName],
|
|
224
|
+
renderArtifactDeletionInto(artifactName, csn.deletions[artifactName], mainResultObj);
|
|
224
225
|
|
|
225
226
|
// Render each artifact extension
|
|
226
227
|
// Only HANA SQL is currently supported.
|
|
@@ -231,7 +232,7 @@ function toSqlDdl(csn, options) {
|
|
|
231
232
|
const artifactName = extension.extend;
|
|
232
233
|
const _artifact = csn.definitions[artifactName];
|
|
233
234
|
const env = { indent: '', _artifact };
|
|
234
|
-
renderArtifactExtensionInto(artifactName, _artifact, extension,
|
|
235
|
+
renderArtifactExtensionInto(artifactName, _artifact, extension, mainResultObj, env);
|
|
235
236
|
}
|
|
236
237
|
}
|
|
237
238
|
}
|
|
@@ -244,7 +245,7 @@ function toSqlDdl(csn, options) {
|
|
|
244
245
|
const artifactName = migration.migrate;
|
|
245
246
|
const _artifact = csn.definitions[artifactName];
|
|
246
247
|
const env = { indent: '', _artifact };
|
|
247
|
-
renderArtifactMigrationInto(artifactName, migration,
|
|
248
|
+
renderArtifactMigrationInto(artifactName, migration, mainResultObj, env);
|
|
248
249
|
}
|
|
249
250
|
}
|
|
250
251
|
}
|
|
@@ -265,22 +266,22 @@ function toSqlDdl(csn, options) {
|
|
|
265
266
|
|
|
266
267
|
// Handle hdbKinds separately from alterTable case
|
|
267
268
|
// eslint-disable-next-line no-unused-vars
|
|
268
|
-
const { deletions, migrations, ...hdbKinds } =
|
|
269
|
+
const { deletions, migrations: _, ...hdbKinds } = mainResultObj;
|
|
269
270
|
for (const hdbKind of Object.keys(hdbKinds)) {
|
|
270
|
-
for (const name in
|
|
271
|
+
for (const name in mainResultObj[hdbKind]) {
|
|
271
272
|
if (options.toSql.src === 'sql') {
|
|
272
|
-
let sourceString =
|
|
273
|
+
let sourceString = mainResultObj[hdbKind][name];
|
|
273
274
|
// Hack: Other than in 'hdbtable' files, in HANA SQL COLUMN is not mandatory but default.
|
|
274
275
|
if (options.toSql.dialect === 'hana' && hdbKind === 'hdbtable' && sourceString.startsWith('COLUMN '))
|
|
275
276
|
sourceString = sourceString.slice('COLUMN '.length);
|
|
276
277
|
sql[name] = `${options.testMode ? '' : sqlVersionLine}CREATE ${sourceString};`;
|
|
277
278
|
}
|
|
278
279
|
else if (!options.testMode) {
|
|
279
|
-
|
|
280
|
+
mainResultObj[hdbKind][name] = sqlVersionLine + mainResultObj[hdbKind][name];
|
|
280
281
|
}
|
|
281
282
|
}
|
|
282
283
|
if (options.toSql.src === 'sql')
|
|
283
|
-
delete
|
|
284
|
+
delete mainResultObj[hdbKind];
|
|
284
285
|
}
|
|
285
286
|
|
|
286
287
|
// add `ALTER TABLE ADD CONSTRAINT` statements if requested
|
|
@@ -289,18 +290,18 @@ function toSqlDdl(csn, options) {
|
|
|
289
290
|
|
|
290
291
|
for ( const constraintName of Object.keys(alterStmts))
|
|
291
292
|
sql[constraintName] = `${options.testMode ? '' : sqlVersionLine}${alterStmts[constraintName]}`;
|
|
292
|
-
|
|
293
|
+
mainResultObj.sql = sql;
|
|
293
294
|
}
|
|
294
295
|
|
|
295
296
|
if (options.toSql.src === 'sql')
|
|
296
|
-
|
|
297
|
+
mainResultObj.sql = sql;
|
|
297
298
|
|
|
298
299
|
for (const name in deletions)
|
|
299
300
|
deletions[name] = `${options.testMode ? '' : sqlVersionLine}${deletions[name]}`;
|
|
300
301
|
|
|
301
302
|
|
|
302
303
|
timetrace.stop();
|
|
303
|
-
return
|
|
304
|
+
return mainResultObj;
|
|
304
305
|
|
|
305
306
|
/**
|
|
306
307
|
* Render an artifact into the appropriate dictionary of 'resultObj'.
|
|
@@ -491,7 +492,9 @@ function toSqlDdl(csn, options) {
|
|
|
491
492
|
env._artifact = art;
|
|
492
493
|
const childEnv = increaseIndent(env);
|
|
493
494
|
const hanaTc = art.technicalConfig && art.technicalConfig.hana;
|
|
494
|
-
|
|
495
|
+
// tables can have @sql.prepend and @sql.append
|
|
496
|
+
const { front, back } = getSqlSnippets(options, art);
|
|
497
|
+
let result = front;
|
|
495
498
|
// Only HANA has row/column tables
|
|
496
499
|
if (options.toSql.dialect === 'hana') {
|
|
497
500
|
if (hanaTc && hanaTc.storeType) {
|
|
@@ -575,6 +578,9 @@ function toSqlDdl(csn, options) {
|
|
|
575
578
|
if (options.toSql.dialect === 'hana' && hasHanaComment(art, options))
|
|
576
579
|
result += ` COMMENT '${getHanaComment(art)}'`;
|
|
577
580
|
|
|
581
|
+
if (back)
|
|
582
|
+
result += back;
|
|
583
|
+
|
|
578
584
|
resultObj.hdbtable[artifactName] = result;
|
|
579
585
|
}
|
|
580
586
|
|
|
@@ -610,12 +616,12 @@ function toSqlDdl(csn, options) {
|
|
|
610
616
|
if (!(artifactName in resultObj.migrations))
|
|
611
617
|
resultObj.migrations[artifactName] = [];
|
|
612
618
|
|
|
613
|
-
const migrations = sqlArray.map(
|
|
619
|
+
const migrations = sqlArray.map(migrationSql => ({ drop, sql: migrationSql }));
|
|
614
620
|
resultObj.migrations[artifactName].push(...migrations);
|
|
615
621
|
}
|
|
616
622
|
|
|
617
|
-
function addDeletion(resultObj, artifactName,
|
|
618
|
-
resultObj.deletions[artifactName] =
|
|
623
|
+
function addDeletion(resultObj, artifactName, deletionSql) {
|
|
624
|
+
resultObj.deletions[artifactName] = deletionSql;
|
|
619
625
|
}
|
|
620
626
|
|
|
621
627
|
/**
|
|
@@ -672,9 +678,15 @@ function toSqlDdl(csn, options) {
|
|
|
672
678
|
if (fzindex && options.toSql.dialect === 'hana')
|
|
673
679
|
result += ` ${renderExpr(fzindex, env)}`;
|
|
674
680
|
|
|
675
|
-
if (options.toSql.dialect === 'hana' && hasHanaComment(elm, options
|
|
681
|
+
if (options.toSql.dialect === 'hana' && hasHanaComment(elm, options))
|
|
676
682
|
result += ` COMMENT '${getHanaComment(elm)}'`;
|
|
677
683
|
|
|
684
|
+
// (table) elements can only have a @sql.append
|
|
685
|
+
const { back } = getSqlSnippets(options, elm);
|
|
686
|
+
|
|
687
|
+
if (back !== '')
|
|
688
|
+
result += back;
|
|
689
|
+
|
|
678
690
|
return result;
|
|
679
691
|
}
|
|
680
692
|
|
|
@@ -984,7 +996,7 @@ function toSqlDdl(csn, options) {
|
|
|
984
996
|
* @param {object} node with `args` to render
|
|
985
997
|
* @param {string} sep Separator between args
|
|
986
998
|
* @param {object} env Render environment
|
|
987
|
-
* @param {string} syntax Some magic A2J
|
|
999
|
+
* @param {string|null} syntax Some magic A2J parameter - for calcview parameter rendering
|
|
988
1000
|
* @returns {string} Rendered arguments
|
|
989
1001
|
* @throws Throws if args is not an array or object.
|
|
990
1002
|
*/
|
|
@@ -1007,14 +1019,13 @@ function toSqlDdl(csn, options) {
|
|
|
1007
1019
|
* Render the given argument/parameter correctly.
|
|
1008
1020
|
*
|
|
1009
1021
|
* @param {string} arg Argument to render
|
|
1010
|
-
* @param {string}
|
|
1022
|
+
* @param {string|null} parameterSyntax Some magic A2J parameter - for calcview parameter rendering
|
|
1011
1023
|
* @returns {string} Rendered argument
|
|
1012
1024
|
*/
|
|
1013
|
-
function decorateParameter(arg,
|
|
1014
|
-
if (
|
|
1025
|
+
function decorateParameter(arg, parameterSyntax) {
|
|
1026
|
+
if (parameterSyntax === 'calcview')
|
|
1015
1027
|
return `PLACEHOLDER."$$${arg}$$"`;
|
|
1016
1028
|
|
|
1017
|
-
|
|
1018
1029
|
return quoteSqlId(arg);
|
|
1019
1030
|
}
|
|
1020
1031
|
}
|
|
@@ -1075,6 +1086,11 @@ function toSqlDdl(csn, options) {
|
|
|
1075
1086
|
result += `${env.indent})`;
|
|
1076
1087
|
}
|
|
1077
1088
|
|
|
1089
|
+
// views can only have a @sql.append
|
|
1090
|
+
const { back } = getSqlSnippets(options, art);
|
|
1091
|
+
if (back)
|
|
1092
|
+
result += back;
|
|
1093
|
+
|
|
1078
1094
|
return result;
|
|
1079
1095
|
}
|
|
1080
1096
|
|
|
@@ -1082,7 +1098,7 @@ function toSqlDdl(csn, options) {
|
|
|
1082
1098
|
* Render the parameter definition of a view if any. Return the parameters in parentheses, or an empty string
|
|
1083
1099
|
*
|
|
1084
1100
|
* @param {string} artifactName Name of the view
|
|
1085
|
-
* @param {
|
|
1101
|
+
* @param {Object} params Dictionary of parameters
|
|
1086
1102
|
* @returns {string} Rendered parameters
|
|
1087
1103
|
*/
|
|
1088
1104
|
function renderParameterDefinitions(artifactName, params) {
|
|
@@ -1338,27 +1354,27 @@ function toSqlDdl(csn, options) {
|
|
|
1338
1354
|
* (no trailing LF, don't indent if inline)
|
|
1339
1355
|
*
|
|
1340
1356
|
* @todo Reuse this with toCdl
|
|
1341
|
-
* @param {Array|object|string}
|
|
1357
|
+
* @param {Array|object|string} expr Expression to render
|
|
1342
1358
|
* @param {object} env Render environment
|
|
1343
1359
|
* @param {boolean} inline Wether to render the expression inline
|
|
1344
1360
|
* @param {boolean} nestedExpr Wether to treat the expression as nested
|
|
1345
1361
|
* @returns {string} Rendered expression
|
|
1346
1362
|
*/
|
|
1347
|
-
function renderExpr(
|
|
1363
|
+
function renderExpr(expr, env, inline = true, nestedExpr = false) {
|
|
1348
1364
|
// Compound expression
|
|
1349
|
-
if (Array.isArray(
|
|
1350
|
-
const tokens =
|
|
1365
|
+
if (Array.isArray(expr)) {
|
|
1366
|
+
const tokens = expr.map(item => renderExpr(item, env, inline, nestedExpr));
|
|
1351
1367
|
return beautifyExprArray(tokens);
|
|
1352
1368
|
}
|
|
1353
|
-
else if (typeof
|
|
1354
|
-
if (nestedExpr &&
|
|
1355
|
-
return renderExplicitTypeCast(renderExprObject());
|
|
1356
|
-
return renderExprObject();
|
|
1369
|
+
else if (typeof expr === 'object' && expr !== null) {
|
|
1370
|
+
if (nestedExpr && expr.cast && expr.cast.type)
|
|
1371
|
+
return renderExplicitTypeCast(expr, renderExprObject(expr));
|
|
1372
|
+
return renderExprObject(expr);
|
|
1357
1373
|
}
|
|
1358
1374
|
// Not a literal value but part of an operator, function etc - just leave as it is
|
|
1359
1375
|
// FIXME: For the sake of simplicity, we should get away from all this uppercasing in toSql
|
|
1360
1376
|
|
|
1361
|
-
return String(
|
|
1377
|
+
return String(expr).toUpperCase();
|
|
1362
1378
|
|
|
1363
1379
|
|
|
1364
1380
|
/**
|
|
@@ -1366,7 +1382,7 @@ function toSqlDdl(csn, options) {
|
|
|
1366
1382
|
*
|
|
1367
1383
|
* @returns {string} String representation of the expression
|
|
1368
1384
|
*/
|
|
1369
|
-
function renderExprObject() {
|
|
1385
|
+
function renderExprObject(x) {
|
|
1370
1386
|
if (x.list) {
|
|
1371
1387
|
return `(${x.list.map(item => renderExpr(item)).join(', ')})`;
|
|
1372
1388
|
}
|
|
@@ -1412,10 +1428,10 @@ function toSqlDdl(csn, options) {
|
|
|
1412
1428
|
throw new Error(`Unknown expression: ${JSON.stringify(x)}`);
|
|
1413
1429
|
}
|
|
1414
1430
|
|
|
1415
|
-
function renderWindowFunction(funcName, node,
|
|
1416
|
-
const suffix = node.xpr
|
|
1417
|
-
let r = `${funcName}(${renderArgs(node, '=>',
|
|
1418
|
-
r += ` ${suffix} (${renderExpr(node.xpr,
|
|
1431
|
+
function renderWindowFunction(funcName, node, fctEnv) {
|
|
1432
|
+
const suffix = node.xpr[0]; // OVER
|
|
1433
|
+
let r = `${funcName}(${renderArgs(node, '=>', fctEnv, null)})`;
|
|
1434
|
+
r += ` ${suffix} (${renderExpr(node.xpr.slice(1), fctEnv)})`; // do not pass suffix in renderExpr
|
|
1419
1435
|
return r;
|
|
1420
1436
|
}
|
|
1421
1437
|
|
|
@@ -1570,10 +1586,11 @@ function toSqlDdl(csn, options) {
|
|
|
1570
1586
|
/**
|
|
1571
1587
|
* Renders an explicit `cast()` inside an 'xpr'.
|
|
1572
1588
|
*
|
|
1589
|
+
* @param {object} x Expression with cast
|
|
1573
1590
|
* @param {string} value Value to cast
|
|
1574
1591
|
* @returns {string} CAST statement
|
|
1575
1592
|
*/
|
|
1576
|
-
function renderExplicitTypeCast(value) {
|
|
1593
|
+
function renderExplicitTypeCast(x, value) {
|
|
1577
1594
|
const typeRef = renderBuiltinType(x.cast.type) + renderTypeParameters(x.cast);
|
|
1578
1595
|
return `CAST(${value} AS ${typeRef})`;
|
|
1579
1596
|
}
|
|
@@ -19,6 +19,7 @@ const {
|
|
|
19
19
|
} = require('../../model/csnUtils');
|
|
20
20
|
|
|
21
21
|
const { implicitAs } = require('../../model/csnRefs');
|
|
22
|
+
const { isBetaEnabled } = require('../../base/model');
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
/**
|
|
@@ -205,12 +206,11 @@ function addMissingChildContexts(csn, artifactName, killList) {
|
|
|
205
206
|
addPossibleGaps(name.slice(artifactName.length + 1).split('.'), artifactName);
|
|
206
207
|
}
|
|
207
208
|
|
|
208
|
-
function addPossibleGaps(possibleGaps,
|
|
209
|
-
let possibleGap = artifactName;
|
|
209
|
+
function addPossibleGaps(possibleGaps, gapArtifactName) {
|
|
210
210
|
for (const gap of possibleGaps) {
|
|
211
|
-
|
|
212
|
-
if (!csn.definitions[
|
|
213
|
-
const contextName =
|
|
211
|
+
gapArtifactName += `.${gap}`;
|
|
212
|
+
if (!csn.definitions[gapArtifactName]) {
|
|
213
|
+
const contextName = gapArtifactName;
|
|
214
214
|
csn.definitions[contextName] = {
|
|
215
215
|
kind: 'context',
|
|
216
216
|
};
|
|
@@ -355,6 +355,24 @@ function getHanaComment(obj) {
|
|
|
355
355
|
return obj.doc.split('\n\n')[0].trim().replace(/'/g, "''");
|
|
356
356
|
}
|
|
357
357
|
|
|
358
|
+
/**
|
|
359
|
+
* Get the @sql.prepend/append if set - already add a space after/before.
|
|
360
|
+
* If no value is set, use '';
|
|
361
|
+
*
|
|
362
|
+
* @param {CSN.Options} options
|
|
363
|
+
* @param {object} obj
|
|
364
|
+
* @returns {object} object with .front and .back
|
|
365
|
+
*/
|
|
366
|
+
function getSqlSnippets(options, obj) {
|
|
367
|
+
if (isBetaEnabled(options, 'sqlSnippets')) {
|
|
368
|
+
const front = obj['@sql.prepend'] ? `${obj['@sql.prepend']} ` : '';
|
|
369
|
+
const back = obj['@sql.append'] ? ` ${obj['@sql.append']}` : '';
|
|
370
|
+
|
|
371
|
+
return { front, back };
|
|
372
|
+
}
|
|
373
|
+
return { front: '', back: '' };
|
|
374
|
+
}
|
|
375
|
+
|
|
358
376
|
/**
|
|
359
377
|
* @typedef CdlRenderEnvironment Rendering environment used throughout the render process.
|
|
360
378
|
*
|
|
@@ -383,4 +401,5 @@ module.exports = {
|
|
|
383
401
|
getHanaComment,
|
|
384
402
|
findElement,
|
|
385
403
|
funcWithoutParen,
|
|
404
|
+
getSqlSnippets,
|
|
386
405
|
};
|
package/lib/render/utils/sql.js
CHANGED
|
@@ -13,11 +13,11 @@ const { smartId, delimitedId } = require('../../sql-identifier');
|
|
|
13
13
|
* @param {boolean} toUpperCase Wether to uppercase the identifier
|
|
14
14
|
* @param {CSN.Model} csn CSN
|
|
15
15
|
* @param {CSN.Options} options is needed for the naming mode and the sql dialect
|
|
16
|
-
* @param {boolean} alterConstraint whether the constraint should be rendered as part of an ALTER TABLE statement
|
|
16
|
+
* @param {boolean} [alterConstraint=false] whether the constraint should be rendered as part of an ALTER TABLE statement
|
|
17
17
|
*
|
|
18
18
|
* @returns {string} SQL statement which can be used to create the referential constraint on the db.
|
|
19
19
|
*/
|
|
20
|
-
function renderReferentialConstraint(constraint, indent, toUpperCase, csn, options, alterConstraint) {
|
|
20
|
+
function renderReferentialConstraint(constraint, indent, toUpperCase, csn, options, alterConstraint = false) {
|
|
21
21
|
let quoteId;
|
|
22
22
|
// for to.hana we can't utilize the sql identifier utils
|
|
23
23
|
if (options.transformation === 'hdbcds') {
|
|
@@ -51,14 +51,16 @@ function renderReferentialConstraint(constraint, indent, toUpperCase, csn, optio
|
|
|
51
51
|
if (!alterConstraint) {
|
|
52
52
|
result += `${indent}FOREIGN KEY(${constraint.foreignKey.map(quoteId).join(', ')})\n`;
|
|
53
53
|
result += `${indent}REFERENCES ${quoteId(getResultingName(csn, names, constraint.parentTable))}(${constraint.parentKey.map(quoteId).join(', ')})\n`;
|
|
54
|
+
const onDeleteRemark = constraint.onDeleteRemark ? ` -- ${constraint.onDeleteRemark}` : '';
|
|
55
|
+
|
|
54
56
|
// omit 'RESTRICT' action for ON UPDATE / ON DELETE, because it interferes with deferred constraint check
|
|
55
57
|
if (forSqlite) {
|
|
56
58
|
if (constraint.onDelete === 'CASCADE' )
|
|
57
|
-
result += `${indent}ON DELETE ${constraint.onDelete}${
|
|
59
|
+
result += `${indent}ON DELETE ${constraint.onDelete}${onDeleteRemark}\n`;
|
|
58
60
|
}
|
|
59
61
|
else {
|
|
60
62
|
result += `${indent}ON UPDATE RESTRICT\n`;
|
|
61
|
-
result += `${indent}ON DELETE ${constraint.onDelete}${
|
|
63
|
+
result += `${indent}ON DELETE ${constraint.onDelete}${onDeleteRemark}\n`;
|
|
62
64
|
}
|
|
63
65
|
}
|
|
64
66
|
// constraint enforcement / validation must be switched off using sqlite pragma statement
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
function isAlreadyBraced(expression, start, end){
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
return start - 1 > -1 &&
|
|
5
|
+
end + 1 < expression.length &&
|
|
6
|
+
expression[start-1] === '(' &&
|
|
7
|
+
expression[end+1] === ')';
|
|
6
8
|
}
|
|
7
9
|
|
|
8
10
|
function binarycomparison(expression, token, index){
|