UNPKG

redis-dump

Version:

Dump redis database into redis commands or json with command line or node.js

240 lines (214 loc) 9.79 kB
run = require('async').waterfall redis = require 'redis' module.exports = (params, callback) -> params.port ?= 6379 params.host ?= '127.0.0.1' params.db ?= '0' params.filter ?= '*' params.format ?= 'redis' params.convert ?= null dumper = new RedisDumper(params) dumper.dump params, (params...) -> dumper.close() callback params... class RedisDumper constructor: ({port, host, auth}) -> # Connect to redis database if auth? @db = redis.createClient(port, host, {auth_pass: auth}) else @db = redis.createClient(port, host) close: -> # Close redis connection @db.end() escape: (value) -> if /^([a-zA-Z0-9_\:\-]+)$/.test "#{value}" return "#{value}" else return "'"+"#{value}".split('\\').join('\\\\').split('\'').join('\\\'')+"'" dump: ({db, filter, format, convert, pretty}, callback) -> keys = [] types = [] values = [] ttls = [] if typeof convert is 'string' try convert = JSON.parse convert catch e return callback e @db.select db run [ # Get keys matching filter (next) => try if convert? next null, (k for k of convert) else @db.keys filter, next catch e next e # For each key, get its type (reply, next) => try for key in reply keys.push key # If there are no keys, return now if keys.length is 0 if format is 'json' callback null, '{}' else if format is 'raw' callback null, {} else callback null, '' next null, null return # Sort keys in alphabetic order (better for versioning) keys = keys.sort(); if convert? next null, (v.type for k, v of convert) else multi = @db.multi() for key in keys multi.type key multi.exec next catch e next e # Get data of each key according to its type (replies, next) => try if keys.length is 0 next null, null return for type in replies types.push type if convert? result = [] for type, i in types switch type when 'string' result.push convert[keys[i]].value when 'list' result.push convert[keys[i]].value when 'set' result.push convert[keys[i]].value when 'zset' val = [] for entry in convert[keys[i]].value val.push entry[1] val.push entry[0] result.push val when 'hash' result.push convert[keys[i]].value next null, result else multi = @db.multi() for type, i in types switch type when 'string' multi.get keys[i] when 'list' multi.lrange keys[i], 0, -1 when 'set' multi.smembers keys[i] when 'zset' multi.zrange keys[i], 0, -1, 'withscores' when 'hash' multi.hgetall keys[i] multi.exec next catch e next e # Get TTL of each key (replies, next) => try if keys.length is 0 next null, null return for value in replies values.push value if convert? result = [] for key in keys if convert[key].ttl? result.push "#{convert[key].ttl}" else result.push "-1" next null, result else multi = @db.multi() for key in keys multi.ttl key multi.exec next catch e next e # Render result as the requested format (replies, next) => try if keys.length is 0 next null, null return for ttl in replies ttls.push ttl switch format when 'json' or 'raw' # Create json from key's type and data (default) json = {} for type, i in types key = keys[i] value = values[i] switch type when 'string' json[key] = type: 'string', value: value when 'list' json[key] = type: 'list', value: value when 'set' json[key] = type: 'set', value: value.sort() # Sort set for better versioning when 'zset' json[key] = type: 'zset', value: ([parseInt(value[j+1],10), value[j]] for item, j in value by 2) when 'hash' json[key] = type: 'hash', value: value ttl = parseInt ttls[i], 10 if not isNaN(ttl) and ttl isnt -1 json[key].ttl = ttl # Return result if format is 'json' if pretty callback null, JSON.stringify(json, null, 4) else callback null, JSON.stringify(json) else callback null, json else # Create redis-cli compliant commands from key's type and data (default) commands = [] for type, i in types key = keys[i] value = values[i] switch type when 'string' commands.push "SET #{@escape key} #{@escape value}" when 'list' commands.push "DEL #{@escape key}" commands.push "RPUSH #{@escape key} #{(@escape(item) for item in value).join(' ')}" when 'set' commands.push "DEL #{@escape key}" if value.length isnt 0 commands.push "SADD #{@escape key} #{(@escape(item) for item in value).join(' ')}" when 'zset' commands.push "DEL #{@escape key}" if value.length isnt 0 commands.push "ZADD #{@escape key} #{((@escape(value[j+1])+' '+@escape(value[j])) for item, j in value by 2).join(' ')}" when 'hash' commands.push "DEL #{@escape key}" len = 0 len++ for k of value if len isnt 0 commands.push "HMSET #{@escape key} #{((@escape(k)+' '+@escape(v)) for k, v of value).join(' ')}" ttl = parseInt ttls[i], 10 if not isNaN(ttl) and ttl isnt -1 commands.push "EXPIRE #{@escape key} #{ttl}" # Return result callback null, commands.join("\n") catch e next e ], (err) -> callback err