├── .travis.yml ├── example ├── simple.js ├── monitor.js ├── select-database.js ├── command-parser.js ├── http-monitor.js ├── rpop-lpush.js ├── hgetall-parse.js └── keys-hvals-sadd.js ├── .gitignore ├── package.json ├── LICENSE ├── test ├── lists.js ├── sets.js └── strings.js ├── index.js └── README.md /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.6 4 | - 0.8 5 | -------------------------------------------------------------------------------- /example/simple.js: -------------------------------------------------------------------------------- 1 | var Redis = require('../') 2 | , client = new Redis(6379, 'localhost') 3 | , lpush = client.stream('lpush', 'mylist') 4 | 5 | lpush.pipe(process.stdout) 6 | lpush.write('value1') 7 | lpush.write('value2') 8 | lpush.end() 9 | -------------------------------------------------------------------------------- /example/monitor.js: -------------------------------------------------------------------------------- 1 | var Redis = require('../') 2 | , client = new Redis(6379, 'localhost') 3 | 4 | // stream monitor to stdout 5 | var monitor = client.stream() 6 | monitor.pipe(Redis.es.join('\r\n')).pipe(process.stdout) 7 | monitor.write('monitor') 8 | -------------------------------------------------------------------------------- /example/select-database.js: -------------------------------------------------------------------------------- 1 | var Redis = require('../') 2 | , client = new Redis(6379, 'localhost', 2) // select database 2 3 | , sadd = client.stream('sadd', 'myset') 4 | 5 | sadd.pipe(process.stdout) 6 | sadd.write('value1') 7 | sadd.write('value2') 8 | sadd.end() 9 | -------------------------------------------------------------------------------- /example/command-parser.js: -------------------------------------------------------------------------------- 1 | var Redis = require('../') 2 | , redis = new Redis(6379, 'localhost') 3 | , stream = redis.stream() 4 | 5 | stream.pipe(Redis.es.join('\r\n')).pipe(process.stdout) 6 | 7 | // interact with the redis network connection directly 8 | // using `Redis.parse`, which is used internally 9 | stream.redis.write(Redis.parse([ 'info' ])) 10 | stream.redis.write(Redis.parse([ 'lpush', 'mylist', 'val' ])) 11 | stream.end() 12 | -------------------------------------------------------------------------------- /example/http-monitor.js: -------------------------------------------------------------------------------- 1 | var Redis = require('../') 2 | , client = new Redis(6379, 'localhost') 3 | 4 | // stream monitor to all http requests 5 | // curl http://0.0.0.0:3000/ 6 | 7 | require('http') 8 | .createServer(function (request, response) { 9 | var redis = client.stream() 10 | redis.pipe(Redis.es.join('\r\n')).pipe(response) 11 | redis.write('monitor') 12 | }) 13 | .listen(3000) 14 | 15 | console.log('monitor streaming at 0.0.0.0:3000') 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Numerous always-ignore extensions 2 | *.diff 3 | *.err 4 | *.orig 5 | *.log 6 | *.rej 7 | *.swo 8 | *.swp 9 | *.vi 10 | *~ 11 | 12 | # OS or Editor folders 13 | .DS_Store 14 | .cache 15 | .project 16 | .settings 17 | nbproject 18 | thumbs.db 19 | 20 | # Logs 21 | .log 22 | .pid 23 | .sock 24 | .monitor 25 | 26 | # Dreamweaver added files 27 | _notes 28 | dwsync.xml 29 | 30 | # Komodo 31 | *.komodoproject 32 | .komodotools 33 | 34 | # Folders to ignore 35 | node_modules 36 | .hg 37 | .svn 38 | publish 39 | .idea 40 | _dev 41 | 42 | # build script local files 43 | build/buildinfo.properties 44 | build/config/buildinfo.properties 45 | -------------------------------------------------------------------------------- /example/rpop-lpush.js: -------------------------------------------------------------------------------- 1 | var Redis = require('../') 2 | , client = new Redis(6379, 'localhost') 3 | , rpush 4 | , rpop 5 | 6 | // add some data to `mylist` first 7 | rpush = client.stream('rpush', 'mylist') 8 | rpush.pipe(process.stdout) 9 | rpush.write('val1') 10 | rpush.write('val2') 11 | rpush.on('end', function () { 12 | 13 | // reimplementation of rpoplpush with redis-stream 14 | // http://redis.io/commands/rpoplpush 15 | rpop = client.stream('rpop') 16 | 17 | // rpop.pipe(myDestinationStream) // send rpopped elements here 18 | 19 | rpop 20 | .pipe(client.stream('lpush', 'myotherlist')) 21 | .pipe(process.stdout) 22 | 23 | rpop.write('mylist') 24 | rpop.end() 25 | 26 | }) 27 | rpush.end() 28 | -------------------------------------------------------------------------------- /example/hgetall-parse.js: -------------------------------------------------------------------------------- 1 | 2 | var Redis = require('../') 3 | , JSONStream = require('JSONStream') 4 | , parser = JSONStream.parse([ true ]) 5 | , client = new Redis(6379, 'localhost') 6 | , stream = client.stream() 7 | , hgetall 8 | 9 | var bootstrapData = [ [ 'hmset', 'my-hash-key-1', 'field1', 'val1', 'field2', 'val2' ] ] 10 | 11 | stream.redis.write(Redis.parse(bootstrapData[0])) 12 | stream.on('close', function () { 13 | 14 | // 15 | // parse the streaming output of HGETALL to JSON 16 | // 17 | hgetall = client.stream('hgetall') 18 | hgetall 19 | .pipe(Redis.parse.hgetall()) 20 | .pipe(JSONStream.stringifyObject()) 21 | .pipe(process.stdout) 22 | 23 | hgetall.write('my-hash-key-1') 24 | hgetall.on('data', function (data) { 25 | hgetall.end() 26 | }) 27 | }) 28 | 29 | stream.end() 30 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "redis-stream", 3 | "version" : "0.1.0", 4 | "description" : "create arbitrary node.js streams to and from redis", 5 | "main" : "index.js", 6 | "bin" : {}, 7 | "directories" : { 8 | "example" : "example", 9 | "test" : "test" 10 | }, 11 | "dependencies" : { 12 | "event-stream" : "~2.1.5" 13 | }, 14 | "devDependencies" : { 15 | "tap" : "~0.2.5" 16 | }, 17 | "scripts" : { 18 | "test" : "tap test/*.js" 19 | }, 20 | "repository" : { 21 | "type" : "git", 22 | "url" : "git://github.com/tblobaum/redis-stream.git" 23 | }, 24 | "homepage" : "https://github.com/tblobaum/redis-stream", 25 | "keywords" : [ 26 | "redis", 27 | "stream" 28 | ], 29 | "author" : { 30 | "name" : "Thomas Blobaum", 31 | "email" : "tblobaum@gmail.com", 32 | "url" : "https://github.com/tblobaum/" 33 | }, 34 | "license" : "MIT" 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2012 Thomas Blobaum 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | 'Software'), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /example/keys-hvals-sadd.js: -------------------------------------------------------------------------------- 1 | 2 | var Redis = require('../') 3 | , client = new Redis(6379, 'localhost') 4 | , stream = client.stream() 5 | 6 | var bootstrapData = [ 7 | [ 'hmset', 'my-hash-key-1', 'field1', 'val1', 'field2', 'val2' ] 8 | , [ 'hmset', 'my-hash-key-2', 'field1', 'val1', 'field2', 'val2' ] 9 | ] 10 | stream.redis.write(Redis.parse(bootstrapData[0])) 11 | stream.redis.write(Redis.parse(bootstrapData[1])) 12 | stream.on('close', function () { 13 | 14 | // 15 | // Example 16 | // keys => hvals => sadd 17 | // 18 | var keys = client.stream('keys') 19 | var hvals = client.stream('hvals') 20 | var sadd = client.stream('sadd', 'my-result-set') 21 | 22 | process.stdin 23 | .pipe(Redis.es.split()) 24 | .pipe(keys) 25 | .pipe(hvals) 26 | .pipe(sadd) 27 | .pipe(process.stdout) 28 | 29 | process.stdout.write('Retrieve all keys of a given pattern, then \r\n') 30 | process.stdout.write('call HVALS on each of those keys, then \r\n') 31 | process.stdout.write('call SADD "my-result-set" on each of the values \r\n') 32 | process.stdout.write('-- \r\n') 33 | process.stdout.write('type a KEYS pattern, e.g. *-hash-key-* to \r\n') 34 | process.stdout.write('stream the result of the SADD command here \r\n') 35 | 36 | }) 37 | 38 | stream.end() 39 | -------------------------------------------------------------------------------- /test/lists.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test 2 | var Redis = require('../') 3 | , client = new Redis(6379, 'localhost') 4 | 5 | var listName = 'testlist' 6 | var values = [ 7 | 'test-value-1' 8 | , 'test-value-2' 9 | , 'test-value-3' 10 | , 'test-value-4' 11 | , 'test-value-5' 12 | , 'test-value-6' 13 | , 'test-value-7' 14 | , 'test-value-8' 15 | , 'test-value-9' 16 | , 'test-value-0' 17 | ] 18 | 19 | var List_rpush = client.stream('rpush', listName) 20 | var List_llen = client.stream('llen') 21 | var List_lpop = client.stream('lpop') 22 | var List_lindex = client.stream('lindex', listName) 23 | 24 | test('List_rpush', function (t) { 25 | t.plan(values.length) 26 | List_rpush.on('data', function (data) { 27 | t.ok((Number(data) > 0), 'rpush should return length') 28 | }) 29 | values.forEach(function (val) { 30 | List_rpush.write(val) 31 | }) 32 | }) 33 | 34 | test('List_llen', function (t) { 35 | t.plan(1) 36 | List_llen.on('data', function (data) { 37 | t.strictEqual(Number(data), values.length, 'llen should return length') 38 | }) 39 | List_llen.write(listName) 40 | }) 41 | 42 | test('List_lindex', function (t) { 43 | t.plan(values.length) 44 | List_lindex.on('data', function (data) { 45 | t.ok(!!~values.indexOf(String(data)), 'lindex, a value by index') 46 | }) 47 | values.forEach(function (val, i) { 48 | List_lindex.write(i) 49 | }) 50 | }) 51 | 52 | test('List_lpop', function (t) { 53 | t.plan(values.length) 54 | List_lpop.on('data', function (data) { 55 | t.ok(!!~values.indexOf(String(data)), 'lpop should return a value') 56 | }) 57 | values.forEach(function (val) { 58 | List_lpop.write(listName) 59 | }) 60 | }) 61 | 62 | test('streams should all close', function (t) { 63 | List_rpush.end() 64 | List_llen.end() 65 | List_lindex.end() 66 | List_lpop.end() 67 | t.ok(true, 'streams should end') 68 | t.end() 69 | }) 70 | -------------------------------------------------------------------------------- /test/sets.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test 2 | var Redis = require('../') 3 | , client = new Redis(6379, 'localhost') 4 | 5 | var setName = 'testset' 6 | var values = [ 7 | 'test-value-1' 8 | , 'test-value-2' 9 | , 'test-value-3' 10 | , 'test-value-4' 11 | , 'test-value-5' 12 | , 'test-value-6' 13 | , 'test-value-7' 14 | , 'test-value-8' 15 | , 'test-value-9' 16 | , 'test-value-0' 17 | ] 18 | 19 | var Set_sadd = client.stream('sadd', setName) 20 | var Set_scard = client.stream('scard') 21 | var Set_sismember = client.stream('sismember', setName) 22 | var Set_smembers = client.stream('smembers') 23 | var Set_spop = client.stream('spop') 24 | var Set_srem = client.stream('srem', setName) 25 | 26 | test('Set_sadd', function (t) { 27 | t.plan(values.length) 28 | Set_sadd.on('data', function (data) { 29 | t.strictEqual(Number(data), 1, 'value should be added to the set') 30 | }) 31 | values.forEach(function (val) { 32 | Set_sadd.write(val) 33 | }) 34 | }) 35 | 36 | test('Set_scard', function (t) { 37 | t.plan(1) 38 | Set_scard.on('data', function (data) { 39 | t.strictEqual(Number(data), values.length, 'scard should return length') 40 | }) 41 | Set_scard.write(setName) 42 | }) 43 | 44 | test('Set_sismember', function (t) { 45 | t.plan(values.length) 46 | Set_sismember.on('data', function (data) { 47 | t.strictEqual(Number(data), 1, 'value should exist') 48 | }) 49 | values.forEach(function (val) { 50 | Set_sismember.write(val) 51 | }) 52 | }) 53 | 54 | test('Set_smembers', function (t) { 55 | t.plan(values.length) 56 | Set_smembers.on('data', function (data) { 57 | t.ok(~values.indexOf(String(data)), 'values should be in the set') 58 | }) 59 | Set_smembers.write(setName) 60 | }) 61 | 62 | test('Set_spop', function (t) { 63 | t.plan(2) 64 | Set_spop.on('data', function (data) { 65 | var index = values.indexOf(String(data)) 66 | values.splice(values.indexOf(String(data)), 1) 67 | t.ok(!!~index, 'a random value should be returned') 68 | t.ok(!~values.indexOf(String(data)), 'value should be removed from array') 69 | }) 70 | Set_spop.write(setName) 71 | }) 72 | 73 | test('Set_srem', function (t) { 74 | t.plan(values.length) 75 | Set_srem.on('data', function (data) { 76 | t.strictEqual(Number(data), 1, 'value should be removed') 77 | }) 78 | values.forEach(function (val) { 79 | Set_srem.write(val) 80 | }) 81 | }) 82 | 83 | test('streams should all close', function (t) { 84 | Set_sadd.end() 85 | Set_scard.end() 86 | Set_sismember.end() 87 | Set_smembers.end() 88 | Set_spop.end() 89 | Set_srem.end() 90 | t.ok(true, 'streams should end') 91 | t.end() 92 | }) 93 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var net = require('net') 2 | , util = require('util') 3 | , es = require('event-stream') 4 | , formatString1 = '*%d\r\n' 5 | , formatString2 = '$%d\r\n%s\r\n' 6 | , replace1 = /^\$[0-9]+/ 7 | , replace2 = /^\*[0-9]+|^\:|^\+|^\$|^\r\n$/ 8 | 9 | function Redis (port, host, db, auth) { 10 | this.port = port || 6379 11 | this.host = host || 'localhost' 12 | this.db = String(db || 0) 13 | return this 14 | } 15 | 16 | // expose event-stream for convenience 17 | Redis.es = es 18 | 19 | Redis.prototype.createConnection = function () { 20 | return net.createConnection(this.port, this.host) 21 | } 22 | 23 | Redis.prototype.stream = function (cmd, key, curry /* moar? */) { 24 | var curry = Array.prototype.slice.call(arguments) 25 | , clip = 1 26 | , _redis = this.createConnection() 27 | , stream = es.pipe( 28 | es.pipe( 29 | es.map(function (data, fn) { 30 | var elems = [].concat(stream.curry) 31 | , str = data+'' 32 | if (!str.length) return fn() 33 | else elems.push(str) 34 | // console.log('write', str) 35 | return Redis.parse(elems, fn) 36 | }), 37 | _redis 38 | ), 39 | es.pipe( 40 | es.split('\r\n'), 41 | es.map(replyParser) 42 | ) 43 | ) 44 | ; 45 | stream.curry = curry 46 | stream.redis = _redis 47 | stream.redis.write(Redis.parse([ 'select', this.db ])) 48 | return stream 49 | 50 | function replyParser (data, fn) { 51 | if (Redis.debug_mode) console.log('replyParser', data+'') 52 | var str = (data+'').replace(replace1, '').replace(replace2, '') 53 | if (!str.length) return fn() 54 | else if (clip) { 55 | clip-- 56 | return fn() 57 | } 58 | else return fn(null, str) 59 | } 60 | } 61 | 62 | Redis.parse = function commandParser (elems, fn) { 63 | var retval = util.format(formatString1, elems.length) 64 | while (elems.length) retval += util.format(formatString2, Buffer.byteLength(elems[0]+''), elems.shift()+'') 65 | if (Redis.debug_mode) console.log('commandParser', retval) 66 | fn && fn(null, retval) 67 | return retval 68 | } 69 | 70 | Redis.parse.hgetall = 71 | Redis.parse.hmget = function () { 72 | var hash = {} 73 | , fields = [] 74 | , vals = [] 75 | , len = 0 76 | 77 | return es.map(function (data, fn) { 78 | var retval = '' 79 | if (!(len++ % 2)) fields.push(data) 80 | else vals.push(String(data)) 81 | if (vals.length === fields.length) { 82 | return fn(null, [ fields.pop(), vals.pop() ]) 83 | } 84 | else { 85 | return fn() 86 | } 87 | }) 88 | } 89 | 90 | module.exports = Redis 91 | -------------------------------------------------------------------------------- /test/strings.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test 2 | var Redis = require('../') 3 | , client = new Redis(6379, 'localhost') 4 | 5 | var set = client.stream('set', 'testkey') 6 | var strlen = client.stream('strlen') 7 | var getset = client.stream('getset', 'testkey') 8 | var get = client.stream('get') 9 | var incr = client.stream('incr') 10 | var decr = client.stream('decr') 11 | var append = client.stream('append', 'testkey') 12 | var getrange = client.stream('getrange', 'testkey', 0) 13 | var setrange = client.stream('setrange', 'testkey', 0) 14 | 15 | test('set testkey testvalue', function (t) { 16 | t.plan(1) 17 | set.on('data', function (data) { 18 | t.strictEqual(String(data), 'OK', 'set should return OK') 19 | }) 20 | set.write('testvalue') 21 | }) 22 | 23 | test('strlen testkey', function (t) { 24 | t.plan(1) 25 | strlen.on('data', function (data) { 26 | t.strictEqual(Number(data), 9, 'strlen should return length 9') 27 | }) 28 | strlen.write('testkey') 29 | }) 30 | 31 | test('getset testkey 50', function (t) { 32 | t.plan(1) 33 | getset.on('data', function (data) { 34 | t.strictEqual(String(data), 'testvalue', 'should be testvalue') 35 | }) 36 | getset.write('50') 37 | }) 38 | 39 | test('get testkey', function (t) { 40 | t.plan(1) 41 | get.on('data', function (data) { 42 | t.strictEqual(Number(data), 50, 'should be 50') 43 | }) 44 | get.write('testkey') 45 | }) 46 | 47 | test('incr testkey', function (t) { 48 | t.plan(1) 49 | incr.on('data', function (data) { 50 | t.strictEqual(Number(data), 51, 'incr should return 51') 51 | }) 52 | incr.write('testkey') 53 | }) 54 | 55 | test('decr testkey', function (t) { 56 | t.plan(1) 57 | decr.on('data', function (data) { 58 | t.strictEqual(Number(data), 50, 'decr should return 50') 59 | }) 60 | decr.write('testkey') 61 | }) 62 | 63 | test('append testkey', function (t) { 64 | t.plan(1) 65 | append.on('data', function (data) { 66 | t.strictEqual(Number(data), 3, 'append should return length 3') 67 | }) 68 | append.write('0') 69 | }) 70 | 71 | test('getrange testkey', function (t) { 72 | t.plan(1) 73 | getrange.on('data', function (data) { 74 | t.strictEqual(Number(data), 50, 'getrange should return 50') 75 | }) 76 | getrange.write(1) 77 | }) 78 | 79 | test('setrange testkey', function (t) { 80 | t.plan(1) 81 | setrange.on('data', function (data) { 82 | t.strictEqual(Number(data), 5, 'setrange should return length 5') 83 | }) 84 | setrange.write(50000) 85 | }) 86 | 87 | test('streams should all close', function (t) { 88 | set.end() 89 | strlen.end() 90 | getset.end() 91 | get.end() 92 | incr.end() 93 | decr.end() 94 | append.end() 95 | getrange.end() 96 | setrange.end() 97 | t.ok(true, 'streams should end') 98 | t.end() 99 | }) 100 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # redis-stream 2 | 3 | Create readable/writeable/pipeable [api compatible streams](http://nodejs.org/api/stream.html) from redis commands. 4 | 5 | [![Build Status](https://secure.travis-ci.org/tblobaum/redis-stream.png)](http://travis-ci.org/tblobaum/redis-stream) 6 | 7 | # Example 8 | 9 | In the `example` directory there are various ways to use `redis-stream` -- such as creating a stream from the redis `monitor` command. 10 | 11 | ``` js 12 | var Redis = require('redis-stream') 13 | , client = new Redis(6379, 'localhost') 14 | 15 | require('http') 16 | .createServer(function (request, response) { 17 | var redis = client.stream() 18 | redis.pipe(Redis.es.join('\r\n')).pipe(response) 19 | redis.write('monitor') 20 | }) 21 | .listen(3000) 22 | ``` 23 | 24 | # Methods 25 | 26 | ``` js 27 | var Redis = require('redis-stream') 28 | , client = new Redis(6379, localhost, 0) 29 | ``` 30 | 31 | ## new Redis([port] [, host] [, database]) 32 | Return an object that streams can be created from with the `port`, `host`, and `database` options. 33 | 34 | * `port` defaults to `6379` 35 | * `host` defaults to `localhsot` 36 | * `database` defaults to `0` 37 | 38 | ## client.stream([arg1] [, arg2] [, argn]) 39 | Return an instance of [stream](http://nodejs.org/api/streams.html). All calls to `write` on this stream will be prepended with the optional arguments passed to `client.stream()` 40 | 41 | Create a streaming instance of rpop: 42 | 43 | ``` js 44 | var rpop = client.stream('rpop') 45 | rpop.pipe(process.stdout) 46 | rpop.write('my-list-key') 47 | ``` 48 | 49 | Or lpush: 50 | 51 | ``` js 52 | var lpush = client.stream('lpush', 'my-list-key') 53 | lpush.pipe(process.stdout) 54 | lpush.write('my-value') 55 | ``` 56 | 57 | Which you can then pipe redis keys to, and the resulting elements will be piped to stdout. 58 | 59 | Check the [examples](https://github.com/tblobaum/redis-stream/tree/master/example) directory for more. However, any [redis command](http://redis.io/commands) can be issued with the same arguments as the command line interface. 60 | 61 | ## Other methods 62 | 63 | ### Redis.parse.hgetall() 64 | 65 | Return a special intermediary stream that can be used to transform an `hmget` or `hgetall` stream into a json object with a little help from [JSONStream](https://github.com/dominictarr/JSONStream). 66 | 67 | ``` js 68 | hgetall = client.stream('hgetall') 69 | hgetall 70 | .pipe(Redis.parse.hgetall()) 71 | .pipe(JSONStream.stringifyObject()) 72 | .pipe(process.stdout) 73 | 74 | hgetall.write('my-hash-key-1') 75 | ``` 76 | 77 | ### Redis.parse(array) 78 | It's possible to interact directly with the command parser that transforms a stream into valid redis data stream 79 | 80 | ``` js 81 | var Redis = require('redis-stream') 82 | , redis = new Redis(6379, 'localhost') 83 | , stream = redis.stream() 84 | 85 | stream.pipe(Redis.es.join('\r\n')).pipe(process.stdout) 86 | 87 | // interact with the redis network connection directly 88 | // using `Redis.parse`, which is used internally 89 | stream.redis.write(Redis.parse([ 'info' ])) 90 | stream.redis.write(Redis.parse([ 'lpush', 'mylist', 'val' ])) 91 | stream.end() 92 | ``` 93 | 94 | # Install 95 | 96 | `npm install redis-stream` 97 | 98 | # Tests 99 | 100 | `npm install -g tap && npm test` 101 | 102 | # License 103 | 104 | (The MIT License) 105 | 106 | Copyright (c) 2012 Thomas Blobaum 107 | 108 | Permission is hereby granted, free of charge, to any person obtaining 109 | a copy of this software and associated documentation files (the 110 | 'Software'), to deal in the Software without restriction, including 111 | without limitation the rights to use, copy, modify, merge, publish, 112 | distribute, sublicense, and/or sell copies of the Software, and to 113 | permit persons to whom the Software is furnished to do so, subject to 114 | the following conditions: 115 | 116 | The above copyright notice and this permission notice shall be 117 | included in all copies or substantial portions of the Software. 118 | 119 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 120 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 121 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 122 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 123 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 124 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 125 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------------------------------