mirror of
https://github.com/Fabio286/antares.git
synced 2025-06-05 21:59:22 +02:00
fix(PostgreSQL): issue exporting tables with primary keys
This commit is contained in:
@ -251,7 +251,7 @@ export default (connections: Record<string, antares.Client>) => {
|
|||||||
setTimeout(() => { // Ensures that writing thread has finished
|
setTimeout(() => { // Ensures that writing thread has finished
|
||||||
exporter?.terminate();
|
exporter?.terminate();
|
||||||
exporter = null;
|
exporter = null;
|
||||||
}, 2000);
|
}, 500);
|
||||||
resolve({ status: 'success', response: payload });
|
resolve({ status: 'success', response: payload });
|
||||||
break;
|
break;
|
||||||
case 'cancel':
|
case 'cancel':
|
||||||
|
@ -591,8 +591,8 @@ export class PostgreSQLClient extends BaseClient {
|
|||||||
}
|
}
|
||||||
/* eslint-enable camelcase */
|
/* eslint-enable camelcase */
|
||||||
|
|
||||||
if (schema !== 'public')
|
// if (schema !== 'public')
|
||||||
await this.use(schema);
|
await this.use(schema);
|
||||||
|
|
||||||
const { rows } = await this.raw<antares.QueryResult<ShowIntexesResult>>(`WITH ndx_list AS (
|
const { rows } = await this.raw<antares.QueryResult<ShowIntexesResult>>(`WITH ndx_list AS (
|
||||||
SELECT pg_index.indexrelid, pg_class.oid
|
SELECT pg_index.indexrelid, pg_class.oid
|
||||||
@ -636,35 +636,7 @@ export class PostgreSQLClient extends BaseClient {
|
|||||||
}, {} as {table: string; schema: string}[]);
|
}, {} as {table: string; schema: string}[]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
async getTableDll ({ schema, table }: { schema: string; table: string }) {
|
async getTableDll ({ schema, table }: { schema: string; table: string }) {
|
||||||
// const { rows } = await this.raw<antares.QueryResult<{'ddl'?: string}>>(`
|
|
||||||
// SELECT
|
|
||||||
// 'CREATE TABLE ' || relname || E'\n(\n' ||
|
|
||||||
// array_to_string(
|
|
||||||
// array_agg(' ' || column_name || ' ' || type || ' '|| not_null)
|
|
||||||
// , E',\n'
|
|
||||||
// ) || E'\n);\n' AS ddl
|
|
||||||
// FROM (
|
|
||||||
// SELECT
|
|
||||||
// a.attname AS column_name
|
|
||||||
// , pg_catalog.format_type(a.atttypid, a.atttypmod) AS type
|
|
||||||
// , CASE WHEN a.attnotnull THEN 'NOT NULL' ELSE 'NULL' END AS not_null
|
|
||||||
// , c.relname
|
|
||||||
// FROM pg_attribute a, pg_class c, pg_type t
|
|
||||||
// WHERE a.attnum > 0
|
|
||||||
// AND a.attrelid = c.oid
|
|
||||||
// AND a.atttypid = t.oid
|
|
||||||
// AND c.relname = '${table}'
|
|
||||||
// ORDER BY a.attnum
|
|
||||||
// ) AS tabledefinition
|
|
||||||
// GROUP BY relname
|
|
||||||
// `);
|
|
||||||
|
|
||||||
// if (rows.length)
|
|
||||||
// return rows[0].ddl;
|
|
||||||
// else return '';
|
|
||||||
|
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
interface SequenceRecord {
|
interface SequenceRecord {
|
||||||
sequence_catalog: string;
|
sequence_catalog: string;
|
||||||
@ -706,6 +678,34 @@ export class PostgreSQLClient extends BaseClient {
|
|||||||
|
|
||||||
if (!rows.length) return '';
|
if (!rows.length) return '';
|
||||||
|
|
||||||
|
const indexes = await this.getTableIndexes({ schema, table });
|
||||||
|
const primaryKey = indexes
|
||||||
|
.filter(i => i.type === 'PRIMARY')
|
||||||
|
.reduce((acc, cur) => {
|
||||||
|
if (!Object.keys(acc).length) {
|
||||||
|
cur.column = `"${cur.column}"`;
|
||||||
|
acc = cur;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
acc.column += `, "${cur.column}"`;
|
||||||
|
return acc;
|
||||||
|
}, {} as { name: string; column: string; type: string});
|
||||||
|
|
||||||
|
const remappedIndexes = indexes
|
||||||
|
.filter(i => i.type !== 'PRIMARY')
|
||||||
|
.reduce((acc, cur) => {
|
||||||
|
const existingIndex = acc.findIndex(i => i.name === cur.name);
|
||||||
|
|
||||||
|
if (existingIndex >= 0)
|
||||||
|
acc[existingIndex].column += `, "${cur.column}"`;
|
||||||
|
else {
|
||||||
|
cur.column = `"${cur.column}"`;
|
||||||
|
acc.push(cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, [] as { name: string; column: string; type: string}[]);
|
||||||
|
|
||||||
for (const column of rows) {
|
for (const column of rows) {
|
||||||
let fieldType = column.data_type;
|
let fieldType = column.data_type;
|
||||||
if (fieldType === 'USER-DEFINED') fieldType = `"${schema}".${column.udt_name}`;
|
if (fieldType === 'USER-DEFINED') fieldType = `"${schema}".${column.udt_name}`;
|
||||||
@ -733,6 +733,9 @@ export class PostgreSQLClient extends BaseClient {
|
|||||||
columnsSql.push(columnArr.join(' '));
|
columnsSql.push(columnArr.join(' '));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (primaryKey)
|
||||||
|
columnsSql.push(`CONSTRAINT "${primaryKey.name}" PRIMARY KEY (${primaryKey.column})`);
|
||||||
|
|
||||||
// Table sequences
|
// Table sequences
|
||||||
for (let sequence of sequences) {
|
for (let sequence of sequences) {
|
||||||
if (sequence.includes('.')) sequence = sequence.split('.')[1];
|
if (sequence.includes('.')) sequence = sequence.split('.')[1];
|
||||||
@ -749,25 +752,22 @@ export class PostgreSQLClient extends BaseClient {
|
|||||||
INCREMENT BY ${rows[0].increment}
|
INCREMENT BY ${rows[0].increment}
|
||||||
MINVALUE ${rows[0].minimum_value}
|
MINVALUE ${rows[0].minimum_value}
|
||||||
MAXVALUE ${rows[0].maximum_value}
|
MAXVALUE ${rows[0].maximum_value}
|
||||||
CACHE 1;\n`;
|
CACHE 1;\n\n`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Table create
|
// Table create
|
||||||
createSql += `\nCREATE TABLE "${schema}"."${table}"(
|
createSql += `CREATE TABLE "${schema}"."${table}"(
|
||||||
${columnsSql.join(',\n ')}
|
${columnsSql.join(',\n ')}
|
||||||
);\n`;
|
);\n`;
|
||||||
|
|
||||||
// Table indexes
|
// Table indexes
|
||||||
createSql += '\n';
|
createSql += '\n';
|
||||||
const { rows: indexes } = await this.select('*')
|
|
||||||
.schema('pg_catalog')
|
|
||||||
.from('pg_indexes')
|
|
||||||
.where({ schemaname: `= '${schema}'`, tablename: `= '${table}'` })
|
|
||||||
.run<{indexdef: string}>();
|
|
||||||
|
|
||||||
for (const index of indexes)
|
for (const index of remappedIndexes) {
|
||||||
createSql += `${index.indexdef};\n`;
|
if (index.type !== 'PRIMARY')
|
||||||
|
createSql += `CREATE ${index.type}${index.type === 'UNIQUE' ? ' INDEX' : ''} "${index.name}" ON "${schema}"."${table}" (${index.column});\n`;
|
||||||
|
}
|
||||||
|
|
||||||
return createSql;
|
return createSql;
|
||||||
}
|
}
|
||||||
|
@ -336,7 +336,8 @@ CREATE TABLE \`${view.Name}\`(
|
|||||||
const connection = await this._client.getConnection();
|
const connection = await this._client.getConnection();
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const stream = (connection as any).connection.query(sql).stream();
|
const stream = (connection as any).connection.query(sql).stream();
|
||||||
const dispose = () => connection.end();
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
const dispose = () => (connection as any).release();
|
||||||
|
|
||||||
stream.on('end', dispose);
|
stream.on('end', dispose);
|
||||||
stream.on('error', dispose);
|
stream.on('error', dispose);
|
||||||
|
@ -39,115 +39,7 @@ SET row_security = off;\n\n\n`;
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getCreateTable (tableName: string) {
|
async getCreateTable (tableName: string) {
|
||||||
/* eslint-disable camelcase */
|
const createSql = await this._client.getTableDll({ schema: this.schemaName, table: tableName });
|
||||||
interface SequenceRecord {
|
|
||||||
sequence_catalog: string;
|
|
||||||
sequence_schema: string;
|
|
||||||
sequence_name: string;
|
|
||||||
data_type: string;
|
|
||||||
numeric_precision: number;
|
|
||||||
numeric_precision_radix: number;
|
|
||||||
numeric_scale: number;
|
|
||||||
start_value: string;
|
|
||||||
minimum_value: string;
|
|
||||||
maximum_value: string;
|
|
||||||
increment: string;
|
|
||||||
cycle_option: string;
|
|
||||||
}
|
|
||||||
/* eslint-enable camelcase */
|
|
||||||
|
|
||||||
let createSql = '';
|
|
||||||
const sequences = [];
|
|
||||||
const columnsSql = [];
|
|
||||||
const arrayTypes: Record<string, string> = {
|
|
||||||
_int2: 'smallint',
|
|
||||||
_int4: 'integer',
|
|
||||||
_int8: 'bigint',
|
|
||||||
_float4: 'real',
|
|
||||||
_float8: 'double precision',
|
|
||||||
_char: '"char"',
|
|
||||||
_varchar: 'character varying'
|
|
||||||
};
|
|
||||||
|
|
||||||
// Table columns
|
|
||||||
const { rows } = await this._client.raw(`
|
|
||||||
SELECT *
|
|
||||||
FROM "information_schema"."columns"
|
|
||||||
WHERE "table_schema" = '${this.schemaName}'
|
|
||||||
AND "table_name" = '${tableName}'
|
|
||||||
ORDER BY "ordinal_position" ASC
|
|
||||||
`, { schema: 'information_schema' });
|
|
||||||
|
|
||||||
if (!rows.length) return '';
|
|
||||||
|
|
||||||
for (const column of rows) {
|
|
||||||
let fieldType = column.data_type;
|
|
||||||
if (fieldType === 'USER-DEFINED') fieldType = `"${this.schemaName}".${column.udt_name}`;
|
|
||||||
else if (fieldType === 'ARRAY') {
|
|
||||||
if (Object.keys(arrayTypes).includes(fieldType))
|
|
||||||
fieldType = arrayTypes[column.udt_name] + '[]';
|
|
||||||
else
|
|
||||||
fieldType = column.udt_name.replaceAll('_', '') + '[]';
|
|
||||||
}
|
|
||||||
|
|
||||||
const columnArr = [
|
|
||||||
`"${column.column_name}"`,
|
|
||||||
`${fieldType}${column.character_maximum_length ? `(${column.character_maximum_length})` : ''}`
|
|
||||||
];
|
|
||||||
|
|
||||||
if (column.column_default) {
|
|
||||||
columnArr.push(`DEFAULT ${column.column_default}`);
|
|
||||||
if (column.column_default.includes('nextval')) {
|
|
||||||
const sequenceName = column.column_default.split('\'')[1];
|
|
||||||
sequences.push(sequenceName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (column.is_nullable === 'NO') columnArr.push('NOT NULL');
|
|
||||||
|
|
||||||
columnsSql.push(columnArr.join(' '));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Table sequences
|
|
||||||
for (let sequence of sequences) {
|
|
||||||
if (sequence.includes('.')) sequence = sequence.split('.')[1];
|
|
||||||
|
|
||||||
const { rows } = await this._client
|
|
||||||
.select('*')
|
|
||||||
.schema('information_schema')
|
|
||||||
.from('sequences')
|
|
||||||
.where({ sequence_schema: `= '${this.schemaName}'`, sequence_name: `= '${sequence}'` })
|
|
||||||
.run<SequenceRecord>();
|
|
||||||
|
|
||||||
if (rows.length) {
|
|
||||||
createSql += `CREATE SEQUENCE "${this.schemaName}"."${sequence}"
|
|
||||||
START WITH ${rows[0].start_value}
|
|
||||||
INCREMENT BY ${rows[0].increment}
|
|
||||||
MINVALUE ${rows[0].minimum_value}
|
|
||||||
MAXVALUE ${rows[0].maximum_value}
|
|
||||||
CACHE 1;\n`;
|
|
||||||
|
|
||||||
// createSql += `\nALTER TABLE "${sequence}" OWNER TO ${this._client._params.user};\n\n`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Table create
|
|
||||||
createSql += `\nCREATE TABLE "${this.schemaName}"."${tableName}"(
|
|
||||||
${columnsSql.join(',\n ')}
|
|
||||||
);\n`;
|
|
||||||
|
|
||||||
// createSql += `\nALTER TABLE "${tableName}" OWNER TO ${this._client._params.user};\n\n`;
|
|
||||||
|
|
||||||
// Table indexes
|
|
||||||
createSql += '\n';
|
|
||||||
const { rows: indexes } = await this._client
|
|
||||||
.select('*')
|
|
||||||
.schema('pg_catalog')
|
|
||||||
.from('pg_indexes')
|
|
||||||
.where({ schemaname: `= '${this.schemaName}'`, tablename: `= '${tableName}'` })
|
|
||||||
.run<{indexdef: string}>();
|
|
||||||
|
|
||||||
for (const index of indexes)
|
|
||||||
createSql += `${index.indexdef};\n`;
|
|
||||||
|
|
||||||
// Table foreigns
|
// Table foreigns
|
||||||
const { rows: foreigns } = await this._client.raw(`
|
const { rows: foreigns } = await this._client.raw(`
|
||||||
|
@ -380,6 +380,7 @@ const startExport = async () => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const { status, response } = await Schema.export(params);
|
const { status, response } = await Schema.export(params);
|
||||||
|
|
||||||
if (status === 'success')
|
if (status === 'success')
|
||||||
progressStatus.value = response.cancelled ? t('general.aborted') : t('general.completed');
|
progressStatus.value = response.cancelled ? t('general.aborted') : t('general.completed');
|
||||||
else {
|
else {
|
||||||
|
Reference in New Issue
Block a user