├── .gitignore ├── .travis.yml ├── example.js ├── package.json ├── LICENSE ├── index.js ├── test.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.10' 4 | - '0.12' 5 | - '4.0' 6 | - '6.0' 7 | -------------------------------------------------------------------------------- /example.js: -------------------------------------------------------------------------------- 1 | var batcher = require('atomic-batcher') 2 | var db = require('level')('some.db') 3 | 4 | var batch = batcher(function work (ops, cb) { 5 | // only one batch will happen at the time 6 | console.log('Batching:', ops, '\n') 7 | db.batch(ops, cb) 8 | }) 9 | 10 | batch({type: 'put', key: 'hello', value: 'world-1'}) 11 | batch({type: 'put', key: 'hello', value: 'world-2'}) 12 | batch({type: 'put', key: 'hello', value: 'world-3'}) 13 | batch({type: 'put', key: 'hi', value: 'hello'}, function () { 14 | console.log('Printing latest values:\n') 15 | db.get('hello', console.log) // returns world-3 16 | db.get('hi', console.log) // returns hello 17 | }) 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "atomic-batcher", 3 | "version": "1.0.2", 4 | "description": "A simple batching function that allows you to atomically batch a series of operations.", 5 | "main": "index.js", 6 | "dependencies": {}, 7 | "devDependencies": { 8 | "standard": "^7.1.2", 9 | "tape": "^4.6.0" 10 | }, 11 | "scripts": { 12 | "test": "standard && tape test.js" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/mafintosh/atomic-batcher.git" 17 | }, 18 | "author": "Mathias Buus (@mafintosh)", 19 | "license": "MIT", 20 | "bugs": { 21 | "url": "https://github.com/mafintosh/atomic-batcher/issues" 22 | }, 23 | "homepage": "https://github.com/mafintosh/atomic-batcher" 24 | } 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Mathias Buus 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = batcher 2 | 3 | function batcher (run) { 4 | var running = false 5 | var pendingBatch = null 6 | var pendingCallbacks = null 7 | var callbacks = null 8 | 9 | return append 10 | 11 | function done (err) { 12 | if (callbacks) callAll(callbacks, err) 13 | 14 | running = false 15 | callbacks = pendingCallbacks 16 | var nextBatch = pendingBatch 17 | 18 | pendingBatch = null 19 | pendingCallbacks = null 20 | 21 | if (!nextBatch || !nextBatch.length) { 22 | if (!callbacks || !callbacks.length) { 23 | callbacks = null 24 | return 25 | } 26 | if (!nextBatch) nextBatch = [] 27 | } 28 | 29 | running = true 30 | run(nextBatch, done) 31 | } 32 | 33 | function append (val, cb) { 34 | if (running) { 35 | if (!pendingBatch) { 36 | pendingBatch = [] 37 | pendingCallbacks = [] 38 | } 39 | pushAll(pendingBatch, val) 40 | if (cb) pendingCallbacks.push(cb) 41 | } else { 42 | if (cb) callbacks = [cb] 43 | running = true 44 | run(Array.isArray(val) ? val : [val], done) 45 | } 46 | } 47 | } 48 | 49 | function pushAll (list, val) { 50 | if (Array.isArray(val)) pushArray(list, val) 51 | else list.push(val) 52 | } 53 | 54 | function pushArray (list, val) { 55 | for (var i = 0; i < val.length; i++) list.push(val[i]) 56 | } 57 | 58 | function callAll (list, err) { 59 | for (var i = 0; i < list.length; i++) list[i](err) 60 | } 61 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | var tape = require('tape') 2 | var batcher = require('./') 3 | 4 | tape('runs once', function (t) { 5 | var batch = batcher(run) 6 | 7 | batch('hello') 8 | 9 | function run (vals, cb) { 10 | t.same(vals, ['hello']) 11 | t.end() 12 | cb() 13 | } 14 | }) 15 | 16 | tape('runs once with two vals', function (t) { 17 | var batch = batcher(run) 18 | 19 | batch(['hello', 'world']) 20 | 21 | function run (vals, cb) { 22 | t.same(vals, ['hello', 'world']) 23 | t.end() 24 | cb() 25 | } 26 | }) 27 | 28 | tape('batches', function (t) { 29 | var batch = batcher(run) 30 | var expected = [['hello'], ['hej', 'hi', 'hey']] 31 | 32 | batch('hello') 33 | batch('hej') 34 | batch('hi') 35 | batch('hey', function () { 36 | t.end() 37 | }) 38 | 39 | function run (vals, cb) { 40 | t.same(vals, expected.shift()) 41 | process.nextTick(cb) 42 | } 43 | }) 44 | 45 | tape('empty batch is called', function (t) { 46 | var batch = batcher(run) 47 | 48 | batch([]) 49 | batch([], function () { 50 | t.end() 51 | }) 52 | 53 | function run (vals, cb) { 54 | t.same(vals, []) 55 | process.nextTick(cb) 56 | } 57 | }) 58 | 59 | tape('forwards error', function (t) { 60 | t.plan(4) 61 | 62 | var batch = batcher(run) 63 | var i = 0 64 | 65 | batch('hello', function (err) { 66 | t.same(err.message, '#0') 67 | }) 68 | batch('hej', function (err) { 69 | t.same(err.message, '#1') 70 | }) 71 | batch('hi', function (err) { 72 | t.same(err.message, '#1') 73 | }) 74 | batch('hey', function (err) { 75 | t.same(err.message, '#1') 76 | }) 77 | 78 | function run (vals, cb) { 79 | process.nextTick(function () { 80 | cb(new Error('#' + i++)) 81 | }) 82 | } 83 | }) 84 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # atomic-batcher 2 | 3 | A simple batching function that allows you to atomically batch a series of operations. If you are looking for the same thing with a stream interface checkout [byte-stream](https://github.com/maxogden/byte-stream). 4 | 5 | ``` 6 | npm install atomic-batcher 7 | ``` 8 | 9 | [![build status](http://img.shields.io/travis/mafintosh/atomic-batcher.svg?style=flat)](http://travis-ci.org/mafintosh/atomic-batcher) 10 | 11 | ## Usage 12 | 13 | ``` js 14 | var batcher = require('atomic-batcher') 15 | var db = require('level')('some.db') 16 | 17 | var batch = batcher(function work (ops, cb) { 18 | // only one batch will happen at the time 19 | console.log('Batching:', ops, '\n') 20 | db.batch(ops, cb) 21 | }) 22 | 23 | batch({type: 'put', key: 'hello', value: 'world-1'}) 24 | batch({type: 'put', key: 'hello', value: 'world-2'}) 25 | batch({type: 'put', key: 'hello', value: 'world-3'}) 26 | batch({type: 'put', key: 'hi', value: 'hello'}, function () { 27 | console.log('Printing latest values:\n') 28 | db.get('hello', console.log) // returns world-3 29 | db.get('hi', console.log) // returns hello 30 | }) 31 | ``` 32 | 33 | Running the above example will print 34 | 35 | ``` 36 | Batching: [ { type: 'put', key: 'hello', value: 'world-1' } ] 37 | 38 | Batching: [ { type: 'put', key: 'hello', value: 'world-2' }, 39 | { type: 'put', key: 'hello', value: 'world-3' }, 40 | { type: 'put', key: 'hi', value: 'hello' } ] 41 | 42 | Printing latest values: 43 | 44 | null 'world-3' 45 | null 'hello' 46 | ``` 47 | 48 | ## API 49 | 50 | #### `var batch = batcher(worker)` 51 | 52 | Create a new batching function. `worker` should be a function that accepts a batch and a callback, `(batch, cb)`. 53 | Only one batch is guaranteed to be run at the time. 54 | 55 | The `batch` function accepts a value or an array of values and a callback, `batch(value(s), cb)`. The callback is called when the batch containing the values have been run. 56 | 57 | ## License 58 | 59 | MIT 60 | --------------------------------------------------------------------------------