src/middleware/Database.js
// Import the necessary modules.
// @flow
import mongoose from 'mongoose'
import { existsSync } from 'fs'
import {
isAbsolute,
join
} from 'path'
import { URL } from 'url'
import { executeCommand } from '../utils'
/**
* Class for setting up a database connection.
* @type {Database}
*/
export default class Database {
/**
* The name of the database. Default is the package name with the
* environment mode.
* @type {string}
*/
database: string
/**
* The host of the server of the database. Default is `['localhost']`.
* @type {Array<string>}
*/
hosts: Array<string>
/**
* The port of the database. Default is `27017`.
* @type {string}
*/
dbPort: number
/**
* The username of the database. By default this is left empty.
* @type {string}
*/
username: string
/**
* The password of the database. By default this is left empty.
* @type {string}
*/
password: string
/**
* Create a new Database object.
* @param {!PopApi} PopApi - The PopApi instance to bind the database to.
* @param {!Object} options - The options for the database.
* @param {!string} options.database - The arguments to be parsed by
* @param {!Array<string>} [options.hosts=['localhost']] - The hosts for the
* database connection.
* @param {!number} [options.dbPort=27017] - The port for the database
* connection.
* @param {?string} [options.username] - The username for the database
* connection.
* @param {?string} [options.password] - The password for the database
* connection.
* @throws {TypeError} - 'database' is a required option for the Database
* middleware!
*/
constructor(PopApi: any, {
database,
hosts = ['localhost'],
dbPort = 27017,
username,
password
}: Object): void {
const { name: debugName } = this.constructor
PopApi.debug(`Registering ${debugName} middleware with options: %o`, {
database,
hosts,
dbPort,
username,
password
})
if (!database) {
throw new TypeError('\'database\' is a required option for the Database middleware!')
}
process.env.NODE_ENV = process.env.NODE_ENV || 'development'
const {
MONGO_PORT_27017_TCP_ADDR,
MONGO_PORT_27017_TCP_PORT,
NODE_ENV
} = process.env
this.database = `${database}-${NODE_ENV}`
this.hosts = MONGO_PORT_27017_TCP_ADDR
? [MONGO_PORT_27017_TCP_ADDR]
: hosts
this.dbPort = Number(MONGO_PORT_27017_TCP_PORT) || dbPort
this.username = username || ''
this.password = password || ''
PopApi.database = this
}
/**
* Connection and configuration of the database.
* @returns {Promise<undefined, Error>} - The promise to connect to the
* database.
*/
connect(): Promise<void> {
const uri = new URL(`mongodb://${this.username}:${this.password}@${this.hosts.join(',')}:${this.dbPort}/${this.database}`)
return mongoose.connect(uri.href)
}
/**
* Disconnect from the database.
* @returns {Promise<undefined, Error>} - The promise to disconnect from
* the database.
*/
disconnect(): Promise<void> {
return mongoose.disconnect()
}
/**
* Export a JSON file collection.
* @param {!string} collection - The collection to export.
* @param {!string} outputFile - The path of the output file of the export.
* @returns {Promise<string, undefined>} - The promise to export a
* collection.
*/
exportFile(
collection: string,
outputFile: string
): Promise<string | void> {
return executeCommand('mongoexport', [
'-d', this.database,
'-c', `${collection}s`,
'-o', outputFile
])
}
/**
* Import a JSON file collection.
* @param {!string} collection - The collection to import.
* @param {!string} jsonFile - The JSON file to import.
* @returns {Promise<string, undefined>} - The promise to import a
* collection.
*/
importFile(
collection: string,
jsonFile: string
): Promise<string | void> {
const file = !isAbsolute(jsonFile)
? jsonFile
: join(...[__dirname, '..', '..', jsonFile])
if (!existsSync(file)) {
const err = new Error(`no such file found for '${file}'`)
return Promise.reject(err)
}
return executeCommand('mongoimport', [
'-d', this.database,
'-c', `${collection}s`,
'--file', jsonFile,
'--upsert'
])
}
}