diff --git a/packages/datalib/src/ChangeSet.ts b/packages/datalib/src/ChangeSet.ts index f983349f8..974bcae8c 100644 --- a/packages/datalib/src/ChangeSet.ts +++ b/packages/datalib/src/ChangeSet.ts @@ -1,6 +1,6 @@ import _ from 'lodash'; -import { Command, Insert, Update, Delete, UpdateField, Condition } from '@dbgate/sqltree'; -import { NamedObjectInfo } from '@dbgate/types'; +import { Command, Insert, Update, Delete, UpdateField, Condition, AllowIdentityInsert } from '@dbgate/sqltree'; +import { NamedObjectInfo, DatabaseInfo } from '@dbgate/types'; export interface ChangeSetItem { pureName: string; @@ -175,17 +175,48 @@ function extractFields(item: ChangeSetItem, allowNulls = true): UpdateField[] { })); } -function insertToSql(item: ChangeSetItem): Insert { +function insertToSql( + item: ChangeSetItem, + dbinfo: DatabaseInfo = null +): [AllowIdentityInsert, Insert, AllowIdentityInsert] { const fields = extractFields(item, false); if (fields.length == 0) return null; - return { - targetTable: { - pureName: item.pureName, - schemaName: item.schemaName, - }, - commandType: 'insert', - fields, + let autoInc = false; + if (dbinfo) { + const table = dbinfo.tables.find((x) => x.schemaName == item.schemaName && x.pureName == item.pureName); + if (table) { + const autoIncCol = table.columns.find((x) => x.autoIncrement); + console.log('autoIncCol', autoIncCol); + if (autoIncCol && fields.find((x) => x.targetColumn == autoIncCol.columnName)) { + autoInc = true; + } + } + } + const targetTable = { + pureName: item.pureName, + schemaName: item.schemaName, }; + return [ + autoInc + ? { + targetTable, + commandType: 'allowIdentityInsert', + allow: true, + } + : null, + { + targetTable, + commandType: 'insert', + fields, + }, + autoInc + ? { + targetTable, + commandType: 'allowIdentityInsert', + allow: false, + } + : null, + ]; } function extractCondition(item: ChangeSetItem): Condition { @@ -239,12 +270,14 @@ function deleteToSql(item: ChangeSetItem): Delete { }; } -export function changeSetToSql(changeSet: ChangeSet): Command[] { - return _.compact([ - ...changeSet.inserts.map(insertToSql), - ...changeSet.updates.map(updateToSql), - ...changeSet.deletes.map(deleteToSql), - ]); +export function changeSetToSql(changeSet: ChangeSet, dbinfo: DatabaseInfo): Command[] { + return _.compact( + _.flatten([ + ...changeSet.inserts.map((item) => insertToSql(item, dbinfo)), + ...changeSet.updates.map(updateToSql), + ...changeSet.deletes.map(deleteToSql), + ]) + ); } export function revertChangeSetRowChanges(changeSet: ChangeSet, definition: ChangeSetRowDefinition): ChangeSet { diff --git a/packages/datalib/src/GridDisplay.ts b/packages/datalib/src/GridDisplay.ts index 143612d12..bb8642139 100644 --- a/packages/datalib/src/GridDisplay.ts +++ b/packages/datalib/src/GridDisplay.ts @@ -1,6 +1,6 @@ import _ from 'lodash'; import { GridConfig, GridCache, GridConfigColumns, createGridCache } from './GridConfig'; -import { ForeignKeyInfo, TableInfo, ColumnInfo, DbType, EngineDriver, NamedObjectInfo } from '@dbgate/types'; +import { ForeignKeyInfo, TableInfo, ColumnInfo, DbType, EngineDriver, NamedObjectInfo, DatabaseInfo } from '@dbgate/types'; import { parseFilter, getFilterType } from '@dbgate/filterparser'; import { filterName } from './filterName'; import { ChangeSetFieldDefinition, ChangeSetRowDefinition } from './ChangeSet'; @@ -47,7 +47,8 @@ export abstract class GridDisplay { protected setConfig: ChangeConfigFunc, public cache: GridCache, protected setCache: ChangeCacheFunc, - public driver?: EngineDriver + public driver?: EngineDriver, + public dbinfo: DatabaseInfo = null ) {} columns: DisplayColumn[]; baseTable?: TableInfo; diff --git a/packages/datalib/src/TableGridDisplay.ts b/packages/datalib/src/TableGridDisplay.ts index cfa42d2c7..62ab1f158 100644 --- a/packages/datalib/src/TableGridDisplay.ts +++ b/packages/datalib/src/TableGridDisplay.ts @@ -15,9 +15,9 @@ export class TableGridDisplay extends GridDisplay { setConfig: ChangeConfigFunc, cache: GridCache, setCache: ChangeCacheFunc, - protected dbinfo: DatabaseInfo + dbinfo: DatabaseInfo ) { - super(config, setConfig, cache, setCache, driver); + super(config, setConfig, cache, setCache, driver, dbinfo); this.table = this.findTable(tableName); if (!this.table) { diff --git a/packages/engines/default/SqlDumper.js b/packages/engines/default/SqlDumper.js index 0a2cf41ed..0705ece45 100644 --- a/packages/engines/default/SqlDumper.js +++ b/packages/engines/default/SqlDumper.js @@ -198,6 +198,7 @@ class SqlDumper { lambda(item); } } + /** @param table {import('@dbgate/types').TableInfo} */ createTable(table) { this.put('^create ^table %f ( &>&n', table); @@ -253,6 +254,12 @@ class SqlDumper { if (fk.deleteAction) this.put(' ^on ^delete %k', fk.deleteAction); if (fk.updateAction) this.put(' ^on ^update %k', fk.updateAction); } + + /** + * @param table {import('@dbgate/types').NamedObjectInfo} + * @param allow {boolean} + */ + allowIdentityInsert(table, allow) {} } module.exports = SqlDumper; diff --git a/packages/engines/mssql/MsSqlDumper.js b/packages/engines/mssql/MsSqlDumper.js index a8bff0e7d..1d465b317 100644 --- a/packages/engines/mssql/MsSqlDumper.js +++ b/packages/engines/mssql/MsSqlDumper.js @@ -11,6 +11,10 @@ class MsSqlDumper extends SqlDumper { } super.putStringValue(value); } + + allowIdentityInsert(table, allow) { + this.putCmd("^set ^identity_insert %f %k;&n", table, allow ? "on" : "off"); + } } module.exports = MsSqlDumper; diff --git a/packages/sqltree/src/dumpSqlCommand.ts b/packages/sqltree/src/dumpSqlCommand.ts index 356d4acf7..d2e397880 100644 --- a/packages/sqltree/src/dumpSqlCommand.ts +++ b/packages/sqltree/src/dumpSqlCommand.ts @@ -18,7 +18,7 @@ export function dumpSqlSelect(dmp: SqlDumper, cmd: Select) { if (cmd.columns) { if (cmd.selectAll) dmp.put('&n,'); dmp.put('&>&n'); - dmp.putCollection(',&n', cmd.columns, fld => { + dmp.putCollection(',&n', cmd.columns, (fld) => { dumpSqlExpression(dmp, fld); if (fld.alias) dmp.put(' ^as %i', fld.alias); }); @@ -33,12 +33,12 @@ export function dumpSqlSelect(dmp: SqlDumper, cmd: Select) { } if (cmd.groupBy) { dmp.put('&n^group ^by '); - dmp.putCollection(', ', cmd.groupBy, expr => dumpSqlExpression(dmp, expr)); + dmp.putCollection(', ', cmd.groupBy, (expr) => dumpSqlExpression(dmp, expr)); dmp.put('&n'); } if (cmd.orderBy) { dmp.put('&n^order ^by '); - dmp.putCollection(', ', cmd.orderBy, expr => { + dmp.putCollection(', ', cmd.orderBy, (expr) => { dumpSqlExpression(dmp, expr); dmp.put(' %k', expr.direction); }); @@ -59,7 +59,7 @@ export function dumpSqlUpdate(dmp: SqlDumper, cmd: Update) { dmp.put('&n^set '); dmp.put('&>'); - dmp.putCollection(', ', cmd.fields, col => { + dmp.putCollection(', ', cmd.fields, (col) => { dmp.put('%i=', col.targetColumn); dumpSqlExpression(dmp, col); }); @@ -73,7 +73,7 @@ export function dumpSqlUpdate(dmp: SqlDumper, cmd: Update) { } export function dumpSqlDelete(dmp: SqlDumper, cmd: Delete) { - dmp.put('^delete '); + dmp.put('^delete ^from '); dumpSqlSourceRef(dmp, cmd.from); if (cmd.where) { @@ -87,9 +87,9 @@ export function dumpSqlInsert(dmp: SqlDumper, cmd: Insert) { dmp.put( '^insert ^into %f (%,i) ^values (', cmd.targetTable, - cmd.fields.map(x => x.targetColumn) + cmd.fields.map((x) => x.targetColumn) ); - dmp.putCollection(',', cmd.fields, x => dumpSqlExpression(dmp, x)); + dmp.putCollection(',', cmd.fields, (x) => dumpSqlExpression(dmp, x)); dmp.put(')'); } @@ -107,5 +107,8 @@ export function dumpSqlCommand(dmp: SqlDumper, cmd: Command) { case 'insert': dumpSqlInsert(dmp, cmd); break; + case 'allowIdentityInsert': + dmp.allowIdentityInsert(cmd.targetTable, cmd.allow); + break; } } diff --git a/packages/sqltree/src/types.ts b/packages/sqltree/src/types.ts index 8243391da..02f8d5de9 100644 --- a/packages/sqltree/src/types.ts +++ b/packages/sqltree/src/types.ts @@ -39,7 +39,13 @@ export interface Insert { targetTable: NamedObjectInfo; } -export type Command = Select | Update | Delete | Insert; +export interface AllowIdentityInsert { + commandType: 'allowIdentityInsert'; + targetTable: NamedObjectInfo; + allow: boolean; +} + +export type Command = Select | Update | Delete | Insert | AllowIdentityInsert; // export interface Condition { // conditionType: "eq" | "not" | "binary"; diff --git a/packages/types/dumper.d.ts b/packages/types/dumper.d.ts index ba3e432a4..3515b720d 100644 --- a/packages/types/dumper.d.ts +++ b/packages/types/dumper.d.ts @@ -1,5 +1,5 @@ -import { TableInfo } from "./dbinfo"; -import { SqlDialect } from "./dialect"; +import { TableInfo } from './dbinfo'; +import { SqlDialect } from './dialect'; export interface SqlDumper { s: string; @@ -9,12 +9,9 @@ export interface SqlDumper { put(format: string, ...args); putCmd(format: string, ...args); putValue(value: string | number | Date); - putCollection( - delimiter: string, - collection: T[], - lambda: (item: T) => void - ); + putCollection(delimiter: string, collection: T[], lambda: (item: T) => void); endCommand(); createTable(table: TableInfo); + allowIdentityInsert(table: NamedObjectInfo, allow: boolean); } diff --git a/packages/web/src/datagrid/DataGridCore.js b/packages/web/src/datagrid/DataGridCore.js index 8a0ac12ec..e66ae05b5 100644 --- a/packages/web/src/datagrid/DataGridCore.js +++ b/packages/web/src/datagrid/DataGridCore.js @@ -816,7 +816,7 @@ export default function DataGridCore(props) { dispatchInsplaceEditor({ type: 'shouldSave' }); return; } - const script = changeSetToSql(changeSetRef.current); + const script = changeSetToSql(changeSetRef.current, display.dbinfo); const sql = scriptToSql(display.driver, script); setConfirmSql(sql); confirmSqlModalState.open();