├── .gitignore ├── package.json ├── LICENSE ├── README.md ├── test.js └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | *.log 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rxredis", 3 | "version": "0.0.4", 4 | "description": "RxJS wrapper for redis", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/acoshift/rxredis.git" 12 | }, 13 | "keywords": [ 14 | "rx", 15 | "rxjs", 16 | "redis" 17 | ], 18 | "author": "Thanatat Tamtan ", 19 | "license": "MIT", 20 | "bugs": { 21 | "url": "https://github.com/acoshift/rxredis/issues" 22 | }, 23 | "homepage": "https://github.com/acoshift/rxredis#readme", 24 | "peerDependencies": { 25 | "rxjs": "^5.4.0" 26 | }, 27 | "devDependencies": { 28 | "ioredis": "^2.5.0", 29 | "redis": "^2.7.1" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Thanatat Tamtan 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RxRedis 2 | RxJS wrapper for Redis 3 | 4 | --- 5 | ### Note 6 | #### ioredis 7 | multi and pipeline result will be map from `[[err, res], [err, res], ...]` to `[res, res, ...]` 8 | 9 | and `[err, err, ...]` will be throw if some of `err != null` 10 | 11 | --- 12 | 13 | ### Example 14 | ```js 15 | 'use strict' 16 | const Observable = require('rxjs').Observable 17 | const Redis = require('ioredis') 18 | const client = require('rxredis')(new Redis()) 19 | 20 | client 21 | .incr('test') 22 | .flatMap((id) => client.hmset(`test:${id}`, 'name', 'abc', 'value', Math.floor(Math.random() * 20)), (id) => id) 23 | .flatMap((id) => client.sadd('test:all', id), (id) => id) 24 | .flatMap((id) => client.hgetall(`test:${id}`)) 25 | .repeat(10) 26 | .subscribe(console.log, console.error, () => console.log('1 Completed!')) 27 | 28 | client 29 | .smembers('test:all') 30 | .flatMap(Observable.fromArray) 31 | .flatMap((id) => client.hgetall(`test:${id}`)) 32 | .toArray() 33 | .subscribe(console.log, console.error, () => console.log('2 Completed!')) 34 | 35 | client 36 | .pipeline() 37 | .hgetall('test:5') 38 | .sismember('test:all', 5) 39 | .get('test') 40 | .exec() 41 | .map((xs) => { 42 | let x = xs[0] 43 | x.id = 5 44 | x.isMember = xs[1] 45 | x.last = xs[2] 46 | return x 47 | }) 48 | .subscribe(console.log, console.error, () => console.log('3 Completed!')) 49 | ``` 50 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const Observable = require('rxjs').Observable 3 | const Redis = require('ioredis') 4 | const redis = require('redis') 5 | const client = require('./index')(new Redis()) 6 | const client2 = require('./index')(redis.createClient()) 7 | 8 | client2 9 | .incr('test') 10 | .flatMap((id) => client.hmset(`test:${id}`, 'name', 'abc', 'value', Math.floor(Math.random() * 20)), (id) => id) 11 | .flatMap((id) => client.sadd('test:all', id), (id) => id) 12 | .flatMap((id) => client.hgetall(`test:${id}`)) 13 | .repeat(10) 14 | .subscribe(console.log, console.error, () => console.log('1 Completed!')) 15 | 16 | client2 17 | .smembers('test:all') 18 | .flatMap(Observable.from) 19 | .flatMap((id) => client.hgetall(`test:${id}`)) 20 | .toArray() 21 | .subscribe(console.log, console.error, () => console.log('2 Completed!')) 22 | 23 | client 24 | .pipeline() 25 | .sadd('a', 'a1') 26 | .hmset('a1', 'name', 'abc', 'value', 123) 27 | .hgetall('a1') 28 | .sismember('a', 'a1') 29 | .exec() 30 | .map((xs) => { 31 | let x = xs[2] 32 | x.isMember = xs[3] 33 | return x 34 | }) 35 | .subscribe(console.log, console.error, () => console.log('3 Completed!')) 36 | 37 | client2 38 | .multi() 39 | .sadd('a', 'a2') 40 | .hmset('a2', 'name', 'abc', 'value', 123) 41 | .hgetall('a2') 42 | .sismember('a', 'a2') 43 | .exec() 44 | .map((xs) => { 45 | let x = xs[2] 46 | x.isMember = xs[3] 47 | return x 48 | }) 49 | .subscribe(console.log, console.error, () => console.log('4 Completed!')) 50 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var Observable = require('rxjs').Observable 2 | 3 | /** 4 | * Create RxRedis wrapper for redis client 5 | * @param {Object} client - redis client 6 | * @return {Object} 7 | */ 8 | function rxredis (client) { 9 | var obj = {} 10 | obj.__client = client 11 | 12 | ;[ 13 | /* Connection */ 14 | 'auth', 15 | 'echo', 16 | 'ping', 17 | 'quit', 18 | 'select', 19 | 'swapdb', 20 | 21 | /* Keys */ 22 | 'del', 23 | 'dump', 24 | 'exists', 25 | 'expire', 26 | 'expireat', 27 | 'keys', 28 | 'migrate', 29 | 'move', 30 | 'object', 31 | 'persist', 32 | 'pexpire', 33 | 'pexpireat', 34 | 'pttl', 35 | 'randomkey', 36 | 'rename', 37 | 'renamenx', 38 | 'restore', 39 | 'sort', 40 | 'touch', 41 | 'ttl', 42 | 'type', 43 | 'unlink', 44 | 'wait', 45 | 'scan', 46 | 47 | /* Strings */ 48 | 'append', 49 | 'bitcount', 50 | 'bitfield', 51 | 'bitop', 52 | 'bitpos', 53 | 'decr', 54 | 'decrby', 55 | 'get', 56 | 'getbit', 57 | 'getrange', 58 | 'getset', 59 | 'incr', 60 | 'incrby', 61 | 'incrbyfloat', 62 | 'mget', 63 | 'mset', 64 | 'msetnx', 65 | 'psetex', 66 | 'set', 67 | 'setbit', 68 | 'setex', 69 | 'setnx', 70 | 'setrange', 71 | 'strlen', 72 | 73 | /* Hashes */ 74 | 'hdel', 75 | 'hexists', 76 | 'hget', 77 | 'hgetall', 78 | 'hincrby', 79 | 'hincrbyfloat', 80 | 'hkeys', 81 | 'hlen', 82 | 'hmget', 83 | 'hmset', 84 | 'hset', 85 | 'hsetnx', 86 | 'hstrlen', 87 | 'hvals', 88 | 'hscan', 89 | 90 | /* Lists */ 91 | 'blpop', 92 | 'brpop', 93 | 'brpoplpush', 94 | 'lindex', 95 | 'linsert', 96 | 'llen', 97 | 'lpop', 98 | 'lpush', 99 | 'lpushx', 100 | 'lrange', 101 | 'lrem', 102 | 'lset', 103 | 'ltrim', 104 | 'rpop', 105 | 'rpoplpush', 106 | 'rpush', 107 | 'rpushx', 108 | 109 | /* Sets */ 110 | 'sadd', 111 | 'scard', 112 | 'sdiff', 113 | 'sdiffstore', 114 | 'sinter', 115 | 'sinterstore', 116 | 'sismember', 117 | 'smembers', 118 | 'smove', 119 | 'spop', 120 | 'srandmember', 121 | 'srem', 122 | 'sunion', 123 | 'sunionstore', 124 | 'sscan', 125 | 126 | /* Sorted Sets */ 127 | 'zadd', 128 | 'zcard', 129 | 'zcount', 130 | 'zincrby', 131 | 'zinterstore', 132 | 'zlexcount', 133 | 'zrange', 134 | 'zrangebylex', 135 | 'zrevrangebylex', 136 | 'zrangebyscore', 137 | 'zrank', 138 | 'zrem', 139 | 'zremrangebylex', 140 | 'zremrangebyrank', 141 | 'zremrangebyscore', 142 | 'zrevrange', 143 | 'zrevrangebyscore', 144 | 'zrevrank', 145 | 'zscore', 146 | 'zunionstore', 147 | 'zscan', 148 | 149 | /* HyperLogLog */ 150 | 'pfadd', 151 | 'pfcount', 152 | 'pfmerge', 153 | 154 | /* Pub/Sub */ 155 | 'psubscribe', 156 | 'pubsub', 157 | 'publish', 158 | 'punsubscribe', 159 | 'subscribe', 160 | 'unsubscribe', 161 | 162 | /* Geo */ 163 | 'geoadd', 164 | 'geohash', 165 | 'geopos', 166 | 'geodist', 167 | 'georadius', 168 | 'georadiusbymember', 169 | 170 | /* Scripting */ 171 | 'eval', 172 | 'evalsha', 173 | 'script', 174 | 175 | /* Server */ 176 | 'bgrewriteaof', 177 | 'bgsave', 178 | 'client', 179 | 'command', 180 | 'config', 181 | 'dbsize', 182 | 'debug', 183 | 'flushall', 184 | 'flushdb', 185 | 'info', 186 | 'lastsave', 187 | 'monitor', 188 | 'role', 189 | 'save', 190 | 'shutdown', 191 | 'slaveof', 192 | 'slowlog', 193 | 'sync', 194 | 'time', 195 | 196 | /* Transactions */ 197 | 'discard', 198 | 'exec', 199 | 'multi', 200 | 'unwatch', 201 | 'watch', 202 | 203 | /* Cluster */ 204 | 'cluster', 205 | 'readonly', 206 | 'readwrite' 207 | ].forEach(function (method) { 208 | obj[method] = Observable.bindNodeCallback(obj.__client[method].bind(obj.__client)) 209 | }) 210 | 211 | if (obj.__client.constructor.name === 'Redis') { 212 | /* ioredis */ 213 | 214 | obj.multi = function () { 215 | var p = obj.__client.multi() 216 | var exec = p.exec 217 | p.exec = function () { 218 | return Observable 219 | .bindNodeCallback(exec.bind(p)).apply(null, arguments) 220 | .map(function (xs) { 221 | // Map result from [[err, res], [err, res], ...] to [res, res, ...] 222 | var err = [] 223 | var hasError = false 224 | var res = xs.map(function (x, i) { 225 | err[i] = x[0] 226 | if (x[0] != null && !hasError) hasError = true 227 | return x[1] 228 | }) 229 | if (hasError) throw err 230 | return res 231 | }) 232 | } 233 | return p 234 | } 235 | 236 | obj.pipeline = function () { 237 | var p = obj.__client.pipeline() 238 | var exec = p.exec 239 | p.exec = function () { 240 | return Observable 241 | .bindNodeCallback(exec.bind(p)).apply(null, arguments) 242 | .map(function (xs) { 243 | // Map result from [[err, res], [err, res], ...] to [res, res, ...] 244 | var err = [] 245 | var hasError = false 246 | var res = xs.map(function (x, i) { 247 | err[i] = x[0] 248 | if (x[0] != null && !hasError) hasError = true 249 | return x[1] 250 | }) 251 | if (hasError) throw err 252 | return res 253 | }) 254 | } 255 | return p 256 | } 257 | } else { // obj.__client.constructor.name === 'RedisClient' 258 | /* node_redis */ 259 | 260 | obj.multi = function () { 261 | var p = obj.__client.multi() 262 | var exec = p.exec 263 | p.exec = Observable.bindNodeCallback(exec.bind(p)) 264 | return p 265 | } 266 | } 267 | 268 | return obj 269 | } 270 | 271 | module.exports = rxredis 272 | --------------------------------------------------------------------------------