├── .gitignore ├── examples └── simple.js ├── package.json ├── LICENCE ├── README.md └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log 3 | *.err -------------------------------------------------------------------------------- /examples/simple.js: -------------------------------------------------------------------------------- 1 | var livefeed = require("..") 2 | , level = require("levelidb") 3 | , WriteStream = require("write-stream") 4 | 5 | , db = level("/tmp/db-livefeed-example", { 6 | createIfMissing: true 7 | }) 8 | 9 | var stream = livefeed(db, { start: "foo:", end: "foo;" }) 10 | 11 | stream.pipe(WriteStream(function (chunk) { 12 | console.log("chunk", chunk.type, chunk.key.toString() 13 | , chunk.value && chunk.value.toString()) 14 | })) 15 | 16 | stream.on("loaded", function () { 17 | console.log("finished loading from disk") 18 | }) 19 | 20 | setTimeout(function () { 21 | db.put("foo:some key", "some value") 22 | 23 | db.del("foo:die") 24 | 25 | db.batch([ 26 | { type: "put", key: "foo:one", value: "two" } 27 | , { type: "del", key: "foo:two" } 28 | ]) 29 | }, 2000) 30 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "level-livefeed", 3 | "version": "0.2.0", 4 | "description": "Live query a range in leveldb", 5 | "keywords": [], 6 | "author": "Raynos ", 7 | "repository": "git://github.com/Raynos/level-livefeed.git", 8 | "main": "index", 9 | "homepage": "https://github.com/Raynos/level-livefeed", 10 | "contributors": [ 11 | { 12 | "name": "Jake Verbaten" 13 | } 14 | ], 15 | "bugs": { 16 | "url": "https://github.com/Raynos/level-livefeed/issues", 17 | "email": "raynos2@gmail.com" 18 | }, 19 | "dependencies": { 20 | "read-stream": "~0.4.8", 21 | "write-stream": "~0.4.3" 22 | }, 23 | "devDependencies": { 24 | "tap": "~0.3.1", 25 | "levelidb": "~0.1.8" 26 | }, 27 | "licenses": [ 28 | { 29 | "type": "MIT", 30 | "url": "http://github.com/Raynos/level-livefeed/raw/master/LICENSE" 31 | } 32 | ], 33 | "scripts": { 34 | "test": "tap --stderr --tap ./test" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Raynos. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # level-livefeed 2 | 3 | Live query a range in leveldb 4 | 5 | ## Example 6 | 7 | You query a range in the database. It will load the range from 8 | disk and then also add on anything else you put or del from 9 | it. 10 | 11 | It's basically a never ending feed like `tail -f` 12 | 13 | ```js 14 | var livefeed = require("..") 15 | , level = require("levelidb") 16 | , WriteStream = require("write-stream") 17 | 18 | , db = level("/tmp/db-livefeed-example", { 19 | createIfMissing: true 20 | }) 21 | 22 | var stream = livefeed(db, { start: "foo:", end: "foo;" }) 23 | 24 | stream.pipe(WriteStream(function (chunk) { 25 | console.log("chunk", chunk.type, chunk.key.toString() 26 | , chunk.value && chunk.value.toString()) 27 | })) 28 | 29 | stream.on("loaded", function () { 30 | console.log("finished loading from disk") 31 | }) 32 | 33 | setTimeout(function () { 34 | db.put("foo:some key", "some value") 35 | 36 | db.del("foo:die") 37 | 38 | db.batch([ 39 | { type: "put", key: "foo:one", value: "two" } 40 | , { type: "del", key: "foo:two" } 41 | ]) 42 | }, 2000) 43 | ``` 44 | 45 | prints 46 | 47 | ``` 48 | chunk put foo:one two 49 | chunk put foo:some key some value 50 | finished loading from disk 51 | chunk put foo:some key some value 52 | chunk del foo:die undefined 53 | chunk put foo:one two 54 | chunk del foo:two undefined 55 | ``` 56 | 57 | ## Installation 58 | 59 | `npm install level-livefeed` 60 | 61 | ## Contributors 62 | 63 | - Raynos 64 | 65 | ## MIT Licenced 66 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var ReadStream = require("read-stream") 2 | , WriteStream = require("write-stream") 3 | 4 | module.exports = query 5 | 6 | function query(db, options) { 7 | options = options || {} 8 | 9 | var queue = ReadStream() 10 | , stream = queue.stream 11 | , start = options.start 12 | , end = options.end 13 | , writer = WriteStream(write, loaded) 14 | , reader = db.readStream(options) 15 | 16 | reader.pipe(writer) 17 | 18 | db.on("put", put) 19 | db.on("del", del) 20 | db.on("batch", batch) 21 | stream.close = stream.destroy = close 22 | 23 | return stream 24 | 25 | function write(chunk) { 26 | chunk.type = "put" 27 | queue.push(chunk) 28 | } 29 | 30 | function loaded() { 31 | stream.emit("loaded") 32 | this.emit("finish") 33 | } 34 | 35 | function put(key, value) { 36 | key = key.toString() 37 | if ((!start || start <= key) && 38 | (!end || key <= end) 39 | ) { 40 | queue.push({ type: "put", key: key , value: value }) 41 | } 42 | } 43 | 44 | function del(key) { 45 | key = key.toString() 46 | if ((!start || start <= key) && 47 | (!end || key <= end) 48 | ) { 49 | queue.push({ type: "del", key: key }) 50 | } 51 | } 52 | 53 | function batch(args) { 54 | args.forEach(function (item) { 55 | var key = item.key.toString() 56 | 57 | if ((!start || start <= key) && 58 | (!end || key <= end) 59 | ) { 60 | return queue.push(item) 61 | } 62 | }) 63 | } 64 | 65 | function close() { 66 | reader.unpipe(writer) 67 | db.removeListener("put", put) 68 | db.removeListener("del", del) 69 | db.removeListener("batch", batch) 70 | queue.end() 71 | } 72 | } 73 | --------------------------------------------------------------------------------