import * as path from 'path' ; import { promisify } from 'util' ; import { exec as rawExec } from 'child_process' ; const exec = promisify ( rawExec ) ; import Knex from 'knex' ; import _ from 'lodash' ; import { SigningWallet } from '../models/signing-wallet' ; import { Channel } from '../models/channel' ; import { Nonce } from '../models/nonce' ; import { ObjectiveModel , ObjectiveChannelModel } from '../models/objective' ; import { Funding } from '../models/funding' ; import { AppBytecode } from '../models/app-bytecode' ; import { LedgerRequest } from '../models/ledger-request' ; import { ChainServiceRequest } from '../models/chain-service-request' ; import { AdjudicatorStatusModel } from '../models/adjudicator-status' ; import { defaultConfig , extractDBConfigFromWalletConfig , getDatabaseConnectionConfig , IncomingWalletConfig , } from '../config' ; type DBConnectionConfig = { database : string ; user : string ; } ; /**
 * A collection of static utility methods for db admin
 */ export class DBAdmin { param config static async createDatabase ( config ) { await createDbIfDoesntExist ( getDbConnectionConfigFromConfig ( config ) ) ; } param knex static async createDatabaseFromKnex ( knex ) { await createDbIfDoesntExist ( getDbConnectionConfigFromKnex ( knex ) ) ; } param config static async dropDatabase ( config ) { await dropDbIfExists ( getDbConnectionConfigFromConfig ( config ) ) ; } param knex static async dropDatabaseFromKnex ( knex ) { await dropDbIfExists ( getDbConnectionConfigFromKnex ( knex ) ) ; } param config static async migrateDatabase ( config ) { const knex = getKnexFromConfig ( config ) ; await DBAdmin . migrateDatabaseFromKnex ( knex ) ; await knex . destroy ( ) ; } param knex static async migrateDatabaseFromKnex ( knex ) { const extensions = [ path . extname ( __filename ) ] ; return knex . migrate . latest ( { directory : path . join ( __dirname , '../db/migrations' ) , loadExtensions : extensions , } ) ; } param config param tables static async truncateDatabase ( config , tables = defaultTables ) { const knex = getKnexFromConfig ( config ) ; await DBAdmin . truncateDataBaseFromKnex ( knex , tables ) ; await knex . destroy ( ) ; } param knex param tables static async truncateDataBaseFromKnex ( knex , tables = defaultTables ) { if ( process . env . NODE_ENV !== 'development' && process . env . NODE_ENV !== 'test' ) { throw 'Cannot truncate unless in test or development environments' ; } await Promise . all ( tables . map ( async ( table ) => { try { await knex . raw ( `TRUNCATE TABLE ${ table } CASCADE;` ) ; } catch ( e ) { console . log ( `Error truncating ${ table }: ${ e }` ) ; } } ) ) ; } } export function getKnexFromConfig ( config ) { const populatedConfig = _ . assign ( { } , defaultConfig , config ) ; return Knex ( extractDBConfigFromWalletConfig ( populatedConfig ) ) ; } function getDbConnectionConfigFromKnex ( knex ) { const { database , user } = knex . client . config . connection ; return { database , user } ; } function getDbConnectionConfigFromConfig ( config ) { const populatedConfig = _ . assign ( { } , defaultConfig , config ) ; const { database , user } = getDatabaseConnectionConfig ( populatedConfig ) ; return { database , user } ; } async function createDbIfDoesntExist ( config ) { try { await exec ( `createdb ${ config . database } -U ${ config . user } $PSQL_ARGS` ) ; } catch ( e ) { if ( ! ( e . stderr && e . stderr . includes ( ' already exists' ) ) ) { throw e ; } } } async function dropDbIfExists ( config ) { await exec ( `dropdb ${ config . database } -U ${ config . user } --if-exists $PSQL_ARGS` ) ; } const defaultTables = [ SigningWallet , Channel , Nonce , ObjectiveModel , ObjectiveChannelModel , Funding , AppBytecode , LedgerRequest , Funding , AdjudicatorStatusModel , ChainServiceRequest , ] . map ( model => model . tableName ) ;