Skip to content

Instantly share code, notes, and snippets.

@stepankuzmin
Last active November 10, 2019 13:59
Show Gist options
  • Save stepankuzmin/bb46449c6f3f1553c1f58be7b2a65e9e to your computer and use it in GitHub Desktop.
Save stepankuzmin/bb46449c6f3f1553c1f58be7b2a65e9e to your computer and use it in GitHub Desktop.
Expand PostgreSQL hstore columns into plain columns with NodeJS
const { Pool, Client } = require('pg');
const groupBy = require('lodash.groupby');
const pool = new Pool({
host: 'localhost',
database: 'db'
});
const oldPoolQuery = pool.query;
pool.query = (...args) => {
console.log('QUERY:', args.join());
return oldPoolQuery.apply(pool, args);
};
const selectColumns = (table) =>
`SELECT column_name, udt_name FROM information_schema.columns WHERE table_name = '${table}'`;
const selectHstoreKeys = (table, column) =>
`select distinct skeys(${column}) from ${table};`;
const groupByType = (columns) => {
const { true: hstoreColumns, false: otherColumns } = groupBy(
columns,
(c) => c.udt_name === 'hstore'
);
return { hstoreColumns, otherColumns };
};
const createNewTable = async (table) => {
const { rows: columns } = await pool.query(selectColumns(table));
const { hstoreColumns, otherColumns } = groupByType(columns);
const skeys = await Promise.all(
hstoreColumns.map(({ column_name }) => {
return pool.query(selectHstoreKeys(table, column_name)).then(({ rows }) => rows);
})
);
const hstoreColumnsSelector = hstoreColumns
.map(({ column_name }, index) => {
const keys = skeys[index];
return keys.map(
({ skeys: key }) => `${column_name}->'${key}' as ${column_name}_${key}`
);
})
.reduce((acc, expandedColumns) => acc.concat(expandedColumns), []);
const otherColumnsSelector = otherColumns.map(({ column_name }) => column_name);
const allColumns = [...otherColumnsSelector, ...hstoreColumnsSelector].join(',\n');
const selectStatement = `select \n${allColumns} from ${table}`;
const createViewStatement = `create or replace view ${table}_plain as ${selectStatement}`;
await pool.query(createViewStatement);
};
const main = async (tables = []) => {
await Promise.all(tables.map((table) => createNewTable(table)));
await pool.end();
};
const tables = [];
try {
main(tables);
} catch (error) {
console.error(error);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment