diff --git a/src/dialogs/common/import-database/import-database.tsx b/src/dialogs/common/import-database/import-database.tsx index e1747aa6..86bd67dd 100644 --- a/src/dialogs/common/import-database/import-database.tsx +++ b/src/dialogs/common/import-database/import-database.tsx @@ -88,16 +88,16 @@ export const ImportDatabase: React.FC = ({ if (!scriptResult.trim()) return; - const result = parseSQLError({ + parseSQLError({ sqlContent: scriptResult, sourceDatabaseType: databaseType, + }).then((result) => { + if (result.success) { + setErrorMessage(''); + } else if (!result.success && result.error) { + setErrorMessage(result.error); + } }); - - if (result.success) { - setErrorMessage(''); - } else if (!result.success && result.error) { - setErrorMessage(result.error); - } }, [importMethod, scriptResult, databaseType]); // Check if the script result is a valid JSON diff --git a/src/dialogs/create-diagram-dialog/create-diagram-dialog.tsx b/src/dialogs/create-diagram-dialog/create-diagram-dialog.tsx index 7d11fd7e..c9ef1424 100644 --- a/src/dialogs/create-diagram-dialog/create-diagram-dialog.tsx +++ b/src/dialogs/create-diagram-dialog/create-diagram-dialog.tsx @@ -70,7 +70,7 @@ export const CreateDiagramDialog: React.FC = ({ let diagram: Diagram | undefined; if (importMethod === 'ddl') { - diagram = sqlImportToDiagram({ + diagram = await sqlImportToDiagram({ sqlContent: scriptResult, sourceDatabaseType: databaseType, targetDatabaseType: databaseType, diff --git a/src/dialogs/import-database-dialog/import-database-dialog.tsx b/src/dialogs/import-database-dialog/import-database-dialog.tsx index 606d14ef..ce29e75b 100644 --- a/src/dialogs/import-database-dialog/import-database-dialog.tsx +++ b/src/dialogs/import-database-dialog/import-database-dialog.tsx @@ -60,7 +60,7 @@ export const ImportDatabaseDialog: React.FC = ({ let diagram: Diagram | undefined; if (importMethod === 'ddl') { - diagram = sqlImportToDiagram({ + diagram = await sqlImportToDiagram({ sqlContent: scriptResult, sourceDatabaseType: databaseType, targetDatabaseType: databaseType, diff --git a/src/lib/data/sql-import/dialect-importers/mysql/mysql-common.ts b/src/lib/data/sql-import/dialect-importers/mysql/mysql-common.ts index 9db5bed4..20872cf4 100644 --- a/src/lib/data/sql-import/dialect-importers/mysql/mysql-common.ts +++ b/src/lib/data/sql-import/dialect-importers/mysql/mysql-common.ts @@ -1,7 +1,3 @@ -import { Parser } from 'node-sql-parser'; - -// Common PostgreSQL parser instance -export const parser = new Parser(); export const parserOpts = { database: 'MySQL', // Set dialect to MySQL }; diff --git a/src/lib/data/sql-import/dialect-importers/mysql/mysql.ts b/src/lib/data/sql-import/dialect-importers/mysql/mysql.ts index 41fe68c9..d3850606 100644 --- a/src/lib/data/sql-import/dialect-importers/mysql/mysql.ts +++ b/src/lib/data/sql-import/dialect-importers/mysql/mysql.ts @@ -13,12 +13,7 @@ import type { CreateTableStatement, TableReference, } from './mysql-common'; -import { - parser, - parserOpts, - extractColumnName, - getTypeArgs, -} from './mysql-common'; +import { parserOpts, extractColumnName, getTypeArgs } from './mysql-common'; // Interface for pending foreign keys that need to be processed later interface PendingForeignKey { @@ -213,7 +208,7 @@ function processCreateIndexStatement( } } -export function fromMySQL(sqlContent: string): SQLParserResult { +export async function fromMySQL(sqlContent: string): Promise { const tables: SQLTable[] = []; const relationships: SQLForeignKey[] = []; const tableMap: Record = {}; // Maps table name to its ID @@ -229,6 +224,8 @@ export function fromMySQL(sqlContent: string): SQLParserResult { // Process only CREATE TABLE statements if (trimmedStmt.toUpperCase().startsWith('CREATE TABLE')) { try { + const { Parser } = await import('node-sql-parser'); + const parser = new Parser(); // Parse with SQL parser const ast = parser.astify(trimmedStmt, parserOpts); if ( diff --git a/src/lib/data/sql-import/dialect-importers/postgresql/postgresql-common.ts b/src/lib/data/sql-import/dialect-importers/postgresql/postgresql-common.ts index 66b62591..32bb4bb3 100644 --- a/src/lib/data/sql-import/dialect-importers/postgresql/postgresql-common.ts +++ b/src/lib/data/sql-import/dialect-importers/postgresql/postgresql-common.ts @@ -1,7 +1,3 @@ -import { Parser } from 'node-sql-parser'; - -// Common PostgreSQL parser instance -export const parser = new Parser(); export const parserOpts = { database: 'postgresql' }; // Define interfaces for AST nodes - Fixed no-explicit-any issues diff --git a/src/lib/data/sql-import/dialect-importers/postgresql/postgresql-dump.ts b/src/lib/data/sql-import/dialect-importers/postgresql/postgresql-dump.ts index 80b54f74..2cea7b7e 100644 --- a/src/lib/data/sql-import/dialect-importers/postgresql/postgresql-dump.ts +++ b/src/lib/data/sql-import/dialect-importers/postgresql/postgresql-dump.ts @@ -14,7 +14,6 @@ import type { TableReference, } from './postgresql-common'; import { - parser, parserOpts, extractColumnName, getTypeArgs, @@ -526,7 +525,9 @@ function processCreateIndexStatement( } // PostgreSQL dump-specific parsing logic - optimized for pg_dump output format -export function fromPostgresDump(sqlContent: string): SQLParserResult { +export async function fromPostgresDump( + sqlContent: string +): Promise { const tables: SQLTable[] = []; const relationships: SQLForeignKey[] = []; const tableMap: Record = {}; // Maps table name to its ID @@ -553,6 +554,8 @@ export function fromPostgresDump(sqlContent: string): SQLParserResult { // Phase 1: Process CREATE TABLE statements individually for (const statement of createTableStatements) { try { + const { Parser } = await import('node-sql-parser'); + const parser = new Parser(); // Parse just this statement with the SQL parser const ast = parser.astify(statement, parserOpts); if (Array.isArray(ast) && ast.length > 0) { diff --git a/src/lib/data/sql-import/dialect-importers/postgresql/postgresql.ts b/src/lib/data/sql-import/dialect-importers/postgresql/postgresql.ts index 70c44aa7..fa13cee2 100644 --- a/src/lib/data/sql-import/dialect-importers/postgresql/postgresql.ts +++ b/src/lib/data/sql-import/dialect-importers/postgresql/postgresql.ts @@ -19,7 +19,6 @@ import type { AlterTableStatement, } from './postgresql-common'; import { - parser, parserOpts, extractColumnName, getTypeArgs, @@ -28,12 +27,16 @@ import { } from './postgresql-common'; // PostgreSQL-specific parsing logic -export function fromPostgres(sqlContent: string): SQLParserResult { +export async function fromPostgres( + sqlContent: string +): Promise { const tables: SQLTable[] = []; const relationships: SQLForeignKey[] = []; const tableMap: Record = {}; // Maps table name to its ID try { + const { Parser } = await import('node-sql-parser'); + const parser = new Parser(); // Parse the SQL DDL statements const ast = parser.astify(sqlContent, parserOpts); diff --git a/src/lib/data/sql-import/dialect-importers/sqlite/sqlite-common.ts b/src/lib/data/sql-import/dialect-importers/sqlite/sqlite-common.ts index e1889508..b65a44a5 100644 --- a/src/lib/data/sql-import/dialect-importers/sqlite/sqlite-common.ts +++ b/src/lib/data/sql-import/dialect-importers/sqlite/sqlite-common.ts @@ -1,8 +1,6 @@ -import { Parser } from 'node-sql-parser'; import type { SQLASTNode } from '../../common'; // Set up the SQL parser with SQLite dialect -export const parser = new Parser(); export const parserOpts = { database: 'sqlite', }; diff --git a/src/lib/data/sql-import/dialect-importers/sqlite/sqlite.ts b/src/lib/data/sql-import/dialect-importers/sqlite/sqlite.ts index 3decb301..a9be199c 100644 --- a/src/lib/data/sql-import/dialect-importers/sqlite/sqlite.ts +++ b/src/lib/data/sql-import/dialect-importers/sqlite/sqlite.ts @@ -16,7 +16,6 @@ import type { AlterTableStatement, } from './sqlite-common'; import { - parser as sqlParser, parserOpts, extractColumnName, getTypeArgs, @@ -27,15 +26,17 @@ import { /** * SQLite-specific parsing logic */ -export function fromSQLite(sqlContent: string): SQLParserResult { +export async function fromSQLite(sqlContent: string): Promise { const tables: SQLTable[] = []; const relationships: SQLForeignKey[] = []; const tableMap: Record = {}; // Maps table name to its ID try { // Parse the SQL DDL statements + const { Parser } = await import('node-sql-parser'); + const parser = new Parser(); - const ast = sqlParser.astify( + const ast = parser.astify( sqlContent, parserOpts ) as unknown as SQLASTNode[]; diff --git a/src/lib/data/sql-import/dialect-importers/sqlserver/sqlserver-common.ts b/src/lib/data/sql-import/dialect-importers/sqlserver/sqlserver-common.ts index 69b96c92..2031c81d 100644 --- a/src/lib/data/sql-import/dialect-importers/sqlserver/sqlserver-common.ts +++ b/src/lib/data/sql-import/dialect-importers/sqlserver/sqlserver-common.ts @@ -1,9 +1,7 @@ -import { Parser } from 'node-sql-parser'; import { generateId } from '@/lib/utils'; import type { SQLASTNode } from '../../common'; // Set up the SQL parser with SQL Server dialect -export const parser = new Parser(); export const parserOpts = { database: 'transactsql', }; diff --git a/src/lib/data/sql-import/dialect-importers/sqlserver/sqlserver.ts b/src/lib/data/sql-import/dialect-importers/sqlserver/sqlserver.ts index 10ef779c..0e2f4e26 100644 --- a/src/lib/data/sql-import/dialect-importers/sqlserver/sqlserver.ts +++ b/src/lib/data/sql-import/dialect-importers/sqlserver/sqlserver.ts @@ -19,7 +19,6 @@ import type { AlterTableStatement, } from './sqlserver-common'; import { - parser, parserOpts, extractColumnName, getTypeArgs, @@ -273,7 +272,9 @@ function normalizeSQLServerDataType(dataType: string): string { * @param sqlContent SQL Server DDL content as string * @returns Parsed structure including tables, columns, and relationships */ -export function fromSQLServer(sqlContent: string): SQLParserResult { +export async function fromSQLServer( + sqlContent: string +): Promise { const tables: SQLTable[] = []; const relationships: SQLForeignKey[] = []; const tableMap: Record = {}; // Maps table name to its ID @@ -302,6 +303,8 @@ export function fromSQLServer(sqlContent: string): SQLParserResult { relationships.push(...fkData); } + const { Parser } = await import('node-sql-parser'); + const parser = new Parser(); let ast; try { ast = parser.astify(preprocessedSQL, parserOpts); diff --git a/src/lib/data/sql-import/index.ts b/src/lib/data/sql-import/index.ts index 25074a49..247b738d 100644 --- a/src/lib/data/sql-import/index.ts +++ b/src/lib/data/sql-import/index.ts @@ -166,7 +166,7 @@ export function detectDatabaseType(sqlContent: string): DatabaseType | null { * @param targetDatabaseType Target database type for the diagram * @returns Diagram object */ -export function sqlImportToDiagram({ +export async function sqlImportToDiagram({ sqlContent, sourceDatabaseType, targetDatabaseType = DatabaseType.GENERIC, @@ -174,7 +174,7 @@ export function sqlImportToDiagram({ sqlContent: string; sourceDatabaseType: DatabaseType; targetDatabaseType: DatabaseType; -}): Diagram { +}): Promise { // If source database type is GENERIC, try to auto-detect the type if (sourceDatabaseType === DatabaseType.GENERIC) { const detectedType = detectDatabaseType(sqlContent); @@ -192,21 +192,21 @@ export function sqlImportToDiagram({ case DatabaseType.POSTGRESQL: // Check if the SQL is from pg_dump and use the appropriate parser if (isPgDumpFormat(sqlContent)) { - parserResult = fromPostgresDump(sqlContent); + parserResult = await fromPostgresDump(sqlContent); } else { - parserResult = fromPostgres(sqlContent); + parserResult = await fromPostgres(sqlContent); } break; case DatabaseType.MYSQL: // Check if the SQL is from MySQL dump and use the appropriate parser - parserResult = fromMySQL(sqlContent); + parserResult = await fromMySQL(sqlContent); break; case DatabaseType.SQL_SERVER: - parserResult = fromSQLServer(sqlContent); + parserResult = await fromSQLServer(sqlContent); break; case DatabaseType.SQLITE: - parserResult = fromSQLite(sqlContent); + parserResult = await fromSQLite(sqlContent); break; default: throw new Error(`Unsupported database type: ${sourceDatabaseType}`); @@ -246,35 +246,40 @@ export function sqlImportToDiagram({ * @param sourceDatabaseType Source database type * @returns Object with success status and error information */ -export function parseSQLError({ +export async function parseSQLError({ sqlContent, sourceDatabaseType, }: { sqlContent: string; sourceDatabaseType: DatabaseType; -}): { success: boolean; error?: string; line?: number; column?: number } { +}): Promise<{ + success: boolean; + error?: string; + line?: number; + column?: number; +}> { try { // Validate SQL based on the database type switch (sourceDatabaseType) { case DatabaseType.POSTGRESQL: // PostgreSQL validation - check format and use appropriate parser if (isPgDumpFormat(sqlContent)) { - fromPostgresDump(sqlContent); + await fromPostgresDump(sqlContent); } else { - fromPostgres(sqlContent); + await fromPostgres(sqlContent); } break; case DatabaseType.MYSQL: - fromMySQL(sqlContent); + await fromMySQL(sqlContent); break; case DatabaseType.SQL_SERVER: // SQL Server validation - fromSQLServer(sqlContent); + await fromSQLServer(sqlContent); break; case DatabaseType.SQLITE: // SQLite validation - fromSQLite(sqlContent); + await fromSQLite(sqlContent); break; // Add more database types here default: