From 539abd0f10bbd92ffb42d25c8db8403e5d80f764 Mon Sep 17 00:00:00 2001 From: Vincent Weevers Date: Mon, 30 Sep 2019 10:57:59 +0300 Subject: [PATCH] Add manifest (Level/community#83) (#351) --- README.md | 28 ++++++++++++++++++++++++++-- abstract-leveldown.js | 8 +++++++- package.json | 1 + test/common.js | 4 ++++ test/index.js | 1 + test/manifest-test.js | 15 +++++++++++++++ test/self.js | 2 +- 7 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 test/manifest-test.js diff --git a/README.md b/README.md index b04445f7..71da49d1 100644 --- a/README.md +++ b/README.md @@ -135,6 +135,20 @@ A read-only property. An `abstract-leveldown` compliant store can be in one of t - `'closing'` - waiting for the store to be closed - `'closed'` - store has been successfully closed, should not be used. +### `db.supports` + +A read-only [manifest](https://github.com/Level/supports). Might be used like so: + +```js +if (!db.supports.permanence) { + throw new Error('Persistent storage is required') +} + +if (db.supports.bufferKeys && db.supports.promises) { + await db.put(Buffer.from('key'), 'value') +} +``` + ### `db.open([options, ]callback)` Open the store. The `callback` function will be called with no arguments when the store has been successfully opened, or with a single error argument if the open operation failed for any reason. @@ -294,9 +308,17 @@ Support of other key and value types depends on the implementation as well as it Each of these methods will receive exactly the number and order of arguments described. Optional arguments will receive sensible defaults. All callbacks are error-first and must be asynchronous. If an operation within your implementation is synchronous, be sure to invoke the callback on a next tick using `process.nextTick(callback, ..)`, `setImmediate` or some other means of micro- or macrotask scheduling. -### `db = AbstractLevelDOWN()` +### `db = AbstractLevelDOWN([manifest])` -The constructor takes no parameters. Sets the `.status` to `'new'`. +The constructor. Sets the `.status` to `'new'`. Optionally takes a [manifest](https://github.com/Level/supports) object which `abstract-leveldown` will enrich: + +```js +AbstractLevelDOWN.call(this, { + bufferKeys: true, + snapshots: true, + // .. +}) +``` ### `db._open(options, callback)` @@ -497,6 +519,8 @@ This also serves as a signal to users of your implementation. The following opti - Snapshots are created asynchronously - `createIfMissing` and `errorIfExists`: set to `false` if `db._open()` does not support these options. +This metadata will be moved to manifests (`db.supports`) in the future. + ### Setup and teardown To perform (a)synchronous work before or after each test, you may define `setUp` and `tearDown` functions: diff --git a/abstract-leveldown.js b/abstract-leveldown.js index cd744c24..259204b4 100644 --- a/abstract-leveldown.js +++ b/abstract-leveldown.js @@ -1,11 +1,17 @@ var xtend = require('xtend') +var supports = require('level-supports') var AbstractIterator = require('./abstract-iterator') var AbstractChainedBatch = require('./abstract-chained-batch') var hasOwnProperty = Object.prototype.hasOwnProperty var rangeOptions = 'start end gt gte lt lte'.split(' ') -function AbstractLevelDOWN () { +function AbstractLevelDOWN (manifest) { this.status = 'new' + + // TODO (next major): make this mandatory + this.supports = supports(manifest, { + status: true + }) } AbstractLevelDOWN.prototype.open = function (options, callback) { diff --git a/package.json b/package.json index 0e16a32e..b2f42a4a 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ }, "dependencies": { "level-concat-iterator": "~2.0.0", + "level-supports": "~1.0.0", "xtend": "~4.0.0" }, "devDependencies": { diff --git a/test/common.js b/test/common.js index 47c53454..cdc216ba 100644 --- a/test/common.js +++ b/test/common.js @@ -13,8 +13,12 @@ function testCommon (options) { return { test: test, factory: factory, + + // TODO (next major): remove setUp: options.setUp || noopTest(), tearDown: options.tearDown || noopTest(), + + // TODO (next major): use db.supports instead bufferKeys: options.bufferKeys !== false, createIfMissing: options.createIfMissing !== false, errorIfExists: options.errorIfExists !== false, diff --git a/test/index.js b/test/index.js index 9c2fa35a..1ef97afc 100644 --- a/test/index.js +++ b/test/index.js @@ -5,6 +5,7 @@ function suite (options) { var test = testCommon.test require('./factory-test')(test, testCommon) + require('./manifest-test')(test, testCommon) require('./leveldown-test')(test, testCommon) require('./open-test').all(test, testCommon) diff --git a/test/manifest-test.js b/test/manifest-test.js new file mode 100644 index 00000000..b09a1f0e --- /dev/null +++ b/test/manifest-test.js @@ -0,0 +1,15 @@ +var suite = require('level-supports/test') + +module.exports = function (test, testCommon) { + test('setUp common', testCommon.setUp) + + suite(test, testCommon) + + test('manifest has status', function (t) { + var db = testCommon.factory() + t.is(db.supports.status, true) + db.close(t.end.bind(t)) + }) + + test('tearDown', testCommon.tearDown) +} diff --git a/test/self.js b/test/self.js index 18e156c0..8dfc6255 100644 --- a/test/self.js +++ b/test/self.js @@ -22,7 +22,7 @@ var legacyRangeOptions = ['start', 'end'] // excluding noop operations that can't pass the test suite. require('./leveldown-test')(test, testCommon) - +require('./manifest-test')(test, testCommon) require('./open-test').all(test, testCommon) require('./open-create-if-missing-test').setUp(test, testCommon)