mongo-utils
Version:
Friendly interface to mongodump and mongorestore commands.
125 lines (108 loc) • 4.87 kB
text/coffeescript
{exec} = require('child_process')
parseURL = require('url').parse
heroku = require 'heroku'
fs = require 'fs'
MSON = require 'mongoson'
module.exports = utils = {}
utils.log = ->
utils.loggedExec = (command, next) ->
utils.log "> #{command}"
exec command, next
utils.parseConnectionString = (connectionString) ->
parsedURL = parseURL connectionString
info = {}
info.hostname = parsedURL.hostname
info.port = parsedURL.port
info.host = if info.port then "#{info.hostname}:#{info.port}" else info.hostname
info.database = info.db = parsedURL.pathname && parsedURL.pathname.replace(/\//g, '')
[info.username,info.password] = parsedURL.auth.split(':') if parsedURL.auth
info
utils.getConnectionInfo = (connectionString) ->
info = utils.parseConnectionString connectionString
info = {}
info.protocol = info.protocol or "mongodb"
info.hostname = info.hostname or "localhost"
info.port = info.port or 27017
info.host = if info.port then "#{info.hostname}:#{info.port}" else info.hostname
info
utils.dumpDatabase = (connectionString, dirName, next) ->
dumpCommand = utils.makeDumpCommand connectionString, dirName
utils.loggedExec dumpCommand, (err, stdOut, stdErr) ->
return next err if err
return next null, stdOut, stdErr
utils.restoreDatabase = (connectionString, dirName, next) ->
restoreCommand = utils.makeRestoreCommand connectionString, dirName
utils.loggedExec restoreCommand, (err, stdOut, stdErr) ->
return next err if err
return next null, stdOut, stdErr
utils.makeDumpCommand = (connectionString, dirName) ->
throw "No target directory given." unless dirName
throw "Target directory must be a string" unless typeof dirName is "string"
connectionParameters = utils.parseConnectionString connectionString
commandOptions = makeCommandOptions connectionParameters
commandOptions.out = dirName
commandArguments = makeCommandArguments commandOptions
argumentString = makeArgumentString commandArguments
"mongodump#{argumentString}"
utils.makeRestoreCommand = (connectionString, dirName) ->
throw "No source directory given." unless dirName
throw "Source directory must be a string" unless typeof dirName is "string"
actualDirName = utils.findDumpDirName dirName
utils.log "Using #{actualDirName}"
connectionParameters = utils.parseConnectionString connectionString
commandOptions = makeCommandOptions connectionParameters
commandOptions.drop = true
commandArguments = makeCommandArguments commandOptions, actualDirName
argumentString = makeArgumentString commandArguments
"mongorestore#{argumentString}"
utils.findDumpDirName = (dirName) ->
dirCount = 0
for entryName in fs.readdirSync dirName
if fs.statSync("#{dirName}/#{entryName}").isDirectory()
dirCount += 1
lastDirName = entryName
switch dirCount
when 0 then return dirName # a proper dump dir
when 1 then return dirName + "/" + lastDirName # assume this one is proper
else throw new Error "#{dirName} contains multiple directories."
utils.dumpHerokuMongoHQDatabase = (appName, dirName, next) ->
utils.findHerokuMongoHQURL appName, (err, url) ->
utils.log "Using #{url}"
return next err if err
return utils.dumpDatabase url, dirName, next
utils.restoreHerokuMongoHQDatabase = (appName, dirName, next) ->
utils.findHerokuMongoHQURL appName, (err, url) ->
utils.log "Using #{url}"
return next err if err
return utils.restoreDatabase url, dirName, next
utils.findHerokuMongoHQURL = (appName, next) ->
return next new Error "Cannot find environment variable HEROKU_API_KEY" unless process.env['HEROKU_API_KEY']
herokuClient = new heroku.Heroku key: process.env['HEROKU_API_KEY']
herokuClient.get_config_vars appName, (err, herokuConfig) ->
return next err if err
return next new Error "Cannot find MONGOHQ_URL in config of #{appName}." unless herokuConfig.MONGOHQ_URL
return next null, herokuConfig.MONGOHQ_URL
utils.makeFindCommand = (collectionName, query, options = {}) ->
command = "db.#{collectionName}.find(#{MSON.stringify query}"
command += ",#{JSON.stringify options.fields}" if options.fields
command += ")"
command += ".sort(#{JSON.stringify options.sort})" if options.sort
command
makeCommandOptions = (connParams) ->
options = {}
options.db = connParams.db
options.host = connParams.host unless connParams.host is "localhost"
options.username = connParams.username if connParams.username
options.password = connParams.password if connParams.password
options
makeCommandArguments = (options, object) ->
args = []
for name, value of options
args.push "--#{name}" unless value is false
args.push "#{value}" unless value is true or value is false
args.push object if object
args
makeArgumentString = (args) ->
str = ""
str += " '#{arg}'" for arg in args
str