Skip to content

Commit

Permalink
Support arbitrary options on chained batch put() and del()
Browse files Browse the repository at this point in the history
Needed for Level/levelup#633.
  • Loading branch information
vweevers committed Apr 9, 2021
1 parent 8057774 commit 184dd1b
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 24 deletions.
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -283,13 +283,13 @@ If no options are provided, all entries will be deleted. The `callback` function

### `chainedBatch`

#### `chainedBatch.put(key, value)`
#### `chainedBatch.put(key, value[, options])`

Queue a `put` operation on this batch. This may throw if `key` or `value` is invalid.
Queue a `put` operation on this batch. This may throw if `key` or `value` is invalid. There are no `options` by default but implementations may add theirs.

#### `chainedBatch.del(key)`
#### `chainedBatch.del(key[, options])`

Queue a `del` operation on this batch. This may throw if `key` is invalid.
Queue a `del` operation on this batch. This may throw if `key` is invalid. There are no `options` by default but implementations may add theirs.

#### `chainedBatch.clear()`

Expand Down Expand Up @@ -494,13 +494,13 @@ The default `_end()` invokes `callback` on a next tick. Overriding is optional.

The first argument to this constructor must be an instance of your `AbstractLevelDOWN` implementation. The constructor will set `chainedBatch.db` which is used to access `db._serialize*` and ensures that `db` will not be garbage collected in case there are no other references to it.

#### `chainedBatch._put(key, value)`
#### `chainedBatch._put(key, value, options)`

Queue a `put` operation on this batch.
Queue a `put` operation on this batch. There are no default options but `options` will always be an object.

#### `chainedBatch._del(key)`
#### `chainedBatch._del(key, options)`

Queue a `del` operation on this batch.
Queue a `del` operation on this batch. There are no default options but `options` will always be an object.

#### `chainedBatch._clear()`

Expand Down
22 changes: 13 additions & 9 deletions abstract-chained-batch.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
'use strict'

const emptyOptions = Object.freeze({})

function AbstractChainedBatch (db) {
if (typeof db !== 'object' || db === null) {
throw new TypeError('First argument must be an abstract-leveldown compliant store')
Expand All @@ -16,7 +18,7 @@ AbstractChainedBatch.prototype._checkWritten = function () {
}
}

AbstractChainedBatch.prototype.put = function (key, value) {
AbstractChainedBatch.prototype.put = function (key, value, options) {
this._checkWritten()

const err = this.db._checkKey(key) || this.db._checkValue(value)
Expand All @@ -25,29 +27,29 @@ AbstractChainedBatch.prototype.put = function (key, value) {
key = this.db._serializeKey(key)
value = this.db._serializeValue(value)

this._put(key, value)
this._put(key, value, options != null ? options : emptyOptions)

return this
}

AbstractChainedBatch.prototype._put = function (key, value) {
this._operations.push({ type: 'put', key: key, value: value })
AbstractChainedBatch.prototype._put = function (key, value, options) {
this._operations.push({ ...options, type: 'put', key, value })
}

AbstractChainedBatch.prototype.del = function (key) {
AbstractChainedBatch.prototype.del = function (key, options) {
this._checkWritten()

const err = this.db._checkKey(key)
if (err) throw err

key = this.db._serializeKey(key)
this._del(key)
this._del(key, options != null ? options : emptyOptions)

return this
}

AbstractChainedBatch.prototype._del = function (key) {
this._operations.push({ type: 'del', key: key })
AbstractChainedBatch.prototype._del = function (key, options) {
this._operations.push({ ...options, type: 'del', key })
}

AbstractChainedBatch.prototype.clear = function () {
Expand All @@ -64,7 +66,9 @@ AbstractChainedBatch.prototype._clear = function () {
AbstractChainedBatch.prototype.write = function (options, callback) {
this._checkWritten()

if (typeof options === 'function') { callback = options }
if (typeof options === 'function') {
callback = options
}
if (typeof callback !== 'function') {
throw new Error('write() requires a callback argument')
}
Expand Down
4 changes: 2 additions & 2 deletions test/chained-batch-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ function collectBatchOps (batch) {
}

batch._put = function (key, value) {
_operations.push({ type: 'put', key: key, value: value })
_operations.push({ type: 'put', key, value })
return _put.apply(this, arguments)
}

batch._del = function (key) {
_operations.push({ type: 'del', key: key })
_operations.push({ type: 'del', key })
return _del.apply(this, arguments)
}

Expand Down
12 changes: 7 additions & 5 deletions test/self.js
Original file line number Diff line number Diff line change
Expand Up @@ -365,14 +365,14 @@ test('test chained batch() extensibility', function (t) {
t.deepEqual(spy.getCall(0).args[1], {}, 'got expected options argument')
t.equal(spy.getCall(0).args[2], expectedCb, 'got expected callback argument')

test.batch().put('foo', 'bar').del('bang').write(expectedOptions, expectedCb)
test.batch().put('foo', 'bar', expectedOptions).del('bang', expectedOptions).write(expectedOptions, expectedCb)

t.equal(spy.callCount, 2, 'got _batch() call')
t.equal(spy.getCall(1).thisValue, test, '`this` on _batch() was correct')
t.equal(spy.getCall(1).args.length, 3, 'got three arguments')
t.equal(spy.getCall(1).args[0].length, 2, 'got expected array argument')
t.deepEqual(spy.getCall(1).args[0][0], { type: 'put', key: 'foo', value: 'bar' }, 'got expected array argument[0]')
t.deepEqual(spy.getCall(1).args[0][1], { type: 'del', key: 'bang' }, 'got expected array argument[1]')
t.deepEqual(spy.getCall(1).args[0][0], { type: 'put', key: 'foo', value: 'bar', options: 1 }, 'got expected array argument[0]')
t.deepEqual(spy.getCall(1).args[0][1], { type: 'del', key: 'bang', options: 1 }, 'got expected array argument[1]')
t.deepEqual(spy.getCall(1).args[1], expectedOptions, 'got expected options argument')
t.equal(spy.getCall(1).args[2], expectedCb, 'got expected callback argument')

Expand Down Expand Up @@ -485,9 +485,10 @@ test('test AbstractChainedBatch#put() extensibility', function (t) {

t.equal(spy.callCount, 1, 'got _put call')
t.equal(spy.getCall(0).thisValue, test, '`this` on _put() was correct')
t.equal(spy.getCall(0).args.length, 2, 'got two arguments')
t.equal(spy.getCall(0).args.length, 3, 'got 3 arguments')
t.equal(spy.getCall(0).args[0], expectedKey, 'got expected key argument')
t.equal(spy.getCall(0).args[1], expectedValue, 'got expected value argument')
t.same(spy.getCall(0).args[2], {}, 'got expected options argument')
t.equal(returnValue, test, 'get expected return value')
t.end()
})
Expand All @@ -501,8 +502,9 @@ test('test AbstractChainedBatch#del() extensibility', function (t) {

t.equal(spy.callCount, 1, 'got _del call')
t.equal(spy.getCall(0).thisValue, test, '`this` on _del() was correct')
t.equal(spy.getCall(0).args.length, 1, 'got one argument')
t.equal(spy.getCall(0).args.length, 2, 'got 2 arguments')
t.equal(spy.getCall(0).args[0], expectedKey, 'got expected key argument')
t.same(spy.getCall(0).args[1], {}, 'got expected options argument')
t.equal(returnValue, test, 'get expected return value')
t.end()
})
Expand Down

0 comments on commit 184dd1b

Please sign in to comment.