2020-02-02 18:27:25 +00:00
|
|
|
class SqlDumper {
|
2020-02-03 18:52:02 +00:00
|
|
|
/** @param driver {import('@dbgate/types').EngineDriver} */
|
2020-02-02 18:27:25 +00:00
|
|
|
constructor(driver) {
|
2020-03-02 21:08:06 +00:00
|
|
|
this.s = "";
|
2020-02-02 18:27:25 +00:00
|
|
|
this.driver = driver;
|
|
|
|
this.dialect = driver.dialect;
|
2020-03-02 21:08:06 +00:00
|
|
|
this.indentLevel = 0;
|
|
|
|
}
|
|
|
|
endCommand() {
|
|
|
|
this.putRaw(";\n");
|
2020-02-02 18:27:25 +00:00
|
|
|
}
|
|
|
|
putRaw(text) {
|
|
|
|
this.s += text;
|
|
|
|
}
|
2020-02-03 19:34:38 +00:00
|
|
|
putCmd(format, ...args) {
|
|
|
|
this.put(format, ...args);
|
2020-03-02 21:08:06 +00:00
|
|
|
this.endCommand();
|
2020-02-02 18:27:25 +00:00
|
|
|
}
|
|
|
|
putFormattedValue(c, value) {
|
|
|
|
switch (c) {
|
2020-03-02 21:08:06 +00:00
|
|
|
case "s":
|
2020-02-02 18:27:25 +00:00
|
|
|
if (value != null) {
|
|
|
|
this.putRaw(value.toString());
|
|
|
|
}
|
|
|
|
break;
|
2020-03-02 21:08:06 +00:00
|
|
|
case "i":
|
|
|
|
{
|
|
|
|
this.putRaw(this.dialect.quoteIdentifier(value));
|
|
|
|
}
|
|
|
|
break;
|
2020-03-03 06:14:12 +00:00
|
|
|
case "k":
|
|
|
|
{
|
|
|
|
this.putRaw(value.toUpperCase());
|
|
|
|
}
|
|
|
|
break;
|
2020-03-02 21:08:06 +00:00
|
|
|
case "f":
|
2020-02-02 18:27:25 +00:00
|
|
|
{
|
|
|
|
const { schemaName, pureName } = value;
|
|
|
|
if (schemaName) {
|
|
|
|
this.putRaw(this.dialect.quoteIdentifier(schemaName));
|
2020-03-02 21:08:06 +00:00
|
|
|
this.putRaw(".");
|
2020-02-02 18:27:25 +00:00
|
|
|
}
|
|
|
|
this.putRaw(this.dialect.quoteIdentifier(pureName));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2020-03-02 21:22:44 +00:00
|
|
|
putFormattedList(c, collection) {
|
|
|
|
this.putCollection(", ", collection, item =>
|
|
|
|
this.putFormattedValue(c, item)
|
|
|
|
);
|
|
|
|
}
|
2020-02-02 18:27:25 +00:00
|
|
|
/** @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) {
|
2020-03-02 21:08:06 +00:00
|
|
|
case "^":
|
|
|
|
while (i < length && format[i].match(/[a-z0-9_]/i)) {
|
2020-02-02 18:27:25 +00:00
|
|
|
this.putRaw(format[i].toUpperCase());
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
break;
|
2020-03-02 21:08:06 +00:00
|
|
|
case "%":
|
2020-02-02 18:27:25 +00:00
|
|
|
c = format[i];
|
|
|
|
i++;
|
2020-03-02 21:22:44 +00:00
|
|
|
switch (c) {
|
|
|
|
case "%":
|
|
|
|
this.putRaw("%");
|
|
|
|
break;
|
|
|
|
case ",":
|
|
|
|
c = format[i];
|
|
|
|
i++;
|
|
|
|
this.putFormattedList(c, args[argIndex]);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
this.putFormattedValue(c, args[argIndex]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-02-02 18:27:25 +00:00
|
|
|
argIndex++;
|
|
|
|
break;
|
2020-03-02 21:08:06 +00:00
|
|
|
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;
|
2020-02-02 18:27:25 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
this.putRaw(c);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-03-02 21:08:06 +00:00
|
|
|
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);
|
2020-03-02 21:22:44 +00:00
|
|
|
this.putCollection(",&n", table.columns, col => {
|
2020-03-02 21:08:06 +00:00
|
|
|
this.put("%i", col.columnName);
|
|
|
|
this.columnDefinition(col);
|
|
|
|
});
|
2020-03-02 21:22:44 +00:00
|
|
|
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)
|
|
|
|
);
|
|
|
|
}
|
2020-03-03 06:14:12 +00:00
|
|
|
table.foreignKeys.forEach(fk => {
|
|
|
|
this.put(",&n");
|
|
|
|
this.createForeignKeyFore(fk);
|
|
|
|
});
|
2020-03-02 21:08:06 +00:00
|
|
|
// foreach (var cnt in table.Uniques)
|
|
|
|
// {
|
2020-03-03 06:14:12 +00:00
|
|
|
// if (!first) this.put(", &n");
|
2020-03-02 21:08:06 +00:00
|
|
|
// first = false;
|
|
|
|
// CreateUniqueCore(cnt);
|
|
|
|
// }
|
|
|
|
// foreach (var cnt in table.Checks)
|
|
|
|
// {
|
2020-03-03 06:14:12 +00:00
|
|
|
// if (!first) this.put(", &n");
|
2020-03-02 21:08:06 +00:00
|
|
|
// first = false;
|
|
|
|
// CreateCheckCore(cnt);
|
|
|
|
// }
|
|
|
|
this.put("&<&n)");
|
|
|
|
this.endCommand();
|
|
|
|
// foreach (var ix in table.Indexes)
|
|
|
|
// {
|
|
|
|
// CreateIndex(ix);
|
|
|
|
// }
|
|
|
|
}
|
2020-03-03 06:14:12 +00:00
|
|
|
|
|
|
|
/** @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);
|
|
|
|
}
|
2020-02-02 18:27:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = SqlDumper;
|