@sap/cds-compiler 5.9.4 → 6.0.10
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 +104 -319
- package/README.md +1 -1
- package/bin/cds_update_identifiers.js +3 -5
- package/bin/cdsc.js +22 -8
- package/bin/cdshi.js +1 -1
- package/bin/cdsse.js +4 -4
- package/doc/CHANGELOG_BETA.md +11 -0
- package/doc/CHANGELOG_DEPRECATED.md +29 -0
- package/lib/api/main.js +8 -5
- package/lib/api/options.js +12 -10
- package/lib/base/builtins.js +1 -0
- package/lib/base/message-registry.js +190 -96
- package/lib/base/messages.js +29 -20
- package/lib/base/model.js +14 -24
- package/lib/checks/actionsFunctions.js +10 -20
- package/lib/checks/annotationsOData.js +1 -1
- package/lib/checks/elements.js +30 -10
- package/lib/checks/enums.js +31 -0
- package/lib/checks/foreignKeys.js +2 -2
- package/lib/checks/hasPersistedElements.js +5 -0
- package/lib/checks/invalidTarget.js +1 -1
- package/lib/checks/managedWithoutKeys.js +5 -4
- package/lib/checks/queryNoDbArtifacts.js +10 -8
- package/lib/checks/types.js +5 -5
- package/lib/checks/validator.js +6 -4
- package/lib/compiler/assert-consistency.js +12 -9
- package/lib/compiler/checks.js +18 -50
- package/lib/compiler/define.js +6 -6
- package/lib/compiler/extend.js +2 -1
- package/lib/compiler/generate.js +14 -17
- package/lib/compiler/populate.js +8 -31
- package/lib/compiler/propagator.js +21 -35
- package/lib/compiler/resolve.js +35 -22
- package/lib/compiler/shared.js +7 -1
- package/lib/compiler/tweak-assocs.js +1 -1
- package/lib/compiler/utils.js +1 -1
- package/lib/edm/annotations/edmJson.js +20 -15
- package/lib/edm/annotations/genericTranslation.js +7 -8
- package/lib/edm/csn2edm.js +46 -50
- package/lib/edm/edm.js +8 -7
- package/lib/edm/edmPreprocessor.js +33 -83
- package/lib/edm/edmUtils.js +2 -2
- package/lib/gen/BaseParser.js +55 -44
- package/lib/gen/CdlGrammar.checksum +1 -1
- package/lib/gen/CdlParser.js +1133 -1150
- package/lib/json/from-csn.js +70 -43
- package/lib/json/to-csn.js +6 -8
- package/lib/language/multiLineStringParser.js +3 -2
- package/lib/main.d.ts +58 -24
- package/lib/model/csnUtils.js +28 -39
- package/lib/model/xprAsTree.js +23 -9
- package/lib/modelCompare/compare.js +5 -4
- package/lib/optionProcessor.js +21 -17
- package/lib/parsers/AstBuildingParser.js +63 -11
- package/lib/parsers/XprTree.js +57 -3
- package/lib/parsers/identifiers.js +1 -1
- package/lib/parsers/index.js +0 -3
- package/lib/render/manageConstraints.js +25 -25
- package/lib/render/toCdl.js +173 -170
- package/lib/render/toHdbcds.js +126 -128
- package/lib/render/toRename.js +7 -7
- package/lib/render/toSql.js +128 -125
- package/lib/render/utils/common.js +47 -22
- package/lib/render/utils/delta.js +25 -25
- package/lib/render/utils/operators.js +2 -2
- package/lib/render/utils/pretty.js +5 -5
- package/lib/render/utils/sql.js +13 -13
- package/lib/render/utils/standardDatabaseFunctions.js +115 -103
- package/lib/render/utils/unique.js +4 -4
- package/lib/transform/db/applyTransformations.js +1 -1
- package/lib/transform/db/assertUnique.js +2 -2
- package/lib/transform/db/associations.js +6 -7
- package/lib/transform/db/assocsToQueries/utils.js +4 -5
- package/lib/transform/db/backlinks.js +12 -9
- package/lib/transform/db/cdsPersistence.js +8 -7
- package/lib/transform/db/constraints.js +13 -10
- package/lib/transform/db/expansion.js +7 -3
- package/lib/transform/db/flattening.js +4 -14
- package/lib/transform/db/processSqlServices.js +2 -1
- package/lib/transform/db/temporal.js +5 -7
- package/lib/transform/db/views.js +2 -4
- package/lib/transform/draft/db.js +8 -8
- package/lib/transform/draft/odata.js +10 -7
- package/lib/transform/forOdata.js +10 -5
- package/lib/transform/forRelationalDB.js +5 -75
- package/lib/transform/localized.js +1 -1
- package/lib/transform/odata/createForeignKeys.js +11 -10
- package/lib/transform/odata/flattening.js +8 -4
- package/lib/transform/odata/foreignKeyRefsInXprAnnos.js +96 -0
- package/lib/transform/odata/typesExposure.js +3 -3
- package/lib/transform/transformUtils.js +4 -8
- package/lib/transform/translateAssocsToJoins.js +14 -7
- package/lib/transform/universalCsn/universalCsnEnricher.js +10 -4
- package/lib/utils/objectUtils.js +0 -17
- package/package.json +10 -13
- package/share/messages/def-upcoming-virtual-change.md +1 -1
- package/LICENSE +0 -37
- package/bin/cds_remove_invalid_whitespace.js +0 -138
- package/doc/CHANGELOG_ARCHIVE.md +0 -3604
- package/lib/gen/genericAntlrParser.js +0 -3
- package/lib/gen/language.checksum +0 -1
- package/lib/gen/language.interp +0 -456
- package/lib/gen/language.tokens +0 -180
- package/lib/gen/languageLexer.interp +0 -439
- package/lib/gen/languageLexer.js +0 -1483
- package/lib/gen/languageLexer.tokens +0 -167
- package/lib/gen/languageParser.js +0 -24941
- package/lib/language/antlrParser.js +0 -205
- package/lib/language/errorStrategy.js +0 -646
- package/lib/language/genericAntlrParser.js +0 -1572
- package/lib/parsers/CdlGrammar.g4 +0 -2070
package/lib/render/toSql.js
CHANGED
|
@@ -38,13 +38,15 @@ class SqlRenderEnvironment {
|
|
|
38
38
|
path = null;
|
|
39
39
|
alterMode = false;
|
|
40
40
|
changeType = null;
|
|
41
|
+
/** Whether we're rendering a default value */
|
|
42
|
+
isInDefault = false;
|
|
41
43
|
|
|
42
44
|
constructor(values) {
|
|
43
45
|
Object.assign(this, values);
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
withIncreasedIndent() {
|
|
47
|
-
return new SqlRenderEnvironment({ ...this, indent: ` ${this.indent}` });
|
|
49
|
+
return new SqlRenderEnvironment({ ...this, indent: ` ${ this.indent }` });
|
|
48
50
|
}
|
|
49
51
|
withSubPath(path) {
|
|
50
52
|
return new SqlRenderEnvironment({ ...this, path: [ ...this.path, ...path ] });
|
|
@@ -121,7 +123,7 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
121
123
|
finalize: x => String(x).toUpperCase(),
|
|
122
124
|
typeCast(x) {
|
|
123
125
|
const typeRef = renderBuiltinType(x.cast.type) + renderTypeParameters(x.cast);
|
|
124
|
-
return `CAST(${this.renderExpr(withoutCast(x))} AS ${typeRef})`;
|
|
126
|
+
return `CAST(${ this.renderExpr(withoutCast(x)) } AS ${ typeRef })`;
|
|
125
127
|
},
|
|
126
128
|
val: renderExpressionLiteral,
|
|
127
129
|
enum(x) {
|
|
@@ -134,7 +136,6 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
134
136
|
ref(x) {
|
|
135
137
|
return renderExpressionRef(x, this.env);
|
|
136
138
|
},
|
|
137
|
-
aliasOnly: x => x.as,
|
|
138
139
|
windowFunction( x) {
|
|
139
140
|
return renderWindowFunction(smartFuncId(prepareIdentifier(x.func), options.sqlDialect), x, this.env);
|
|
140
141
|
},
|
|
@@ -144,14 +145,14 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
144
145
|
xpr(x) {
|
|
145
146
|
const env = this.env.withSubPath([ 'xpr' ]);
|
|
146
147
|
if (this.isNestedXpr && !x.cast)
|
|
147
|
-
return `(${this.renderSubExpr(x.xpr, env)})`;
|
|
148
|
+
return `(${ this.renderSubExpr(x.xpr, env) })`;
|
|
148
149
|
return this.renderSubExpr(x.xpr, env);
|
|
149
150
|
},
|
|
150
151
|
SELECT( x) {
|
|
151
|
-
return `(${renderQuery(x, this.env.withIncreasedIndent())})`;
|
|
152
|
+
return `(${ renderQuery(x, this.env.withIncreasedIndent()) })`;
|
|
152
153
|
},
|
|
153
154
|
SET( x) {
|
|
154
|
-
return `(${renderQuery(x, this.env.withIncreasedIndent())})`;
|
|
155
|
+
return `(${ renderQuery(x, this.env.withIncreasedIndent()) })`;
|
|
155
156
|
},
|
|
156
157
|
});
|
|
157
158
|
|
|
@@ -273,7 +274,7 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
273
274
|
Object.keys(sqlServiceEntities).forEach((sqlServiceName) => {
|
|
274
275
|
const accessRole = {
|
|
275
276
|
role: {
|
|
276
|
-
name: renderArtifactNameWithoutQuotes(`${sqlServiceName }.access`),
|
|
277
|
+
name: renderArtifactNameWithoutQuotes(`${ sqlServiceName }.access`),
|
|
277
278
|
object_privileges: Object.entries(sqlServiceEntities[sqlServiceName]).map(([ name, entity ]) => ({
|
|
278
279
|
name: renderArtifactNameWithoutQuotes(name),
|
|
279
280
|
type: entity.query || entity.projection ? 'VIEW' : 'TABLE',
|
|
@@ -284,7 +285,7 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
284
285
|
};
|
|
285
286
|
|
|
286
287
|
if (accessRole.role.object_privileges.length > 0)
|
|
287
|
-
mainResultObj.hdbrole[`${sqlServiceName }_access`] = JSON.stringify(accessRole, null, 2);
|
|
288
|
+
mainResultObj.hdbrole[`${ sqlServiceName }_access`] = JSON.stringify(accessRole, null, 2);
|
|
288
289
|
});
|
|
289
290
|
|
|
290
291
|
// Can only happen for HDI based deployment
|
|
@@ -292,7 +293,7 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
292
293
|
const synonym = Object.create(null);
|
|
293
294
|
Object.entries(dummySqlServiceEntities[sqlServiceName]).forEach(([ name ]) => {
|
|
294
295
|
const artName = renderArtifactNameWithoutQuotes(name);
|
|
295
|
-
const dummyArtName = renderArtifactNameWithoutQuotes(`dummy.${ name}`);
|
|
296
|
+
const dummyArtName = renderArtifactNameWithoutQuotes(`dummy.${ name }`);
|
|
296
297
|
synonym[artName] = {
|
|
297
298
|
target: {
|
|
298
299
|
object: dummyArtName,
|
|
@@ -300,7 +301,7 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
300
301
|
};
|
|
301
302
|
});
|
|
302
303
|
|
|
303
|
-
mainResultObj.hdbsynonym[`${sqlServiceName}`] = JSON.stringify(synonym, null, 2);
|
|
304
|
+
mainResultObj.hdbsynonym[`${ sqlServiceName }`] = JSON.stringify(synonym, null, 2);
|
|
304
305
|
});
|
|
305
306
|
|
|
306
307
|
// trigger artifact and element name checks
|
|
@@ -328,7 +329,7 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
328
329
|
// Hack: Other than in 'hdbtable' files, in HANA SQL COLUMN is not mandatory but default.
|
|
329
330
|
if (options.sqlDialect === 'hana' && hdbKind === 'hdbtable' && sourceString.startsWith('COLUMN '))
|
|
330
331
|
sourceString = sourceString.slice('COLUMN '.length);
|
|
331
|
-
sql[name] = `CREATE ${sourceString};`;
|
|
332
|
+
sql[name] = `CREATE ${ sourceString };`;
|
|
332
333
|
}
|
|
333
334
|
}
|
|
334
335
|
if (options.src === 'sql')
|
|
@@ -342,7 +343,7 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
342
343
|
|
|
343
344
|
forEachKey(alterStmts, (constraintName) => {
|
|
344
345
|
if (!csn.unchangedConstraints?.has(constraintName))
|
|
345
|
-
constraints[constraintName] = `${alterStmts[constraintName]}`;
|
|
346
|
+
constraints[constraintName] = `${ alterStmts[constraintName] }`;
|
|
346
347
|
});
|
|
347
348
|
mainResultObj.constraints = constraints;
|
|
348
349
|
}
|
|
@@ -351,7 +352,7 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
351
352
|
mainResultObj.sql = sql;
|
|
352
353
|
|
|
353
354
|
for (const name in deletions)
|
|
354
|
-
deletions[name] = `${deletions[name]}`;
|
|
355
|
+
deletions[name] = `${ deletions[name] }`;
|
|
355
356
|
|
|
356
357
|
timetrace.stop('SQL rendering');
|
|
357
358
|
return mainResultObj;
|
|
@@ -404,7 +405,7 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
404
405
|
// Ignore: not SQL-relevant
|
|
405
406
|
return;
|
|
406
407
|
default:
|
|
407
|
-
throw new ModelError(`Unknown artifact kind: ${art.kind}`);
|
|
408
|
+
throw new ModelError(`Unknown artifact kind: ${ art.kind }`);
|
|
408
409
|
}
|
|
409
410
|
}
|
|
410
411
|
|
|
@@ -443,7 +444,7 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
443
444
|
}
|
|
444
445
|
|
|
445
446
|
if (!artifactName)
|
|
446
|
-
throw new ModelError(`Undefined artifact name: ${artifactName}`);
|
|
447
|
+
throw new ModelError(`Undefined artifact name: ${ artifactName }`);
|
|
447
448
|
}
|
|
448
449
|
|
|
449
450
|
// Render an artifact deletion into the appropriate dictionary of 'resultObj'.
|
|
@@ -451,7 +452,7 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
451
452
|
const tableName = renderArtifactName(artifactName);
|
|
452
453
|
deletionsDuplicateChecker.addArtifact(tableName, art.$location, artifactName);
|
|
453
454
|
|
|
454
|
-
addDeletion(resultObj, artifactName, `-- [WARNING] this statement is lossy\nDROP TABLE ${tableName}`);
|
|
455
|
+
addDeletion(resultObj, artifactName, `-- [WARNING] this statement is lossy\nDROP TABLE ${ tableName }`);
|
|
455
456
|
}
|
|
456
457
|
|
|
457
458
|
// Render an artifact migration into the appropriate dictionary of 'resultObj'.
|
|
@@ -474,15 +475,15 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
474
475
|
return getEltStr(defNoProps, eltName);
|
|
475
476
|
}
|
|
476
477
|
function oldAnnoChangedIncompatibly( defOld, defNew ) {
|
|
477
|
-
return typeof defOld === 'string' && defOld.trim().length && !(typeof defNew === 'string' && defNew.trim().startsWith(`${defOld.trim()} `));
|
|
478
|
+
return typeof defOld === 'string' && defOld.trim().length && !(typeof defNew === 'string' && defNew.trim().startsWith(`${ defOld.trim() } `));
|
|
478
479
|
}
|
|
479
480
|
function getUnknownSqlReason( anno, artName, defOld, defNew, eltName ) {
|
|
480
481
|
const changeKind = defNew === undefined
|
|
481
|
-
? `removed (previous value: ${JSON.stringify(defOld)})`
|
|
482
|
-
: `changed from ${JSON.stringify(defOld)} to ${JSON.stringify(defNew)}`;
|
|
482
|
+
? `removed (previous value: ${ JSON.stringify(defOld) })`
|
|
483
|
+
: `changed from ${ JSON.stringify(defOld) } to ${ JSON.stringify(defNew) }`;
|
|
483
484
|
return eltName
|
|
484
|
-
? `annotation ${anno} of element ${artName}:${eltName} has been ${changeKind}`
|
|
485
|
-
: `annotation ${anno} of artifact ${artName} has been ${changeKind}`;
|
|
485
|
+
? `annotation ${ anno } of element ${ artName }:${ eltName } has been ${ changeKind }`
|
|
486
|
+
: `annotation ${ anno } of artifact ${ artName } has been ${ changeKind }`;
|
|
486
487
|
}
|
|
487
488
|
|
|
488
489
|
const sqlSnippetAnnos = [ '@sql.prepend', '@sql.append' ];
|
|
@@ -520,7 +521,7 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
520
521
|
|
|
521
522
|
// Remove columns.
|
|
522
523
|
if (removeCols.length)
|
|
523
|
-
addMigration(resultObj, artifactName, true, render.dropColumns(artifactName, removeCols).map(s => (options.src !== 'hdi' ? `-- [WARNING] this statement is lossy\n${s}` : s)));
|
|
524
|
+
addMigration(resultObj, artifactName, true, render.dropColumns(artifactName, removeCols).map(s => (options.src !== 'hdi' ? `-- [WARNING] this statement is lossy\n${ s }` : s)));
|
|
524
525
|
|
|
525
526
|
// Remove associations.
|
|
526
527
|
removeAssocs.forEach(assoc => addMigration(resultObj, artifactName, true, render.dropAssociation(artifactName, assoc)));
|
|
@@ -537,7 +538,7 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
537
538
|
if (constraintType === 'referential')
|
|
538
539
|
renderer = constraint => manageConstraint(constraint, csn, optionsWithDrop, '', quoteSqlId);
|
|
539
540
|
else
|
|
540
|
-
renderer = (constraint, constraintName) => renderUniqueConstraintDrop(constraint, renderArtifactName(`${artifactName}_${constraintName}`), tableName, quoteSqlId);
|
|
541
|
+
renderer = (constraint, constraintName) => renderUniqueConstraintDrop(constraint, renderArtifactName(`${ artifactName }_${ constraintName }`), tableName, quoteSqlId);
|
|
541
542
|
entries.forEach(( [ constraintName, constraint ]) => {
|
|
542
543
|
addConstraintDeletion(resultObj, constraint.parentTable, renderer(constraint, constraintName));
|
|
543
544
|
});
|
|
@@ -595,10 +596,10 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
595
596
|
const add = def.new.target
|
|
596
597
|
? render.addAssociations(artifactName, { [eltName]: def.new }, env)
|
|
597
598
|
: render.addColumnsFromElementsObj(artifactName, { [eltName]: def.new }, env);
|
|
598
|
-
addMigration(resultObj, artifactName, true, render.concat(...drop, ...add).map(s => (def.lossy !== undefined && options.src !== 'hdi' ? `-- [WARNING] this statement could ${def.lossy ? 'be lossy' : 'fail'}: ${def.details}\n${s}` : s)));
|
|
599
|
+
addMigration(resultObj, artifactName, true, render.concat(...drop, ...add).map(s => (def.lossy !== undefined && options.src !== 'hdi' ? `-- [WARNING] this statement could ${ def.lossy ? 'be lossy' : 'fail' }: ${ def.details }\n${ s }` : s)));
|
|
599
600
|
}
|
|
600
601
|
else { // Lossless change: no associations directly affected, no size reduction.
|
|
601
|
-
addMigration(resultObj, artifactName, false, render.alterColumns(artifactName, sqlId, def, eltStrNew, eltName, activateAlterMode(env, 'migration')).map(s => (def.lossy !== undefined ? `-- [WARNING] this statement could ${def.lossy ? 'be lossy' : 'fail'}: ${def.details}\n${s}` : s)));
|
|
602
|
+
addMigration(resultObj, artifactName, false, render.alterColumns(artifactName, sqlId, def, eltStrNew, eltName, activateAlterMode(env, 'migration')).map(s => (def.lossy !== undefined ? `-- [WARNING] this statement could ${ def.lossy ? 'be lossy' : 'fail' }: ${ def.details }\n${ s }` : s)));
|
|
602
603
|
}
|
|
603
604
|
}
|
|
604
605
|
}
|
|
@@ -628,7 +629,7 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
628
629
|
if (options.sqlDialect === 'hana') {
|
|
629
630
|
if (art.technicalConfig?.hana?.storeType) {
|
|
630
631
|
// Explicitly specified
|
|
631
|
-
result += `${art.technicalConfig.hana.storeType.toUpperCase()} `;
|
|
632
|
+
result += `${ art.technicalConfig.hana.storeType.toUpperCase() } `;
|
|
632
633
|
}
|
|
633
634
|
else if (!front) {
|
|
634
635
|
// in 'hdbtable' files, COLUMN or ROW is mandatory, and COLUMN is the default
|
|
@@ -637,7 +638,7 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
637
638
|
}
|
|
638
639
|
const tableName = renderArtifactName(artifactName);
|
|
639
640
|
definitionsDuplicateChecker.addArtifact(art['@cds.persistence.name'], art.$location, artifactName);
|
|
640
|
-
result += `TABLE ${tableName}`;
|
|
641
|
+
result += `TABLE ${ tableName }`;
|
|
641
642
|
result += ' (\n';
|
|
642
643
|
result += Object.keys(art.elements)
|
|
643
644
|
.map(eltName => renderElement(eltName, art.elements[eltName], definitionsDuplicateChecker, getFzIndex(eltName, art.technicalConfig?.hana), childEnv))
|
|
@@ -648,11 +649,11 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
648
649
|
.map(name => quoteSqlId(name))
|
|
649
650
|
.join(', ');
|
|
650
651
|
if (uniqueFields !== '')
|
|
651
|
-
result += `,\n${childEnv.indent}UNIQUE(${uniqueFields})`;
|
|
652
|
+
result += `,\n${ childEnv.indent }UNIQUE(${ uniqueFields })`;
|
|
652
653
|
|
|
653
654
|
const primaryKeys = render.primaryKey(art.elements);
|
|
654
655
|
if (primaryKeys !== '')
|
|
655
|
-
result += `,\n${childEnv.indent}${primaryKeys}`;
|
|
656
|
+
result += `,\n${ childEnv.indent }${ primaryKeys }`;
|
|
656
657
|
|
|
657
658
|
// for `to.sql` w/ dialect `hana` the constraints will be part of the alter statement
|
|
658
659
|
const constraintsAsAlter = !options.constraintsInCreateTable && options.src === 'sql' && (options.sqlDialect === 'hana' || options.sqlDialect === 'postgres');
|
|
@@ -669,7 +670,7 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
669
670
|
}
|
|
670
671
|
else {
|
|
671
672
|
forEachValue(referentialConstraints, (constraint) => {
|
|
672
|
-
result += `,\n${constraint}`;
|
|
673
|
+
result += `,\n${ constraint }`;
|
|
673
674
|
});
|
|
674
675
|
}
|
|
675
676
|
}
|
|
@@ -678,13 +679,13 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
678
679
|
// OR create a unique index for HDI
|
|
679
680
|
const uniqueConstraints = art.$tableConstraints?.unique;
|
|
680
681
|
for (const cn in uniqueConstraints) {
|
|
681
|
-
const constraint = renderUniqueConstraintString(uniqueConstraints[cn], renderArtifactName(`${artifactName}_${cn}`), tableName, quoteSqlId, options);
|
|
682
|
+
const constraint = renderUniqueConstraintString(uniqueConstraints[cn], renderArtifactName(`${ artifactName }_${ cn }`), tableName, quoteSqlId, options);
|
|
682
683
|
if (options.src === 'hdi')
|
|
683
|
-
resultObj.hdbindex[`${artifactName}.${cn}`] = constraint;
|
|
684
|
+
resultObj.hdbindex[`${ artifactName }.${ cn }`] = constraint;
|
|
684
685
|
else
|
|
685
|
-
result += `,\n${childEnv.indent}${constraint}`;
|
|
686
|
+
result += `,\n${ childEnv.indent }${ constraint }`;
|
|
686
687
|
}
|
|
687
|
-
result += `${env.indent}\n)`;
|
|
688
|
+
result += `${ env.indent }\n)`;
|
|
688
689
|
|
|
689
690
|
if (options.sqlDialect === 'hana')
|
|
690
691
|
result += renderTechnicalConfiguration(art.technicalConfig, childEnv);
|
|
@@ -696,8 +697,8 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
696
697
|
.filter(s => s !== '')
|
|
697
698
|
.join(',\n');
|
|
698
699
|
if (associations !== '') {
|
|
699
|
-
result += `${env.indent} WITH ASSOCIATIONS (\n${associations}\n`;
|
|
700
|
-
result += `${env.indent})`;
|
|
700
|
+
result += `${ env.indent } WITH ASSOCIATIONS (\n${ associations }\n`;
|
|
701
|
+
result += `${ env.indent })`;
|
|
701
702
|
}
|
|
702
703
|
}
|
|
703
704
|
// Only HANA has indices
|
|
@@ -706,7 +707,7 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
706
707
|
renderIndexesInto(art.technicalConfig?.hana?.indexes, artifactName, resultObj, env);
|
|
707
708
|
|
|
708
709
|
if (options.sqlDialect === 'hana' && hasHanaComment(art, options))
|
|
709
|
-
result += ` COMMENT ${renderStringForSql(getHanaComment(art), options.sqlDialect)}`;
|
|
710
|
+
result += ` COMMENT ${ renderStringForSql(getHanaComment(art), options.sqlDialect) }`;
|
|
710
711
|
|
|
711
712
|
if (back)
|
|
712
713
|
result += back;
|
|
@@ -723,7 +724,7 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
723
724
|
* @param {object} resultObj Result collector
|
|
724
725
|
*/
|
|
725
726
|
function renderConstraintExtendInto( artifactName, { constraint, constraintName, constraintType }, resultObj ) {
|
|
726
|
-
const result = constraintType === 'unique' ? renderUniqueConstraintAdd(constraint, renderArtifactName(`${artifactName}_${constraintName}`), renderArtifactName(constraint.parentTable), quoteSqlId, options)
|
|
727
|
+
const result = constraintType === 'unique' ? renderUniqueConstraintAdd(constraint, renderArtifactName(`${ artifactName }_${ constraintName }`), renderArtifactName(constraint.parentTable), quoteSqlId, options)
|
|
727
728
|
: manageConstraint(constraint, csn, options, '', quoteSqlId);
|
|
728
729
|
|
|
729
730
|
addMigration(resultObj, artifactName, false, [ result ]);
|
|
@@ -815,24 +816,26 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
815
816
|
if (duplicateChecker)
|
|
816
817
|
duplicateChecker.addElement(quotedElementName, elm.$location, elementName);
|
|
817
818
|
|
|
818
|
-
let result = `${env.indent + quotedElementName}${isPostgresAlterColumn ? ' TYPE' : ''} ${renderTypeReference(elm, env)
|
|
819
|
-
}${renderNullability(elm, true, env.alterMode)}`;
|
|
819
|
+
let result = `${ env.indent + quotedElementName }${ isPostgresAlterColumn ? ' TYPE' : '' } ${ renderTypeReference(elm, env)
|
|
820
|
+
}${ renderNullability(elm, true, env.alterMode) }`;
|
|
820
821
|
// calculated elements (on write) can't have a default; ignore it
|
|
822
|
+
env.isInDefault = true;
|
|
821
823
|
if (elm.$default && env.alterMode && !elm.value && options.sqlDialect !== 'postgres')
|
|
822
|
-
result += ` DEFAULT ${renderExpr(elm.$default, env.withSubPath([ '$default' ]))}`;
|
|
824
|
+
result += ` DEFAULT ${ renderExpr(elm.$default, env.withSubPath([ '$default' ])) }`;
|
|
823
825
|
else if (elm.default && !elm.value)
|
|
824
|
-
result += ` DEFAULT ${renderExpr(elm.default, env.withSubPath([ 'default' ]))}`;
|
|
826
|
+
result += ` DEFAULT ${ renderExpr(elm.default, env.withSubPath([ 'default' ])) }`;
|
|
827
|
+
env.isInDefault = false;
|
|
825
828
|
|
|
826
829
|
// Only SAP HANA has fuzzy indices
|
|
827
830
|
if (fzindex && options.sqlDialect === 'hana')
|
|
828
|
-
result += ` ${renderExpr(fzindex, env)}`;
|
|
831
|
+
result += ` ${ renderExpr(fzindex, env) }`;
|
|
829
832
|
|
|
830
833
|
// (table) elements can only have a @sql.append
|
|
831
834
|
const { back } = getSqlSnippets(options, elm);
|
|
832
835
|
result += back; // Needs to be rendered before the COMMENT
|
|
833
836
|
|
|
834
837
|
if (options.sqlDialect === 'hana' && hasHanaComment(elm, options))
|
|
835
|
-
result += ` COMMENT ${renderStringForSql(getHanaComment(elm), options.sqlDialect)}`;
|
|
838
|
+
result += ` COMMENT ${ renderStringForSql(getHanaComment(elm), options.sqlDialect) }`;
|
|
836
839
|
|
|
837
840
|
return result;
|
|
838
841
|
}
|
|
@@ -870,8 +873,8 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
870
873
|
result += 'MANY TO ONE';
|
|
871
874
|
}
|
|
872
875
|
result += ' JOIN ';
|
|
873
|
-
result += `${renderArtifactName(elm.target)} AS ${quoteSqlId(elementName)} ON (`;
|
|
874
|
-
result += `${renderExpr(elm.on, env.withSubPath([ 'on' ]))})`;
|
|
876
|
+
result += `${ renderArtifactName(elm.target) } AS ${ quoteSqlId(elementName) } ON (`;
|
|
877
|
+
result += `${ renderExpr(elm.on, env.withSubPath([ 'on' ])) })`;
|
|
875
878
|
}
|
|
876
879
|
return result;
|
|
877
880
|
}
|
|
@@ -917,7 +920,7 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
917
920
|
for (const xpr of tc.tableSuffix) {
|
|
918
921
|
const clause = renderExpr(xpr, env);
|
|
919
922
|
if (!ignore.includes(clause.toUpperCase()))
|
|
920
|
-
result += `\n${env.indent}${clause}`;
|
|
923
|
+
result += `\n${ env.indent }${ clause }`;
|
|
921
924
|
}
|
|
922
925
|
}
|
|
923
926
|
return result;
|
|
@@ -945,10 +948,10 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
945
948
|
}
|
|
946
949
|
// FIXME: Full text index should already be different in compact CSN
|
|
947
950
|
if (result.startsWith('FULLTEXT'))
|
|
948
|
-
resultObj.hdbfulltextindex[`${artifactName}.${idxName}`] = result;
|
|
951
|
+
resultObj.hdbfulltextindex[`${ artifactName }.${ idxName }`] = result;
|
|
949
952
|
|
|
950
953
|
else
|
|
951
|
-
resultObj.hdbindex[`${artifactName}.${idxName}`] = result;
|
|
954
|
+
resultObj.hdbindex[`${ artifactName }.${ idxName }`] = result;
|
|
952
955
|
}
|
|
953
956
|
|
|
954
957
|
|
|
@@ -967,9 +970,9 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
967
970
|
const i = index.indexOf('index');
|
|
968
971
|
const j = index.indexOf('(');
|
|
969
972
|
if (i > index.length - 2 || !index[i + 1].ref || j < i || j > index.length - 2)
|
|
970
|
-
throw new ModelError(`Unexpected form of index: "${index}"`);
|
|
973
|
+
throw new ModelError(`Unexpected form of index: "${ index }"`);
|
|
971
974
|
|
|
972
|
-
let indexName = renderArtifactName(`${artifactName}.${index[i + 1].ref}`);
|
|
975
|
+
let indexName = renderArtifactName(`${ artifactName }.${ index[i + 1].ref }`);
|
|
973
976
|
if (options.sqlMapping === 'plain')
|
|
974
977
|
indexName = indexName.replace(/(\.|::)/g, '_');
|
|
975
978
|
|
|
@@ -995,23 +998,23 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
995
998
|
function renderQuerySource( source, env ) {
|
|
996
999
|
// Sub-SELECT
|
|
997
1000
|
if (source.SELECT || source.SET) {
|
|
998
|
-
let result = `(${renderQuery(source, env.withIncreasedIndent())})`;
|
|
1001
|
+
let result = `(${ renderQuery(source, env.withIncreasedIndent()) })`;
|
|
999
1002
|
if (source.as)
|
|
1000
|
-
result += ` AS ${quoteSqlId(source.as)}`;
|
|
1003
|
+
result += ` AS ${ quoteSqlId(source.as) }`;
|
|
1001
1004
|
|
|
1002
1005
|
return result;
|
|
1003
1006
|
}
|
|
1004
1007
|
// JOIN
|
|
1005
1008
|
else if (source.join) {
|
|
1006
1009
|
// One join operation, possibly with ON-condition
|
|
1007
|
-
let result = `${renderQuerySource(source.args[0], env.withSubPath([ 'args', 0 ]))}`;
|
|
1010
|
+
let result = `${ renderQuerySource(source.args[0], env.withSubPath([ 'args', 0 ])) }`;
|
|
1008
1011
|
for (let i = 1; i < source.args.length; i++) {
|
|
1009
|
-
result = `(${result} ${source.join.toUpperCase()} `;
|
|
1012
|
+
result = `(${ result } ${ source.join.toUpperCase() } `;
|
|
1010
1013
|
if (options.sqlDialect === 'hana')
|
|
1011
1014
|
result += renderJoinCardinality(source.cardinality);
|
|
1012
|
-
result += `JOIN ${renderQuerySource(source.args[i], env.withSubPath([ 'args', i ]))}`;
|
|
1015
|
+
result += `JOIN ${ renderQuerySource(source.args[i], env.withSubPath([ 'args', i ])) }`;
|
|
1013
1016
|
if (source.on)
|
|
1014
|
-
result += ` ON ${renderExpr(source.on, env.withSubPath([ 'on' ]))}`;
|
|
1017
|
+
result += ` ON ${ renderExpr(source.on, env.withSubPath([ 'on' ])) }`;
|
|
1015
1018
|
|
|
1016
1019
|
result += ')';
|
|
1017
1020
|
}
|
|
@@ -1021,7 +1024,7 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
1021
1024
|
|
|
1022
1025
|
// Sanity check
|
|
1023
1026
|
if (!source.ref)
|
|
1024
|
-
throw new ModelError(`Expecting ref in ${JSON.stringify(source)}`);
|
|
1027
|
+
throw new ModelError(`Expecting ref in ${ JSON.stringify(source) }`);
|
|
1025
1028
|
|
|
1026
1029
|
return renderAbsolutePathWithAlias(source, env);
|
|
1027
1030
|
}
|
|
@@ -1062,7 +1065,7 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
1062
1065
|
function renderAbsolutePathWithAlias( path, env ) {
|
|
1063
1066
|
// This actually can't happen anymore because assoc2joins should have taken care of it
|
|
1064
1067
|
if (path.ref[0].where)
|
|
1065
|
-
throw new ModelError(`"At ${JSON.stringify(env.path)}": Filters in FROM are not supported for conversion to SQL (path: ${JSON.stringify(path)})`);
|
|
1068
|
+
throw new ModelError(`"At ${ JSON.stringify(env.path) }": Filters in FROM are not supported for conversion to SQL (path: ${ JSON.stringify(path) })`);
|
|
1066
1069
|
|
|
1067
1070
|
// SQL needs a ':' after path.ref[0] to separate associations
|
|
1068
1071
|
let result = renderAbsolutePath(path, ':', env);
|
|
@@ -1071,13 +1074,13 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
1071
1074
|
const implicitAlias = path.ref.length === 0 ? getLastPartOf(getResultingName(csn, options.sqlMapping, path.ref[0])) : getLastPartOfRef(path.ref);
|
|
1072
1075
|
if (path.as) {
|
|
1073
1076
|
// Source had an alias - render it
|
|
1074
|
-
result += ` AS ${quoteSqlId(path.as)}`;
|
|
1077
|
+
result += ` AS ${ quoteSqlId(path.as) }`;
|
|
1075
1078
|
}
|
|
1076
1079
|
else {
|
|
1077
1080
|
const quotedAlias = quoteSqlId(implicitAlias);
|
|
1078
1081
|
if (getLastPartOf(result) !== quotedAlias) {
|
|
1079
1082
|
// Render an artificial alias if the result would produce a different one
|
|
1080
|
-
result += ` AS ${quotedAlias}`;
|
|
1083
|
+
result += ` AS ${ quotedAlias }`;
|
|
1081
1084
|
}
|
|
1082
1085
|
}
|
|
1083
1086
|
return result;
|
|
@@ -1099,7 +1102,7 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
1099
1102
|
function renderAbsolutePath( path, sep, env ) {
|
|
1100
1103
|
// Sanity checks
|
|
1101
1104
|
if (!path.ref)
|
|
1102
|
-
throw new ModelError(`Expecting ref in path: ${JSON.stringify(path)}`);
|
|
1105
|
+
throw new ModelError(`Expecting ref in path: ${ JSON.stringify(path) }`);
|
|
1103
1106
|
|
|
1104
1107
|
// Determine the absolute name of the first artifact on the path (before any associations or element traversals)
|
|
1105
1108
|
const firstArtifactName = path.ref[0].id || path.ref[0];
|
|
@@ -1115,7 +1118,7 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
1115
1118
|
const ref = csn.definitions[path.ref[0].id] || csn.definitions[path.ref[0]];
|
|
1116
1119
|
if (ref?.params) {
|
|
1117
1120
|
result += path.ref[0]?.args
|
|
1118
|
-
? `(${renderArgs(path.ref[0], '=>', env.withSubPath([ 'ref', 0 ]), syntax)})`
|
|
1121
|
+
? `(${ renderArgs(path.ref[0], '=>', env.withSubPath([ 'ref', 0 ]), syntax) })`
|
|
1119
1122
|
: '()';
|
|
1120
1123
|
}
|
|
1121
1124
|
else if (syntax === 'udf') {
|
|
@@ -1124,13 +1127,13 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
1124
1127
|
result += '()';
|
|
1125
1128
|
}
|
|
1126
1129
|
if (path.ref[0].where) {
|
|
1127
|
-
const cardinality = path.ref[0].cardinality ? (`${path.ref[0].cardinality.max}: `) : '';
|
|
1128
|
-
result += `[${cardinality}${renderExpr(path.ref[0].where, env.withSubPath([ 'ref', 0, 'where' ]))}]`;
|
|
1130
|
+
const cardinality = path.ref[0].cardinality ? (`${ path.ref[0].cardinality.max }: `) : '';
|
|
1131
|
+
result += `[${ cardinality }${ renderExpr(path.ref[0].where, env.withSubPath([ 'ref', 0, 'where' ])) }]`;
|
|
1129
1132
|
}
|
|
1130
1133
|
|
|
1131
1134
|
// Add any path steps (possibly with parameters and filters) that may follow after that
|
|
1132
1135
|
if (path.ref.length > 1)
|
|
1133
|
-
result += `${sep}${renderTypeRef({ ref: path.ref.slice(1) }, env)}`;
|
|
1136
|
+
result += `${ sep }${ renderTypeRef({ ref: path.ref.slice(1) }, env) }`;
|
|
1134
1137
|
|
|
1135
1138
|
return result;
|
|
1136
1139
|
}
|
|
@@ -1157,10 +1160,10 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
1157
1160
|
// Named arguments (object/dict)
|
|
1158
1161
|
else if (typeof node.args === 'object')
|
|
1159
1162
|
// if this is a function param which is not a reference to the model, we must not quote it
|
|
1160
|
-
return Object.keys(node.args).map(key => `${node.func ? key : decorateParameter(key, syntax)} ${sep} ${renderExpr(node.args[key], env.withSubPath([ 'args', key ]))}`).join(', ');
|
|
1163
|
+
return Object.keys(node.args).map(key => `${ node.func ? key : decorateParameter(key, syntax) } ${ sep } ${ renderExpr(node.args[key], env.withSubPath([ 'args', key ])) }`).join(', ');
|
|
1161
1164
|
|
|
1162
1165
|
|
|
1163
|
-
throw new ModelError(`Unknown args: ${JSON.stringify(node.args)}`);
|
|
1166
|
+
throw new ModelError(`Unknown args: ${ JSON.stringify(node.args) }`);
|
|
1164
1167
|
|
|
1165
1168
|
|
|
1166
1169
|
/**
|
|
@@ -1172,7 +1175,7 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
1172
1175
|
*/
|
|
1173
1176
|
function decorateParameter( arg, parameterSyntax ) {
|
|
1174
1177
|
if (parameterSyntax === 'calcview')
|
|
1175
|
-
return `PLACEHOLDER."$$${arg}$$"`;
|
|
1178
|
+
return `PLACEHOLDER."$$${ arg }$$"`;
|
|
1176
1179
|
|
|
1177
1180
|
return quoteSqlId(arg);
|
|
1178
1181
|
}
|
|
@@ -1193,14 +1196,14 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
1193
1196
|
if (leaf && elements[leaf]?.virtual) {
|
|
1194
1197
|
if (isDeprecatedEnabled(options, '_renderVirtualElements'))
|
|
1195
1198
|
// render a virtual column 'null as <alias>'
|
|
1196
|
-
result += `${env.indent}NULL AS ${quoteSqlId(col.as || leaf)}`;
|
|
1199
|
+
result += `${ env.indent }NULL AS ${ quoteSqlId(col.as || leaf) }`;
|
|
1197
1200
|
}
|
|
1198
1201
|
else {
|
|
1199
1202
|
result = env.indent + renderExpr(withoutCast(col), env);
|
|
1200
1203
|
if (col.as)
|
|
1201
|
-
result += ` AS ${quoteSqlId(col.as)}`;
|
|
1204
|
+
result += ` AS ${ quoteSqlId(col.as) }`;
|
|
1202
1205
|
else if (col.func && !col.args) // e.g. CURRENT_TIMESTAMP
|
|
1203
|
-
result += ` AS ${quoteSqlId(col.func)}`;
|
|
1206
|
+
result += ` AS ${ quoteSqlId(col.func) }`;
|
|
1204
1207
|
}
|
|
1205
1208
|
return result;
|
|
1206
1209
|
}
|
|
@@ -1216,15 +1219,15 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
1216
1219
|
function renderView( artifactName, art, env ) {
|
|
1217
1220
|
const viewName = renderArtifactName(artifactName);
|
|
1218
1221
|
definitionsDuplicateChecker.addArtifact(art['@cds.persistence.name'], art?.$location, artifactName);
|
|
1219
|
-
let result = `VIEW ${viewName}`;
|
|
1222
|
+
let result = `VIEW ${ viewName }`;
|
|
1220
1223
|
|
|
1221
1224
|
if (options.sqlDialect === 'hana' && hasHanaComment(art, options))
|
|
1222
|
-
result += ` COMMENT ${renderStringForSql(getHanaComment(art), options.sqlDialect)}`;
|
|
1225
|
+
result += ` COMMENT ${ renderStringForSql(getHanaComment(art), options.sqlDialect) }`;
|
|
1223
1226
|
|
|
1224
1227
|
result += renderParameterDefinitions(art.params, env);
|
|
1225
|
-
result += ` AS ${renderQuery(getNormalizedQuery(art).query,
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
+
result += ` AS ${ renderQuery(getNormalizedQuery(art).query,
|
|
1229
|
+
env.withSubPath([ art.projection ? 'projection' : 'query' ]),
|
|
1230
|
+
art.elements, !!art.projection) }`;
|
|
1228
1231
|
|
|
1229
1232
|
const childEnv = env.withIncreasedIndent();
|
|
1230
1233
|
const associations = Object.keys(art.elements)
|
|
@@ -1233,8 +1236,8 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
1233
1236
|
.filter(s => s !== '')
|
|
1234
1237
|
.join(',\n');
|
|
1235
1238
|
if (associations !== '' && withHanaAssociations) {
|
|
1236
|
-
result += `${env.indent}\nWITH ASSOCIATIONS (\n${associations}\n`;
|
|
1237
|
-
result += `${env.indent})`;
|
|
1239
|
+
result += `${ env.indent }\nWITH ASSOCIATIONS (\n${ associations }\n`;
|
|
1240
|
+
result += `${ env.indent })`;
|
|
1238
1241
|
}
|
|
1239
1242
|
|
|
1240
1243
|
// views can only have a @sql.append
|
|
@@ -1269,13 +1272,13 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
1269
1272
|
pIdentifier = prepareIdentifier(pn);
|
|
1270
1273
|
else
|
|
1271
1274
|
pIdentifier = quoteSqlId(pn);
|
|
1272
|
-
let pstr = `IN ${pIdentifier} ${renderTypeReference(p, paramEnv)}`;
|
|
1275
|
+
let pstr = `IN ${ pIdentifier } ${ renderTypeReference(p, paramEnv) }`;
|
|
1273
1276
|
if (p.default)
|
|
1274
|
-
pstr += ` DEFAULT ${renderExpr(p.default, new SqlRenderEnvironment({ ...env, indent: '' }))}`;
|
|
1277
|
+
pstr += ` DEFAULT ${ renderExpr(p.default, new SqlRenderEnvironment({ ...env, indent: '', isInDefault: true })) }`;
|
|
1275
1278
|
|
|
1276
1279
|
parray.push(pstr);
|
|
1277
1280
|
}
|
|
1278
|
-
result = `(${parray.join(', ')})`;
|
|
1281
|
+
result = `(${ parray.join(', ') })`;
|
|
1279
1282
|
}
|
|
1280
1283
|
return result;
|
|
1281
1284
|
}
|
|
@@ -1301,9 +1304,9 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
1301
1304
|
// - has an ORDER BY/LIMIT (because UNION etc. can't stand directly behind an ORDER BY)
|
|
1302
1305
|
const argEnv = env.withSubPath([ 'args', index ]);
|
|
1303
1306
|
const queryString = renderQuery( arg, argEnv, elements || query.SET.elements, false);
|
|
1304
|
-
return (arg.SET || arg.SELECT?.orderBy || arg.SELECT?.limit) ? `(${queryString})` : queryString;
|
|
1307
|
+
return (arg.SET || arg.SELECT?.orderBy || arg.SELECT?.limit) ? `(${ queryString })` : queryString;
|
|
1305
1308
|
})
|
|
1306
|
-
.join(`\n${env.indent}${query.SET.op?.toUpperCase()}${query.SET.all ? ' ALL ' : ' '}`);
|
|
1309
|
+
.join(`\n${ env.indent }${ query.SET.op?.toUpperCase() }${ query.SET.all ? ' ALL ' : ' ' }`);
|
|
1307
1310
|
|
|
1308
1311
|
// Set operation may also have an ORDER BY and LIMIT/OFFSET (in contrast to the ones belonging to
|
|
1309
1312
|
// each SELECT)
|
|
@@ -1311,14 +1314,14 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
1311
1314
|
// (otherwise some SQL implementations (e.g. sqlite) would interpret the ORDER BY/LIMIT as belonging
|
|
1312
1315
|
// to the last SET argument, not to the whole SET)
|
|
1313
1316
|
if (query.SET.orderBy || query.SET.limit) {
|
|
1314
|
-
result = `(${result})`;
|
|
1317
|
+
result = `(${ result })`;
|
|
1315
1318
|
if (query.SET.orderBy) {
|
|
1316
1319
|
const orderBy = query.SET.orderBy.map(entry => renderOrderByEntry(entry, env.withSubPath([ 'orderBy' ]))).join(', ');
|
|
1317
|
-
result += `\n${env.indent}ORDER BY ${orderBy}`;
|
|
1320
|
+
result += `\n${ env.indent }ORDER BY ${ orderBy }`;
|
|
1318
1321
|
}
|
|
1319
1322
|
if (query.SET.limit) {
|
|
1320
1323
|
const limit = renderLimit(query.SET.limit, env.withSubPath([ 'limit' ]));
|
|
1321
|
-
result += `\n${env.indent}${limit}`;
|
|
1324
|
+
result += `\n${ env.indent }${ limit }`;
|
|
1322
1325
|
}
|
|
1323
1326
|
}
|
|
1324
1327
|
|
|
@@ -1326,15 +1329,15 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
1326
1329
|
}
|
|
1327
1330
|
// Otherwise must have a SELECT
|
|
1328
1331
|
else if (!query.SELECT) {
|
|
1329
|
-
throw new ModelError(`Unexpected query operation ${JSON.stringify(query)}`);
|
|
1332
|
+
throw new ModelError(`Unexpected query operation ${ JSON.stringify(query) }`);
|
|
1330
1333
|
}
|
|
1331
1334
|
if (!isProjection)
|
|
1332
1335
|
env = env.withSubPath([ 'SELECT' ]);
|
|
1333
1336
|
const select = query.SELECT;
|
|
1334
1337
|
const childEnv = env.withIncreasedIndent();
|
|
1335
|
-
result += `SELECT${select.distinct ? ' DISTINCT' : ''}`;
|
|
1338
|
+
result += `SELECT${ select.distinct ? ' DISTINCT' : '' }`;
|
|
1336
1339
|
// FIXME: We probably also need to consider `excluding` here ?
|
|
1337
|
-
result += `\n${(select.columns || [ '*' ])
|
|
1340
|
+
result += `\n${ (select.columns || [ '*' ])
|
|
1338
1341
|
.map((col, index) => {
|
|
1339
1342
|
if (!select.mixin?.[firstPathStepId(col.ref)]) {
|
|
1340
1343
|
const colEnv = select.columns ? childEnv.withSubPath([ 'columns', index ]) : childEnv;
|
|
@@ -1343,22 +1346,22 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
1343
1346
|
return ''; // No mixin columns
|
|
1344
1347
|
})
|
|
1345
1348
|
.filter(s => s !== '')
|
|
1346
|
-
.join(',\n')}\n`;
|
|
1347
|
-
result += `${env.indent}FROM ${renderQuerySource( select.from, env.withSubPath([ 'from' ]))}`;
|
|
1349
|
+
.join(',\n') }\n`;
|
|
1350
|
+
result += `${ env.indent }FROM ${ renderQuerySource( select.from, env.withSubPath([ 'from' ])) }`;
|
|
1348
1351
|
if (select.where)
|
|
1349
|
-
result += `\n${env.indent}WHERE ${renderExpr(select.where, env.withSubPath([ 'where' ]))}`;
|
|
1352
|
+
result += `\n${ env.indent }WHERE ${ renderExpr(select.where, env.withSubPath([ 'where' ])) }`;
|
|
1350
1353
|
|
|
1351
1354
|
if (select.groupBy)
|
|
1352
|
-
result += `\n${env.indent}GROUP BY ${select.groupBy.map((expr, i) => renderExpr(expr, env.withSubPath([ 'groupBy', i ]))).join(', ')}`;
|
|
1355
|
+
result += `\n${ env.indent }GROUP BY ${ select.groupBy.map((expr, i) => renderExpr(expr, env.withSubPath([ 'groupBy', i ]))).join(', ') }`;
|
|
1353
1356
|
|
|
1354
1357
|
if (select.having)
|
|
1355
|
-
result += `\n${env.indent}HAVING ${renderExpr(select.having, env.withSubPath([ 'having' ]))}`;
|
|
1358
|
+
result += `\n${ env.indent }HAVING ${ renderExpr(select.having, env.withSubPath([ 'having' ])) }`;
|
|
1356
1359
|
|
|
1357
1360
|
if (select.orderBy)
|
|
1358
|
-
result += `\n${env.indent}ORDER BY ${select.orderBy.map((entry, i) => renderOrderByEntry(entry, env.withSubPath([ 'orderBy', i ]))).join(', ')}`;
|
|
1361
|
+
result += `\n${ env.indent }ORDER BY ${ select.orderBy.map((entry, i) => renderOrderByEntry(entry, env.withSubPath([ 'orderBy', i ]))).join(', ') }`;
|
|
1359
1362
|
|
|
1360
1363
|
if (select.limit)
|
|
1361
|
-
result += `\n${env.indent}${renderLimit(select.limit, env.withSubPath([ 'limit' ]))}`;
|
|
1364
|
+
result += `\n${ env.indent }${ renderLimit(select.limit, env.withSubPath([ 'limit' ])) }`;
|
|
1362
1365
|
|
|
1363
1366
|
return result;
|
|
1364
1367
|
}
|
|
@@ -1383,11 +1386,11 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
1383
1386
|
function renderLimit( limit, env ) {
|
|
1384
1387
|
let result = '';
|
|
1385
1388
|
if (limit.rows !== undefined)
|
|
1386
|
-
result += `LIMIT ${renderExpr(limit.rows, env.withSubPath([ 'rows' ]))}`;
|
|
1389
|
+
result += `LIMIT ${ renderExpr(limit.rows, env.withSubPath([ 'rows' ])) }`;
|
|
1387
1390
|
|
|
1388
1391
|
if (limit.offset !== undefined) {
|
|
1389
|
-
const indent = result !== '' ? `\n${env.indent}` : '';
|
|
1390
|
-
result += `${indent}OFFSET ${renderExpr(limit.offset, env.withSubPath([ 'offset' ]))}`;
|
|
1392
|
+
const indent = result !== '' ? `\n${ env.indent }` : '';
|
|
1393
|
+
result += `${ indent }OFFSET ${ renderExpr(limit.offset, env.withSubPath([ 'offset' ])) }`;
|
|
1391
1394
|
}
|
|
1392
1395
|
|
|
1393
1396
|
return result;
|
|
@@ -1404,10 +1407,10 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
1404
1407
|
function renderOrderByEntry( entry, env ) {
|
|
1405
1408
|
let result = renderExpr(entry, env);
|
|
1406
1409
|
if (entry.sort)
|
|
1407
|
-
result += ` ${entry.sort.toUpperCase()}`;
|
|
1410
|
+
result += ` ${ entry.sort.toUpperCase() }`;
|
|
1408
1411
|
|
|
1409
1412
|
if (entry.nulls)
|
|
1410
|
-
result += ` NULLS ${entry.nulls.toUpperCase()}`;
|
|
1413
|
+
result += ` NULLS ${ entry.nulls.toUpperCase() }`;
|
|
1411
1414
|
|
|
1412
1415
|
return result;
|
|
1413
1416
|
}
|
|
@@ -1425,12 +1428,12 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
1425
1428
|
if (!elm.type && !elm.value) {
|
|
1426
1429
|
// Anonymous structured type: Not supported with SQL, but doesn't happen anyway after flattening.
|
|
1427
1430
|
if (options.testMode)
|
|
1428
|
-
throw new ModelError(`to.sql(): Missing type of: ${JSON.stringify(env.path)}`);
|
|
1431
|
+
throw new ModelError(`to.sql(): Missing type of: ${ JSON.stringify(env.path) }`);
|
|
1429
1432
|
return result;
|
|
1430
1433
|
}
|
|
1431
1434
|
else if (elm.target) {
|
|
1432
1435
|
if (options.testMode)
|
|
1433
|
-
throw new ModelError(`to.sql(): Unexpected association in: ${JSON.stringify(env.path)}`);
|
|
1436
|
+
throw new ModelError(`to.sql(): Unexpected association in: ${ JSON.stringify(env.path) }`);
|
|
1434
1437
|
return result;
|
|
1435
1438
|
}
|
|
1436
1439
|
|
|
@@ -1442,7 +1445,7 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
1442
1445
|
result += renderTypeParameters(elm);
|
|
1443
1446
|
}
|
|
1444
1447
|
else {
|
|
1445
|
-
throw new ModelError(`Unexpected non-primitive type of: ${JSON.stringify(env.path)}`);
|
|
1448
|
+
throw new ModelError(`Unexpected non-primitive type of: ${ JSON.stringify(env.path) }`);
|
|
1446
1449
|
}
|
|
1447
1450
|
}
|
|
1448
1451
|
|
|
@@ -1452,7 +1455,7 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
1452
1455
|
// The SQL standard 2016 describes the syntax in section 11.3 - 11.4
|
|
1453
1456
|
// of the SQL Foundation spec (for 2003 in 5WD-02-Foundation-2003-09.pdf). Summarized:
|
|
1454
1457
|
// <generation clause> ::= GENERATED ALWAYS AS '(' <value expression> ')'
|
|
1455
|
-
result += ` GENERATED ALWAYS AS (${renderExpr(elm.value, env.withSubPath([ 'value' ]))})`;
|
|
1458
|
+
result += ` GENERATED ALWAYS AS (${ renderExpr(elm.value, env.withSubPath([ 'value' ])) })`;
|
|
1456
1459
|
// However, it appears many databases require a trailing "STORED".
|
|
1457
1460
|
if (options.sqlDialect === 'sqlite' || options.sqlDialect === 'postgres')
|
|
1458
1461
|
result += ' STORED';
|
|
@@ -1471,7 +1474,7 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
1471
1474
|
const types = cdsToSqlTypes[options.sqlDialect];
|
|
1472
1475
|
const result = types?.[typeName] || cdsToSqlTypes.standard[typeName];
|
|
1473
1476
|
if (!result && options.testMode)
|
|
1474
|
-
throw new CompilerAssertion(`Expected to find a type mapping for ${typeName}`);
|
|
1477
|
+
throw new CompilerAssertion(`Expected to find a type mapping for ${ typeName }`);
|
|
1475
1478
|
return result || 'CHAR';
|
|
1476
1479
|
}
|
|
1477
1480
|
|
|
@@ -1521,7 +1524,7 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
1521
1524
|
else
|
|
1522
1525
|
params.push(elm.srid);
|
|
1523
1526
|
}
|
|
1524
|
-
return params.length === 0 ? '' : `(${params.join(', ')})`;
|
|
1527
|
+
return params.length === 0 ? '' : `(${ params.join(', ') })`;
|
|
1525
1528
|
}
|
|
1526
1529
|
|
|
1527
1530
|
function renderExpressionLiteral( x ) {
|
|
@@ -1534,16 +1537,16 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
1534
1537
|
return String(x.val).toUpperCase();
|
|
1535
1538
|
case 'x':
|
|
1536
1539
|
// x'f000'
|
|
1537
|
-
return `${x.literal}'${x.val}'`;
|
|
1540
|
+
return `${ x.literal }'${ x.val }'`;
|
|
1538
1541
|
case 'date':
|
|
1539
1542
|
case 'time':
|
|
1540
1543
|
case 'timestamp':
|
|
1541
1544
|
if (options.sqlDialect === 'sqlite') {
|
|
1542
1545
|
// simple string literal '2017-11-02'
|
|
1543
|
-
return `'${x.val}'`;
|
|
1546
|
+
return `'${ x.val }'`;
|
|
1544
1547
|
}
|
|
1545
1548
|
// date'2017-11-02'
|
|
1546
|
-
return `${x.literal}'${x.val}'`;
|
|
1549
|
+
return `${ x.literal }'${ x.val }'`;
|
|
1547
1550
|
|
|
1548
1551
|
case 'string':
|
|
1549
1552
|
// 'foo', with proper escaping
|
|
@@ -1554,7 +1557,7 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
1554
1557
|
|
|
1555
1558
|
// otherwise fall through to
|
|
1556
1559
|
default:
|
|
1557
|
-
throw new ModelError(`Unknown literal or type: ${JSON.stringify(x)}`);
|
|
1560
|
+
throw new ModelError(`Unknown literal or type: ${ JSON.stringify(x) }`);
|
|
1558
1561
|
}
|
|
1559
1562
|
}
|
|
1560
1563
|
|
|
@@ -1575,7 +1578,7 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
1575
1578
|
return renderStringForSql(magicReplacement, options.sqlDialect);
|
|
1576
1579
|
|
|
1577
1580
|
const name = pathName(ref);
|
|
1578
|
-
const result = variableForDialect(options, name);
|
|
1581
|
+
const result = variableForDialect(options, name, env.isInDefault ? 'default' : null);
|
|
1579
1582
|
if (result)
|
|
1580
1583
|
return result;
|
|
1581
1584
|
|
|
@@ -1608,10 +1611,10 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
1608
1611
|
// assume that it was not if the path has length 2
|
|
1609
1612
|
if (firstPathStepId(x.ref) === '$parameters' && x.ref.length === 2) {
|
|
1610
1613
|
// Parameters must be uppercased and unquoted in SQL
|
|
1611
|
-
return `:${x.ref[1].toUpperCase()}`;
|
|
1614
|
+
return `:${ x.ref[1].toUpperCase() }`;
|
|
1612
1615
|
}
|
|
1613
1616
|
if (x.param)
|
|
1614
|
-
return `:${x.ref[0].toUpperCase()}`;
|
|
1617
|
+
return `:${ x.ref[0].toUpperCase() }`;
|
|
1615
1618
|
|
|
1616
1619
|
return x.ref.map((step, i) => renderPathStep(step, i, env.withSubPath([ 'ref', i ])))
|
|
1617
1620
|
.filter(s => s !== '')
|
|
@@ -1621,7 +1624,7 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
1621
1624
|
function renderTypeRef( x, env ) {
|
|
1622
1625
|
const prefix = x.param ? ':' : '';
|
|
1623
1626
|
const ref = x.ref.map((step, index) => renderPathStep(step, index, env.withSubPath([ 'ref', index ]))).join('.');
|
|
1624
|
-
return `${prefix}${ref}`;
|
|
1627
|
+
return `${ prefix }${ ref }`;
|
|
1625
1628
|
}
|
|
1626
1629
|
|
|
1627
1630
|
/**
|
|
@@ -1645,33 +1648,33 @@ function toSqlDdl( csn, options, messageFunctions ) {
|
|
|
1645
1648
|
else if (typeof s === 'object') {
|
|
1646
1649
|
// Sanity check
|
|
1647
1650
|
if (!s.func && !s.id)
|
|
1648
|
-
throw new ModelError(`Unknown path step object: ${JSON.stringify(s)}`);
|
|
1651
|
+
throw new ModelError(`Unknown path step object: ${ JSON.stringify(s) }`);
|
|
1649
1652
|
|
|
1650
1653
|
// Not really a path step but an object-like function call
|
|
1651
1654
|
if (s.func)
|
|
1652
|
-
return `${s.func}(${renderArgs(s, '=>', env, null)})`;
|
|
1655
|
+
return `${ s.func }(${ renderArgs(s, '=>', env, null) })`;
|
|
1653
1656
|
|
|
1654
1657
|
// Path step, possibly with view parameters and/or filters
|
|
1655
|
-
let result = `${quoteSqlId(s.id)}`;
|
|
1658
|
+
let result = `${ quoteSqlId(s.id) }`;
|
|
1656
1659
|
if (s.args) {
|
|
1657
1660
|
// View parameters
|
|
1658
|
-
result += `(${renderArgs(s, '=>', env, null)})`;
|
|
1661
|
+
result += `(${ renderArgs(s, '=>', env, null) })`;
|
|
1659
1662
|
}
|
|
1660
1663
|
if (s.where) {
|
|
1661
1664
|
// Filter, possibly with cardinality
|
|
1662
1665
|
// FIXME: Does SQL understand filter cardinalities?
|
|
1663
|
-
const cardinality = s.cardinality ? (`${s.cardinality.max}: `) : '';
|
|
1664
|
-
result += `[${cardinality}${renderExpr(s.where, env.withSubPath([ 'where' ]))}]`;
|
|
1666
|
+
const cardinality = s.cardinality ? (`${ s.cardinality.max }: `) : '';
|
|
1667
|
+
result += `[${ cardinality }${ renderExpr(s.where, env.withSubPath([ 'where' ])) }]`;
|
|
1665
1668
|
}
|
|
1666
1669
|
return result;
|
|
1667
1670
|
}
|
|
1668
1671
|
|
|
1669
|
-
throw new ModelError(`Unknown path step: ${JSON.stringify(s)}`);
|
|
1672
|
+
throw new ModelError(`Unknown path step: ${ JSON.stringify(s) }`);
|
|
1670
1673
|
}
|
|
1671
1674
|
|
|
1672
1675
|
|
|
1673
1676
|
function renderWindowFunction( funcName, node, fctEnv ) {
|
|
1674
|
-
let r = `${funcName}(${renderArgs(node, '=>', fctEnv, null)}) `;
|
|
1677
|
+
let r = `${ funcName }(${ renderArgs(node, '=>', fctEnv, null) }) `;
|
|
1675
1678
|
r += renderExpr(node.xpr, fctEnv.withSubPath([ 'xpr' ])); // xpr[0] is 'over'
|
|
1676
1679
|
return r;
|
|
1677
1680
|
}
|
|
@@ -1742,7 +1745,7 @@ function renderStringForSql( str, sqlDialect ) {
|
|
|
1742
1745
|
// - <https://www.postgresql.org/docs/9.1/functions-string.html>
|
|
1743
1746
|
str = str.replace(/'/g, '\'\'');
|
|
1744
1747
|
}
|
|
1745
|
-
return `'${str}'`;
|
|
1748
|
+
return `'${ str }'`;
|
|
1746
1749
|
}
|
|
1747
1750
|
|
|
1748
1751
|
module.exports = {
|