mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-05 13:39:24 +08:00
104 lines
2.9 KiB
TypeScript
104 lines
2.9 KiB
TypeScript
import QueryInterface from './query-interface';
|
|
import { Collection } from '../collection';
|
|
import sqlParser from '../sql-parser';
|
|
|
|
export default class PostgresQueryInterface extends QueryInterface {
|
|
constructor(db) {
|
|
super(db);
|
|
}
|
|
|
|
async collectionTableExists(collection: Collection, options?) {
|
|
const transaction = options?.transaction;
|
|
|
|
const tableName = collection.model.tableName;
|
|
const schema = collection.collectionSchema() || 'public';
|
|
|
|
const sql = `SELECT EXISTS(SELECT 1
|
|
FROM information_schema.tables
|
|
WHERE table_schema = '${schema}'
|
|
AND table_name = '${tableName}')`;
|
|
|
|
const results = await this.db.sequelize.query(sql, { type: 'SELECT', transaction });
|
|
return results[0]['exists'];
|
|
}
|
|
|
|
async listViews() {
|
|
const sql = `
|
|
SELECT viewname as name, definition, schemaname as schema
|
|
FROM pg_views
|
|
WHERE schemaname NOT IN ('pg_catalog', 'information_schema')
|
|
ORDER BY viewname;
|
|
`;
|
|
|
|
return await this.db.sequelize.query(sql, { type: 'SELECT' });
|
|
}
|
|
|
|
async viewColumnUsage(options): Promise<{
|
|
[view_column_name: string]: {
|
|
column_name: string;
|
|
table_name: string;
|
|
table_schema?: string;
|
|
};
|
|
}> {
|
|
const { viewName, schema = 'public' } = options;
|
|
const sql = `
|
|
SELECT *
|
|
FROM information_schema.view_column_usage
|
|
WHERE view_schema = '${schema}'
|
|
AND view_name = '${viewName}';
|
|
`;
|
|
|
|
const columnUsages = (await this.db.sequelize.query(sql, { type: 'SELECT' })) as Array<{
|
|
column_name: string;
|
|
table_name: string;
|
|
table_schema: string;
|
|
}>;
|
|
|
|
const viewDefQuery = await this.db.sequelize.query(
|
|
`
|
|
select pg_get_viewdef(format('%I.%I', '${schema}', '${viewName}')::regclass, true) as definition
|
|
`,
|
|
{ type: 'SELECT' },
|
|
);
|
|
|
|
const def = viewDefQuery[0]['definition'];
|
|
try {
|
|
const { ast } = sqlParser.parse(def);
|
|
const columns = ast[0].columns;
|
|
|
|
const usages = columns
|
|
.map((column) => {
|
|
const fieldAlias = column.as || column.expr.column;
|
|
const columnUsage = columnUsages.find((columnUsage) => {
|
|
let columnExprTable = column.expr.table;
|
|
|
|
// handle column alias
|
|
const from = ast[0].from;
|
|
const findAs = from.find((from) => from.as === columnExprTable);
|
|
|
|
if (findAs) {
|
|
columnExprTable = findAs.table;
|
|
}
|
|
|
|
return columnUsage.column_name === column.expr.column && columnUsage.table_name === columnExprTable;
|
|
});
|
|
|
|
return [
|
|
fieldAlias,
|
|
columnUsage
|
|
? {
|
|
...columnUsage,
|
|
}
|
|
: null,
|
|
];
|
|
})
|
|
.filter(([, columnUsage]) => columnUsage !== null);
|
|
|
|
return Object.fromEntries(usages);
|
|
} catch (e) {
|
|
this.db.logger.warn(e);
|
|
return {};
|
|
}
|
|
}
|
|
}
|