diff --git a/integration-tests/__tests__/db-import-export.spec.js b/integration-tests/__tests__/db-import-export.spec.js index 2a0d6b449..37a4134ca 100644 --- a/integration-tests/__tests__/db-import-export.spec.js +++ b/integration-tests/__tests__/db-import-export.spec.js @@ -182,7 +182,7 @@ describe('DB Import/export', () => { }) ); - test.each(engines.map(engine => [engine.label, engine]))( + test.each(engines.filter(engine => !engine.skipImportModel).map(engine => [engine.label, engine]))( 'Import guitar shop - schema + data - %s', testWrapper(async (conn, driver, engine) => { await importDbFromFolder({ diff --git a/integration-tests/engines.js b/integration-tests/engines.js index 4ac2003c7..603788d35 100644 --- a/integration-tests/engines.js +++ b/integration-tests/engines.js @@ -539,6 +539,7 @@ const clickhouseEngine = { alterTableAddColumnSyntax: true, dbSnapshotBySeconds: true, skipChangeColumn: true, + skipImportModel: true, }; /** @type {import('dbgate-types').TestEngineInfo} */ @@ -627,6 +628,7 @@ const cassandraEngine = { skipDataModifications: true, skipDataDuplicator: true, skipDeploy: true, + skipImportModel: true, forceSortResults: true, forceSortStructureColumns: true, @@ -657,8 +659,8 @@ const enginesOnLocal = [ // sqlServerEngine, // sqliteEngine, // cockroachDbEngine, - // clickhouseEngine, - oracleEngine, + clickhouseEngine, + // oracleEngine, ]; /** @type {import('dbgate-types').TestEngineInfo[] & Record} */ diff --git a/packages/api/src/shell/importDbFromFolder.js b/packages/api/src/shell/importDbFromFolder.js index 25053db27..caffb2996 100644 --- a/packages/api/src/shell/importDbFromFolder.js +++ b/packages/api/src/shell/importDbFromFolder.js @@ -3,7 +3,7 @@ const fs = require('fs-extra'); const executeQuery = require('./executeQuery'); const { connectUtility } = require('../utility/connectUtility'); const requireEngineDriver = require('../utility/requireEngineDriver'); -const { getAlterDatabaseScript, DatabaseAnalyser } = require('dbgate-tools'); +const { getAlterDatabaseScript, DatabaseAnalyser, runCommandOnDriver } = require('dbgate-tools'); const importDbModel = require('../utility/importDbModel'); const jsonLinesReader = require('./jsonLinesReader'); const tableWriter = require('./tableWriter'); @@ -41,17 +41,38 @@ async function importDbFromFolder({ connection, systemConnection, driver, folder })), }; + // const plan = createAlterDatabasePlan( + // DatabaseAnalyser.createEmptyStructure(), + // driver.dialect.enableAllForeignKeys ? modelAdapted : modelNoFk, + // {}, + // DatabaseAnalyser.createEmptyStructure(), + // driver.dialect.enableAllForeignKeys ? modelAdapted : modelNoFk, + // driver + // ); + // const dmp1 = driver.createDumper({ useHardSeparator: true }); + // if (driver.dialect.enableAllForeignKeys) { + // dmp1.enableAllForeignKeys(false); + // } + // plan.run(dmp1); + // if (driver.dialect.enableAllForeignKeys) { + // dmp1.enableAllForeignKeys(true); + // } + const { sql } = getAlterDatabaseScript( DatabaseAnalyser.createEmptyStructure(), - modelNoFk, + driver.dialect.enableAllForeignKeys ? modelAdapted : modelNoFk, {}, DatabaseAnalyser.createEmptyStructure(), - modelNoFk, + driver.dialect.enableAllForeignKeys ? modelAdapted : modelNoFk, driver ); // console.log('CREATING STRUCTURE:', sql); await executeQuery({ connection, systemConnection: dbhan, driver, sql, logScriptItems: true }); + if (driver.dialect.enableAllForeignKeys) { + await runCommandOnDriver(dbhan, driver, dmp => dmp.enableAllForeignKeys(false)); + } + for (const table of modelAdapted.tables) { const fileName = path.join(folder, `${table.pureName}.jsonl`); if (await fs.exists(fileName)) { @@ -66,14 +87,19 @@ async function importDbFromFolder({ connection, systemConnection, driver, folder } } - const dmp = driver.createDumper(); - for (const table of modelAdapted.tables) { - for (const fk of table.foreignKeys) { - dmp.createForeignKey(fk); + if (driver.dialect.enableAllForeignKeys) { + await runCommandOnDriver(dbhan, driver, dmp => dmp.enableAllForeignKeys(true)); + } else if (driver.dialect.createForeignKey) { + const dmp = driver.createDumper(); + for (const table of modelAdapted.tables) { + for (const fk of table.foreignKeys) { + dmp.createForeignKey(fk); + } } + + // create foreign keys + await executeQuery({ connection, systemConnection: dbhan, driver, sql: dmp.s, logScriptItems: true }); } - // create foreign keys - await executeQuery({ connection, systemConnection: dbhan, driver, sql: dmp.s, logScriptItems: true }); } finally { if (!systemConnection) { await driver.close(dbhan); diff --git a/packages/tools/src/SqlDumper.ts b/packages/tools/src/SqlDumper.ts index 031d3a091..371fb75fe 100644 --- a/packages/tools/src/SqlDumper.ts +++ b/packages/tools/src/SqlDumper.ts @@ -350,7 +350,9 @@ export class SqlDumper implements AlterProcessor { } createForeignKeyFore(fk: ForeignKeyInfo) { - if (fk.constraintName != null) this.put('^constraint %i ', fk.constraintName); + 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), @@ -367,6 +369,7 @@ export class SqlDumper implements AlterProcessor { allowIdentityInsert(table: NamedObjectInfo, allow: boolean) {} enableConstraints(table: NamedObjectInfo, enabled: boolean) {} + enableAllForeignKeys(enabled: boolean) {} comment(value: string) { if (!value) return; diff --git a/packages/types/dialect.d.ts b/packages/types/dialect.d.ts index 02dbe595c..1f31eb123 100644 --- a/packages/types/dialect.d.ts +++ b/packages/types/dialect.d.ts @@ -13,8 +13,10 @@ export interface SqlDialect { fallbackDataType?: string; explicitDropConstraint?: boolean; anonymousPrimaryKey?: boolean; + anonymousForeignKey?: boolean; defaultSchemaName?: string; enableConstraintsPerTable?: boolean; + enableAllForeignKeys?: boolean; requireStandaloneSelectForScopeIdentity?: boolean; allowMultipleValuesInsert?: boolean; diff --git a/packages/types/test-engines.d.ts b/packages/types/test-engines.d.ts index 10642118e..c08e07f56 100644 --- a/packages/types/test-engines.d.ts +++ b/packages/types/test-engines.d.ts @@ -39,6 +39,7 @@ export type TestEngineInfo = { skipNonPkRename?: boolean; skipPkDrop?: boolean; skipOrderBy?: boolean; + skipImportModel?: boolean; forceSortResults?: boolean; forceSortStructureColumns?: boolean; diff --git a/plugins/dbgate-plugin-cassandra/src/frontend/Dumper.js b/plugins/dbgate-plugin-cassandra/src/frontend/Dumper.js index 703b71944..d7be5d2b6 100644 --- a/plugins/dbgate-plugin-cassandra/src/frontend/Dumper.js +++ b/plugins/dbgate-plugin-cassandra/src/frontend/Dumper.js @@ -4,6 +4,7 @@ const { SqlDumper } = global.DBGATE_PACKAGES['dbgate-tools']; const numericDataTypes = ['tinyint', 'smallint', 'int', 'bigint', 'varint', 'float', 'double', 'decimal']; +const stringDataTypes = ['text', 'varchar']; class Dumper extends SqlDumper { /** @@ -64,7 +65,12 @@ class Dumper extends SqlDumper { } if (numericDataTypes.includes(dataType?.toLowerCase()) && !Number.isNaN(parseFloat(value))) { - this.putRaw(value); + this.putRaw(parseFloat(value)); + return; + } + + if (stringDataTypes.includes(dataType?.toLowerCase())) { + super.putValue(value?.toString()); return; } diff --git a/plugins/dbgate-plugin-sqlite/src/frontend/Dumper.js b/plugins/dbgate-plugin-sqlite/src/frontend/Dumper.js index 299e96ca5..c11fe4c97 100644 --- a/plugins/dbgate-plugin-sqlite/src/frontend/Dumper.js +++ b/plugins/dbgate-plugin-sqlite/src/frontend/Dumper.js @@ -36,6 +36,10 @@ class Dumper extends SqlDumper { } super.createTablePrimaryKeyCore(table); } + + enableAllForeignKeys(enabled) { + this.putCmd('^pragma ^foreign_keys = %s', enabled ? 'on' : 'off'); + } } module.exports = Dumper; diff --git a/plugins/dbgate-plugin-sqlite/src/frontend/driver.js b/plugins/dbgate-plugin-sqlite/src/frontend/driver.js index af82e3ba6..08fa19f48 100644 --- a/plugins/dbgate-plugin-sqlite/src/frontend/driver.js +++ b/plugins/dbgate-plugin-sqlite/src/frontend/driver.js @@ -30,11 +30,13 @@ const dialect = { createIndex: true, dropIndex: true, createForeignKey: false, + enableForeignKeyChecks: false, dropForeignKey: false, createPrimaryKey: false, dropPrimaryKey: false, dropReferencesWhenDropTable: false, filteredIndexes: true, + anonymousForeignKey: true, }; /** @type {import('dbgate-types').EngineDriver} */