dbgate/packages/engines/default/SqlDumper.js

239 lines
5.7 KiB
JavaScript

class SqlDumper {
/** @param driver {import('@dbgate/types').EngineDriver} */
constructor(driver) {
this.s = "";
this.driver = driver;
this.dialect = driver.dialect;
this.indentLevel = 0;
}
endCommand() {
this.putRaw(";\n");
}
putRaw(text) {
this.s += text;
}
putCmd(format, ...args) {
this.put(format, ...args);
this.endCommand();
}
putFormattedValue(c, value) {
switch (c) {
case "s":
if (value != null) {
this.putRaw(value.toString());
}
break;
case "i":
{
this.putRaw(this.dialect.quoteIdentifier(value));
}
break;
case "k":
{
if (value) {
this.putRaw(value.toUpperCase());
}
}
break;
case "f":
{
const { schemaName, pureName } = value;
if (schemaName) {
this.putRaw(this.dialect.quoteIdentifier(schemaName));
this.putRaw(".");
}
this.putRaw(this.dialect.quoteIdentifier(pureName));
}
break;
}
}
putFormattedList(c, collection) {
if (!collection) return;
this.putCollection(", ", collection, item =>
this.putFormattedValue(c, item)
);
}
/** @param format {string} */
put(format, ...args) {
let i = 0;
let argIndex = 0;
const length = format.length;
while (i < length) {
let c = format[i];
i++;
switch (c) {
case "^":
while (i < length && format[i].match(/[a-z0-9_]/i)) {
this.putRaw(format[i].toUpperCase());
i++;
}
break;
case "%":
c = format[i];
i++;
switch (c) {
case "%":
this.putRaw("%");
break;
case ",":
c = format[i];
i++;
this.putFormattedList(c, args[argIndex]);
break;
default:
this.putFormattedValue(c, args[argIndex]);
break;
}
argIndex++;
break;
case "&":
c = format[i];
i++;
switch (c) {
case "&":
this.putRaw("&");
break;
case ">":
this.indentLevel++;
break;
case "<":
this.indentLevel--;
break;
case "n":
this.putRaw("\n");
this.putRaw(" ".repeat(2 * this.indentLevel));
break;
}
break;
default:
this.putRaw(c);
break;
}
}
}
autoIncrement() {
this.put(" ^auto_increment");
}
/**
* @param column {import('@dbgate/types').ColumnInfo}
*/
columnDefinition(
column,
{
includeDefault = true,
includeNullable = true,
includeCollate = true
} = {}
) {
if (column.computedExpression) {
this.put("^as %s", column.computedExpression);
if (column.isPersisted) this.put(" ^persisted");
return;
}
this.put("%k", column.dataType);
if (column.autoIncrement) {
this.autoIncrement();
}
this.putRaw(" ");
if (column.isSparse) {
this.put(" ^sparse ");
}
if (includeNullable) {
this.put(column.notNull ? "^not ^null" : "^null");
}
if (includeDefault && column.defaultValue != null) {
this.columnDefault(column);
}
}
/**
* @param column {import('@dbgate/types').ColumnInfo}
*/
columnDefault(column) {
if (column.defaultConstraint != null) {
this.put(
" ^constraint %i ^default %s ",
column.defaultConstraint,
column.defaultValue
);
} else {
this.put(" ^default %s ", column.defaultValue);
}
}
/**
* @template T
* @param {string} delimiter
* @param {T[]} collection
* @param {(col: T) => void} lambda
*/
putCollection(delimiter, collection, lambda) {
let first = true;
for (const item of collection) {
if (!first) this.put(delimiter);
first = false;
lambda(item);
}
}
/** @param table {import('@dbgate/types').TableInfo} */
createTable(table) {
this.put("^create ^table %f ( &>&n", table);
this.putCollection(",&n", table.columns, col => {
this.put("%i ", col.columnName);
this.columnDefinition(col);
});
if (table.primaryKey) {
this.put(",&n");
if (table.primaryKey.constraintName) {
this.put("^constraint %i", table.primaryKey.constraintName);
}
this.put(
" ^primary ^key (%,i)",
table.primaryKey.columns.map(x => x.columnName)
);
}
table.foreignKeys.forEach(fk => {
this.put(",&n");
this.createForeignKeyFore(fk);
});
// foreach (var cnt in table.Uniques)
// {
// if (!first) this.put(", &n");
// first = false;
// CreateUniqueCore(cnt);
// }
// foreach (var cnt in table.Checks)
// {
// if (!first) this.put(", &n");
// first = false;
// CreateCheckCore(cnt);
// }
this.put("&<&n)");
this.endCommand();
// foreach (var ix in table.Indexes)
// {
// CreateIndex(ix);
// }
}
/** @param fk {import('@dbgate/types').ForeignKeyInfo} */
createForeignKeyFore(fk) {
if (fk.constraintName != null)
this.put("^constraint %i ", fk.constraintName);
this.put(
"^foreign ^key (%,i) ^references %f (%,i)",
fk.columns.map(x => x.columnName),
{ schemaName: fk.refSchemaName, pureName: fk.refTableName },
fk.columns.map(x => x.refColumnName)
);
if (fk.deleteAction) this.put(" ^on ^delete %k", fk.deleteAction);
if (fk.updateAction) this.put(" ^on ^update %k", fk.updateAction);
}
}
module.exports = SqlDumper;