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

Add clear() #669

Merged
merged 4 commits into from
Sep 8, 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
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ db.put('name', 'levelup', function (err) {
- <a href="#createKeyStream"><code>db.<b>createKeyStream()</b></code></a>
- <a href="#createValueStream"><code>db.<b>createValueStream()</b></code></a>
- <a href="#iterator"><code>db.<b>iterator()</b></code></a>
- <a href="#clear"><code>db.<b>clear()</b></code></a>

### Special Notes

Expand Down Expand Up @@ -391,6 +392,23 @@ db.createReadStream({ keys: false, values: true })

Returns an [`abstract-leveldown` iterator](https://github.com/Level/abstract-leveldown/#abstractleveldown_iteratoroptions), which is what powers the readable streams above. Options are the same as the range options of <a href="#createReadStream"><code>createReadStream</code></a> and are passed to the underlying store.

<a name="clear"></a>

### `db.clear([options][, callback])`

**This method is experimental. Not all underlying stores support it yet. Consult [Level/community#79](https://github.com/Level/community/issues/79) to find out if your (combination of) dependencies support `db.clear()`.**

Delete all entries or a range. Not guaranteed to be atomic. Accepts the following range options (with the same rules as on iterators):

- `gt` (greater than), `gte` (greater than or equal) define the lower bound of the range to be deleted. Only entries where the key is greater than (or equal to) this option will be included in the range. When `reverse=true` the order will be reversed, but the entries deleted will be the same.
- `lt` (less than), `lte` (less than or equal) define the higher bound of the range to be deleted. Only entries where the key is less than (or equal to) this option will be included in the range. When `reverse=true` the order will be reversed, but the entries deleted will be the same.
- `reverse` _(boolean, default: `false`)_: delete entries in reverse order. Only effective in combination with `limit`, to remove the last N records.
- `limit` _(number, default: `-1`)_: limit the number of entries to be deleted. This number represents a _maximum_ number of entries and may not be reached if you get to the end of the range first. A value of `-1` means there is no limit. When `reverse=true` the entries with the highest keys will be deleted instead of the lowest keys.

If no options are provided, all entries will be deleted. The `callback` function will be called with no arguments if the operation was successful or with an `WriteError` if it failed for any reason.

If no callback is passed, a promise is returned.

<a name="writeStreams"></a>

#### What happened to `db.createWriteStream`?
Expand Down Expand Up @@ -446,6 +464,7 @@ const main = async () => {
| `put` | Key has been updated | `key, value` (any) |
| `del` | Key has been deleted | `key` (any) |
| `batch` | Batch has executed | `operations` (array) |
| `clear` | Entries were deleted | `options` (object) |
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not 100% sure about the argument (options). I figured a listener might want to inspect the range options, to find out what was deleted. But that information is not exact (in contrast with the put, del and batch events that tell you exactly which keys were modified).

| `opening` | Underlying store is opening | - |
| `open` | Store has opened | - |
| `ready` | Alias of `open` | - |
Expand Down
27 changes: 27 additions & 0 deletions lib/levelup.js
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,33 @@ LevelUP.prototype.iterator = function (options) {
return this.db.iterator(options)
}

LevelUP.prototype.clear = function (options, callback) {
var self = this
var promise

callback = getCallback(options, callback)
options = getOptions(options)

if (!callback) {
callback = promisify()
promise = callback.promise
}

if (maybeError(this, callback)) {
return promise
}

this.db.clear(options, function (err) {
if (err) {
return callback(new WriteError(err))
}
self.emit('clear', options)
callback()
})

return promise
}

LevelUP.prototype.readStream =
LevelUP.prototype.createReadStream = function (options) {
options = extend({ keys: true, values: true }, options)
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"prepublishOnly": "npm run dependency-check"
},
"dependencies": {
"deferred-leveldown": "~5.1.0",
"deferred-leveldown": "~5.2.0",
"level-errors": "~2.0.0",
"level-iterator-stream": "~4.0.0",
"xtend": "~4.0.0"
Expand All @@ -30,9 +30,10 @@
"coveralls": "^3.0.2",
"delayed": "^2.0.0",
"dependency-check": "^3.3.0",
"encoding-down": "^6.0.0",
"encoding-down": "^6.2.0",
"hallmark": "^2.0.0",
"level-community": "^3.0.0",
"level-concat-iterator": "^2.0.1",
"memdown": "^5.0.0",
"nyc": "^14.0.0",
"pinkie": "^2.0.4",
Expand Down
83 changes: 83 additions & 0 deletions test/clear-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
var test = require('tape')
var memdown = require('memdown')
var encode = require('encoding-down')
var concat = require('level-concat-iterator')
var levelup = require('../lib/levelup')

test('clear()', function (t) {
function makeTest (name, fn) {
t.test(name, function (t) {
var mem = memdown()

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

mem.batch([
{ type: 'put', key: '"a"', value: 'a' },
{ type: 'put', key: '"b"', value: 'b' }
], function (err) {
t.ifError(err, 'no batch error')

mem.close(function (err) {
t.ifError(err, 'no close error')
fn(t, mem)
})
})
})
})
}

function verify (t, db, expectedKey) {
concat(db.iterator({ keyAsBuffer: false }), function (err, entries) {
t.ifError(err, 'no concat error')
t.same(entries.map(function (e) { return e.key }), [expectedKey], 'got expected keys')
db.close(t.end.bind(t))
})
}

makeTest('clear() without encoding, without deferred-open', function (t, mem) {
var db = levelup(mem)

db.open(function (err) {
t.ifError(err)

db.clear({ gte: '"b"' }, function (err) {
t.ifError(err, 'no clear error')
verify(t, db, '"a"')
})
})
})

makeTest('clear() without encoding, with deferred-open', function (t, mem) {
var db = levelup(mem)

db.clear({ gte: '"b"' }, function (err) {
t.ifError(err, 'no clear error')
verify(t, db, '"a"')
})
})

makeTest('clear() with encoding, with deferred-open', function (t, mem) {
var db = levelup(encode(mem, { keyEncoding: 'json' }))

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

makeTest('clear() with encoding, without deferred-open', function (t, mem) {
var db = levelup(encode(mem, { keyEncoding: 'json' }))

db.open(function (err) {
t.ifError(err)

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

t.end()
})
1 change: 1 addition & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ if (process.browser && typeof Promise !== 'function') {
require('./argument-checking-test')
require('./batch-test')
require('./binary-test')
require('./clear-test')
require('./deferred-open-test')
require('./get-put-del-test')
require('./idempotent-test')
Expand Down