mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-30 15:03:57 +00:00
Merge branch 'develop'
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "5.2.1",
|
"version": "5.2.2-beta.1",
|
||||||
"name": "dbgate-all",
|
"name": "dbgate-all",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/*",
|
"packages/*",
|
||||||
|
|||||||
@@ -170,9 +170,9 @@ export class DatabaseAnalyser {
|
|||||||
// return this.structure.tables.find((x) => x.objectId == id);
|
// return this.structure.tables.find((x) => x.objectId == id);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
containsObjectIdCondition(typeFields) {
|
// containsObjectIdCondition(typeFields) {
|
||||||
return this.createQueryCore('=OBJECT_ID_CONDITION', typeFields) != ' is not null';
|
// return this.createQueryCore('=OBJECT_ID_CONDITION', typeFields) != ' is not null';
|
||||||
}
|
// }
|
||||||
|
|
||||||
createQuery(template, typeFields) {
|
createQuery(template, typeFields) {
|
||||||
return this.createQueryCore(template, typeFields);
|
return this.createQueryCore(template, typeFields);
|
||||||
@@ -197,7 +197,7 @@ export class DatabaseAnalyser {
|
|||||||
.filter(x => typeFields.includes(x.objectTypeField) && (x.action == 'add' || x.action == 'change'))
|
.filter(x => typeFields.includes(x.objectTypeField) && (x.action == 'add' || x.action == 'change'))
|
||||||
.map(x => x.objectId);
|
.map(x => x.objectId);
|
||||||
if (filterIds.length == 0) {
|
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(',')})`);
|
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)];
|
return [..._compact(res), ...this.getDeletedObjects(snapshot)];
|
||||||
}
|
}
|
||||||
|
|
||||||
async safeQuery(sql) {
|
async analyserQuery(template, typeFields) {
|
||||||
|
const sql = this.createQuery(template, typeFields);
|
||||||
|
|
||||||
|
if (!sql) {
|
||||||
|
return {
|
||||||
|
rows: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
return await this.driver.query(this.pool, sql);
|
return await this.driver.query(this.pool, sql);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
@@ -82,33 +82,35 @@ class MsSqlAnalyser extends DatabaseAnalyser {
|
|||||||
|
|
||||||
async _runAnalysis() {
|
async _runAnalysis() {
|
||||||
this.feedback({ analysingMessage: 'Loading tables' });
|
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' });
|
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' });
|
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' });
|
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' });
|
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' });
|
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' });
|
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' });
|
this.feedback({ analysingMessage: 'Loading default schema' });
|
||||||
const defaultSchemaRows = await this.driver.query(this.pool, 'SELECT SCHEMA_NAME() as name');
|
const defaultSchemaRows = await this.driver.query(this.pool, 'SELECT SCHEMA_NAME() as name');
|
||||||
this.feedback({ analysingMessage: 'Loading table sizes' });
|
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 schemas = schemaRows.rows;
|
||||||
|
|
||||||
const tableSizesDict = _.mapValues(_.keyBy(tableSizes.rows, 'objectId'), 'tableRowCount');
|
const tableSizesDict = _.mapValues(_.keyBy(tableSizes.rows, 'objectId'), 'tableRowCount');
|
||||||
|
|
||||||
this.feedback({ analysingMessage: 'Loading SQL code' });
|
this.feedback({ analysingMessage: 'Loading SQL code' });
|
||||||
const sqlCodeRows = await this.driver.query(
|
const sqlCodeRows = await this.analyserQuery('loadSqlCode', [
|
||||||
this.pool,
|
'views',
|
||||||
this.createQuery('loadSqlCode', ['views', 'procedures', 'functions', 'triggers'])
|
'procedures',
|
||||||
);
|
'functions',
|
||||||
|
'triggers',
|
||||||
|
]);
|
||||||
const getCreateSql = row =>
|
const getCreateSql = row =>
|
||||||
sqlCodeRows.rows
|
sqlCodeRows.rows
|
||||||
.filter(x => x.pureName == row.pureName && x.schemaName == row.schemaName)
|
.filter(x => x.pureName == row.pureName && x.schemaName == row.schemaName)
|
||||||
@@ -116,14 +118,11 @@ class MsSqlAnalyser extends DatabaseAnalyser {
|
|||||||
.join('');
|
.join('');
|
||||||
|
|
||||||
this.feedback({ analysingMessage: 'Loading views' });
|
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' });
|
this.feedback({ analysingMessage: 'Loading procedures & functions' });
|
||||||
const programmableRows = await this.driver.query(
|
const programmableRows = await this.analyserQuery('programmables', ['procedures', 'functions']);
|
||||||
this.pool,
|
|
||||||
this.createQuery('programmables', ['procedures', 'functions'])
|
|
||||||
);
|
|
||||||
this.feedback({ analysingMessage: 'Loading view columns' });
|
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' });
|
this.feedback({ analysingMessage: 'Finalizing DB structure' });
|
||||||
const tables = tablesRows.rows.map(row => ({
|
const tables = tablesRows.rows.map(row => ({
|
||||||
@@ -190,8 +189,8 @@ class MsSqlAnalyser extends DatabaseAnalyser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async _getFastSnapshot() {
|
async _getFastSnapshot() {
|
||||||
const modificationsQueryData = await this.driver.query(this.pool, this.createQuery('modifications'));
|
const modificationsQueryData = await this.analyserQuery('modifications');
|
||||||
const tableSizes = await this.driver.query(this.pool, this.createQuery('tableSizes'));
|
const tableSizes = await this.analyserQuery('tableSizes');
|
||||||
|
|
||||||
const res = DatabaseAnalyser.createEmptyStructure();
|
const res = DatabaseAnalyser.createEmptyStructure();
|
||||||
for (const item of modificationsQueryData.rows) {
|
for (const item of modificationsQueryData.rows) {
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ class Analyser extends DatabaseAnalyser {
|
|||||||
async getViewTexts(allViewNames) {
|
async getViewTexts(allViewNames) {
|
||||||
const res = {};
|
const res = {};
|
||||||
|
|
||||||
const views = await this.safeQuery(this.createQuery('viewTexts', ['views']));
|
const views = await this.analyserQuery('viewTexts', ['views']);
|
||||||
for (const view of views.rows) {
|
for (const view of views.rows) {
|
||||||
res[view.pureName] = `CREATE VIEW \`${view.pureName}\` AS ${view.viewDefinition}`;
|
res[view.pureName] = `CREATE VIEW \`${view.pureName}\` AS ${view.viewDefinition}`;
|
||||||
}
|
}
|
||||||
@@ -76,24 +76,24 @@ class Analyser extends DatabaseAnalyser {
|
|||||||
|
|
||||||
async _runAnalysis() {
|
async _runAnalysis() {
|
||||||
this.feedback({ analysingMessage: 'Loading tables' });
|
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' });
|
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' });
|
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' });
|
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' });
|
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' });
|
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' });
|
this.feedback({ analysingMessage: 'Loading view texts' });
|
||||||
const viewTexts = await this.getViewTexts(views.rows.map(x => x.pureName));
|
const viewTexts = await this.getViewTexts(views.rows.map(x => x.pureName));
|
||||||
this.feedback({ analysingMessage: 'Loading indexes' });
|
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' });
|
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' });
|
this.feedback({ analysingMessage: 'Finalizing DB structure' });
|
||||||
|
|
||||||
const res = {
|
const res = {
|
||||||
@@ -169,15 +169,9 @@ class Analyser extends DatabaseAnalyser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async _getFastSnapshot() {
|
async _getFastSnapshot() {
|
||||||
const tableModificationsQueryData = await this.driver.query(this.pool, this.createQuery('tableModifications'));
|
const tableModificationsQueryData = await this.analyserQuery('tableModifications');
|
||||||
const procedureModificationsQueryData = await this.driver.query(
|
const procedureModificationsQueryData = await this.analyserQuery('procedureModifications');
|
||||||
this.pool,
|
const functionModificationsQueryData = await this.analyserQuery('functionModifications');
|
||||||
this.createQuery('procedureModifications')
|
|
||||||
);
|
|
||||||
const functionModificationsQueryData = await this.driver.query(
|
|
||||||
this.pool,
|
|
||||||
this.createQuery('functionModifications')
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
tables: tableModificationsQueryData.rows
|
tables: tableModificationsQueryData.rows
|
||||||
|
|||||||
@@ -68,45 +68,40 @@ class Analyser extends DatabaseAnalyser {
|
|||||||
|
|
||||||
async _runAnalysis() {
|
async _runAnalysis() {
|
||||||
this.feedback({ analysingMessage: 'Loading tables' });
|
this.feedback({ analysingMessage: 'Loading tables' });
|
||||||
const tables = await this.driver.query(
|
const tables = await this.analyserQuery(this.driver.dialect.stringAgg ? 'tableList' : 'tableList', ['tables']);
|
||||||
this.pool,
|
|
||||||
this.createQuery(this.driver.dialect.stringAgg ? 'tableList' : 'tableList', ['tables'])
|
|
||||||
);
|
|
||||||
this.feedback({ analysingMessage: 'Loading columns' });
|
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' });
|
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;
|
//let fkColumns = null;
|
||||||
|
|
||||||
this.feedback({ analysingMessage: 'Loading foreign keys' });
|
this.feedback({ analysingMessage: 'Loading foreign keys' });
|
||||||
const fkColumns = await this.driver.query(this.pool, this.createQuery('foreignKeys', ['tables']));
|
const fkColumns = await this.analyserQuery('foreignKeys', ['tables']);
|
||||||
this.feedback({ analysingMessage: 'Loading views' });
|
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 geometryColumns = { rows: [] };
|
||||||
let geographyColumns = { rows: [] };
|
let geographyColumns = { rows: [] };
|
||||||
|
|
||||||
this.feedback({ analysingMessage: 'Loading materialized views' });
|
this.feedback({ analysingMessage: 'Loading materialized views' });
|
||||||
const matviews = this.driver.dialect.materializedViews
|
const matviews = this.driver.dialect.materializedViews ? await this.analyserQuery('matviews', ['matviews']) : null;
|
||||||
? await this.driver.query(this.pool, this.createQuery('matviews', ['matviews']))
|
|
||||||
: null;
|
|
||||||
this.feedback({ analysingMessage: 'Loading materialized view columns' });
|
this.feedback({ analysingMessage: 'Loading materialized view columns' });
|
||||||
const matviewColumns = this.driver.dialect.materializedViews
|
const matviewColumns = this.driver.dialect.materializedViews
|
||||||
? await this.driver.query(this.pool, this.createQuery('matviewColumns', ['matviews']))
|
? await this.analyserQuery('matviewColumns', ['matviews'])
|
||||||
: null;
|
: null;
|
||||||
this.feedback({ analysingMessage: 'Loading routines' });
|
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' });
|
this.feedback({ analysingMessage: 'Loading indexes' });
|
||||||
const indexes = this.driver.__analyserInternals.skipIndexes
|
const indexes = this.driver.__analyserInternals.skipIndexes
|
||||||
? { rows: [] }
|
? { rows: [] }
|
||||||
: await this.driver.query(this.pool, this.createQuery('indexes', ['tables']));
|
: await this.analyserQuery('indexes', ['tables']);
|
||||||
this.feedback({ analysingMessage: 'Loading index columns' });
|
this.feedback({ analysingMessage: 'Loading index columns' });
|
||||||
// const indexcols = this.driver.__analyserInternals.skipIndexes
|
// const indexcols = this.driver.__analyserInternals.skipIndexes
|
||||||
// ? { rows: [] }
|
// ? { rows: [] }
|
||||||
// : await this.driver.query(this.pool, this.createQuery('indexcols', ['tables']));
|
// : await this.driver.query(this.pool, this.createQuery('indexcols', ['tables']));
|
||||||
this.feedback({ analysingMessage: 'Loading unique names' });
|
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' });
|
this.feedback({ analysingMessage: 'Finalizing DB structure' });
|
||||||
|
|
||||||
const columnColumnsMapped = fkColumns.rows.map(x => ({
|
const columnColumnsMapped = fkColumns.rows.map(x => ({
|
||||||
@@ -144,34 +139,35 @@ class Analyser extends DatabaseAnalyser {
|
|||||||
.map(col => getColumnInfo(col, newTable, geometryColumns, geographyColumns)),
|
.map(col => getColumnInfo(col, newTable, geometryColumns, geographyColumns)),
|
||||||
primaryKey: DatabaseAnalyser.extractPrimaryKeys(newTable, pkColumnsMapped),
|
primaryKey: DatabaseAnalyser.extractPrimaryKeys(newTable, pkColumnsMapped),
|
||||||
foreignKeys: DatabaseAnalyser.extractForeignKeys(newTable, columnColumnsMapped),
|
foreignKeys: DatabaseAnalyser.extractForeignKeys(newTable, columnColumnsMapped),
|
||||||
indexes: _.uniqBy(
|
indexes: _.uniqBy(
|
||||||
indexes.rows.filter(
|
indexes.rows.filter(
|
||||||
idx =>
|
idx =>
|
||||||
idx.tableName == table.pureName && !uniqueNames.rows.find(x => x.constraintName == idx.constraintName)
|
idx.tableName == table.pureName && !uniqueNames.rows.find(x => x.constraintName == idx.constraintName)
|
||||||
),
|
),
|
||||||
'constraintName'
|
'constraintName'
|
||||||
).map(idx => ({
|
).map(idx => ({
|
||||||
..._.pick(idx, ['constraintName', 'indexType']),
|
..._.pick(idx, ['constraintName', 'indexType']),
|
||||||
isUnique: idx.Unique === 'UNIQUE',
|
isUnique: idx.Unique === 'UNIQUE',
|
||||||
columns: indexes.rows
|
columns: indexes.rows
|
||||||
.filter(col => col.tableName == idx.tableName && col.constraintName == idx.constraintName)
|
.filter(col => col.tableName == idx.tableName && col.constraintName == idx.constraintName)
|
||||||
.map(col => ({
|
.map(col => ({
|
||||||
..._.pick(col, ['columnName']),
|
..._.pick(col, ['columnName']),
|
||||||
})),
|
})),
|
||||||
})),
|
})),
|
||||||
uniques: _.uniqBy(
|
uniques: _.uniqBy(
|
||||||
indexes.rows.filter(
|
indexes.rows.filter(
|
||||||
idx => idx.tableName == table.pureName && uniqueNames.rows.find(x => x.constraintName == idx.constraintName)
|
idx =>
|
||||||
),
|
idx.tableName == table.pureName && uniqueNames.rows.find(x => x.constraintName == idx.constraintName)
|
||||||
'constraintName'
|
),
|
||||||
).map(idx => ({
|
'constraintName'
|
||||||
..._.pick(idx, ['constraintName']),
|
).map(idx => ({
|
||||||
columns: indexes.rows
|
..._.pick(idx, ['constraintName']),
|
||||||
.filter(col => col.tableName == idx.tableName && col.constraintName == idx.constraintName)
|
columns: indexes.rows
|
||||||
.map(col => ({
|
.filter(col => col.tableName == idx.tableName && col.constraintName == idx.constraintName)
|
||||||
..._.pick(col, ['columnName']),
|
.map(col => ({
|
||||||
})),
|
..._.pick(col, ['columnName']),
|
||||||
})),
|
})),
|
||||||
|
})),
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
views: views.rows.map(view => ({
|
views: views.rows.map(view => ({
|
||||||
@@ -225,13 +221,13 @@ class Analyser extends DatabaseAnalyser {
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
const tableModificationsQueryData = this.driver.dialect.stringAgg
|
const tableModificationsQueryData = this.driver.dialect.stringAgg
|
||||||
? await this.driver.query(this.pool, this.createQuery('tableModifications'))
|
? await this.analyserQuery('tableModifications')
|
||||||
: null;
|
: null;
|
||||||
const viewModificationsQueryData = await this.driver.query(this.pool, this.createQuery('viewModifications'));
|
const viewModificationsQueryData = await this.analyserQuery('viewModifications');
|
||||||
const matviewModificationsQueryData = this.driver.dialect.materializedViews
|
const matviewModificationsQueryData = this.driver.dialect.materializedViews
|
||||||
? await this.driver.query(this.pool, this.createQuery('matviewModifications'))
|
? await this.analyserQuery('matviewModifications')
|
||||||
: null;
|
: null;
|
||||||
const routineModificationsQueryData = await this.driver.query(this.pool, this.createQuery('routineModifications'));
|
const routineModificationsQueryData = await this.analyserQuery('routineModifications');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
tables: tableModificationsQueryData
|
tables: tableModificationsQueryData
|
||||||
@@ -243,13 +239,13 @@ class Analyser extends DatabaseAnalyser {
|
|||||||
}))
|
}))
|
||||||
: null,
|
: null,
|
||||||
views: viewModificationsQueryData
|
views: viewModificationsQueryData
|
||||||
? viewModificationsQueryData.rows.map(x => ({
|
? viewModificationsQueryData.rows.map(x => ({
|
||||||
objectId: `views:${x.schema_name}.${x.pure_name}`,
|
objectId: `views:${x.schema_name}.${x.pure_name}`,
|
||||||
pureName: x.pure_name,
|
pureName: x.pure_name,
|
||||||
schemaName: x.schema_name,
|
schemaName: x.schema_name,
|
||||||
contentHash: x.hash_code,
|
contentHash: x.hash_code,
|
||||||
}))
|
}))
|
||||||
: undefined,
|
: undefined,
|
||||||
matviews: matviewModificationsQueryData
|
matviews: matviewModificationsQueryData
|
||||||
? matviewModificationsQueryData.rows.map(x => ({
|
? matviewModificationsQueryData.rows.map(x => ({
|
||||||
objectId: `matviews:${x.schema_name}.${x.pure_name}`,
|
objectId: `matviews:${x.schema_name}.${x.pure_name}`,
|
||||||
|
|||||||
@@ -57,8 +57,7 @@ class Analyser extends DatabaseAnalyser {
|
|||||||
|
|
||||||
createQuery(resFileName, typeFields) {
|
createQuery(resFileName, typeFields) {
|
||||||
const query = super.createQuery(sql[resFileName], typeFields);
|
const query = super.createQuery(sql[resFileName], typeFields);
|
||||||
if (query) return query.replace('#REFTABLECOND#', this.driver.__analyserInternals.refTableCond);
|
return query;
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async _computeSingleObjectId() {
|
async _computeSingleObjectId() {
|
||||||
@@ -68,108 +67,92 @@ class Analyser extends DatabaseAnalyser {
|
|||||||
|
|
||||||
async _runAnalysis() {
|
async _runAnalysis() {
|
||||||
this.feedback({ analysingMessage: 'Loading tables' });
|
this.feedback({ analysingMessage: 'Loading tables' });
|
||||||
const tables = await this.driver.query(
|
const tables = await this.analyserQuery(this.driver.dialect.stringAgg ? 'tableModifications' : 'tableList', [
|
||||||
this.pool,
|
'tables',
|
||||||
this.createQuery(this.driver.dialect.stringAgg ? 'tableModifications' : 'tableList', ['tables'])
|
]);
|
||||||
);
|
|
||||||
this.feedback({ analysingMessage: 'Loading columns' });
|
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' });
|
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;
|
let fkColumns = null;
|
||||||
|
|
||||||
// if (true) {
|
this.feedback({ analysingMessage: 'Loading foreign key constraints' });
|
||||||
if (this.containsObjectIdCondition(['tables']) || this.driver.__analyserInternals.refTableCond) {
|
const fk_tableConstraints = await this.analyserQuery('fk_tableConstraints', ['tables']);
|
||||||
this.feedback({ analysingMessage: 'Loading foreign keys' });
|
|
||||||
fkColumns = await this.driver.query(this.pool, this.createQuery('foreignKeys', ['tables']));
|
this.feedback({ analysingMessage: 'Loading foreign key refs' });
|
||||||
} else {
|
const fk_referentialConstraints = await this.analyserQuery('fk_referentialConstraints', ['tables']);
|
||||||
this.feedback({ analysingMessage: 'Loading foreign key constraints' });
|
this.feedback({ analysingMessage: 'Loading foreign key columns' });
|
||||||
const fk_tableConstraints = await this.driver.query(
|
const fk_keyColumnUsage = await this.analyserQuery('fk_keyColumnUsage', ['tables']);
|
||||||
this.pool,
|
|
||||||
this.createQuery('fk_tableConstraints', ['tables'])
|
const cntKey = x => `${x.constraint_name}|${x.constraint_schema}`;
|
||||||
|
const fkRows = [];
|
||||||
|
const fkConstraintDct = _.keyBy(fk_tableConstraints.rows, cntKey);
|
||||||
|
for (const fkRef of fk_referentialConstraints.rows) {
|
||||||
|
const cntBase = fkConstraintDct[cntKey(fkRef)];
|
||||||
|
const cntRef = fkConstraintDct[`${fkRef.unique_constraint_name}|${fkRef.unique_constraint_schema}`];
|
||||||
|
if (!cntBase || !cntRef) continue;
|
||||||
|
const baseCols = _.sortBy(
|
||||||
|
fk_keyColumnUsage.rows.filter(
|
||||||
|
x => x.table_name == cntBase.table_name && x.constraint_name == cntBase.constraint_name
|
||||||
|
),
|
||||||
|
'ordinal_position'
|
||||||
);
|
);
|
||||||
|
const refCols = _.sortBy(
|
||||||
this.feedback({ analysingMessage: 'Loading foreign key refs' });
|
fk_keyColumnUsage.rows.filter(
|
||||||
const fk_referentialConstraints = await this.driver.query(
|
x => x.table_name == cntRef.table_name && x.constraint_name == cntRef.constraint_name
|
||||||
this.pool,
|
),
|
||||||
this.createQuery('fk_referentialConstraints', ['tables'])
|
'ordinal_position'
|
||||||
);
|
);
|
||||||
|
if (baseCols.length != refCols.length) continue;
|
||||||
|
|
||||||
this.feedback({ analysingMessage: 'Loading foreign key columns' });
|
for (let i = 0; i < baseCols.length; i++) {
|
||||||
const fk_keyColumnUsage = await this.driver.query(this.pool, this.createQuery('fk_keyColumnUsage', ['tables']));
|
const baseCol = baseCols[i];
|
||||||
|
const refCol = refCols[i];
|
||||||
|
|
||||||
const cntKey = x => `${x.constraint_name}|${x.constraint_schema}`;
|
fkRows.push({
|
||||||
const rows = [];
|
...fkRef,
|
||||||
const constraintDct = _.keyBy(fk_tableConstraints.rows, cntKey);
|
pure_name: cntBase.table_name,
|
||||||
for (const fkRef of fk_referentialConstraints.rows) {
|
schema_name: cntBase.table_schema,
|
||||||
const cntBase = constraintDct[cntKey(fkRef)];
|
ref_table_name: cntRef.table_name,
|
||||||
const cntRef = constraintDct[`${fkRef.unique_constraint_name}|${fkRef.unique_constraint_schema}`];
|
ref_schema_name: cntRef.table_schema,
|
||||||
if (!cntBase || !cntRef) continue;
|
column_name: baseCol.column_name,
|
||||||
const baseCols = _.sortBy(
|
ref_column_name: refCol.column_name,
|
||||||
fk_keyColumnUsage.rows.filter(
|
});
|
||||||
x => x.table_name == cntBase.table_name && x.constraint_name == cntBase.constraint_name
|
|
||||||
),
|
|
||||||
'ordinal_position'
|
|
||||||
);
|
|
||||||
const refCols = _.sortBy(
|
|
||||||
fk_keyColumnUsage.rows.filter(
|
|
||||||
x => x.table_name == cntRef.table_name && x.constraint_name == cntRef.constraint_name
|
|
||||||
),
|
|
||||||
'ordinal_position'
|
|
||||||
);
|
|
||||||
if (baseCols.length != refCols.length) continue;
|
|
||||||
|
|
||||||
for (let i = 0; i < baseCols.length; i++) {
|
|
||||||
const baseCol = baseCols[i];
|
|
||||||
const refCol = refCols[i];
|
|
||||||
|
|
||||||
rows.push({
|
|
||||||
...fkRef,
|
|
||||||
pure_name: cntBase.table_name,
|
|
||||||
schema_name: cntBase.table_schema,
|
|
||||||
ref_table_name: cntRef.table_name,
|
|
||||||
ref_schema_name: cntRef.table_schema,
|
|
||||||
column_name: baseCol.column_name,
|
|
||||||
ref_column_name: refCol.column_name,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
fkColumns = { rows };
|
|
||||||
}
|
}
|
||||||
|
fkColumns = { rows: fkRows };
|
||||||
|
|
||||||
this.feedback({ analysingMessage: 'Loading views' });
|
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' });
|
this.feedback({ analysingMessage: 'Loading materialized views' });
|
||||||
const matviews = this.driver.dialect.materializedViews
|
const matviews = this.driver.dialect.materializedViews ? await this.analyserQuery('matviews', ['matviews']) : null;
|
||||||
? await this.driver.query(this.pool, this.createQuery('matviews', ['matviews']))
|
|
||||||
: null;
|
|
||||||
this.feedback({ analysingMessage: 'Loading materialized view columns' });
|
this.feedback({ analysingMessage: 'Loading materialized view columns' });
|
||||||
const matviewColumns = this.driver.dialect.materializedViews
|
const matviewColumns = this.driver.dialect.materializedViews
|
||||||
? await this.driver.query(this.pool, this.createQuery('matviewColumns', ['matviews']))
|
? await this.analyserQuery('matviewColumns', ['matviews'])
|
||||||
: null;
|
: null;
|
||||||
this.feedback({ analysingMessage: 'Loading routines' });
|
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' });
|
this.feedback({ analysingMessage: 'Loading indexes' });
|
||||||
const indexes = this.driver.__analyserInternals.skipIndexes
|
const indexes = this.driver.__analyserInternals.skipIndexes
|
||||||
? { rows: [] }
|
? { rows: [] }
|
||||||
: await this.driver.query(this.pool, this.createQuery('indexes', ['tables']));
|
: await this.analyserQuery('indexes', ['tables']);
|
||||||
this.feedback({ analysingMessage: 'Loading index columns' });
|
this.feedback({ analysingMessage: 'Loading index columns' });
|
||||||
const indexcols = this.driver.__analyserInternals.skipIndexes
|
const indexcols = this.driver.__analyserInternals.skipIndexes
|
||||||
? { rows: [] }
|
? { rows: [] }
|
||||||
: await this.driver.query(this.pool, this.createQuery('indexcols', ['tables']));
|
: await this.analyserQuery('indexcols', ['tables']);
|
||||||
this.feedback({ analysingMessage: 'Loading unique names' });
|
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: [] };
|
let geometryColumns = { rows: [] };
|
||||||
if (views.rows.find(x => x.pure_name == 'geometry_columns' && x.schema_name == 'public')) {
|
if (views.rows.find(x => x.pure_name == 'geometry_columns' && x.schema_name == 'public')) {
|
||||||
this.feedback({ analysingMessage: 'Loading geometry columns' });
|
this.feedback({ analysingMessage: 'Loading geometry columns' });
|
||||||
geometryColumns = await this.safeQuery(this.createQuery('geometryColumns', ['tables']));
|
geometryColumns = await this.analyserQuery('geometryColumns', ['tables']);
|
||||||
}
|
}
|
||||||
let geographyColumns = { rows: [] };
|
let geographyColumns = { rows: [] };
|
||||||
if (views.rows.find(x => x.pure_name == 'geography_columns' && x.schema_name == 'public')) {
|
if (views.rows.find(x => x.pure_name == 'geography_columns' && x.schema_name == 'public')) {
|
||||||
this.feedback({ analysingMessage: 'Loading geography columns' });
|
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' });
|
this.feedback({ analysingMessage: 'Finalizing DB structure' });
|
||||||
@@ -299,13 +282,13 @@ class Analyser extends DatabaseAnalyser {
|
|||||||
|
|
||||||
async _getFastSnapshot() {
|
async _getFastSnapshot() {
|
||||||
const tableModificationsQueryData = this.driver.dialect.stringAgg
|
const tableModificationsQueryData = this.driver.dialect.stringAgg
|
||||||
? await this.driver.query(this.pool, this.createQuery('tableModifications'))
|
? await this.analyserQuery('tableModifications')
|
||||||
: null;
|
: null;
|
||||||
const viewModificationsQueryData = await this.driver.query(this.pool, this.createQuery('viewModifications'));
|
const viewModificationsQueryData = await this.analyserQuery('viewModifications');
|
||||||
const matviewModificationsQueryData = this.driver.dialect.materializedViews
|
const matviewModificationsQueryData = this.driver.dialect.materializedViews
|
||||||
? await this.driver.query(this.pool, this.createQuery('matviewModifications'))
|
? await this.analyserQuery('matviewModifications')
|
||||||
: null;
|
: null;
|
||||||
const routineModificationsQueryData = await this.driver.query(this.pool, this.createQuery('routineModifications'));
|
const routineModificationsQueryData = await this.analyserQuery('routineModifications');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
tables: tableModificationsQueryData
|
tables: tableModificationsQueryData
|
||||||
|
|||||||
@@ -78,8 +78,6 @@ const drivers = driverBases.map(driverBase => ({
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('OPTIONS', options);
|
|
||||||
|
|
||||||
const client = new pg.Client(options);
|
const client = new pg.Client(options);
|
||||||
await client.connect();
|
await client.connect();
|
||||||
|
|
||||||
|
|||||||
@@ -7,4 +7,5 @@ select
|
|||||||
basecol.table_name,
|
basecol.table_name,
|
||||||
basecol.ordinal_position
|
basecol.ordinal_position
|
||||||
from information_schema.key_column_usage basecol
|
from information_schema.key_column_usage basecol
|
||||||
|
where ('tables:' || basecol.table_schema || '.' || basecol.table_name) =OBJECT_ID_CONDITION
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -5,4 +5,5 @@ select
|
|||||||
base.constraint_name as "constraint_name",
|
base.constraint_name as "constraint_name",
|
||||||
base.constraint_schema as "constraint_schema"
|
base.constraint_schema as "constraint_schema"
|
||||||
from information_schema.table_constraints base
|
from information_schema.table_constraints base
|
||||||
|
where ('tables:' || base.table_schema || '.' || base.table_name) =OBJECT_ID_CONDITION
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
module.exports = `
|
|
||||||
select
|
|
||||||
fk.constraint_name as "constraint_name",
|
|
||||||
fk.constraint_schema as "constraint_schema",
|
|
||||||
base.table_name as "pure_name",
|
|
||||||
base.table_schema as "schema_name",
|
|
||||||
fk.update_rule as "update_action",
|
|
||||||
fk.delete_rule as "delete_action",
|
|
||||||
ref.table_name as "ref_table_name",
|
|
||||||
ref.table_schema as "ref_schema_name",
|
|
||||||
basecol.column_name as "column_name",
|
|
||||||
refcol.column_name as "ref_column_name"
|
|
||||||
from information_schema.referential_constraints fk
|
|
||||||
inner join information_schema.table_constraints base on fk.constraint_name = base.constraint_name and fk.constraint_schema = base.constraint_schema
|
|
||||||
inner join information_schema.table_constraints ref on fk.unique_constraint_name = ref.constraint_name and fk.unique_constraint_schema = ref.constraint_schema #REFTABLECOND#
|
|
||||||
inner join information_schema.key_column_usage basecol on base.table_name = basecol.table_name and base.constraint_name = basecol.constraint_name
|
|
||||||
inner join information_schema.key_column_usage refcol on ref.table_name = refcol.table_name and ref.constraint_name = refcol.constraint_name and basecol.ordinal_position = refcol.ordinal_position
|
|
||||||
where
|
|
||||||
base.table_schema <> 'information_schema'
|
|
||||||
and base.table_schema <> 'pg_catalog'
|
|
||||||
and base.table_schema !~ '^pg_toast'
|
|
||||||
and ('tables:' || base.table_schema || '.' || base.table_name) =OBJECT_ID_CONDITION
|
|
||||||
order by basecol.ordinal_position
|
|
||||||
`;
|
|
||||||
@@ -4,7 +4,6 @@ const tableList = require('./tableList');
|
|||||||
const viewModifications = require('./viewModifications');
|
const viewModifications = require('./viewModifications');
|
||||||
const matviewModifications = require('./matviewModifications');
|
const matviewModifications = require('./matviewModifications');
|
||||||
const primaryKeys = require('./primaryKeys');
|
const primaryKeys = require('./primaryKeys');
|
||||||
const foreignKeys = require('./foreignKeys');
|
|
||||||
const views = require('./views');
|
const views = require('./views');
|
||||||
const matviews = require('./matviews');
|
const matviews = require('./matviews');
|
||||||
const routines = require('./routines');
|
const routines = require('./routines');
|
||||||
@@ -26,7 +25,6 @@ module.exports = {
|
|||||||
tableList,
|
tableList,
|
||||||
viewModifications,
|
viewModifications,
|
||||||
primaryKeys,
|
primaryKeys,
|
||||||
foreignKeys,
|
|
||||||
fk_keyColumnUsage,
|
fk_keyColumnUsage,
|
||||||
fk_referentialConstraints,
|
fk_referentialConstraints,
|
||||||
fk_tableConstraints,
|
fk_tableConstraints,
|
||||||
|
|||||||
@@ -140,9 +140,7 @@ const postgresDriverBase = {
|
|||||||
return connection;
|
return connection;
|
||||||
},
|
},
|
||||||
|
|
||||||
__analyserInternals: {
|
__analyserInternals: {},
|
||||||
refTableCond: '',
|
|
||||||
},
|
|
||||||
|
|
||||||
getNewObjectTemplates() {
|
getNewObjectTemplates() {
|
||||||
return [
|
return [
|
||||||
@@ -212,9 +210,7 @@ const cockroachDriver = {
|
|||||||
dropColumnDependencies: ['primaryKey', 'dependencies'],
|
dropColumnDependencies: ['primaryKey', 'dependencies'],
|
||||||
dropPrimaryKey: false,
|
dropPrimaryKey: false,
|
||||||
},
|
},
|
||||||
__analyserInternals: {
|
__analyserInternals: {},
|
||||||
refTableCond: 'and fk.referenced_table_name = ref.table_name',
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @type {import('dbgate-types').EngineDriver} */
|
/** @type {import('dbgate-types').EngineDriver} */
|
||||||
@@ -225,7 +221,6 @@ const redshiftDriver = {
|
|||||||
stringAgg: false,
|
stringAgg: false,
|
||||||
},
|
},
|
||||||
__analyserInternals: {
|
__analyserInternals: {
|
||||||
refTableCond: '',
|
|
||||||
skipIndexes: true,
|
skipIndexes: true,
|
||||||
},
|
},
|
||||||
engine: 'redshift@dbgate-plugin-postgres',
|
engine: 'redshift@dbgate-plugin-postgres',
|
||||||
|
|||||||
@@ -53,12 +53,9 @@ class Analyser extends DatabaseAnalyser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async _runAnalysis() {
|
async _runAnalysis() {
|
||||||
const objects = await this.driver.query(
|
const objects = await this.analyserQuery(
|
||||||
this.pool,
|
"select * from sqlite_master where (type='table' or type='view') and name =OBJECT_ID_CONDITION",
|
||||||
super.createQuery(
|
['tables', 'views']
|
||||||
"select * from sqlite_master where (type='table' or type='view') and name =OBJECT_ID_CONDITION",
|
|
||||||
['tables', 'views']
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
const tables = objects.rows.filter((x) => x.type == 'table');
|
const tables = objects.rows.filter((x) => x.type == 'table');
|
||||||
const views = objects.rows.filter((x) => x.type == 'view');
|
const views = objects.rows.filter((x) => x.type == 'view');
|
||||||
|
|||||||
Reference in New Issue
Block a user