nocobase/packages/core/database/src/query-interface/postgres-query-interface.ts
ChengLei Shao 86abc251d9
fix: get pg view def (#1641)
* fix: get pg view def

* chore: console.log
2023-04-02 22:50:55 +08:00

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 {};
}
}
}