diff --git a/packages/tools/src/DatabaseAnalyser.ts b/packages/tools/src/DatabaseAnalyser.ts index 5d79ccd0f..126c77ab3 100644 --- a/packages/tools/src/DatabaseAnalyser.ts +++ b/packages/tools/src/DatabaseAnalyser.ts @@ -197,7 +197,7 @@ export class DatabaseAnalyser { .filter(x => typeFields.includes(x.objectTypeField) && (x.action == 'add' || x.action == 'change')) .map(x => x.objectId); if (filterIds.length == 0) { - return template.replace(/=OBJECT_ID_CONDITION/g, " = '0'"); + return null; } return template.replace(/=OBJECT_ID_CONDITION/g, ` in (${filterIds.map(x => `'${x}'`).join(',')})`); } @@ -293,7 +293,14 @@ export class DatabaseAnalyser { return [..._compact(res), ...this.getDeletedObjects(snapshot)]; } - async safeQuery(sql) { + async analyserQuery(template, typeFields) { + const sql = this.createQuery(template, typeFields); + + if (!sql) { + return { + rows: [], + }; + } try { return await this.driver.query(this.pool, sql); } catch (err) { diff --git a/plugins/dbgate-plugin-mssql/src/backend/MsSqlAnalyser.js b/plugins/dbgate-plugin-mssql/src/backend/MsSqlAnalyser.js index 76f0f91df..cb21583e5 100644 --- a/plugins/dbgate-plugin-mssql/src/backend/MsSqlAnalyser.js +++ b/plugins/dbgate-plugin-mssql/src/backend/MsSqlAnalyser.js @@ -82,33 +82,35 @@ class MsSqlAnalyser extends DatabaseAnalyser { async _runAnalysis() { this.feedback({ analysingMessage: 'Loading tables' }); - const tablesRows = await this.driver.query(this.pool, this.createQuery('tables', ['tables'])); + const tablesRows = await this.analyserQuery('tables', ['tables']); this.feedback({ analysingMessage: 'Loading columns' }); - const columnsRows = await this.driver.query(this.pool, this.createQuery('columns', ['tables'])); + const columnsRows = await this.analyserQuery('columns', ['tables']); this.feedback({ analysingMessage: 'Loading primary keys' }); - const pkColumnsRows = await this.driver.query(this.pool, this.createQuery('primaryKeys', ['tables'])); + const pkColumnsRows = await this.analyserQuery('primaryKeys', ['tables']); this.feedback({ analysingMessage: 'Loading foreign keys' }); - const fkColumnsRows = await this.driver.query(this.pool, this.createQuery('foreignKeys', ['tables'])); + const fkColumnsRows = await this.analyserQuery('foreignKeys', ['tables']); this.feedback({ analysingMessage: 'Loading schemas' }); - const schemaRows = await this.driver.query(this.pool, this.createQuery('getSchemas')); + const schemaRows = await this.analyserQuery('getSchemas'); this.feedback({ analysingMessage: 'Loading indexes' }); - const indexesRows = await this.driver.query(this.pool, this.createQuery('indexes', ['tables'])); + const indexesRows = await this.analyserQuery('indexes', ['tables']); this.feedback({ analysingMessage: 'Loading index columns' }); - const indexcolsRows = await this.driver.query(this.pool, this.createQuery('indexcols', ['tables'])); + const indexcolsRows = await this.analyserQuery('indexcols', ['tables']); this.feedback({ analysingMessage: 'Loading default schema' }); - const defaultSchemaRows = await this.driver.query(this.pool, 'SELECT SCHEMA_NAME() as name'); + const defaultSchemaRows = await this.query(this.pool, 'SELECT SCHEMA_NAME() as name'); this.feedback({ analysingMessage: 'Loading table sizes' }); - const tableSizes = await this.driver.query(this.pool, this.createQuery('tableSizes')); + const tableSizes = await this.analyserQuery('tableSizes'); const schemas = schemaRows.rows; const tableSizesDict = _.mapValues(_.keyBy(tableSizes.rows, 'objectId'), 'tableRowCount'); this.feedback({ analysingMessage: 'Loading SQL code' }); - const sqlCodeRows = await this.driver.query( - this.pool, - this.createQuery('loadSqlCode', ['views', 'procedures', 'functions', 'triggers']) - ); + const sqlCodeRows = await this.analyserQuery('loadSqlCode', [ + 'views', + 'procedures', + 'functions', + 'triggers', + ]); const getCreateSql = row => sqlCodeRows.rows .filter(x => x.pureName == row.pureName && x.schemaName == row.schemaName) @@ -116,14 +118,11 @@ class MsSqlAnalyser extends DatabaseAnalyser { .join(''); this.feedback({ analysingMessage: 'Loading views' }); - const viewsRows = await this.driver.query(this.pool, this.createQuery('views', ['views'])); + const viewsRows = await this.analyserQuery('views', ['views']); this.feedback({ analysingMessage: 'Loading procedures & functions' }); - const programmableRows = await this.driver.query( - this.pool, - this.createQuery('programmables', ['procedures', 'functions']) - ); + const programmableRows = await this.analyserQuery('programmables', ['procedures', 'functions']); this.feedback({ analysingMessage: 'Loading view columns' }); - const viewColumnRows = await this.driver.query(this.pool, this.createQuery('viewColumns', ['views'])); + const viewColumnRows = await this.analyserQuery('viewColumns', ['views']); this.feedback({ analysingMessage: 'Finalizing DB structure' }); const tables = tablesRows.rows.map(row => ({ @@ -190,8 +189,8 @@ class MsSqlAnalyser extends DatabaseAnalyser { } async _getFastSnapshot() { - const modificationsQueryData = await this.driver.query(this.pool, this.createQuery('modifications')); - const tableSizes = await this.driver.query(this.pool, this.createQuery('tableSizes')); + const modificationsQueryData = await this.analyserQuery('modifications'); + const tableSizes = await this.analyserQuery('tableSizes'); const res = DatabaseAnalyser.createEmptyStructure(); for (const item of modificationsQueryData.rows) { diff --git a/plugins/dbgate-plugin-mysql/src/backend/Analyser.js b/plugins/dbgate-plugin-mysql/src/backend/Analyser.js index f0f8edae3..1656893d2 100644 --- a/plugins/dbgate-plugin-mysql/src/backend/Analyser.js +++ b/plugins/dbgate-plugin-mysql/src/backend/Analyser.js @@ -57,7 +57,7 @@ class Analyser extends DatabaseAnalyser { async getViewTexts(allViewNames) { const res = {}; - const views = await this.safeQuery(this.createQuery('viewTexts', ['views'])); + const views = await this.analyserQuery('viewTexts', ['views']); for (const view of views.rows) { res[view.pureName] = `CREATE VIEW \`${view.pureName}\` AS ${view.viewDefinition}`; } @@ -76,24 +76,24 @@ class Analyser extends DatabaseAnalyser { async _runAnalysis() { this.feedback({ analysingMessage: 'Loading tables' }); - const tables = await this.driver.query(this.pool, this.createQuery('tables', ['tables'])); + const tables = await this.analyserQuery('tables', ['tables']); this.feedback({ analysingMessage: 'Loading columns' }); - const columns = await this.driver.query(this.pool, this.createQuery('columns', ['tables', 'views'])); + const columns = await this.analyserQuery('columns', ['tables', 'views']); this.feedback({ analysingMessage: 'Loading primary keys' }); - const pkColumns = await this.safeQuery(this.createQuery('primaryKeys', ['tables'])); + const pkColumns = await this.analyserQuery('primaryKeys', ['tables']); this.feedback({ analysingMessage: 'Loading foreign keys' }); - const fkColumns = await this.safeQuery(this.createQuery('foreignKeys', ['tables'])); + const fkColumns = await this.analyserQuery('foreignKeys', ['tables']); this.feedback({ analysingMessage: 'Loading views' }); - const views = await this.safeQuery(this.createQuery('views', ['views'])); + const views = await this.analyserQuery('views', ['views']); this.feedback({ analysingMessage: 'Loading programmables' }); - const programmables = await this.safeQuery(this.createQuery('programmables', ['procedures', 'functions'])); + const programmables = await this.analyserQuery('programmables', ['procedures', 'functions']); this.feedback({ analysingMessage: 'Loading view texts' }); const viewTexts = await this.getViewTexts(views.rows.map(x => x.pureName)); this.feedback({ analysingMessage: 'Loading indexes' }); - const indexes = await this.safeQuery(this.createQuery('indexes', ['tables'])); + const indexes = await this.analyserQuery('indexes', ['tables']); this.feedback({ analysingMessage: 'Loading uniques' }); - const uniqueNames = await this.safeQuery(this.createQuery('uniqueNames', ['tables'])); + const uniqueNames = await this.analyserQuery('uniqueNames', ['tables']); this.feedback({ analysingMessage: 'Finalizing DB structure' }); const res = { @@ -169,15 +169,9 @@ class Analyser extends DatabaseAnalyser { } async _getFastSnapshot() { - const tableModificationsQueryData = await this.driver.query(this.pool, this.createQuery('tableModifications')); - const procedureModificationsQueryData = await this.driver.query( - this.pool, - this.createQuery('procedureModifications') - ); - const functionModificationsQueryData = await this.driver.query( - this.pool, - this.createQuery('functionModifications') - ); + const tableModificationsQueryData = await this.analyserQuery('tableModifications'); + const procedureModificationsQueryData = await this.analyserQuery('procedureModifications'); + const functionModificationsQueryData = await this.analyserQuery('functionModifications'); return { tables: tableModificationsQueryData.rows diff --git a/plugins/dbgate-plugin-oracle/src/backend/Analyser.js b/plugins/dbgate-plugin-oracle/src/backend/Analyser.js index f1130880f..45aeb777f 100644 --- a/plugins/dbgate-plugin-oracle/src/backend/Analyser.js +++ b/plugins/dbgate-plugin-oracle/src/backend/Analyser.js @@ -68,45 +68,40 @@ class Analyser extends DatabaseAnalyser { async _runAnalysis() { this.feedback({ analysingMessage: 'Loading tables' }); - const tables = await this.driver.query( - this.pool, - this.createQuery(this.driver.dialect.stringAgg ? 'tableList' : 'tableList', ['tables']) - ); + const tables = await this.analyserQuery(this.driver.dialect.stringAgg ? 'tableList' : 'tableList', ['tables']); this.feedback({ analysingMessage: 'Loading columns' }); - const columns = await this.driver.query(this.pool, this.createQuery('columns', ['tables', 'views'])); + const columns = await this.analyserQuery('columns', ['tables', 'views']); this.feedback({ analysingMessage: 'Loading primary keys' }); - const pkColumns = await this.driver.query(this.pool, this.createQuery('primaryKeys', ['tables'])); + const pkColumns = await this.analyserQuery('primaryKeys', ['tables']); //let fkColumns = null; - this.feedback({ analysingMessage: 'Loading foreign keys' }); - const fkColumns = await this.driver.query(this.pool, this.createQuery('foreignKeys', ['tables'])); + this.feedback({ analysingMessage: 'Loading foreign keys' }); + const fkColumns = await this.analyserQuery('foreignKeys', ['tables']); this.feedback({ analysingMessage: 'Loading views' }); - const views = await this.driver.query(this.pool, this.createQuery('views', ['views'])); + const views = await this.analyserQuery('views', ['views']); let geometryColumns = { rows: [] }; let geographyColumns = { rows: [] }; this.feedback({ analysingMessage: 'Loading materialized views' }); - const matviews = this.driver.dialect.materializedViews - ? await this.driver.query(this.pool, this.createQuery('matviews', ['matviews'])) - : null; + const matviews = this.driver.dialect.materializedViews ? await this.analyserQuery('matviews', ['matviews']) : null; this.feedback({ analysingMessage: 'Loading materialized view columns' }); const matviewColumns = this.driver.dialect.materializedViews - ? await this.driver.query(this.pool, this.createQuery('matviewColumns', ['matviews'])) + ? await this.analyserQuery('matviewColumns', ['matviews']) : null; this.feedback({ analysingMessage: 'Loading routines' }); - const routines = await this.driver.query(this.pool, this.createQuery('routines', ['procedures', 'functions'])); + const routines = await this.analyserQuery('routines', ['procedures', 'functions']); this.feedback({ analysingMessage: 'Loading indexes' }); const indexes = this.driver.__analyserInternals.skipIndexes ? { rows: [] } - : await this.driver.query(this.pool, this.createQuery('indexes', ['tables'])); + : await this.analyserQuery('indexes', ['tables']); this.feedback({ analysingMessage: 'Loading index columns' }); -// const indexcols = this.driver.__analyserInternals.skipIndexes -// ? { rows: [] } -// : await this.driver.query(this.pool, this.createQuery('indexcols', ['tables'])); + // const indexcols = this.driver.__analyserInternals.skipIndexes + // ? { rows: [] } + // : await this.driver.query(this.pool, this.createQuery('indexcols', ['tables'])); this.feedback({ analysingMessage: 'Loading unique names' }); - const uniqueNames = await this.driver.query(this.pool, this.createQuery('uniqueNames', ['tables'])); + const uniqueNames = await this.analyserQuery('uniqueNames', ['tables']); this.feedback({ analysingMessage: 'Finalizing DB structure' }); const columnColumnsMapped = fkColumns.rows.map(x => ({ @@ -144,34 +139,35 @@ class Analyser extends DatabaseAnalyser { .map(col => getColumnInfo(col, newTable, geometryColumns, geographyColumns)), primaryKey: DatabaseAnalyser.extractPrimaryKeys(newTable, pkColumnsMapped), foreignKeys: DatabaseAnalyser.extractForeignKeys(newTable, columnColumnsMapped), - indexes: _.uniqBy( - indexes.rows.filter( - idx => - idx.tableName == table.pureName && !uniqueNames.rows.find(x => x.constraintName == idx.constraintName) - ), - 'constraintName' - ).map(idx => ({ - ..._.pick(idx, ['constraintName', 'indexType']), - isUnique: idx.Unique === 'UNIQUE', - columns: indexes.rows - .filter(col => col.tableName == idx.tableName && col.constraintName == idx.constraintName) - .map(col => ({ - ..._.pick(col, ['columnName']), - })), - })), - uniques: _.uniqBy( - indexes.rows.filter( - idx => idx.tableName == table.pureName && uniqueNames.rows.find(x => x.constraintName == idx.constraintName) - ), - 'constraintName' - ).map(idx => ({ - ..._.pick(idx, ['constraintName']), - columns: indexes.rows - .filter(col => col.tableName == idx.tableName && col.constraintName == idx.constraintName) - .map(col => ({ - ..._.pick(col, ['columnName']), - })), - })), + indexes: _.uniqBy( + indexes.rows.filter( + idx => + idx.tableName == table.pureName && !uniqueNames.rows.find(x => x.constraintName == idx.constraintName) + ), + 'constraintName' + ).map(idx => ({ + ..._.pick(idx, ['constraintName', 'indexType']), + isUnique: idx.Unique === 'UNIQUE', + columns: indexes.rows + .filter(col => col.tableName == idx.tableName && col.constraintName == idx.constraintName) + .map(col => ({ + ..._.pick(col, ['columnName']), + })), + })), + uniques: _.uniqBy( + indexes.rows.filter( + idx => + idx.tableName == table.pureName && uniqueNames.rows.find(x => x.constraintName == idx.constraintName) + ), + 'constraintName' + ).map(idx => ({ + ..._.pick(idx, ['constraintName']), + columns: indexes.rows + .filter(col => col.tableName == idx.tableName && col.constraintName == idx.constraintName) + .map(col => ({ + ..._.pick(col, ['columnName']), + })), + })), }; }), views: views.rows.map(view => ({ @@ -225,13 +221,13 @@ class Analyser extends DatabaseAnalyser { return null; const tableModificationsQueryData = this.driver.dialect.stringAgg - ? await this.driver.query(this.pool, this.createQuery('tableModifications')) + ? await this.analyserQuery('tableModifications') : null; - const viewModificationsQueryData = await this.driver.query(this.pool, this.createQuery('viewModifications')); + const viewModificationsQueryData = await this.analyserQuery('viewModifications'); const matviewModificationsQueryData = this.driver.dialect.materializedViews - ? await this.driver.query(this.pool, this.createQuery('matviewModifications')) + ? await this.analyserQuery('matviewModifications') : null; - const routineModificationsQueryData = await this.driver.query(this.pool, this.createQuery('routineModifications')); + const routineModificationsQueryData = await this.analyserQuery('routineModifications'); return { tables: tableModificationsQueryData @@ -243,13 +239,13 @@ class Analyser extends DatabaseAnalyser { })) : null, views: viewModificationsQueryData - ? viewModificationsQueryData.rows.map(x => ({ - objectId: `views:${x.schema_name}.${x.pure_name}`, - pureName: x.pure_name, - schemaName: x.schema_name, - contentHash: x.hash_code, - })) - : undefined, + ? viewModificationsQueryData.rows.map(x => ({ + objectId: `views:${x.schema_name}.${x.pure_name}`, + pureName: x.pure_name, + schemaName: x.schema_name, + contentHash: x.hash_code, + })) + : undefined, matviews: matviewModificationsQueryData ? matviewModificationsQueryData.rows.map(x => ({ objectId: `matviews:${x.schema_name}.${x.pure_name}`, diff --git a/plugins/dbgate-plugin-postgres/src/backend/Analyser.js b/plugins/dbgate-plugin-postgres/src/backend/Analyser.js index b15dc6b42..fb536c5f9 100644 --- a/plugins/dbgate-plugin-postgres/src/backend/Analyser.js +++ b/plugins/dbgate-plugin-postgres/src/backend/Analyser.js @@ -67,28 +67,23 @@ class Analyser extends DatabaseAnalyser { async _runAnalysis() { this.feedback({ analysingMessage: 'Loading tables' }); - const tables = await this.driver.query( - this.pool, - this.createQuery(this.driver.dialect.stringAgg ? 'tableModifications' : 'tableList', ['tables']) - ); + const tables = await this.analyserQuery(this.driver.dialect.stringAgg ? 'tableModifications' : 'tableList', [ + 'tables', + ]); this.feedback({ analysingMessage: 'Loading columns' }); - const columns = await this.driver.query(this.pool, this.createQuery('columns', ['tables', 'views'])); + const columns = await this.analyserQuery('columns', ['tables', 'views']); this.feedback({ analysingMessage: 'Loading primary keys' }); - const pkColumns = await this.driver.query(this.pool, this.createQuery('primaryKeys', ['tables'])); + const pkColumns = await this.analyserQuery('primaryKeys', ['tables']); let fkColumns = null; this.feedback({ analysingMessage: 'Loading foreign key constraints' }); - const fk_tableConstraints = await this.driver.query(this.pool, this.createQuery('fk_tableConstraints', ['tables'])); + const fk_tableConstraints = await this.analyserQuery('fk_tableConstraints', ['tables']); this.feedback({ analysingMessage: 'Loading foreign key refs' }); - const fk_referentialConstraints = await this.driver.query( - this.pool, - this.createQuery('fk_referentialConstraints', ['tables']) - ); - + const fk_referentialConstraints = await this.analyserQuery('fk_referentialConstraints', ['tables']); this.feedback({ analysingMessage: 'Loading foreign key columns' }); - const fk_keyColumnUsage = await this.driver.query(this.pool, this.createQuery('fk_keyColumnUsage', ['tables'])); + const fk_keyColumnUsage = await this.analyserQuery('fk_keyColumnUsage', ['tables']); const cntKey = x => `${x.constraint_name}|${x.constraint_schema}`; const fkRows = []; @@ -129,37 +124,35 @@ class Analyser extends DatabaseAnalyser { fkColumns = { rows: fkRows }; this.feedback({ analysingMessage: 'Loading views' }); - const views = await this.driver.query(this.pool, this.createQuery('views', ['views'])); + const views = await this.analyserQuery('views', ['views']); this.feedback({ analysingMessage: 'Loading materialized views' }); - const matviews = this.driver.dialect.materializedViews - ? await this.driver.query(this.pool, this.createQuery('matviews', ['matviews'])) - : null; + const matviews = this.driver.dialect.materializedViews ? await this.analyserQuery('matviews', ['matviews']) : null; this.feedback({ analysingMessage: 'Loading materialized view columns' }); const matviewColumns = this.driver.dialect.materializedViews - ? await this.driver.query(this.pool, this.createQuery('matviewColumns', ['matviews'])) + ? await this.analyserQuery('matviewColumns', ['matviews']) : null; this.feedback({ analysingMessage: 'Loading routines' }); - const routines = await this.driver.query(this.pool, this.createQuery('routines', ['procedures', 'functions'])); + const routines = await this.analyserQuery('routines', ['procedures', 'functions']); this.feedback({ analysingMessage: 'Loading indexes' }); const indexes = this.driver.__analyserInternals.skipIndexes ? { rows: [] } - : await this.driver.query(this.pool, this.createQuery('indexes', ['tables'])); + : await this.analyserQuery('indexes', ['tables']); this.feedback({ analysingMessage: 'Loading index columns' }); const indexcols = this.driver.__analyserInternals.skipIndexes ? { rows: [] } - : await this.driver.query(this.pool, this.createQuery('indexcols', ['tables'])); + : await this.analyserQuery('indexcols', ['tables']); this.feedback({ analysingMessage: 'Loading unique names' }); - const uniqueNames = await this.driver.query(this.pool, this.createQuery('uniqueNames', ['tables'])); + const uniqueNames = await this.analyserQuery('uniqueNames', ['tables']); let geometryColumns = { rows: [] }; if (views.rows.find(x => x.pure_name == 'geometry_columns' && x.schema_name == 'public')) { this.feedback({ analysingMessage: 'Loading geometry columns' }); - geometryColumns = await this.safeQuery(this.createQuery('geometryColumns', ['tables'])); + geometryColumns = await this.analyserQuery('geometryColumns', ['tables']); } let geographyColumns = { rows: [] }; if (views.rows.find(x => x.pure_name == 'geography_columns' && x.schema_name == 'public')) { this.feedback({ analysingMessage: 'Loading geography columns' }); - geographyColumns = await this.safeQuery(this.createQuery('geographyColumns', ['tables'])); + geographyColumns = await this.analyserQuery('geographyColumns', ['tables']); } this.feedback({ analysingMessage: 'Finalizing DB structure' }); @@ -289,13 +282,13 @@ class Analyser extends DatabaseAnalyser { async _getFastSnapshot() { const tableModificationsQueryData = this.driver.dialect.stringAgg - ? await this.driver.query(this.pool, this.createQuery('tableModifications')) + ? await this.analyserQuery('tableModifications') : null; - const viewModificationsQueryData = await this.driver.query(this.pool, this.createQuery('viewModifications')); + const viewModificationsQueryData = await this.analyserQuery('viewModifications'); const matviewModificationsQueryData = this.driver.dialect.materializedViews - ? await this.driver.query(this.pool, this.createQuery('matviewModifications')) + ? await this.analyserQuery('matviewModifications') : null; - const routineModificationsQueryData = await this.driver.query(this.pool, this.createQuery('routineModifications')); + const routineModificationsQueryData = await this.analyserQuery('routineModifications'); return { tables: tableModificationsQueryData