Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support clear() #182

Merged
merged 2 commits into from
Sep 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ var serialize = require('./util/serialize')
var deserialize = require('./util/deserialize')
var setImmediate = require('./util/immediate')
var support = require('./util/support')
var clear = require('./util/clear')
var createKeyRange = require('./util/key-range')

var DEFAULT_PREFIX = 'level-js-'

Expand Down Expand Up @@ -181,6 +183,33 @@ Level.prototype._batch = function (operations, options, callback) {
loop()
}

Level.prototype._clear = function (options, callback) {
try {
var keyRange = createKeyRange(options)
} catch (e) {
// The lower key is greater than the upper key.
// IndexedDB throws an error, but we'll just do nothing.
return setImmediate(callback)
}

if (options.limit >= 0) {
// IDBObjectStore#delete(range) doesn't have such an option.
// Fall back to cursor-based implementation.
return clear(this, this.location, keyRange, options, callback)
}

try {
var store = this.store('readwrite')
var req = keyRange ? store.delete(keyRange) : store.clear()
} catch (err) {
return setImmediate(function () {
vweevers marked this conversation as resolved.
Show resolved Hide resolved
callback(err)
})
}

this.await(req, callback)
}

Level.prototype._close = function (callback) {
this.db.close()
setImmediate(callback)
Expand Down
23 changes: 2 additions & 21 deletions iterator.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
/* global IDBKeyRange */

'use strict'

var inherits = require('inherits')
var AbstractIterator = require('abstract-leveldown').AbstractIterator
var ltgt = require('ltgt')
var createKeyRange = require('./util/key-range')
var deserialize = require('./util/deserialize')
var setImmediate = require('./util/immediate')
var noop = function () {}
Expand Down Expand Up @@ -34,7 +32,7 @@ function Iterator (db, location, options) {
}

try {
var keyRange = this.createKeyRange(options)
var keyRange = createKeyRange(options)
} catch (e) {
// The lower key is greater than the upper key.
// IndexedDB throws an error, but we'll just return 0 results.
Expand All @@ -47,23 +45,6 @@ function Iterator (db, location, options) {

inherits(Iterator, AbstractIterator)

Iterator.prototype.createKeyRange = function (options) {
var lower = ltgt.lowerBound(options)
var upper = ltgt.upperBound(options)
var lowerOpen = ltgt.lowerBoundExclusive(options)
var upperOpen = ltgt.upperBoundExclusive(options)

if (lower !== undefined && upper !== undefined) {
return IDBKeyRange.bound(lower, upper, lowerOpen, upperOpen)
} else if (lower !== undefined) {
return IDBKeyRange.lowerBound(lower, lowerOpen)
} else if (upper !== undefined) {
return IDBKeyRange.upperBound(upper, upperOpen)
} else {
return null
}
}

Iterator.prototype.createIterator = function (location, keyRange, reverse) {
var self = this
var transaction = this.db.db.transaction([location], 'readonly')
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"./util/immediate.js": "./util/immediate-browser.js"
},
"dependencies": {
"abstract-leveldown": "~6.0.1",
"abstract-leveldown": "~6.1.1",
"immediate": "~3.2.3",
"inherits": "^2.0.3",
"ltgt": "^2.1.2"
Expand Down
24 changes: 24 additions & 0 deletions test/custom-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -296,5 +296,29 @@ module.exports = function (leveljs, test, testCommon) {
})
})

// TODO: move to abstract-leveldown test suite (and add to iterator tests too)
test('clear() with lower key greater than upper key', function (t) {
var db = testCommon.factory()

db.open(function (err) {
t.ifError(err, 'no open error')

db.put('a', 'a', function (err) {
t.ifError(err, 'no put error')

db.clear({ gt: 'b', lt: 'a' }, function (err) {
t.ifError(err, 'no clear error')

db.get('a', { asBuffer: false }, function (err, value) {
t.ifError(err, 'no get error')
t.is(value, 'a')

db.close(t.end.bind(t))
})
})
})
})
})

test('teardown', testCommon.tearDown)
}
5 changes: 4 additions & 1 deletion test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ var testCommon = suite.common({
seek: false,

// Support of buffer keys depends on environment
bufferKeys: leveljs(uuid()).supports.bufferKeys
bufferKeys: leveljs(uuid()).supports.bufferKeys,

// Opt-in to new clear() tests
clear: true
})

// Test abstract-leveldown compliance
Expand Down
36 changes: 36 additions & 0 deletions util/clear.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
'use strict'

var setImmediate = require('./immediate')

module.exports = function clear (db, location, keyRange, options, callback) {
if (options.limit === 0) return setImmediate(callback)

var transaction = db.db.transaction([location], 'readwrite')
var store = transaction.objectStore(location)
var count = 0

transaction.oncomplete = function () {
callback()
vweevers marked this conversation as resolved.
Show resolved Hide resolved
}

transaction.onabort = function () {
callback(transaction.error || new Error('aborted by user'))
}

// A key cursor is faster (skips reading values) but not supported by IE
var method = store.openKeyCursor ? 'openKeyCursor' : 'openCursor'
var direction = options.reverse ? 'prev' : 'next'

store[method](keyRange, direction).onsuccess = function (ev) {
var cursor = ev.target.result

if (cursor) {
// Wait for a request to complete before continuing, saving CPU.
store.delete(cursor.key).onsuccess = function () {
if (options.limit <= 0 || ++count < options.limit) {
cursor.continue()
}
}
}
}
}
23 changes: 23 additions & 0 deletions util/key-range.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/* global IDBKeyRange */

'use strict'

var ltgt = require('ltgt')
var NONE = {}

module.exports = function createKeyRange (options) {
var lower = ltgt.lowerBound(options, NONE)
var upper = ltgt.upperBound(options, NONE)
var lowerOpen = ltgt.lowerBoundExclusive(options, NONE)
var upperOpen = ltgt.upperBoundExclusive(options, NONE)

if (lower !== NONE && upper !== NONE) {
return IDBKeyRange.bound(lower, upper, lowerOpen, upperOpen)
} else if (lower !== NONE) {
return IDBKeyRange.lowerBound(lower, lowerOpen)
} else if (upper !== NONE) {
return IDBKeyRange.upperBound(upper, upperOpen)
} else {
return null
}
}