From c808bd9196f69cf93c5101cc2b45dbbff6f73eb7 Mon Sep 17 00:00:00 2001 From: Vincent Weevers Date: Sun, 18 Aug 2019 15:40:51 +0200 Subject: [PATCH 1/4] Add clear() method to delete all entries or a range --- README.md | 19 +++++++++++ lib/levelup.js | 27 +++++++++++++++ package.json | 1 + test/clear-test.js | 83 ++++++++++++++++++++++++++++++++++++++++++++++ test/index.js | 1 + 5 files changed, 131 insertions(+) create mode 100644 test/clear-test.js diff --git a/README.md b/README.md index 0d718f49..52450a97 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,7 @@ db.put('name', 'levelup', function (err) { - db.createKeyStream() - db.createValueStream() - db.iterator() +- db.clear() ### Special Notes @@ -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 createReadStream and are passed to the underlying store. + + +### `db.clear([options][, callback])` + +**This method is experimental. Not all stores support it yet.** + +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. + #### What happened to `db.createWriteStream`? @@ -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) | | `opening` | Underlying store is opening | - | | `open` | Store has opened | - | | `ready` | Alias of `open` | - | diff --git a/lib/levelup.js b/lib/levelup.js index a6853913..462010d2 100644 --- a/lib/levelup.js +++ b/lib/levelup.js @@ -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) diff --git a/package.json b/package.json index 86635468..f7007f6b 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "encoding-down": "^6.0.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", diff --git a/test/clear-test.js b/test/clear-test.js new file mode 100644 index 00000000..083df816 --- /dev/null +++ b/test/clear-test.js @@ -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() +}) diff --git a/test/index.js b/test/index.js index 57e30535..ce630379 100644 --- a/test/index.js +++ b/test/index.js @@ -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') From 06fe4c2e40baad0bf13430d0de7d6c3205715375 Mon Sep 17 00:00:00 2001 From: Vincent Weevers Date: Sun, 18 Aug 2019 15:42:47 +0200 Subject: [PATCH 2/4] Upgrade deferred-leveldown from ~5.1.0 to ~5.2.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f7007f6b..e1e56714 100644 --- a/package.json +++ b/package.json @@ -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" From 62492c231af3783a44bd0f41f18df25c653afe13 Mon Sep 17 00:00:00 2001 From: Vincent Weevers Date: Sun, 18 Aug 2019 15:43:48 +0200 Subject: [PATCH 3/4] Upgrade encoding-down devDependency from ^6.0.0 to ^6.2.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e1e56714..ccd6d77f 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "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", From 47139d4df44457388aa15e64a9a7b57c2381285d Mon Sep 17 00:00:00 2001 From: Vincent Weevers Date: Sat, 7 Sep 2019 10:56:07 +0200 Subject: [PATCH 4/4] Add link to Level/community#79 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 52450a97..e76d009e 100644 --- a/README.md +++ b/README.md @@ -396,7 +396,7 @@ Returns an [`abstract-leveldown` iterator](https://github.com/Level/abstract-lev ### `db.clear([options][, callback])` -**This method is experimental. Not all stores support it yet.** +**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):