dbgate-tools
Version:
Auxiliary tools for other DbGate packages.
782 lines (781 loc) • 30.4 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SqlDumper = void 0;
const isString_1 = __importDefault(require("lodash/isString"));
const isNumber_1 = __importDefault(require("lodash/isNumber"));
const isDate_1 = __importDefault(require("lodash/isDate"));
const isArray_1 = __importDefault(require("lodash/isArray"));
const isPlainObject_1 = __importDefault(require("lodash/isPlainObject"));
const keys_1 = __importDefault(require("lodash/keys"));
const cloneDeep_1 = __importDefault(require("lodash/cloneDeep"));
const v1_1 = __importDefault(require("uuid/v1"));
class SqlDumper {
static convertKeywordCase(keyword) {
var _a, _b;
if (this.keywordsCase == 'lowerCase')
return (_a = keyword === null || keyword === void 0 ? void 0 : keyword.toString()) === null || _a === void 0 ? void 0 : _a.toLowerCase();
return (_b = keyword === null || keyword === void 0 ? void 0 : keyword.toString()) === null || _b === void 0 ? void 0 : _b.toUpperCase();
}
constructor(driver) {
this.s = '';
this.indentLevel = 0;
this.driver = driver;
this.dialect = driver.dialect;
}
endCommand() {
this.putRaw(';\n');
}
putRaw(text) {
this.s += text;
}
escapeString(value) {
const esc = this.dialect.stringEscapeChar;
let res = '';
for (let i = 0; i < value.length; i++) {
const c = value[i];
if (c == esc || c == "'") {
res += esc;
}
res += c;
}
return res;
}
putStringValue(value) {
this.putRaw("'");
this.putRaw(this.escapeString(value));
this.putRaw("'");
}
putByteArrayValue(value) {
this.put('^null');
}
putValue(value, dataType = null) {
var _a;
if (value === null)
this.put('^null');
else if (value === true)
this.putRaw('1');
else if (value === false)
this.putRaw('0');
else if ((0, isString_1.default)(value))
this.putStringValue(value);
else if ((0, isNumber_1.default)(value))
this.putRaw(value.toString());
else if ((0, isDate_1.default)(value))
this.putStringValue(new Date(value).toISOString());
else if ((value === null || value === void 0 ? void 0 : value.type) == 'Buffer' && (0, isArray_1.default)(value === null || value === void 0 ? void 0 : value.data))
this.putByteArrayValue(value === null || value === void 0 ? void 0 : value.data);
else if ((_a = value === null || value === void 0 ? void 0 : value.$binary) === null || _a === void 0 ? void 0 : _a.base64) {
const binary = atob(value.$binary.base64);
const bytes = new Array(binary.length);
for (let i = 0; i < binary.length; i++) {
bytes[i] = binary.charCodeAt(i);
}
this.putByteArrayValue(bytes);
}
else if (value === null || value === void 0 ? void 0 : value.$bigint)
this.putRaw(value === null || value === void 0 ? void 0 : value.$bigint);
else if (value === null || value === void 0 ? void 0 : value.$decimal)
this.putRaw(value === null || value === void 0 ? void 0 : value.$decimal);
else if ((0, isPlainObject_1.default)(value) || (0, isArray_1.default)(value))
this.putStringValue(JSON.stringify(value));
else
this.put('^null');
}
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(SqlDumper.convertKeywordCase(value));
}
}
break;
case 'f':
{
const { schemaName, pureName } = value;
if (schemaName) {
this.putRaw(this.dialect.quoteIdentifier(schemaName));
this.putRaw('.');
}
this.putRaw(this.dialect.quoteIdentifier(pureName));
}
break;
case 'v':
this.putValue(value);
break;
case 'V':
this.putValue(value.value, value.dataType);
break;
case 'c':
value(this);
break;
}
}
putFormattedList(c, collection) {
if (!collection)
return;
this.putCollection(', ', collection, item => this.putFormattedValue(c, item));
}
put(format, ...args) {
let i = 0;
let argIndex = 0;
const length = format.length;
while (i < length) {
let c = format[i];
i++;
switch (c) {
case '^':
if (format[i] == '^') {
this.putRaw('^');
i++;
break;
}
while (i < length && format[i].match(/[a-z0-9_]/i)) {
this.putRaw(SqlDumper.convertKeywordCase(format[i]));
i++;
}
break;
case '~':
if (format[i] == '~') {
this.putRaw('~');
i++;
break;
}
let ident = '';
while (i < length && format[i].match(/[a-z0-9_]/i)) {
ident += format[i];
i++;
}
this.putRaw(this.dialect.quoteIdentifier(ident));
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');
}
createDatabase(name) {
this.putCmd('^create ^database %i', name);
}
dropDatabase(name) {
this.putCmd('^drop ^database %i', name);
}
createSchema(name) {
this.putCmd('^create ^schema %i', name);
}
dropSchema(name) {
this.putCmd('^drop ^schema %i', name);
}
specialColumnOptions(column) { }
selectScopeIdentity(table) { }
columnType(dataType) {
const type = dataType || this.dialect.fallbackDataType;
const typeWithValues = type.match(/([^(]+)(\(.+[^)]\))/);
if (typeWithValues === null || typeWithValues === void 0 ? void 0 : typeWithValues.length) {
typeWithValues.shift();
this.putRaw(SqlDumper.convertKeywordCase(typeWithValues.shift()));
this.putRaw(typeWithValues);
}
else {
this.putRaw(SqlDumper.convertKeywordCase(type));
}
}
columnDefinition(column, { includeDefault = true, includeNullable = true, includeCollate = true } = {}) {
var _a, _b, _c, _d, _e, _f, _g, _h;
if (column.computedExpression) {
this.put('^as %s', column.computedExpression);
if (column.isPersisted)
this.put(' ^persisted');
return;
}
this.columnType(column.dataType);
if (column.autoIncrement && !((_a = this.dialect) === null || _a === void 0 ? void 0 : _a.disableAutoIncrement)) {
this.autoIncrement();
}
this.putRaw(' ');
this.specialColumnOptions(column);
if ((_b = this.dialect) === null || _b === void 0 ? void 0 : _b.defaultValueBeforeNullability) {
if (includeDefault && ((_d = (_c = column.defaultValue) === null || _c === void 0 ? void 0 : _c.toString()) === null || _d === void 0 ? void 0 : _d.trim())) {
this.columnDefault(column);
}
if (includeNullable && !((_e = this.dialect) === null || _e === void 0 ? void 0 : _e.specificNullabilityImplementation)) {
this.put(column.notNull ? '^not ^null' : this.dialect.implicitNullDeclaration ? '' : '^null');
}
}
else {
if (includeNullable && !((_f = this.dialect) === null || _f === void 0 ? void 0 : _f.specificNullabilityImplementation)) {
this.put(column.notNull ? '^not ^null' : this.dialect.implicitNullDeclaration ? '' : '^null');
}
if (includeDefault && ((_h = (_g = column.defaultValue) === null || _g === void 0 ? void 0 : _g.toString()) === null || _h === void 0 ? void 0 : _h.trim())) {
this.columnDefault(column);
}
}
}
columnDefault(column) {
var _a;
if (column.defaultConstraint != null && ((_a = this.dialect) === null || _a === void 0 ? void 0 : _a.namedDefaultConstraint)) {
this.put(' ^constraint %i ^default %s ', column.defaultConstraint, column.defaultValue);
}
else {
this.put(' ^default %s ', column.defaultValue);
}
}
putCollection(delimiter, collection, lambda) {
if (!collection)
return;
let first = true;
for (const item of collection) {
if (!first)
this.put(delimiter);
first = false;
lambda(item);
}
}
createTable(table) {
this.put('^create ^table %f ( &>&n', table);
this.putCollection(',&n', table.columns, col => {
this.put('%i ', col.columnName);
this.columnDefinition(col);
});
this.createTablePrimaryKeyCore(table);
(table.foreignKeys || []).forEach(fk => {
this.put(',&n');
this.createForeignKeyFore(fk);
});
(table.uniques || []).forEach(uq => {
this.put(',&n');
this.createUniqueCore(uq);
});
(table.checks || []).forEach(chk => {
this.put(',&n');
this.createCheckCore(chk);
});
this.put('&<&n)');
this.tableOptions(table);
this.endCommand();
(table.indexes || []).forEach(ix => {
this.createIndex(ix);
});
}
tableOptions(table) {
var _a, _b, _c;
const options = ((_c = (_b = (_a = this.driver) === null || _a === void 0 ? void 0 : _a.dialect) === null || _b === void 0 ? void 0 : _b.getTableFormOptions) === null || _c === void 0 ? void 0 : _c.call(_b, 'sqlCreateTable')) || [];
for (const option of options) {
if (table[option.name]) {
this.put('&n');
this.put(option.sqlFormatString, table[option.name]);
}
}
}
createTablePrimaryKeyCore(table) {
if (table.primaryKey) {
this.put(',&n');
if (table.primaryKey.constraintName && !this.dialect.anonymousPrimaryKey) {
this.put('^constraint %i', table.primaryKey.constraintName);
}
this.put(' ^primary ^key (%,i)', table.primaryKey.columns.map(x => x.columnName));
}
}
createForeignKeyFore(fk) {
if (fk.constraintName != null && !this.dialect.anonymousForeignKey) {
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);
}
transform(type, dumpExpr) {
dumpExpr();
}
allowIdentityInsert(table, allow) { }
enableConstraints(table, enabled) { }
enableAllForeignKeys(enabled) { }
comment(value) {
if (!value)
return;
for (const line of value.split('\n')) {
this.put(' -- %s', line.trimRight());
}
}
createView(obj) {
this.putRaw(obj.createSql);
this.endCommand();
}
dropView(obj, { testIfExists = false }) {
this.putCmd('^drop ^view %f', obj);
}
alterView(obj) {
this.putRaw(obj.createSql.replace(/create\s+view/i, 'ALTER VIEW'));
this.endCommand();
}
changeViewSchema(obj, newSchema) { }
renameView(obj, newSchema) { }
createMatview(obj) {
this.putRaw(obj.createSql);
this.endCommand();
}
dropMatview(obj, { testIfExists = false }) {
this.putCmd('^drop ^materialized ^view %f', obj);
}
alterMatview(obj) {
this.putRaw(obj.createSql.replace(/create\s+view/i, 'ALTER VIEW'));
this.endCommand();
}
changeMatviewSchema(obj, newSchema) { }
renameMatview(obj, newSchema) { }
createProcedure(obj) {
this.putRaw(obj.createSql);
this.endCommand();
}
dropProcedure(obj, { testIfExists = false }) {
this.putCmd('^drop ^procedure %f', obj);
}
alterProcedure(obj) {
this.putRaw(obj.createSql.replace(/create\s+procedure/i, 'ALTER PROCEDURE'));
this.endCommand();
}
changeProcedureSchema(obj, newSchema) { }
renameProcedure(obj, newSchema) { }
createFunction(obj) {
this.putRaw(obj.createSql);
this.endCommand();
}
dropFunction(obj, { testIfExists = false }) {
this.putCmd('^drop ^function %f', obj);
}
alterFunction(obj) {
this.putRaw(obj.createSql.replace(/create\s+function/i, 'ALTER FUNCTION'));
this.endCommand();
}
changeFunctionSchema(obj, newSchema) { }
renameFunction(obj, newSchema) { }
createTrigger(obj) {
this.putRaw(obj.createSql);
this.endCommand();
}
dropTrigger(obj, { testIfExists = false }) {
this.putCmd('^drop ^trigger %f', obj);
}
alterTrigger(obj) {
this.putRaw(obj.createSql.replace(/create\s+trigger/i, 'ALTER TRIGGER'));
this.endCommand();
}
changeTriggerSchema(obj, newSchema) { }
renameTrigger(obj, newSchema) { }
createSchedulerEvent(obj) {
this.putRaw(obj.createSql);
this.endCommand();
}
dropSchedulerEvent(obj, { testIfExists = false }) {
this.putCmd('^drop ^event %f', obj);
}
dropConstraintCore(cnt) {
this.putCmd('^alter ^table %f ^drop ^constraint %i', cnt, cnt.constraintName);
}
dropConstraint(cnt) {
switch (cnt.constraintType) {
case 'primaryKey':
this.dropPrimaryKey(cnt);
break;
case 'foreignKey':
this.dropForeignKey(cnt);
break;
case 'unique':
this.dropUnique(cnt);
break;
case 'check':
this.dropCheck(cnt);
break;
case 'index':
this.dropIndex(cnt);
break;
}
}
createConstraint(cnt) {
switch (cnt.constraintType) {
case 'primaryKey':
this.createPrimaryKey(cnt);
break;
case 'foreignKey':
this.createForeignKey(cnt);
break;
case 'unique':
this.createUnique(cnt);
break;
case 'check':
this.createCheck(cnt);
break;
case 'index':
this.createIndex(cnt);
break;
}
}
changeConstraint(oldConstraint, newConstraint) { }
dropForeignKey(fk) {
if (this.dialect.explicitDropConstraint) {
this.putCmd('^alter ^table %f ^drop ^foreign ^key %i', fk, fk.constraintName);
}
else {
this.dropConstraintCore(fk);
}
}
createForeignKey(fk) {
this.put('^alter ^table %f ^add ', fk);
this.createForeignKeyFore(fk);
this.endCommand();
}
dropPrimaryKey(pk) {
if (this.dialect.explicitDropConstraint) {
this.putCmd('^alter ^table %f ^drop ^primary ^key', pk);
}
else {
this.dropConstraintCore(pk);
}
}
createPrimaryKey(pk) {
this.putCmd('^alter ^table %f ^add ^constraint %i ^primary ^key (%,i)', pk, pk.constraintName, pk.columns.map(x => x.columnName));
}
dropIndex(ix) {
this.put('^drop ^index %i', ix.constraintName);
if (this.dialect.dropIndexContainsTableSpec) {
this.put(' ^on %f', ix);
}
this.endCommand();
}
createIndex(ix) {
this.put('^create');
if (ix.isUnique)
this.put(' ^unique');
this.put(' ^index %i &n^on %f (&>&n', ix.constraintName, ix);
this.putCollection(',&n', ix.columns, col => {
this.put('%i %k', col.columnName, col.isDescending == true ? 'DESC' : 'ASC');
});
this.put('&<&n)');
if (ix.filterDefinition && this.dialect.filteredIndexes) {
this.put('&n^where %s', ix.filterDefinition);
}
this.endCommand();
}
dropUnique(uq) {
this.dropConstraintCore(uq);
}
createUniqueCore(uq) {
this.put('^constraint %i ^unique (%,i)', uq.constraintName, uq.columns.map(x => x.columnName));
}
createUnique(uq) {
this.put('^alter ^table %f ^add ', uq);
this.createUniqueCore(uq);
this.endCommand();
}
dropCheck(ch) {
this.dropConstraintCore(ch);
}
createCheckCore(ch) {
this.put('^constraint %i ^check (%s)', ch.constraintName, ch.definition);
}
createCheck(ch) {
this.put('^alter ^table %f ^add ', ch);
this.createCheckCore(ch);
this.endCommand();
}
renameConstraint(constraint, newName) { }
createColumn(column, constraints) {
this.put('^alter ^table %f ^add ', column);
if (this.dialect.createColumnWithColumnKeyword)
this.put('^column ');
this.put(' %i ', column.columnName);
this.columnDefinition(column);
this.inlineConstraints(constraints);
this.endCommand();
}
inlineConstraints(constrains) {
if (constrains == null)
return;
for (const cnt of constrains) {
if (cnt.constraintType == 'primaryKey') {
if (cnt.constraintName != null && !this.dialect.anonymousPrimaryKey) {
this.put(' ^constraint %i', cnt.constraintName);
}
this.put(' ^primary ^key ');
}
}
}
dropColumn(column) {
this.putCmd('^alter ^table %f ^drop ^column %i', column, column.columnName);
}
renameColumn(column, newName) { }
changeColumn(oldcol, newcol, constraints) { }
dropTable(obj, { testIfExists = false } = {}) {
this.putCmd('^drop ^table %f', obj);
}
changeTableSchema(obj, schema) { }
renameTable(obj, newname) { }
renameSqlObject(obj, newname) { }
beginTransaction() {
this.putCmd('^begin ^transaction');
}
commitTransaction() {
this.putCmd('^commit');
}
rollbackTransaction() {
this.putCmd('^rollback');
}
alterProlog() { }
alterEpilog() { }
selectTableIntoNewTable(sourceName, targetName) {
this.putCmd('^select * ^into %f ^from %f', targetName, sourceName);
}
truncateTable(name) {
this.putCmd('^truncate ^table %f', name);
}
dropConstraints(table, dropReferences = false) {
if (dropReferences && this.dialect.dropForeignKey) {
table.dependencies.forEach(cnt => this.dropConstraint(cnt));
}
if (this.dialect.dropIndex) {
table.indexes.forEach(cnt => this.dropIndex(cnt));
}
if (this.dialect.dropForeignKey) {
table.foreignKeys.forEach(cnt => this.dropForeignKey(cnt));
}
if (this.dialect.dropPrimaryKey && table.primaryKey) {
this.dropPrimaryKey(table.primaryKey);
}
}
sanitizeTableConstraints(table) {
// Create a deep copy of the table
const sanitized = (0, cloneDeep_1.default)(table);
// Get the set of existing column names
const existingColumns = new Set(sanitized.columns.map(col => col.columnName));
// Filter primary key columns to only include existing columns
if (sanitized.primaryKey) {
const validPkColumns = sanitized.primaryKey.columns.filter(col => existingColumns.has(col.columnName));
if (validPkColumns.length === 0) {
// If no valid columns remain, remove the primary key entirely
sanitized.primaryKey = null;
}
else if (validPkColumns.length < sanitized.primaryKey.columns.length) {
// Update primary key with only valid columns
sanitized.primaryKey = {
...sanitized.primaryKey,
columns: validPkColumns
};
}
}
// Filter sorting key columns to only include existing columns
if (sanitized.sortingKey) {
const validSkColumns = sanitized.sortingKey.columns.filter(col => existingColumns.has(col.columnName));
if (validSkColumns.length === 0) {
sanitized.sortingKey = null;
}
else if (validSkColumns.length < sanitized.sortingKey.columns.length) {
sanitized.sortingKey = {
...sanitized.sortingKey,
columns: validSkColumns
};
}
}
// Filter foreign keys to only include those with all columns present
if (sanitized.foreignKeys) {
sanitized.foreignKeys = sanitized.foreignKeys.filter(fk => fk.columns.every(col => existingColumns.has(col.columnName)));
}
// Filter indexes to only include those with all columns present
if (sanitized.indexes) {
sanitized.indexes = sanitized.indexes.filter(idx => idx.columns.every(col => existingColumns.has(col.columnName)));
}
// Filter unique constraints to only include those with all columns present
if (sanitized.uniques) {
sanitized.uniques = sanitized.uniques.filter(uq => uq.columns.every(col => existingColumns.has(col.columnName)));
}
// Filter dependencies (references from other tables) - these should remain as-is
// since they don't affect the CREATE TABLE statement for this table
return sanitized;
}
recreateTable(oldTable, newTable) {
if (!oldTable.pairingId || !newTable.pairingId || oldTable.pairingId != newTable.pairingId) {
throw new Error('Recreate is not possible: oldTable.paringId != newTable.paringId');
}
const tmpTable = `temp_${(0, v1_1.default)()}`;
const columnPairs = oldTable.columns
.map(oldcol => ({
oldcol,
newcol: newTable.columns.find(x => x.pairingId == oldcol.pairingId),
}))
.filter(x => x.newcol);
// Create a sanitized version of newTable with constraints that only reference existing columns
const sanitizedNewTable = this.sanitizeTableConstraints(newTable);
if (this.driver.supportsTransactions) {
this.dropConstraints(oldTable, true);
this.renameTable(oldTable, tmpTable);
this.createTable(sanitizedNewTable);
const autoinc = sanitizedNewTable.columns.find(x => x.autoIncrement);
if (autoinc) {
this.allowIdentityInsert(sanitizedNewTable, true);
}
this.putCmd('^insert ^into %f (%,i) select %,i ^from %f', sanitizedNewTable, columnPairs.map(x => x.newcol.columnName), columnPairs.map(x => x.oldcol.columnName), { ...oldTable, pureName: tmpTable });
if (autoinc) {
this.allowIdentityInsert(sanitizedNewTable, false);
}
if (this.dialect.dropForeignKey) {
sanitizedNewTable.dependencies.forEach(cnt => this.createConstraint(cnt));
}
this.dropTable({ ...oldTable, pureName: tmpTable });
}
else {
// we have to preserve old table as long as possible
this.createTable({ ...sanitizedNewTable, pureName: tmpTable });
this.putCmd('^insert ^into %f (%,i) select %,s ^from %f', { ...sanitizedNewTable, pureName: tmpTable }, columnPairs.map(x => x.newcol.columnName), columnPairs.map(x => x.oldcol.columnName), oldTable);
this.dropTable(oldTable);
this.renameTable({ ...sanitizedNewTable, pureName: tmpTable }, newTable.pureName);
}
}
createSqlObject(obj) {
this.putRaw(obj.createSql);
this.endCommand();
}
getSqlObjectSqlName(ojectTypeField) {
switch (ojectTypeField) {
case 'procedures':
return 'PROCEDURE';
case 'views':
return 'VIEW';
case 'functions':
return 'FUNCTION';
case 'triggers':
return 'TRIGGER';
case 'matviews':
return 'MATERIALIZED VIEW';
case 'schedulerEvents':
return 'EVENT';
}
}
dropSqlObject(obj) {
this.putCmd('^drop %s %f', this.getSqlObjectSqlName(obj.objectTypeField), obj);
}
setTableOption(table, optionName, optionValue) {
var _a, _b;
const options = (_b = (_a = this === null || this === void 0 ? void 0 : this.dialect) === null || _a === void 0 ? void 0 : _a.getTableFormOptions) === null || _b === void 0 ? void 0 : _b.call(_a, 'sqlAlterTable');
const option = options === null || options === void 0 ? void 0 : options.find(x => x.name == optionName && !x.disabled);
if (!option) {
return;
}
this.setTableOptionCore(table, optionName, optionValue, option.sqlFormatString);
this.endCommand();
}
setTableOptionCore(table, optionName, optionValue, formatString) {
this.put('^alter ^table %f ', table);
this.put(formatString, optionValue);
}
fillNewNotNullDefaults(col) {
if (col.notNull && col.defaultValue != null) {
this.putCmd('^update %f ^set %i = %s ^where %i ^is ^null', col, col.columnName, col.defaultValue, col.columnName);
}
}
fillPreloadedRows(table, oldRows, newRows, key, insertOnly, autoIncrementColumn) {
let was = false;
for (const row of newRows) {
const old = oldRows === null || oldRows === void 0 ? void 0 : oldRows.find(r => key.every(col => r[col] == row[col]));
const rowKeys = (0, keys_1.default)(row);
if (old) {
const updated = [];
for (const col of rowKeys) {
if (row[col] != old[col] && !(insertOnly === null || insertOnly === void 0 ? void 0 : insertOnly.includes(col))) {
updated.push(col);
}
}
if (updated.length > 0) {
if (was)
this.put(';\n');
was = true;
this.put('^update %f ^set ', table);
this.putCollection(', ', updated, col => this.put('%i=%v', col, row[col]));
this.put(' ^where ');
this.putCollection(' ^and ', key, col => this.put('%i=%v', col, row[col]));
}
}
else {
if (was)
this.put(';\n');
was = true;
const autoinc = rowKeys.includes(autoIncrementColumn);
if (autoinc)
this.allowIdentityInsert(table, true);
this.put('^insert ^into %f (%,i) ^values (%,v)', table, rowKeys, rowKeys.map(x => row[x]));
if (autoinc)
this.allowIdentityInsert(table, false);
}
}
if (was) {
this.endCommand();
}
}
callableTemplate(func) {
this.put('^call %f(&>&n', func);
this.putCollection(',&n', func.parameters || [], param => {
this.putRaw(param.parameterMode == 'IN' ? ':' + param.parameterName : param.parameterName);
});
this.put('&<&n)');
this.endCommand();
}
}
exports.SqlDumper = SqlDumper;
SqlDumper.keywordsCase = 'upperCase';