Last active
November 10, 2019 13:59
-
-
Save stepankuzmin/bb46449c6f3f1553c1f58be7b2a65e9e to your computer and use it in GitHub Desktop.
Expand PostgreSQL hstore columns into plain columns with NodeJS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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