├── LICENSE ├── README.rst ├── index.js └── package.json /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Maxim 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ------------- 2 | promise-redis 3 | ------------- 4 | 5 | `promise-redis` is a tiny library that adds promise awareness to `node_redis`_, 6 | the main node.js redis client. You may provide any promise-library. But if you 7 | don't provide any, then `native JavaScript Promise`_ will be used instead. 8 | 9 | Features: 10 | 11 | * It is agnostic about what promise library you use. You will want to provide 12 | promise library of your choice (no lock-in) or just use native JavaScript 13 | promises. 14 | 15 | * Nothing new to learn. `promise-redis` just lifts redis commands to return 16 | promises, and then exposes to you the original `node_redis`_ object. So for 17 | API docs visit `node_redis documentation`_. 18 | 19 | * It is very small. 20 | 21 | .. contents:: 22 | 23 | 24 | Installation 25 | ------------ 26 | 27 | The only dependency of `promise-redis` is `node_redis`_. To install 28 | `promise-redis` run: 29 | 30 | .. code-block:: bash 31 | 32 | npm install promise-redis 33 | 34 | 35 | Usage 36 | ----- 37 | 38 | Using redis with native promises is easy: 39 | 40 | .. code-block:: javascript 41 | 42 | var redis = require('promise-redis')(); 43 | 44 | Now you can use ``redis`` object as usual, but each command will return 45 | a promise: 46 | 47 | .. code-block:: javascript 48 | 49 | var client = redis.createClient(); 50 | client.set('mykey', 'myvalue') 51 | .then(console.log) 52 | .catch(console.log) 53 | 54 | If you want to use some promise library, you need to provide factory function: 55 | 56 | .. code-block:: javascript 57 | 58 | var redis = require('promise-redis')(function(resolver) { 59 | // do something here that provides a way to create new promise. 60 | }); 61 | 62 | See below for examples of integration with some well-known promise libraries. 63 | 64 | Q 65 | === 66 | 67 | Integration with `Q`_ is easy. Just use ``Q.Promise`` as a factory function. 68 | 69 | .. code-block:: javascript 70 | 71 | var promiseFactory = require("q").Promise, 72 | redis = require('promise-redis')(promiseFactory); 73 | 74 | // redis is the usual node_redis object. Do what you usually do with it: 75 | var client = redis.createClient(); 76 | client.on("error", function (err) { 77 | console.log("uh oh", err); 78 | }); 79 | 80 | // All your redis commands return promises now. 81 | client.set('mykey', 'myvalue') 82 | .then(console.log) 83 | .catch(console.log) 84 | 85 | // Callback style code is still supported. This can be useful if some of 86 | // old code still relies on callbacks. 87 | client.hmset('myotherkey', {'one': 1, 'two': 2}, function (err, value) { 88 | if (err) { 89 | return console.log("Error: ", err.message); 90 | } 91 | console.log(value); 92 | }); 93 | 94 | when 95 | ==== 96 | 97 | Integration with `when`_ is easy as well. Just use ``when.promise`` as a factory 98 | function: 99 | 100 | .. code-block:: javascript 101 | 102 | var promiseFactory = require("when").promise, 103 | redis = require('promise-redis')(promiseFactory); 104 | 105 | // redis is the usual node_redis object. Do what you usually do with it: 106 | var client = redis.createClient(); 107 | client.on("error", function (err) { 108 | console.log("uh oh", err); 109 | }); 110 | 111 | // All your redis commands return promises now. 112 | client.set('mykey', 'myvalue') 113 | .then(console.log) 114 | .catch(console.log) 115 | 116 | // Callback style code is still supported. This can be useful if some of 117 | // old code still relies on callbacks. 118 | client.hmset('myotherkey', {'one': 1, 'two': 2}, function (err, value) { 119 | if (err) { 120 | return console.log("Error: ", err.message); 121 | } 122 | console.log(value); 123 | }); 124 | 125 | Bluebird 126 | ======== 127 | 128 | `Bluebird`_ is a bit different, but still nothing special: 129 | 130 | .. code-block:: javascript 131 | 132 | var Promise = require("bluebird"), 133 | redis = require('promise-redis')(function(resolver) { 134 | return new Promise(resolver); 135 | }); 136 | 137 | // redis is the usual node_redis object. Do what you usually do with it: 138 | var client = redis.createClient(); 139 | client.on("error", function (err) { 140 | console.log("uh oh", err); 141 | }); 142 | 143 | // All your redis commands return promises now. 144 | client.set('mykey', 'myvalue') 145 | .then(console.log) 146 | .catch(console.log) 147 | 148 | // Callback style code is still supported. This can be useful if some of 149 | // old code still relies on callbacks. 150 | client.hmset('myotherkey', {'one': 1, 'two': 2}, function (err, value) { 151 | if (err) { 152 | return console.log("Error: ", err.message); 153 | } 154 | console.log(value); 155 | }); 156 | 157 | Other libraries 158 | =============== 159 | 160 | Pull requests that demonstrate how other libraries can be integrated are 161 | welcome. 162 | 163 | 164 | Examples 165 | -------- 166 | 167 | Here is a copy-and-paste example from "Usage" section of `node_redis 168 | documentation`_. The example is silly and doesn't demonstrate any advantages of 169 | promises. I use `when`_ library here, but as you already know it really doesn't 170 | matter: 171 | 172 | .. code-block:: javascript 173 | 174 | var promiseFactory = require("when").promise, 175 | redis = require("promise-redis")(promiseFactory), 176 | client = redis.createClient(); 177 | 178 | // if you'd like to select database 3, instead of 0 (default), call 179 | client.select(3).then(function() { 180 | console.log("Selected database 3"); 181 | }); 182 | 183 | client.on("error", function (err) { 184 | console.log("Error " + err); 185 | }); 186 | 187 | client.set("string key", "string val").then(console.log); 188 | client.hset("hash key", "hashtest 1", "some value").then(console.log); 189 | client.hset(["hash key", "hashtest 2", "some other value"]).then(console.log); 190 | client.hkeys("hash key").then(function (replies) { 191 | console.log(replies.length + " replies:"); 192 | replies.forEach(function (reply, i) { 193 | console.log(" " + i + ": " + reply); 194 | }); 195 | client.quit(); 196 | }); 197 | 198 | And finally here is an example of using ``client.multi`` (it is also from 199 | `node_redis`_ docs): 200 | 201 | .. code-block:: javascript 202 | 203 | var promiseFactory = require("when").promise, 204 | redis = require("promise-redis")(promiseFactory), 205 | client = redis.createClient(); 206 | 207 | client.sadd("bigset", "a member"); 208 | client.sadd("bigset", "another member"); 209 | 210 | while (set_size > 0) { 211 | client.sadd("bigset", "member " + set_size); 212 | set_size -= 1; 213 | } 214 | 215 | // multi chain 216 | client.multi() 217 | .scard("bigset") 218 | .smembers("bigset") 219 | .keys("*") 220 | .dbsize() 221 | .exec() 222 | .then(function (replies) { 223 | console.log("MULTI got " + replies.length + " replies"); 224 | replies.forEach(function (reply, index) { 225 | console.log("Reply " + index + ": " + reply.toString()); 226 | }); 227 | }); 228 | 229 | ``client.multi`` is a constructor that returns an object, which you can use to 230 | chain (queue) multiple redis commands together. All commands, but ``exec``, 231 | that you issue on ``Multi`` don't start any I/O. But when ``exec`` command is 232 | issued, all queued operations are executed atomically. ``exec`` returns a 233 | promise. 234 | 235 | .. _node_redis: https://github.com/mranney/node_redis 236 | .. _`node_redis documentation`: https://github.com/mranney/node_redis#redis---a-nodejs-redis-client 237 | .. _Q: https://github.com/kriskowal/q/ 238 | .. _when: https://github.com/cujojs/when 239 | .. _Bluebird: https://github.com/petkaantonov/bluebird 240 | .. _`native JavaScript Promise`: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise 241 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var redis = require('redis'), 4 | redisCmds = require('redis-commands').list; 5 | 6 | function createCb(resolve, reject) { 7 | return function (err, value) { 8 | if (err !== null) { 9 | reject(err); 10 | } else { 11 | resolve(value); 12 | } 13 | }; 14 | } 15 | 16 | module.exports = function (promiseFactory) { 17 | var mlproto = redis.Multi.prototype, 18 | clproto = redis.RedisClient.prototype; 19 | 20 | if (!promiseFactory) { 21 | promiseFactory = function (resolver) { 22 | return new Promise(resolver); 23 | }; 24 | } 25 | 26 | function promisify(f) { 27 | return function () { 28 | var args = Array.prototype.slice.call(arguments), 29 | that = this; 30 | if (typeof args[args.length - 1] === 'function') { 31 | // Okay. Someone supplied a callback. Most likely some internal 32 | // node-redis call (ready probe etc.). Oh, as a result of 33 | // supporting internal callback-style calls, one can now use 34 | // promise-redis as a dropin replacement for node-redis. 35 | f.apply(this, args); 36 | } else { 37 | return promiseFactory(function (resolve, reject) { 38 | args.push(createCb(resolve, reject)); 39 | f.apply(that, args); 40 | }); 41 | } 42 | }; 43 | } 44 | 45 | redisCmds.forEach(function (fullCommand) { 46 | var cmd = fullCommand.split(' ')[0]; 47 | 48 | if (cmd !== 'multi') { 49 | clproto[cmd] = promisify(clproto[cmd]); 50 | clproto[cmd.toUpperCase()] = clproto[cmd]; 51 | } 52 | 53 | }); 54 | 55 | // For Multi only `exec` command returns promise. 56 | mlproto.exec_transaction = promisify(mlproto.exec_transaction); 57 | mlproto.exec = mlproto.exec_transaction; 58 | mlproto.EXEC = mlproto.exec; 59 | 60 | return redis; 61 | }; 62 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "promise-redis", 3 | "version": "0.0.5", 4 | "description": "Tiny library that adds promise awareness to node_redis", 5 | "main": "index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/maxbrieiev/promise-redis" 9 | }, 10 | "keywords": [ 11 | "redis", 12 | "promise", 13 | "when", 14 | "q", 15 | "bluebird", 16 | "then" 17 | ], 18 | "author": "Maksym Brieiev", 19 | "license": "MIT", 20 | "dependencies": { 21 | "redis": "*", 22 | "redis-commands": "*" 23 | } 24 | } 25 | --------------------------------------------------------------------------------