feat(PostgreSQL): export user-defined types before tables

This commit is contained in:
Fabio Di Stasio 2022-03-22 12:40:14 +01:00
parent a67071e284
commit bb02479b71
2 changed files with 71 additions and 16 deletions

View File

@ -17,11 +17,13 @@ SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0; SET idle_in_transaction_session_timeout = 0;
SET client_encoding = 'UTF8'; SET client_encoding = 'UTF8';
SET standard_conforming_strings = on; SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false); -- SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false; SET check_function_bodies = false;
SET xmloption = content; SET xmloption = content;
SET client_min_messages = warning; SET client_min_messages = warning;
SET row_security = off;`; SET row_security = off;\n\n\n`;
dump += await this.getTypes();
return dump; return dump;
} }
@ -30,6 +32,15 @@ SET row_security = off;`;
let createSql = ''; let createSql = '';
const sequences = []; const sequences = [];
const columnsSql = []; const columnsSql = [];
const arrayTypes = {
_int2: 'smallint',
_int4: 'integer',
_int8: 'bigint',
_float4: 'real',
_float8: 'double precision',
_char: '"char"',
_varchar: 'character varying'
};
// Table columns // Table columns
const { rows } = await this._client const { rows } = await this._client
@ -43,9 +54,18 @@ SET row_security = off;`;
if (!rows.length) return ''; if (!rows.length) return '';
for (const column of rows) { for (const column of rows) {
let fieldType = column.data_type;
if (fieldType === 'USER-DEFINED') fieldType = column.udt_name;
else if (fieldType === 'ARRAY') {
if (Object.keys(arrayTypes).includes(fieldType))
fieldType = arrayTypes[type] + '[]';
else
fieldType = column.udt_name.replaceAll('_', '') + '[]';
}
const columnArr = [ const columnArr = [
`"${column.column_name}"`, `"${column.column_name}"`,
`${column.data_type}${column.character_maximum_length ? `(${column.character_maximum_length})` : ''}` `${fieldType}${column.character_maximum_length ? `(${column.character_maximum_length})` : ''}`
]; ];
if (column.column_default) { if (column.column_default) {
@ -71,25 +91,26 @@ SET row_security = off;`;
.run(); .run();
if (rows.length) { if (rows.length) {
createSql += `CREATE SEQUENCE "${this.schemaName}"."${sequence}" createSql += `CREATE SEQUENCE "${sequence}"
START WITH ${rows[0].start_value} START WITH ${rows[0].start_value}
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`;
createSql += `\nALTER TABLE "${this.schemaName}"."${sequence}" OWNER TO ${this._client._params.user};\n\n`; // createSql += `\nALTER TABLE "${sequence}" OWNER TO ${this._client._params.user};\n\n`;
} }
} }
// Table create // Table create
createSql += `CREATE TABLE "${this.schemaName}"."${tableName}"( createSql += `\nCREATE TABLE "${tableName}"(
${columnsSql.join(',\n ')} ${columnsSql.join(',\n ')}
);\n`; );\n`;
createSql += `\nALTER TABLE "${this.schemaName}"."${tableName}" OWNER TO ${this._client._params.user};\n\n`; // createSql += `\nALTER TABLE "${tableName}" OWNER TO ${this._client._params.user};\n\n`;
// Table indexes // Table indexes
createSql += '\n';
const { rows: indexes } = await this._client const { rows: indexes } = await this._client
.select('*') .select('*')
.schema('pg_catalog') .schema('pg_catalog')
@ -126,7 +147,7 @@ SET row_security = off;`;
`); `);
for (const foreign of foreigns) { for (const foreign of foreigns) {
createSql += `\nALTER TABLE ONLY "${this.schemaName}"."${tableName}" createSql += `\nALTER TABLE ONLY "${tableName}"
ADD CONSTRAINT "${foreign.constraint_name}" FOREIGN KEY ("${foreign.column_name}") REFERENCES "${foreign.table_schema}"."${foreign.table_name}" ("${foreign.foreign_column_name}") ON UPDATE ${foreign.update_rule} ON DELETE ${foreign.delete_rule};\n`; ADD CONSTRAINT "${foreign.constraint_name}" FOREIGN KEY ("${foreign.column_name}") REFERENCES "${foreign.table_schema}"."${foreign.table_name}" ("${foreign.foreign_column_name}") ON UPDATE ${foreign.update_rule} ON DELETE ${foreign.delete_rule};\n`;
} }
@ -141,7 +162,7 @@ SET row_security = off;`;
let rowCount = 0; let rowCount = 0;
let sqlStr = ''; let sqlStr = '';
const countResults = await this._client.raw(`SELECT COUNT(1) as count FROM "${this.schemaName}"."${tableName}"`); const countResults = await this._client.raw(`SELECT COUNT(1) as count FROM "${tableName}"`);
if (countResults.rows.length === 1) rowCount = countResults.rows[0].count; if (countResults.rows.length === 1) rowCount = countResults.rows[0].count;
if (rowCount > 0) { if (rowCount > 0) {
@ -159,7 +180,7 @@ SET row_security = off;`;
yield sqlStr; yield sqlStr;
const stream = await this._queryStream( const stream = await this._queryStream(
`SELECT ${columnNames} FROM "${this.schemaName}"."${tableName}"` `SELECT ${columnNames} FROM "${tableName}"`
); );
for await (const row of stream) { for await (const row of stream) {
@ -169,7 +190,7 @@ SET row_security = off;`;
return; return;
} }
let sqlInsertString = `\nINSERT INTO "${tableName}" (${columnNames}) VALUES`; let sqlInsertString = `INSERT INTO "${tableName}" (${columnNames}) VALUES`;
if ( if (
(sqlInsertDivider === 'bytes' && queryLength >= sqlInsertAfter * 1024) || (sqlInsertDivider === 'bytes' && queryLength >= sqlInsertAfter * 1024) ||
@ -238,7 +259,7 @@ SET row_security = off;`;
sqlInsertString += ', '; sqlInsertString += ', ';
} }
sqlInsertString += ');'; sqlInsertString += ');\n';
queryLength += sqlInsertString.length; queryLength += sqlInsertString.length;
rowsWritten++; rowsWritten++;
@ -251,15 +272,49 @@ SET row_security = off;`;
} }
} }
async getTypes () {
let sqlString = '';
const { rows: types } = await this._client.raw(`
SELECT pg_type.typname, pg_enum.enumlabel
FROM pg_type
JOIN pg_enum ON pg_enum.enumtypid = pg_type.oid;
`);
if (types.length) { // TODO: refactor
sqlString += this.buildComment('Dump of types\n------------------------------------------------------------') + '\n\n';
const typesArr = types.reduce((arr, type) => {
if (arr.every(el => el.name !== type.typname))
arr.push({ name: type.typname, enums: [this.escapeAndQuote(type.enumlabel)] });
else {
const i = arr.findIndex(el => el.name === type.typname);
arr[i].enums.push(this.escapeAndQuote(type.enumlabel));
}
return arr;
}, []);
for (const type of typesArr) {
sqlString += `CREATE TYPE "${type.name}" AS ENUM (
${type.enums.join(',\n\t')}
);`;
}
// sqlString += `\nALTER TYPE "${tableName}" OWNER TO ${this._client._params.user};\n`
}
return sqlString;
}
async getViews () { async getViews () {
const { rows: views } = await this._client.raw( const { rows: views } = await this._client.raw(
`SHOW TABLE STATUS FROM \`${this.schemaName}\` WHERE Comment = 'VIEW'` `SELECT * FROM "pg_views" WHERE "schemaname"='${this.schemaName}'`
); );
let sqlString = ''; let sqlString = '';
for (const view of views) { for (const view of views) {
sqlString += `DROP VIEW IF EXISTS \`${view.Name}\`;\n`; sqlString += `DROP VIEW IF EXISTS '${view.viewname}';\n`;
const viewSyntax = await this.getCreateTable(view.Name); const viewSyntax = await this.getCreateTable(view.viewname);
sqlString += viewSyntax.replaceAll('`' + this.schemaName + '`.', ''); sqlString += viewSyntax.replaceAll('`' + this.schemaName + '`.', '');
sqlString += '\n'; sqlString += '\n';
} }

View File

@ -1,7 +1,7 @@
import fs from 'fs'; import fs from 'fs';
import { ClientsFactory } from '../libs/ClientsFactory'; import { ClientsFactory } from '../libs/ClientsFactory';
import MysqlExporter from '../libs/exporters/sql/MysqlExporter.js'; import MysqlExporter from '../libs/exporters/sql/MysqlExporter.js';
import PostgreSQLExporter from '../libs/exporters/sql/PostgresqlExporter'; import PostgreSQLExporter from '../libs/exporters/sql/PostgreSQLExporter';
let exporter; let exporter;
process.on('message', async ({ type, client, tables, options }) => { process.on('message', async ({ type, client, tables, options }) => {