mirror of
https://github.com/dbgate/dbgate
synced 2024-11-07 20:26:23 +00:00
DatabaseAnalyser.createQuery core moved to base class
This commit is contained in:
parent
4a4c4b41c0
commit
2eb1c04fcf
@ -8,6 +8,7 @@ export class DatabaseAnalyser {
|
||||
structure: DatabaseInfo;
|
||||
modifications: DatabaseModification[];
|
||||
singleObjectFilter: any;
|
||||
singleObjectId: string = null;
|
||||
|
||||
constructor(public pool, public driver: EngineDriver) {}
|
||||
|
||||
@ -15,6 +16,8 @@ export class DatabaseAnalyser {
|
||||
return DatabaseAnalyser.createEmptyStructure();
|
||||
}
|
||||
|
||||
async _computeSingleObjectId() {}
|
||||
|
||||
/** @returns {Promise<import('dbgate-types').DatabaseModification[]>} */
|
||||
async getModifications() {
|
||||
if (this.structure == null) throw new Error('DatabaseAnalyse.getModifications - structure must be filled');
|
||||
@ -28,6 +31,7 @@ export class DatabaseAnalyser {
|
||||
|
||||
async singleObjectAnalysis(name, typeField) {
|
||||
this.singleObjectFilter = { ...name, typeField };
|
||||
await this._computeSingleObjectId();
|
||||
const res = this._runAnalysis();
|
||||
if (res[typeField].length == 1) return res[typeField][0];
|
||||
const obj = res[typeField].find(x => x.pureName == name.pureName && x.schemaName == name.schemaName);
|
||||
@ -94,6 +98,29 @@ export class DatabaseAnalyser {
|
||||
// return this.structure.tables.find((x) => x.objectId == id);
|
||||
// }
|
||||
|
||||
createQuery(template, typeFields) {
|
||||
let res = template;
|
||||
if (this.singleObjectFilter) {
|
||||
const { typeField } = this.singleObjectFilter;
|
||||
if (!this.singleObjectId) return null;
|
||||
if (!typeFields || !typeFields.includes(typeField)) return null;
|
||||
return res.replace(/=OBJECT_ID_CONDITION/g, ` = ${this.singleObjectId}`);
|
||||
}
|
||||
if (!this.modifications || !typeFields || this.modifications.length == 0) {
|
||||
res = res.replace(/=OBJECT_ID_CONDITION/g, ' is not null');
|
||||
} else {
|
||||
const filterIds = this.modifications
|
||||
.filter(x => typeFields.includes(x.objectTypeField) && (x.action == 'add' || x.action == 'change'))
|
||||
.map(x => x.objectId);
|
||||
if (filterIds.length == 0) {
|
||||
res = res.replace(/=OBJECT_ID_CONDITION/g, ' = 0');
|
||||
} else {
|
||||
res = res.replace(/=OBJECT_ID_CONDITION/g, ` in (${filterIds.join(',')})`);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static createEmptyStructure(): DatabaseInfo {
|
||||
return {
|
||||
tables: [],
|
||||
|
@ -48,43 +48,20 @@ function getColumnInfo({
|
||||
class MsSqlAnalyser extends DatabaseAnalyser {
|
||||
constructor(pool, driver) {
|
||||
super(pool, driver);
|
||||
this.singleObjectId = null;
|
||||
}
|
||||
|
||||
createQuery(resFileName, typeFields) {
|
||||
let res = sql[resFileName];
|
||||
if (this.singleObjectFilter) {
|
||||
const { typeField } = this.singleObjectFilter;
|
||||
if (!this.singleObjectId) return null;
|
||||
if (!typeFields || !typeFields.includes(typeField)) return null;
|
||||
return res.replace('=[OBJECT_ID_CONDITION]', ` = ${this.singleObjectId}`);
|
||||
}
|
||||
if (!this.modifications || !typeFields || this.modifications.length == 0) {
|
||||
res = res.replace('=[OBJECT_ID_CONDITION]', ' is not null');
|
||||
} else {
|
||||
const filterIds = this.modifications
|
||||
.filter((x) => typeFields.includes(x.objectTypeField) && (x.action == 'add' || x.action == 'change'))
|
||||
.map((x) => x.objectId);
|
||||
if (filterIds.length == 0) {
|
||||
res = res.replace('=[OBJECT_ID_CONDITION]', ' = 0');
|
||||
} else {
|
||||
res = res.replace('=[OBJECT_ID_CONDITION]', ` in (${filterIds.join(',')})`);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
return super.createQuery(sql[resFileName], typeFields);
|
||||
}
|
||||
|
||||
async getSingleObjectId() {
|
||||
if (this.singleObjectFilter) {
|
||||
const { schemaName, pureName, typeField } = this.singleObjectFilter;
|
||||
const fullName = schemaName ? `[${schemaName}].[${pureName}]` : pureName;
|
||||
const resId = await this.driver.query(this.pool, `SELECT OBJECT_ID('${fullName}') AS id`);
|
||||
this.singleObjectId = resId.rows[0].id;
|
||||
}
|
||||
async _computeSingleObjectId() {
|
||||
const { schemaName, pureName, typeField } = this.singleObjectFilter;
|
||||
const fullName = schemaName ? `[${schemaName}].[${pureName}]` : pureName;
|
||||
const resId = await this.driver.query(this.pool, `SELECT OBJECT_ID('${fullName}') AS id`);
|
||||
this.singleObjectId = resId.rows[0].id;
|
||||
}
|
||||
|
||||
async _runAnalysis() {
|
||||
await this.getSingleObjectId();
|
||||
const tablesRows = await this.driver.query(this.pool, this.createQuery('tables', ['tables']));
|
||||
const columnsRows = await this.driver.query(this.pool, this.createQuery('columns', ['tables']));
|
||||
const pkColumnsRows = await this.driver.query(this.pool, this.createQuery('primaryKeys', ['tables']));
|
||||
@ -97,10 +74,10 @@ class MsSqlAnalyser extends DatabaseAnalyser {
|
||||
this.pool,
|
||||
this.createQuery('loadSqlCode', ['views', 'procedures', 'functions', 'triggers'])
|
||||
);
|
||||
const getCreateSql = (row) =>
|
||||
const getCreateSql = row =>
|
||||
sqlCodeRows.rows
|
||||
.filter((x) => x.pureName == row.pureName && x.schemaName == row.schemaName)
|
||||
.map((x) => x.codeText)
|
||||
.filter(x => x.pureName == row.pureName && x.schemaName == row.schemaName)
|
||||
.map(x => x.codeText)
|
||||
.join('');
|
||||
const viewsRows = await this.driver.query(this.pool, this.createQuery('views', ['views']));
|
||||
const programmableRows = await this.driver.query(
|
||||
@ -109,29 +86,29 @@ class MsSqlAnalyser extends DatabaseAnalyser {
|
||||
);
|
||||
const viewColumnRows = await this.driver.query(this.pool, this.createQuery('viewColumns', ['views']));
|
||||
|
||||
const tables = tablesRows.rows.map((row) => ({
|
||||
const tables = tablesRows.rows.map(row => ({
|
||||
...row,
|
||||
columns: columnsRows.rows.filter((col) => col.objectId == row.objectId).map(getColumnInfo),
|
||||
columns: columnsRows.rows.filter(col => col.objectId == row.objectId).map(getColumnInfo),
|
||||
primaryKey: DatabaseAnalyser.extractPrimaryKeys(row, pkColumnsRows.rows),
|
||||
foreignKeys: DatabaseAnalyser.extractForeignKeys(row, fkColumnsRows.rows),
|
||||
}));
|
||||
|
||||
const views = viewsRows.rows.map((row) => ({
|
||||
const views = viewsRows.rows.map(row => ({
|
||||
...row,
|
||||
createSql: getCreateSql(row),
|
||||
columns: viewColumnRows.rows.filter((col) => col.objectId == row.objectId).map(getColumnInfo),
|
||||
columns: viewColumnRows.rows.filter(col => col.objectId == row.objectId).map(getColumnInfo),
|
||||
}));
|
||||
|
||||
const procedures = programmableRows.rows
|
||||
.filter((x) => x.sqlObjectType.trim() == 'P')
|
||||
.map((row) => ({
|
||||
.filter(x => x.sqlObjectType.trim() == 'P')
|
||||
.map(row => ({
|
||||
...row,
|
||||
createSql: getCreateSql(row),
|
||||
}));
|
||||
|
||||
const functions = programmableRows.rows
|
||||
.filter((x) => ['FN', 'IF', 'TF'].includes(x.sqlObjectType.trim()))
|
||||
.map((row) => ({
|
||||
.filter(x => ['FN', 'IF', 'TF'].includes(x.sqlObjectType.trim()))
|
||||
.map(row => ({
|
||||
...row,
|
||||
createSql: getCreateSql(row),
|
||||
}));
|
||||
@ -147,8 +124,8 @@ class MsSqlAnalyser extends DatabaseAnalyser {
|
||||
|
||||
getDeletedObjectsForField(idArray, objectTypeField) {
|
||||
return this.structure[objectTypeField]
|
||||
.filter((x) => !idArray.includes(x.objectId))
|
||||
.map((x) => ({
|
||||
.filter(x => !idArray.includes(x.objectId))
|
||||
.map(x => ({
|
||||
oldName: _.pick(x, ['schemaName', 'pureName']),
|
||||
objectId: x.objectId,
|
||||
action: 'remove',
|
||||
@ -173,12 +150,12 @@ class MsSqlAnalyser extends DatabaseAnalyser {
|
||||
// 'MODs',
|
||||
// this.structure.tables.map((x) => x.modifyDate)
|
||||
// );
|
||||
const modifications = modificationsQueryData.rows.map((x) => {
|
||||
const modifications = modificationsQueryData.rows.map(x => {
|
||||
const { type, objectId, modifyDate, schemaName, pureName } = x;
|
||||
const field = objectTypeToField(type);
|
||||
if (!this.structure[field]) return null;
|
||||
// @ts-ignore
|
||||
const obj = this.structure[field].find((x) => x.objectId == objectId);
|
||||
const obj = this.structure[field].find(x => x.objectId == objectId);
|
||||
|
||||
// object not modified
|
||||
if (obj && Math.abs(new Date(modifyDate).getTime() - new Date(obj.modifyDate).getTime()) < 1000) return null;
|
||||
@ -201,7 +178,7 @@ class MsSqlAnalyser extends DatabaseAnalyser {
|
||||
return action;
|
||||
});
|
||||
|
||||
return [..._.compact(modifications), ...this.getDeletedObjects(modificationsQueryData.rows.map((x) => x.objectId))];
|
||||
return [..._.compact(modifications), ...this.getDeletedObjects(modificationsQueryData.rows.map(x => x.objectId))];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,6 @@ INNER JOIN sys.schemas u ON u.schema_id=o.schema_id
|
||||
INNER JOIN INFORMATION_SCHEMA.COLUMNS col ON col.TABLE_NAME = o.name AND col.TABLE_SCHEMA = u.name and col.COLUMN_NAME = c.name
|
||||
left join sys.default_constraints d on c.default_object_id = d.object_id
|
||||
left join sys.computed_columns m on m.object_id = c.object_id and m.column_id = c.column_id
|
||||
where o.type = 'U' and o.object_id =[OBJECT_ID_CONDITION]
|
||||
where o.type = 'U' and o.object_id =OBJECT_ID_CONDITION
|
||||
order by c.column_id
|
||||
`;
|
||||
|
@ -36,5 +36,5 @@ LEFT JOIN sys.schemas IXS ON IXT.schema_id = IXS.schema_id
|
||||
inner join sys.objects o on FK.TABLE_NAME = o.name
|
||||
inner join sys.schemas s on o.schema_id = s.schema_id and FK.TABLE_SCHEMA = s.name
|
||||
|
||||
where o.object_id =[OBJECT_ID_CONDITION]
|
||||
where o.object_id =OBJECT_ID_CONDITION
|
||||
`;
|
||||
|
@ -3,6 +3,6 @@ select s.name as pureName, u.name as schemaName, c.text AS codeText
|
||||
from sys.objects s
|
||||
inner join sys.syscomments c on s.object_id = c.id
|
||||
inner join sys.schemas u on u.schema_id = s.schema_id
|
||||
where (s.object_id =[OBJECT_ID_CONDITION])
|
||||
where (s.object_id =OBJECT_ID_CONDITION)
|
||||
order by u.name, s.name, c.colid
|
||||
`;
|
||||
|
@ -10,5 +10,5 @@ where
|
||||
and o.schema_id = s.schema_id and t.Table_Schema = s.name
|
||||
and c.Table_Name = t.Table_Name
|
||||
and Constraint_Type = 'PRIMARY KEY'
|
||||
and o.object_id =[OBJECT_ID_CONDITION]
|
||||
and o.object_id =OBJECT_ID_CONDITION
|
||||
`;
|
||||
|
@ -2,5 +2,5 @@ module.exports = `
|
||||
select o.name as pureName, s.name as schemaName, o.object_id as objectId, o.create_date as createDate, o.modify_date as modifyDate, o.type as sqlObjectType
|
||||
from sys.objects o
|
||||
inner join sys.schemas s on o.schema_id = s.schema_id
|
||||
where o.type in ('P', 'IF', 'FN', 'TF') and o.object_id =[OBJECT_ID_CONDITION]
|
||||
where o.type in ('P', 'IF', 'FN', 'TF') and o.object_id =OBJECT_ID_CONDITION
|
||||
`;
|
||||
|
@ -4,5 +4,5 @@ select
|
||||
o.create_date as createDate, o.modify_date as modifyDate
|
||||
from sys.tables o
|
||||
inner join sys.schemas s on o.schema_id = s.schema_id
|
||||
where o.object_id =[OBJECT_ID_CONDITION]
|
||||
where o.object_id =OBJECT_ID_CONDITION
|
||||
`;
|
||||
|
@ -13,6 +13,6 @@ select
|
||||
FROM sys.objects o
|
||||
INNER JOIN sys.schemas u ON u.schema_id=o.schema_id
|
||||
INNER JOIN INFORMATION_SCHEMA.COLUMNS col ON col.TABLE_NAME = o.name AND col.TABLE_SCHEMA = u.name
|
||||
WHERE o.type in ('V') and o.object_id =[OBJECT_ID_CONDITION]
|
||||
WHERE o.type in ('V') and o.object_id =OBJECT_ID_CONDITION
|
||||
order by col.ORDINAL_POSITION
|
||||
`;
|
||||
|
@ -6,5 +6,5 @@ SELECT
|
||||
o.create_date as createDate,
|
||||
o.modify_date as modifyDate
|
||||
FROM sys.objects o INNER JOIN sys.schemas u ON u.schema_id=o.schema_id
|
||||
WHERE type in ('V') and o.object_id =[OBJECT_ID_CONDITION]
|
||||
WHERE type in ('V') and o.object_id =OBJECT_ID_CONDITION
|
||||
`;
|
||||
|
@ -42,27 +42,8 @@ class Analyser extends DatabaseAnalyser {
|
||||
|
||||
createQuery(resFileName, typeFields) {
|
||||
let res = sql[resFileName];
|
||||
if (this.singleObjectFilter) {
|
||||
const { typeField, pureName } = this.singleObjectFilter;
|
||||
if (!typeFields || !typeFields.includes(typeField)) return null;
|
||||
res = res.replace('=[OBJECT_ID_CONDITION]', ` = '${pureName}'`).replace('#DATABASE#', this.pool._database_name);
|
||||
return res;
|
||||
}
|
||||
if (!this.modifications || !typeFields || this.modifications.length == 0) {
|
||||
res = res.replace('=[OBJECT_ID_CONDITION]', ' is not null');
|
||||
} else {
|
||||
const filterNames = this.modifications
|
||||
.filter(x => typeFields.includes(x.objectTypeField) && (x.action == 'add' || x.action == 'change'))
|
||||
.map(x => x.newName && x.newName.pureName)
|
||||
.filter(Boolean);
|
||||
if (filterNames.length == 0) {
|
||||
res = res.replace('=[OBJECT_ID_CONDITION]', ' IS NULL');
|
||||
} else {
|
||||
res = res.replace('=[OBJECT_ID_CONDITION]', ` in (${filterNames.map(x => `'${x}'`).join(',')})`);
|
||||
}
|
||||
}
|
||||
res = res.replace('#DATABASE#', this.pool._database_name);
|
||||
return res;
|
||||
return super.createQuery(res, typeFields);
|
||||
}
|
||||
|
||||
getRequestedViewNames(allViewNames) {
|
||||
|
@ -10,6 +10,6 @@ select
|
||||
COLUMN_DEFAULT as defaultValue,
|
||||
EXTRA as extra
|
||||
from INFORMATION_SCHEMA.COLUMNS
|
||||
where TABLE_SCHEMA = '#DATABASE#' and TABLE_NAME =[OBJECT_ID_CONDITION]
|
||||
where TABLE_SCHEMA = '#DATABASE#' and TABLE_NAME =OBJECT_ID_CONDITION
|
||||
order by ORDINAL_POSITION
|
||||
`;
|
||||
|
@ -12,6 +12,6 @@ inner join INFORMATION_SCHEMA.KEY_COLUMN_USAGE
|
||||
on REFERENTIAL_CONSTRAINTS.TABLE_NAME = KEY_COLUMN_USAGE.TABLE_NAME
|
||||
and REFERENTIAL_CONSTRAINTS.CONSTRAINT_NAME = KEY_COLUMN_USAGE.CONSTRAINT_NAME
|
||||
and REFERENTIAL_CONSTRAINTS.CONSTRAINT_SCHEMA = KEY_COLUMN_USAGE.CONSTRAINT_SCHEMA
|
||||
where REFERENTIAL_CONSTRAINTS.CONSTRAINT_SCHEMA = '#DATABASE#' and REFERENTIAL_CONSTRAINTS.TABLE_NAME =[OBJECT_ID_CONDITION]
|
||||
where REFERENTIAL_CONSTRAINTS.CONSTRAINT_SCHEMA = '#DATABASE#' and REFERENTIAL_CONSTRAINTS.TABLE_NAME =OBJECT_ID_CONDITION
|
||||
order by KEY_COLUMN_USAGE.ORDINAL_POSITION
|
||||
`;
|
||||
|
@ -7,6 +7,6 @@ inner join INFORMATION_SCHEMA.KEY_COLUMN_USAGE
|
||||
on TABLE_CONSTRAINTS.TABLE_NAME = KEY_COLUMN_USAGE.TABLE_NAME
|
||||
and TABLE_CONSTRAINTS.CONSTRAINT_NAME = KEY_COLUMN_USAGE.CONSTRAINT_NAME
|
||||
and TABLE_CONSTRAINTS.CONSTRAINT_SCHEMA = KEY_COLUMN_USAGE.CONSTRAINT_SCHEMA
|
||||
where TABLE_CONSTRAINTS.CONSTRAINT_SCHEMA = '#DATABASE#' and TABLE_CONSTRAINTS.TABLE_NAME =[OBJECT_ID_CONDITION] AND TABLE_CONSTRAINTS.CONSTRAINT_TYPE = 'PRIMARY KEY'
|
||||
where TABLE_CONSTRAINTS.CONSTRAINT_SCHEMA = '#DATABASE#' and TABLE_CONSTRAINTS.TABLE_NAME =OBJECT_ID_CONDITION AND TABLE_CONSTRAINTS.CONSTRAINT_TYPE = 'PRIMARY KEY'
|
||||
order by KEY_COLUMN_USAGE.ORDINAL_POSITION
|
||||
`;
|
||||
|
@ -5,5 +5,5 @@ select
|
||||
COALESCE(LAST_ALTERED, CREATED) as modifyDate,
|
||||
ROUTINE_DEFINITION as createSql
|
||||
from information_schema.routines
|
||||
where ROUTINE_SCHEMA = '#DATABASE#' and ROUTINE_NAME =[OBJECT_ID_CONDITION]
|
||||
where ROUTINE_SCHEMA = '#DATABASE#' and ROUTINE_NAME =OBJECT_ID_CONDITION
|
||||
`;
|
||||
|
@ -3,5 +3,5 @@ select
|
||||
TABLE_NAME as pureName,
|
||||
case when ENGINE='InnoDB' then CREATE_TIME else coalesce(UPDATE_TIME, CREATE_TIME) end as modifyDate
|
||||
from information_schema.tables
|
||||
where TABLE_SCHEMA = '#DATABASE#' and TABLE_TYPE='BASE TABLE' and TABLE_NAME =[OBJECT_ID_CONDITION];
|
||||
where TABLE_SCHEMA = '#DATABASE#' and TABLE_TYPE='BASE TABLE' and TABLE_NAME =OBJECT_ID_CONDITION;
|
||||
`;
|
||||
|
@ -3,5 +3,5 @@ select
|
||||
TABLE_NAME as pureName,
|
||||
coalesce(UPDATE_TIME, CREATE_TIME) as modifyDate
|
||||
from information_schema.tables
|
||||
where TABLE_SCHEMA = '#DATABASE#' and TABLE_NAME =[OBJECT_ID_CONDITION] and TABLE_TYPE = 'VIEW';
|
||||
where TABLE_SCHEMA = '#DATABASE#' and TABLE_NAME =OBJECT_ID_CONDITION and TABLE_TYPE = 'VIEW';
|
||||
`;
|
||||
|
@ -41,33 +41,14 @@ class Analyser extends DatabaseAnalyser {
|
||||
}
|
||||
|
||||
createQuery(resFileName, typeFields) {
|
||||
let res = sql[resFileName];
|
||||
|
||||
if (this.singleObjectFilter) {
|
||||
const { typeField, schemaName, pureName } = this.singleObjectFilter;
|
||||
if (!typeFields || !typeFields.includes(typeField)) return null;
|
||||
res = res.replace(/=OBJECT_ID_CONDITION/g, ` = '${typeField}:${schemaName || 'public'}.${pureName}'`);
|
||||
return res;
|
||||
}
|
||||
if (!this.modifications || !typeFields || this.modifications.length == 0) {
|
||||
res = res.replace(/=OBJECT_ID_CONDITION/g, ' is not null');
|
||||
} else {
|
||||
const filterNames = this.modifications
|
||||
.filter(x => typeFields.includes(x.objectTypeField) && (x.action == 'add' || x.action == 'change'))
|
||||
.filter(x => x.newName)
|
||||
.map(x => `${x.objectTypeField}:${x.newName.schemaName}.${x.newName.pureName}`);
|
||||
if (filterNames.length == 0) {
|
||||
res = res.replace(/=OBJECT_ID_CONDITION/g, ' IS NULL');
|
||||
} else {
|
||||
res = res.replace(/=OBJECT_ID_CONDITION/g, ` in (${filterNames.map(x => `'${x}'`).join(',')})`);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
|
||||
// let res = sql[resFileName];
|
||||
// res = res.replace('=[OBJECT_ID_CONDITION]', ' is not null');
|
||||
// return res;
|
||||
return super.createQuery(sql[resFileName], typeFields);
|
||||
}
|
||||
|
||||
async _computeSingleObjectId() {
|
||||
const { typeField, schemaName, pureName } = this.singleObjectFilter;
|
||||
this.singleObjectId = `${typeField}:${schemaName || 'public'}.${pureName}`;
|
||||
}
|
||||
|
||||
async _runAnalysis() {
|
||||
const tables = await this.driver.query(this.pool, this.createQuery('tableModifications', ['tables']));
|
||||
const columns = await this.driver.query(this.pool, this.createQuery('columns', ['tables']));
|
||||
|
Loading…
Reference in New Issue
Block a user