pax_global_header00006660000000000000000000000064136442710770014525gustar00rootroot0000000000000052 comment=7e6e3cf7312d7cf7970c082d6da7079f79b3aed2 abstract-leveldown-6.3.0/000077500000000000000000000000001364427107700153335ustar00rootroot00000000000000abstract-leveldown-6.3.0/.airtap.yml000066400000000000000000000004521364427107700174150ustar00rootroot00000000000000browsers: - name: chrome version: latest platform: Windows 10 - name: internet explorer version: '11' - name: firefox version: latest platform: Windows 10 - name: iphone version: '9.0' - name: android version: '6.0' - name: microsoftedge version: latest abstract-leveldown-6.3.0/.gitignore000066400000000000000000000000421364427107700173170ustar00rootroot00000000000000node_modules coverage .nyc_output abstract-leveldown-6.3.0/.travis.yml000066400000000000000000000006551364427107700174520ustar00rootroot00000000000000sudo: false language: node_js matrix: fast_finish: true include: - node_js: 6 env: CMD=test - node_js: 8 env: CMD=test - node_js: 10 env: CMD=test - node_js: stable env: CMD=test-browsers addons: sauce_connect: true hosts: - airtap.local before_script: git fetch --tags script: - DEBUG=airtap:* npm run $CMD after_success: npm run coverage notifications: email: false abstract-leveldown-6.3.0/CHANGELOG.md000066400000000000000000001226131364427107700171510ustar00rootroot00000000000000# Changelog _**If you are upgrading:** please see [`UPGRADING.md`](UPGRADING.md)._ ## [6.3.0] - 2020-04-11 ### Changed - Upgrade devDependency `dependency-check` from `^3.3.0` to `^4.1.0` ([`9193656`](https://github.com/Level/abstract-leveldown/commit/9193656)) ([**@vweevers**](https://github.com/vweevers)) ### Added - Support running test suite on a `levelup` db, as well as skipping `start` and `end` tests (for `multileveldown`) ([#364](https://github.com/Level/abstract-leveldown/issues/364)) ([**@vweevers**](https://github.com/vweevers)) ## [6.2.3] - 2020-04-03 ### Changed - Upgrade `airtap` devDependency from `^2.0.0` to `^3.0.0` ([#360](https://github.com/Level/abstract-leveldown/issues/360)) ([**@vweevers**](https://github.com/vweevers)) ### Fixed - Add `buffer` and `immediate` for browsers ([#355](https://github.com/Level/abstract-leveldown/issues/355), [#362](https://github.com/Level/abstract-leveldown/issues/362), [#363](https://github.com/Level/abstract-leveldown/issues/363)) ([**@Raynos**](https://github.com/Raynos), [**@hugomrdias**](https://github.com/hugomrdias), [**@vweevers**](https://github.com/vweevers)) ## [6.2.2] - 2019-10-21 ### Added - Add more range tests ([#353](https://github.com/Level/abstract-leveldown/issues/353)) ([**@vweevers**](https://github.com/vweevers)) ## [6.2.1] - 2019-10-01 ### Fixed - Fix `manifest-test` to open & close its db ([#352](https://github.com/Level/abstract-leveldown/issues/352)) ([**@vweevers**](https://github.com/vweevers)) ## [6.2.0] - 2019-09-30 ### Changed - Upgrade `hallmark` devDependency from `^1.0.0` to `^2.0.0` ([#349](https://github.com/Level/abstract-leveldown/issues/349)) ([**@vweevers**](https://github.com/vweevers)) - Upgrade `standard` devDependency from `^13.0.1` to `^14.0.0` ([#348](https://github.com/Level/abstract-leveldown/issues/348)) ([**@vweevers**](https://github.com/vweevers)) ### Added - Add manifest ([Level/community#83](https://github.com/Level/community/issues/83)) ([#351](https://github.com/Level/abstract-leveldown/issues/351)) ([**@vweevers**](https://github.com/vweevers)) - Document mandatory methods ([#350](https://github.com/Level/abstract-leveldown/issues/350)) ([**@vweevers**](https://github.com/vweevers)) ## [6.1.1] - 2019-08-18 ### Fixed - Remove `process.emitWarning` because it breaks AppVeyor builds ([`8e963c3`](https://github.com/Level/abstract-leveldown/commit/8e963c3)) ([**@vweevers**](https://github.com/vweevers)) ## [6.1.0] - 2019-08-18 ### Changed - Upgrade `hallmark` devDependency from `^0.1.0` to `^1.0.0` ([#343](https://github.com/Level/abstract-leveldown/issues/343)) ([**@vweevers**](https://github.com/vweevers)) - Upgrade `standard` devDependency from `^12.0.0` to `^13.0.1` ([#341](https://github.com/Level/abstract-leveldown/issues/341)) ([**@vweevers**](https://github.com/vweevers)) ### Added - Add `clear()` method to delete all entries or a range ([#310](https://github.com/Level/abstract-leveldown/issues/310)) ([**@vweevers**](https://github.com/vweevers)). **Historical Note** The `clear()` method is experimental and optional for the time being. Please see the [README](https://github.com/Level/abstract-leveldown) for details. ## [6.0.3] - 2019-04-26 ### Changed - Upgrade `nyc` devDependency from `^13.2.0` to `^14.0.0` ([#334](https://github.com/Level/abstract-leveldown/issues/334)) ([**@vweevers**](https://github.com/vweevers)) ### Fixed - Fix and test asynchronicity of empty batch ([#337](https://github.com/Level/abstract-leveldown/issues/337)) ([**@vweevers**](https://github.com/vweevers)) - Fix Level badge ([`8993257`](https://github.com/Level/abstract-leveldown/commit/8993257)) ([**@vweevers**](https://github.com/vweevers)) - Remove link to dead website ([`c0abe28`](https://github.com/Level/abstract-leveldown/commit/c0abe28)) ([**@vweevers**](https://github.com/vweevers)) ## [6.0.2] - 2019-03-30 ### Changed - Upgrade `sinon` devDependency from `^6.0.0` to `^7.2.4` ([#330](https://github.com/Level/abstract-leveldown/issues/330)) ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Upgrade `nyc` devDependency from `^12.0.2` to `^13.2.0` ([#327](https://github.com/Level/abstract-leveldown/issues/327)) ([**@vweevers**](https://github.com/vweevers)) - Upgrade `airtap` devDependency from `0.1.0` to `^2.0.0` ([#323](https://github.com/Level/abstract-leveldown/issues/323)) ([**@vweevers**](https://github.com/vweevers)) - Apply common project tweaks ([#324](https://github.com/Level/abstract-leveldown/issues/324), [#325](https://github.com/Level/abstract-leveldown/issues/325)) ([**@vweevers**](https://github.com/vweevers)) ### Fixed - Fix subtests by adding `t.plan()` ([#329](https://github.com/Level/abstract-leveldown/issues/329)) ([**@vweevers**](https://github.com/vweevers)) ## [6.0.1] - 2018-12-27 ### Changed - Upgrade `hallmark` devDependency from `0.0.2` to `0.1.0` ([#316](https://github.com/level/abstract-leveldown/issues/316)) ([**@vweevers**](https://github.com/vweevers)) - Split v6 upgrade guide into sections for consumers and implementors ([**@vweevers**](https://github.com/vweevers)) ### Fixed - Remove range tests that assumed zero-length strings or Buffers meant "not defined" ([#319](https://github.com/level/abstract-leveldown/issues/319)) ([**@vweevers**](https://github.com/vweevers)) ## [6.0.0] - 2018-10-20 _If you are upgrading, please consult the [Upgrade Guide](UPGRADING.md#v6)._ ### Changed - Upgrade `airtap` devDependency from `0.0.5` to `0.1.0` ([#229](https://github.com/level/abstract-leveldown/issues/229), [#231](https://github.com/level/abstract-leveldown/issues/231), [#245](https://github.com/level/abstract-leveldown/issues/245), [`029f56a`](https://github.com/level/abstract-leveldown/commit/029f56a), [#252](https://github.com/level/abstract-leveldown/issues/252)) ([**@vweevers**](https://github.com/vweevers), [**@ralphtheninja**](https://github.com/ralphtheninja)) - Upgrade `sinon` devDependency from `^5.0.0` to `^6.0.0` ([#232](https://github.com/level/abstract-leveldown/issues/232)) ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Upgrade `standard` devDependency from `^11.0.0` to `^12.0.0` ([#303](https://github.com/level/abstract-leveldown/issues/303)) ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Reject nullish values ([#277](https://github.com/level/abstract-leveldown/issues/277)) ([**@vweevers**](https://github.com/vweevers)) - Make default `_serializeKey` and `_serializeValue` identity functions ([#277](https://github.com/level/abstract-leveldown/issues/277)) ([**@vweevers**](https://github.com/vweevers)) - Don't coerce keys to strings to check if they're empty, instead check arrays explicitly ([#277](https://github.com/level/abstract-leveldown/issues/277)) ([**@vweevers**](https://github.com/vweevers)) - Make `db` property mandatory and public on iterator and chained batch ([#257](https://github.com/level/abstract-leveldown/issues/257), [#309](https://github.com/level/abstract-leveldown/issues/309)) ([**@vweevers**](https://github.com/vweevers)) - Align `AbstractChainedBatch#_clear` with `_put` and `_del` ([#257](https://github.com/level/abstract-leveldown/issues/257)) ([**@vweevers**](https://github.com/vweevers)) - Add `AbstractChainedBatch#_write` with options ([#257](https://github.com/level/abstract-leveldown/issues/257)) ([**@vweevers**](https://github.com/vweevers)) - Use `level-concat-iterator` instead of `collectEntries` ([#246](https://github.com/level/abstract-leveldown/issues/246)) ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Document API and test suite ([#251](https://github.com/level/abstract-leveldown/issues/251), [#290](https://github.com/level/abstract-leveldown/issues/290), [#295](https://github.com/level/abstract-leveldown/issues/295), [#296](https://github.com/level/abstract-leveldown/issues/296), [#305](https://github.com/level/abstract-leveldown/issues/305)) ([**@vweevers**](https://github.com/vweevers)) - Export test suite as a single function ([#271](https://github.com/level/abstract-leveldown/issues/271), [#293](https://github.com/level/abstract-leveldown/issues/293), [#297](https://github.com/level/abstract-leveldown/issues/297)) ([**@vweevers**](https://github.com/vweevers), [**@ralphtheninja**](https://github.com/ralphtheninja)) - Use factory function to create `db` instances in test suite ([#258](https://github.com/level/abstract-leveldown/issues/258), [#268](https://github.com/level/abstract-leveldown/issues/268), [#282](https://github.com/level/abstract-leveldown/issues/282)) ([**@ralphtheninja**](https://github.com/ralphtheninja), [**@vweevers**](https://github.com/vweevers)) - Isolate snapshot tests so that they can be skipped ([#239](https://github.com/level/abstract-leveldown/issues/239), [#274](https://github.com/level/abstract-leveldown/issues/274)) ([**@vweevers**](https://github.com/vweevers), [**@ralphtheninja**](https://github.com/ralphtheninja)) - Isolate openAdvanced tests so that they can be skipped ([#271](https://github.com/level/abstract-leveldown/issues/271)) ([**@vweevers**](https://github.com/vweevers)) - Rename `abstract/` to `test/` ([#253](https://github.com/level/abstract-leveldown/issues/253)) ([**@vweevers**](https://github.com/vweevers)) - Refactor internal test methods to have the same signature `(test, testCommon)` ([#268](https://github.com/level/abstract-leveldown/issues/268), [#275](https://github.com/level/abstract-leveldown/issues/275)) ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Prefer `exports.*` over `module.exports.*` ([#276](https://github.com/level/abstract-leveldown/issues/276)) ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Tweak copyright years for less maintenance ([`0b2949a`](https://github.com/level/abstract-leveldown/commit/0b2949a)) ([**@ralphtheninja**](https://github.com/ralphtheninja)) ### Added - Add `iterator#seek()` ([#237](https://github.com/level/abstract-leveldown/issues/237), [#302](https://github.com/level/abstract-leveldown/issues/302), [#307](https://github.com/level/abstract-leveldown/issues/307)) ([**@vweevers**](https://github.com/vweevers), [**@ralphtheninja**](https://github.com/ralphtheninja)) - Add `nyc` and `coveralls` devDependencies for code coverage ([#253](https://github.com/level/abstract-leveldown/issues/253)) ([**@vweevers**](https://github.com/vweevers)) - Add `setUp` and `tearDown` to all sub tests ([#279](https://github.com/level/abstract-leveldown/issues/279), [#289](https://github.com/level/abstract-leveldown/issues/289)) ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Add test for implementations that cannot support snapshots ([#239](https://github.com/level/abstract-leveldown/issues/239)) ([**@vweevers**](https://github.com/vweevers)) - Add `hallmark` devDependency for Markdown style and contributors ([#312](https://github.com/level/abstract-leveldown/issues/312)) ([**@vweevers**](https://github.com/vweevers)) ### Removed - Remove `location` ([#258](https://github.com/level/abstract-leveldown/issues/258)) ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Remove `lastLocation`, `cleanup`, `rimraf` ([#249](https://github.com/level/abstract-leveldown/issues/249)) ([**@vweevers**](https://github.com/vweevers)) - Remove IE10 from Sauce Labs test matrix ([#312](https://github.com/level/abstract-leveldown/issues/312)) ([**@vweevers**](https://github.com/vweevers)) - Remove node 9 from Travis ([`0b52395`](https://github.com/level/abstract-leveldown/commit/0b52395)) ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Remove tests that assumed support of boolean and NaN keys ([#277](https://github.com/level/abstract-leveldown/issues/277)) ([**@vweevers**](https://github.com/vweevers)) - Remove range tests that assumed `null` meant "not defined" ([#277](https://github.com/level/abstract-leveldown/issues/277)) ([**@vweevers**](https://github.com/vweevers)) - Remove sync test from `test/put-test.js` ([#300](https://github.com/level/abstract-leveldown/issues/300)) ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Remove empty `errorValues()` test ([#273](https://github.com/level/abstract-leveldown/issues/273)) ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Remove default `testCommon` parameter ([#264](https://github.com/level/abstract-leveldown/issues/264), [#271](https://github.com/level/abstract-leveldown/issues/271)) ([**@vweevers**](https://github.com/vweevers)) - Remove `contributors` from `package.json` ([`542f350`](https://github.com/level/abstract-leveldown/commit/542f350)) ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Remove copyright headers from code ([`a36c04f`](https://github.com/level/abstract-leveldown/commit/a36c04f)) ([**@ralphtheninja**](https://github.com/ralphtheninja)) ### Fixed - Make sure all `t.throw` tests check error messages correctly ([#286](https://github.com/level/abstract-leveldown/issues/286)) ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Check options objects properly for `null` ([#257](https://github.com/level/abstract-leveldown/issues/257), [#288](https://github.com/level/abstract-leveldown/issues/288)) ([**@ralphtheninja**](https://github.com/ralphtheninja), [**@vweevers**](https://github.com/vweevers)) - Serialize range options same as keys ([#277](https://github.com/level/abstract-leveldown/issues/277)) ([**@vweevers**](https://github.com/vweevers)) - Allow nullish and empty range options ([#277](https://github.com/level/abstract-leveldown/issues/277)) ([**@vweevers**](https://github.com/vweevers)) ## [5.0.0] - 2018-05-22 ### Changed - Upgrade `sinon` to `^5.0.0` ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Tweak README ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Replace `const` with `var` to support IE10 ([**@vweevers**](https://github.com/vweevers)) ### Added - Add node 10 to Travis ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Add `airtap` for browser tests ([**@vweevers**](https://github.com/vweevers)) ### Removed - Remove node 4, 5 and 7 from Travis ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Remove TypeScript tests ([**@vweevers**](https://github.com/vweevers)) - Remove TypeScript typings ([**@ralphtheninja**](https://github.com/ralphtheninja)) ## [4.0.3] - 2018-02-21 ### Changed - Upgrade `ts-node` to `^5.0.0` ([**@zixia**](https://github.com/zixia)) - Upgrade `standard` to `^11.0.0` ([**@ralphtheninja**](https://github.com/ralphtheninja)) ### Fixed - Remove invalid TypeScript from `Batch` ([**@Tapppi**](https://github.com/Tapppi)) - Add JSDoc to incorrectly inferred TypeScript types ([**@Tapppi**](https://github.com/Tapppi)) ## [4.0.2] - 2018-02-09 ### Fixed - Fix `iterator#next` to return `this` ([**@vweevers**](https://github.com/vweevers)) ## [4.0.1] - 2018-02-09 ### Added - Run test suite in TypeScript in addition to Node.js ([**@vweevers**](https://github.com/vweevers)) - Add TypeScript smoke test ([**@vweevers**](https://github.com/vweevers)) - Add TypeScript readme section with stability badge ([**@vweevers**](https://github.com/vweevers)) ### Removed - Remove obsolete parameters from tests ([**@vweevers**](https://github.com/vweevers)) ### Fixed - Update TypeScript typings for v4 ([**@vweevers**](https://github.com/vweevers)) - Use ES6 classes in tests to please TypeScript ([**@vweevers**](https://github.com/vweevers)) - Define default methods on prototype to please TypeScript ([**@vweevers**](https://github.com/vweevers)) **Historical Note** This was released as a patch because it only changed tests and TypeScript typings (which are marked experimental and don't follow semver). ## [4.0.0] - 2018-01-20 ### Changed - Ignore empty range options in `AbstractLevelDOWN#_setupIteratorOptions` ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Make `testCommon.js` the default value for `testCommon` parameter ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Use `Buffer.isBuffer()` instead of `AbstractLevelDOWN#isBuffer` ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Cleanup iterator tests ([#161](https://github.com/level/abstract-leveldown/issues/161)) ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Pass test function as a parameter instead of setting local global ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Assert batch type is `'put'` or `'del'` ([**@vweevers**](https://github.com/vweevers)) - Assert batch array elements are objects ([**@vweevers**](https://github.com/vweevers)) ### Added - Add `standard` for linting ([#150](https://github.com/level/abstract-leveldown/issues/150)) ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Test that callbacks are called asynchronously ([**@vweevers**](https://github.com/vweevers)) - Test serialization extensibility ([**@vweevers**](https://github.com/vweevers)) - Add [**@vweevers**](https://github.com/vweevers) to contributors ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Add upgrade guide in `UPGRADING.md` ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Add node 9 to Travis ([**@ralphtheninja**](https://github.com/ralphtheninja)) ### Removed - Remove `isLevelDOWN` function and corresponding tests ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Remove `AbstractLevelDOWN#approximateSize` method and corresponding tests ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Remove `testBuffer` in `abstract/put-get-del-test.js` ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Remove object value test in `abstract/put-test.js` ([**@vweevers**](https://github.com/vweevers)) - Remove serialize buffer tests ([**@vweevers**](https://github.com/vweevers)) - Remove serialize object tests ([**@vweevers**](https://github.com/vweevers)) - Remove `BufferType` parameter in `abstract/put-get-del-test.js`, use `Buffer` ([**@ralphtheninja**](https://github.com/ralphtheninja)) ### Fixed - Ensure stores are closed properly (fixes problems on Windows) ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Call back errors on next tick to avoid `zalgo` ([**@vweevers**](https://github.com/vweevers)) ## [3.0.0] - 2017-11-04 ### Added - Add node version badge ([**@vweevers**](https://github.com/vweevers)) ### Removed - Drop support for `0.12`. Cause for new major version! ([**@vweevers**](https://github.com/vweevers)) ### Fixed - Fix errors in `index.d.ts` ([**@sandersn**](https://github.com/sandersn)) ## [2.7.2] - 2017-10-11 ### Changed - Update `README` with new style ([**@ralphtheninja**](https://github.com/ralphtheninja)) ## [2.7.1] - 2017-09-30 ### Changed - Refactor typings as ES2015 module ([**@MeirionHughes**](https://github.com/MeirionHughes)) ## [2.7.0] - 2017-09-12 ### Added - Add `TypeScript` definitions in `index.d.ts` ([**@MeirionHughes**](https://github.com/MeirionHughes)) ## [2.6.3] - 2017-09-05 ### Changed - Upgrade dependencies ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Convert nullish values to empty strings ([**@bigeasy**](https://github.com/bigeasy)) - Use `t.equal(a, b)` instead of `t.ok(a === b)` ([**@bigeasy**](https://github.com/bigeasy)) - Relax tests for serializing object in `abstract/chained-batch-test.js` ([**@ralphtheninja**](https://github.com/ralphtheninja)) ### Added - Add `GreenKeeper` ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Test key/value serialization ([**@bigeasy**](https://github.com/bigeasy)) - Test `undefined` value serializing to empty string ([**@ralphtheninja**](https://github.com/ralphtheninja)) ### Fixed - Document `.status` property ([**@ralphtheninja**](https://github.com/ralphtheninja)) ## [2.6.2] - 2017-07-30 ### Changed - Upgrade dependencies and float `devDependencies` ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Update copyright years ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Update node versions on Travis ([**@ralphtheninja**](https://github.com/ralphtheninja)) ### Added - Test serialization extensibility ([**@juliangruber**](https://github.com/juliangruber)) ### Fixed - Fix put test on object serialization ([**@juliangruber**](https://github.com/juliangruber)) ## [2.6.1] - 2016-09-12 ### Fixed - Fix `null` case in default value serializer (fixes problems in `2.6.0`) ([**@juliangruber**](https://github.com/juliangruber)) ## [2.6.0] - 2016-03-10 ### Changed - Use proto delegation to patch methods on db ([**@deanlandolt**](https://github.com/deanlandolt)) - Allow serialization functions to return buffers ([**@deanlandolt**](https://github.com/deanlandolt)) ### Added - Add `collectBatchOps` function to buffer `_put` and `_del` inputs in `abstract/chained-batch-test.js` ([**@deanlandolt**](https://github.com/deanlandolt)) ### Removed - Remove unnecessary initialization hackery in `abstract/chained-batch-test.js` ([**@deanlandolt**](https://github.com/deanlandolt)) **Historical Note** This release was a breaking change. See [**@juliangruber**](https://github.com/juliangruber)'s [comment](https://github.com/Level/abstract-leveldown/pull/85#issuecomment-246980978) for more information. ## [2.5.0] - 2016-05-01 ### Changed - Upgrade dependencies and add more node versions to Travis ([**@ralphtheninja**](https://github.com/ralphtheninja)) ### Added - Add dependency badge to `README` ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Add `AbstractLevelDOWN#_serializeKey` ([**@juliangruber**](https://github.com/juliangruber)) - Add `AbstractLevelDOWN#_serializeValue` ([**@juliangruber**](https://github.com/juliangruber)) - Add `AbstractChainedBatch#_serializeKey` ([**@juliangruber**](https://github.com/juliangruber)) - Add `AbstractChainedBatch#_serializeValue` ([**@juliangruber**](https://github.com/juliangruber)) - Test `_serialize` with object and buffer ([**@juliangruber**](https://github.com/juliangruber)) ### Removed - Remove stringification of keys and values ([**@juliangruber**](https://github.com/juliangruber)) - Remove `.toBuffer` ([**@juliangruber**](https://github.com/juliangruber)) ### Fixed - Update `memdown` url ([**@ralphtheninja**](https://github.com/ralphtheninja)) - `AbstractLevelDOWN#._checkKey` does not take three parameters ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Only show build status for the master branch ([**@watson**](https://github.com/watson)) - Fix minor typos in `README` ([**@timkuijsten**](https://github.com/timkuijsten)) ## [2.4.1] - 2015-08-29 ### Fixed - Remove use of `const` ([**@nolanlawson**](https://github.com/nolanlawson)) ## [2.4.0] - 2015-05-19 ### Added - Add `.status` property to `AbstractLevelDOWN` ([**@juliangruber**](https://github.com/juliangruber)) ## [2.3.1] - 2015-05-18 ### Added - Link to `level/community` ([**@ralphtheninja**](https://github.com/ralphtheninja)) ### Removed - Extract `Contributors` section from `README` into `level/community` ([**@ralphtheninja**](https://github.com/ralphtheninja)) ### Fixed - Document `isLevelDown` function ([**@ralphtheninja**](https://github.com/ralphtheninja)) ## [2.3.0] - 2015-05-18 ### Changed - Use `t.equal(a, b)` instead of `t.ok(a === b)` ([**@juliangruber**](https://github.com/juliangruber)) - Export API from `index.js` ([**@ralphtheninja**](https://github.com/ralphtheninja)) ### Added - Import `isLevelDOWN` function to `is-leveldown.js` ([**@ralphtheninja**](https://github.com/ralphtheninja)) ## [2.2.2] - 2015-05-13 ### Fixed - Revert changes to `location` in `2.2.1` ([**@juliangruber**](https://github.com/juliangruber)) ## [2.2.1] - 2015-05-12 ### Fixed - Copy paste error gave wrong test description ([**@ralphtheninja**](https://github.com/ralphtheninja)) - `t.throws()` is different for `tape` ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Assert `location` is not an empty string ([**@ralphtheninja**](https://github.com/ralphtheninja)) ## [2.2.0] - 2015-05-10 ### Added - Test `{ sync: true }` option in `abstract/put-test.js` ([**@juliangruber**](https://github.com/juliangruber)) ## [2.1.4] - 2015-04-28 ### Fixed - Use `t.equal()` with `tape` ([**@ralphtheninja**](https://github.com/ralphtheninja)) ## [2.1.3] - 2015-04-28 ### Changed - Change from `tap` to `tape` ([**@ralphtheninja**](https://github.com/ralphtheninja)) ## [2.1.2] - 2015-04-27 ### Changed - Convert buffer to string so we can compare ([**@ralphtheninja**](https://github.com/ralphtheninja)) ## [2.1.1] - 2015-04-27 ### Changed - Update logo and copyright ([**@ralphtheninja**](https://github.com/ralphtheninja)) ### Added - Add [**@ralphtheninja**](https://github.com/ralphtheninja) to contributors ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Add `0.12` and `iojs` to Travis ([**@ralphtheninja**](https://github.com/ralphtheninja)) ### Fixed - Include `.nonErrorValues()` test in `abstract/put-get-del-test.js` ([**@hden**](https://github.com/hden)) - `rvagg/node-abstract-leveldown` moved to `level/abstract-leveldown` ([**@ralphtheninja**](https://github.com/ralphtheninja)) - Fix Travis for `0.8` ([**@ralphtheninja**](https://github.com/ralphtheninja)) ## [2.1.0] - 2014-11-09 ### Changed - Use `setTimeout` instead of `process.nextTick` ([**@bigeasy**](https://github.com/bigeasy)) ### Added - Add [**@watson**](https://github.com/watson) to contributors ([**@rvagg**](https://github.com/rvagg)) ### Fixed - Don't fail if no value is returned by `._get` ([**@watson**](https://github.com/watson)) - Use `error` test function when testing for errors ([**@watson**](https://github.com/watson)) ## [2.0.3] - 2014-10-02 No change. ## [2.0.2] - 2014-10-02 ### Added - Test atomic batch operations ([**@calvinmetcalf**](https://github.com/calvinmetcalf)) ## [2.0.1] - 2014-09-01 ### Changed - Set default values for options to `.open`, `.get`, `.put`, `.del` and `.batch` ([**@watson**](https://github.com/watson)) - Update pattern for setting default options for the iterator ([**@watson**](https://github.com/watson)) - Allow boolean options to be falsy/truthy ([**@watson**](https://github.com/watson)) ### Removed - Remove default options that are too `LevelDOWN` specific ([**@watson**](https://github.com/watson)) ## [2.0.0] - 2014-08-26 ### Changed - Switch to allowing writes of empty values, `null`, `undefined`, `''`, `[]` and empty buffer ([**@juliangruber**](https://github.com/juliangruber)) - Rename `AbstractLevelDOWN#_checkKeyValue` to `AbstractLevelDOWN#_checkKey` ([**@rvagg**](https://github.com/rvagg)) ## [1.0.0] - 2014-08-24 ### Changed - Ensure `Boolean` iterator options are `Boolean` ([**@watson**](https://github.com/watson)) ### Added - Test that an error is thrown when location isn't a string ([**@calvinmetcalf**](https://github.com/calvinmetcalf)) - Test opening and closing the store ([**@calvinmetcalf**](https://github.com/calvinmetcalf)) - Test iterator with `limit` set to `0` ([**@watson**](https://github.com/watson)) - Add more tests to `abstract/batch-test.js` ([**@calvinmetcalf**](https://github.com/calvinmetcalf)) - Set default values of iterator options ([**@watson**](https://github.com/watson)) - Account for batch options that are `null` ([**@calvinmetcalf**](https://github.com/calvinmetcalf)) ### Removed - Remove options.start hackery ([**@rvagg**](https://github.com/rvagg)) ## [0.12.4] - 2014-08-20 ### Changed - Change license to plain MIT ([**@andrewrk**](https://github.com/andrewrk)) ### Added - Test that `simple-iterator` returns buffers ([**@kesla**](https://github.com/kesla)) - Test implicit snapshots ([**@kesla**](https://github.com/kesla)) ## [0.12.3] - 2014-06-27 ### Changed - Upgrade `xtend` dependency ([**@andrewrk**](https://github.com/andrewrk)) ## [0.12.2] - 2014-04-26 ### Changed - Have `isTypedArray` check for existence of `ArrayBuffer` and `Uint8Array` constructors before usage ([**@rvagg**](https://github.com/rvagg)) ## [0.12.1] - 2014-04-26 ### Changed - Set default `BufferType` in `abstract/put-get-del-test.js` to `Buffer` instead of `ArrayBuffer` ([**@maxogden**](https://github.com/maxogden)) ## [0.12.0] - 2014-03-12 ### Changed - Revert to pure `Buffer` and remove usage of `Uint16Array` ([**@rvagg**](https://github.com/rvagg)) ## [0.11.4] - 2014-03-11 ### Removed - Remove duplicate call to `t.end()` ([**@maxogden**](https://github.com/maxogden)) ## [0.11.3] - 2014-01-26 ### Changed - Loosen the buffer type check ([**@rvagg**](https://github.com/rvagg)) ## [0.11.2] - 2013-12-05 ### Added - Add npm badges ([**@rvagg**](https://github.com/rvagg)) ### Fixed - Fix iterator tests in `test.js` ([**@rvagg**](https://github.com/rvagg)) ## [0.11.1] - 2013-11-15 ### Changed - Adjust `abstract/approximate-size-test.js` to account for snappy compression ([**@rvagg**](https://github.com/rvagg)) ## [0.11.0] - 2013-10-14 ### Added - Normalize `iterator()` options with `AbstractLevelDOWN#_setupIteratorOptions` ([**@rvagg**](https://github.com/rvagg)) ## [0.10.2] - 2013-09-06 ### Changed - Refactor duplicated versions of `isTypedArray` into `abstract/util.js` ([**@rvagg**](https://github.com/rvagg)) - Refactor duplicated versions of `'NotFound'` checks into `abstract/util.js`, fixed too-strict version in `get-test.js` ([**@rvagg**](https://github.com/rvagg)) ## [0.10.1] - 2013-08-29 ### Changed - Relax check for `Not Found` error message to be case insensitive in `get-test.js` ([**@rvagg**](https://github.com/rvagg)) ### Added - Add [**@substack**](https://github.com/substack) to contributors ([**@rvagg**](https://github.com/rvagg)) ## [0.10.0] - 2013-08-19 ### Added - Test `gt`, `gte`, `lt` and `lte` ranges ([**@dominictarr**](https://github.com/dominictarr)) ## [0.9.0] - 2013-08-11 ### Changed - Make `AbstractChainedBatch` extensible ([**@kesla**](https://github.com/kesla)) - Export `AbstractChainedBatch` from `abstract-leveldown.js` ([**@kesla**](https://github.com/kesla)) ### Added - Test simultaneous get's ([**@kesla**](https://github.com/kesla)) - Test `AbstractChainedBatch` extensibility ([**@kesla**](https://github.com/kesla)) ### Fixed - Fix broken test assertion in `abstract/get-test.js` ([**@rvagg**](https://github.com/rvagg)) - Fix tests that weren't running properly ([**@kesla**](https://github.com/kesla)) ## [0.8.2] - 2013-08-02 No changes. Merely published changes made in `0.8.1`. ## [0.8.1] - 2013-08-02 ### Changed - Remove use of `const` in `testCommon.js` ([**@rvagg**](https://github.com/rvagg)) **Historical Note** The version in `package.json` was changed from `0.7.4` to `0.8.1`. The `0.8.1` tag exists but this version was never published to npm. ## [0.8.0] - 2013-08-02 ### Changed - Use `process.browser` check instead of `process.title == 'browser'` ([**@rvagg**](https://github.com/rvagg)) ### Added - Add `BufferType` parameter to `abstract/put-get-del-test.js` for `bops` support ([**@rvagg**](https://github.com/rvagg)) - Add `isTypedArray` function which checks `ArrayBuffer` or `Uint8Array` for `bops` support ([**@rvagg**](https://github.com/rvagg)) ### Fixed - Fix `cleanup` function not calling back when browserified ([**@rvagg**](https://github.com/rvagg)) **Historical Note** It seems the version in `package.json` was never changed to `0.8.0` in the git history, even though the `0.8.0` tag exists. Most likely `package.json` was modified locally during `npm publish` but was never committed. ## [0.7.4] - 2013-08-02 ### Fixed - Fix problems related to `browserify` and `rimraf` ([**@rvagg**](https://github.com/rvagg)) ## [0.7.3] - 2013-07-26 ### Added - Add [**@pgte**](https://github.com/pgte) to contributors ([**@rvagg**](https://github.com/rvagg)) - Test iterator with `limit` set to `-1` ([**@kesla**](https://github.com/kesla)) ## [0.7.2] - 2013-07-08 ### Changed - Freeze chained batch state after `.write()` has been called ([**@rvagg**](https://github.com/rvagg)) - Make `NotFound` error case insensitive ([**@rvagg**](https://github.com/rvagg)) - Use `self` rather than binding functions to `this` ([**@juliangruber**](https://github.com/juliangruber)) ### Added - Add `AbstractChainedBatch#_checkWritten` ([**@rvagg**](https://github.com/rvagg)) - Test delete on non-existent key ([**@rvagg**](https://github.com/rvagg)) - Test iterator with `start` after database `end` ([**@juliangruber**](https://github.com/juliangruber)) ### Fixed - Don't coerce values to strings in browser ([**@maxogden**](https://github.com/maxogden)) - Make tests work in node and browser ([**@maxogden**](https://github.com/maxogden)) ## [0.7.1] - 2013-05-15 ### Changed - Adjust tests to be browserable ([**@rvagg**](https://github.com/rvagg)) ## [0.7.0] - 2013-05-14 ### Added - Add `AbstractChainedBatch#clear` ([**@rvagg**](https://github.com/rvagg)) ## [0.6.1] - 2013-05-14 ### Changed - Make `AbstractIterator` call back with an error instead of throwing on nexting and ending ([**@mcollina**](https://github.com/mcollina)) ## [0.6.0] - 2013-05-14 ### Changed - Split `t.deepEqual()` into multiple `t.equal()` in `abstract/iterator-test.js` ([**@rvagg**](https://github.com/rvagg)) - Make `AbstractIterator` call back with an error instead of throwing on nexting and ending ([**@mcollina**](https://github.com/mcollina)) ## [0.5.0] - 2013-05-14 ### Changed - Make `iterator.end(cb)` and `iterator.next(cb)` call back with an error instead of throwing ([**@mcollina**](https://github.com/mcollina)) ## [0.4.0] - 2013-05-14 ### Changed - Move `AbstractIterator` from `abstract-leveldown.js` to `abstract-iterator.js` ([**@rvagg**](https://github.com/rvagg)) ### Added - Add `AbstractChainedBatch` ([**@rvagg**](https://github.com/rvagg)) - Add `AbstractLevelDOWN#_chainedBatch` ([**@rvagg**](https://github.com/rvagg)) - Add `abstract/batch-test.js` and `abstract/chained-batch-test.js` ([**@rvagg**](https://github.com/rvagg)) ## [0.4.0-1] - 2013-05-14 ### Added - Add [**@No9**](https://github.com/No9) and [**@mcollina**](https://github.com/mcollina) to contributors ([**@rvagg**](https://github.com/rvagg)) ## [0.3.0] - 2013-05-04 ### Changed - Use `this._checkKeyValue()` instead of local function ([**@rvagg**](https://github.com/rvagg)) - Use `this._isBuffer()` instead of `Buffer.isBuffer()` ([**@rvagg**](https://github.com/rvagg)) ### Added - Restore test for opening the database without options ([**@rvagg**](https://github.com/rvagg)) - Add `AbstractLevelDOWN#_isBuffer` so it can be overridden ([**@rvagg**](https://github.com/rvagg)) - Add `AbstractLevelDOWN#_checkKeyValue` so it can be overridden ([**@rvagg**](https://github.com/rvagg)) ## [0.2.3] - 2013-05-04 ### Removed - Remove test for opening the database without options ([**@rvagg**](https://github.com/rvagg)) ## [0.2.2] - 2013-05-04 ### Changed - Split `.open()` tests into `.open()` and `.openAdvanced()` ([**@rvagg**](https://github.com/rvagg)) ## [0.2.1] - 2013-05-04 ### Changed - Convert values to `string` in `abstract/put-get-del-test.js` if `Buffer` is `undefined` ([**@rvagg**](https://github.com/rvagg)) ## [0.2.0] - 2013-05-04 ### Changed - Convert values to `string` in `abstract/get-test.js` if `Buffer` is `undefined` ([**@rvagg**](https://github.com/rvagg)) - Don't stringify keys and values in `abstract/iterator-test.js` ([**@maxogden**](https://github.com/maxogden)) ### Added - Add `process.browser` check for `start` and `end` keys in browser ([**@maxogden**](https://github.com/maxogden)) - Add `levelup` contributors ([**@rvagg**](https://github.com/rvagg)) ### Fixed - Fix `tape` compatibility issues ([**@maxogden**](https://github.com/maxogden)) ## [0.1.0] - 2013-04-23 ### Added - Import abstract tests from `leveldown` ([**@maxogden**](https://github.com/maxogden)) ### Fixed - Clarify `README` ([**@rvagg**](https://github.com/rvagg)) ## [0.0.2] - 2013-03-18 ### Changed - Export `checkKeyValue` ([**@rvagg**](https://github.com/rvagg)) ### Added - Add node 0.10 to Travis ([**@rvagg**](https://github.com/rvagg)) - Add `Buffer.isBuffer()` checks to keys and values ([**@rvagg**](https://github.com/rvagg)) ## [0.0.1] - 2013-03-18 ### Added - Add `checkKeyValue` function for more complete error checking ([**@rvagg**](https://github.com/rvagg)) ## 0.0.0 - 2013-03-15 First release. :seedling: [6.3.0]: https://github.com/Level/abstract-leveldown/compare/v6.2.3...v6.3.0 [6.2.3]: https://github.com/Level/abstract-leveldown/compare/v6.2.2...v6.2.3 [6.2.2]: https://github.com/Level/abstract-leveldown/compare/v6.2.1...v6.2.2 [6.2.1]: https://github.com/Level/abstract-leveldown/compare/v6.2.0...v6.2.1 [6.2.0]: https://github.com/Level/abstract-leveldown/compare/v6.1.1...v6.2.0 [6.1.1]: https://github.com/Level/abstract-leveldown/compare/v6.1.0...v6.1.1 [6.1.0]: https://github.com/Level/abstract-leveldown/compare/v6.0.3...v6.1.0 [6.0.3]: https://github.com/Level/abstract-leveldown/compare/v6.0.2...v6.0.3 [6.0.2]: https://github.com/Level/abstract-leveldown/compare/v6.0.1...v6.0.2 [6.0.1]: https://github.com/Level/abstract-leveldown/compare/v6.0.0...v6.0.1 [6.0.0]: https://github.com/Level/abstract-leveldown/compare/v5.0.0...v6.0.0 [5.0.0]: https://github.com/Level/abstract-leveldown/compare/v4.0.3...v5.0.0 [4.0.3]: https://github.com/Level/abstract-leveldown/compare/v4.0.2...v4.0.3 [4.0.2]: https://github.com/Level/abstract-leveldown/compare/v4.0.1...v4.0.2 [4.0.1]: https://github.com/Level/abstract-leveldown/compare/v4.0.0...v4.0.1 [4.0.0]: https://github.com/Level/abstract-leveldown/compare/v3.0.0...v4.0.0 [3.0.0]: https://github.com/Level/abstract-leveldown/compare/v2.7.2...v3.0.0 [2.7.2]: https://github.com/Level/abstract-leveldown/compare/v2.7.1...v2.7.2 [2.7.1]: https://github.com/Level/abstract-leveldown/compare/v2.7.0...v2.7.1 [2.7.0]: https://github.com/Level/abstract-leveldown/compare/v2.6.3...v2.7.0 [2.6.3]: https://github.com/Level/abstract-leveldown/compare/v2.6.2...v2.6.3 [2.6.2]: https://github.com/Level/abstract-leveldown/compare/v2.6.1...v2.6.2 [2.6.1]: https://github.com/Level/abstract-leveldown/compare/v2.6.0...v2.6.1 [2.6.0]: https://github.com/Level/abstract-leveldown/compare/v2.5.0...v2.6.0 [2.5.0]: https://github.com/Level/abstract-leveldown/compare/v2.4.1...v2.5.0 [2.4.1]: https://github.com/Level/abstract-leveldown/compare/v2.4.0...v2.4.1 [2.4.0]: https://github.com/Level/abstract-leveldown/compare/v2.3.1...v2.4.0 [2.3.1]: https://github.com/Level/abstract-leveldown/compare/v2.3.0...v2.3.1 [2.3.0]: https://github.com/Level/abstract-leveldown/compare/v2.2.2...v2.3.0 [2.2.2]: https://github.com/Level/abstract-leveldown/compare/v2.2.1...v2.2.2 [2.2.1]: https://github.com/Level/abstract-leveldown/compare/v2.2.0...v2.2.1 [2.2.0]: https://github.com/Level/abstract-leveldown/compare/v2.1.4...v2.2.0 [2.1.4]: https://github.com/Level/abstract-leveldown/compare/v2.1.3...v2.1.4 [2.1.3]: https://github.com/Level/abstract-leveldown/compare/v2.1.2...v2.1.3 [2.1.2]: https://github.com/Level/abstract-leveldown/compare/v2.1.1...v2.1.2 [2.1.1]: https://github.com/Level/abstract-leveldown/compare/v2.1.0...v2.1.1 [2.1.0]: https://github.com/Level/abstract-leveldown/compare/v2.0.3...v2.1.0 [2.0.3]: https://github.com/Level/abstract-leveldown/compare/v2.0.2...v2.0.3 [2.0.2]: https://github.com/Level/abstract-leveldown/compare/v2.0.1...v2.0.2 [2.0.1]: https://github.com/Level/abstract-leveldown/compare/v2.0.0...v2.0.1 [2.0.0]: https://github.com/Level/abstract-leveldown/compare/v1.0.0...v2.0.0 [1.0.0]: https://github.com/Level/abstract-leveldown/compare/v0.12.4...v1.0.0 [0.12.4]: https://github.com/Level/abstract-leveldown/compare/v0.12.3...v0.12.4 [0.12.3]: https://github.com/Level/abstract-leveldown/compare/v0.12.2...v0.12.3 [0.12.2]: https://github.com/Level/abstract-leveldown/compare/v0.12.1...v0.12.2 [0.12.1]: https://github.com/Level/abstract-leveldown/compare/v0.12.0...v0.12.1 [0.12.0]: https://github.com/Level/abstract-leveldown/compare/v0.11.4...v0.12.0 [0.11.4]: https://github.com/Level/abstract-leveldown/compare/v0.11.3...v0.11.4 [0.11.3]: https://github.com/Level/abstract-leveldown/compare/v0.11.2...v0.11.3 [0.11.2]: https://github.com/Level/abstract-leveldown/compare/0.11.1...v0.11.2 [0.11.1]: https://github.com/Level/abstract-leveldown/compare/0.11.0...0.11.1 [0.11.0]: https://github.com/Level/abstract-leveldown/compare/0.10.2...0.11.0 [0.10.2]: https://github.com/Level/abstract-leveldown/compare/0.10.1...0.10.2 [0.10.1]: https://github.com/Level/abstract-leveldown/compare/0.10.0...0.10.1 [0.10.0]: https://github.com/Level/abstract-leveldown/compare/0.9.0...0.10.0 [0.9.0]: https://github.com/Level/abstract-leveldown/compare/0.8.2...0.9.0 [0.8.2]: https://github.com/Level/abstract-leveldown/compare/0.8.1...0.8.2 [0.8.1]: https://github.com/Level/abstract-leveldown/compare/0.8.0...0.8.1 [0.8.0]: https://github.com/Level/abstract-leveldown/compare/0.7.4...0.8.0 [0.7.4]: https://github.com/Level/abstract-leveldown/compare/0.7.3...0.7.4 [0.7.3]: https://github.com/Level/abstract-leveldown/compare/0.7.2...0.7.3 [0.7.2]: https://github.com/Level/abstract-leveldown/compare/0.7.1...0.7.2 [0.7.1]: https://github.com/Level/abstract-leveldown/compare/0.7.0...0.7.1 [0.7.0]: https://github.com/Level/abstract-leveldown/compare/0.6.1...0.7.0 [0.6.1]: https://github.com/Level/abstract-leveldown/compare/0.6.0...0.6.1 [0.6.0]: https://github.com/Level/abstract-leveldown/compare/0.5.0...0.6.0 [0.5.0]: https://github.com/Level/abstract-leveldown/compare/0.4.0...0.5.0 [0.4.0]: https://github.com/Level/abstract-leveldown/compare/0.4.0-1...0.4.0 [0.4.0-1]: https://github.com/Level/abstract-leveldown/compare/0.3.0...0.4.0-1 [0.3.0]: https://github.com/Level/abstract-leveldown/compare/0.2.3...0.3.0 [0.2.3]: https://github.com/Level/abstract-leveldown/compare/0.2.2...0.2.3 [0.2.2]: https://github.com/Level/abstract-leveldown/compare/0.2.1...0.2.2 [0.2.1]: https://github.com/Level/abstract-leveldown/compare/0.2.0...0.2.1 [0.2.0]: https://github.com/Level/abstract-leveldown/compare/0.1.0...0.2.0 [0.1.0]: https://github.com/Level/abstract-leveldown/compare/0.0.2...0.1.0 [0.0.2]: https://github.com/Level/abstract-leveldown/compare/0.0.1...0.0.2 [0.0.1]: https://github.com/Level/abstract-leveldown/compare/0.0.0...0.0.1 abstract-leveldown-6.3.0/CONTRIBUTORS.md000066400000000000000000000077741364427107700176310ustar00rootroot00000000000000# Contributors | Name | GitHub | Social | | :------------------------- | :----------------------------------------------------- | :----------------------------------------------------------------------- | | **Rod Vagg** | [**@rvagg**](https://github.com/rvagg) | [**@rvagg@twitter**](https://twitter.com/rvagg) | | **Vincent Weevers** | [**@vweevers**](https://github.com/vweevers) | [**@vweevers@twitter**](https://twitter.com/vweevers) | | **Lars-Magnus Skog** | [**@ralphtheninja**](https://github.com/ralphtheninja) | [**@ralph@social.weho.st**](https://social.weho.st/@ralph) | | **Julian Gruber** | [**@juliangruber**](https://github.com/juliangruber) | [**@juliangruber@twitter**](https://twitter.com/juliangruber) | | **David Björklund** | [**@kesla**](https://github.com/kesla) | [**@david_bjorklund@twitter**](https://twitter.com/david_bjorklund) | | **Max Ogden** | [**@maxogden**](https://github.com/maxogden) | [**@maxogden@twitter**](https://twitter.com/maxogden) | | **Thomas Watson Steen** | | | | **Alan Gutierrez** | [**@bigeasy**](https://github.com/bigeasy) | [**@bigeasy@twitter**](https://twitter.com/bigeasy) | | **Dean Landolt** | [**@deanlandolt**](https://github.com/deanlandolt) | | | **Calvin Metcalf** | [**@calvinmetcalf**](https://github.com/calvinmetcalf) | | | **Meirion Hughes** | [**@MeirionHughes**](https://github.com/MeirionHughes) | | | **Matteo Collina** | [**@mcollina**](https://github.com/mcollina) | [**@matteocollina@twitter**](https://twitter.com/matteocollina) | | **Andrew Kelley** | [**@andrewrk**](https://github.com/andrewrk) | | | **Tapani Moilanen** | [**@Tapppi**](https://github.com/Tapppi) | | | **Dominic Tarr** | [**@dominictarr**](https://github.com/dominictarr) | [**@dominictarr@twitter**](https://twitter.com/dominictarr) | | **Hao-kang Den** | | | | **Hugo Dias** | | | | **Jake Verbaten** | [**@Raynos**](https://github.com/Raynos) | [**@raynos@twitter**](https://twitter.com/raynos) | | **Kyle Robinson Young** | [**@shama**](https://github.com/shama) | [**@shamakry@twitter**](https://twitter.com/shamakry) | | **Nathan Shively-Sanders** | [**@sandersn**](https://github.com/sandersn) | | | **Nolan Lawson** | [**@nolanlawson**](https://github.com/nolanlawson) | [**@nolan@toot.cafe**](https://toot.cafe/@nolan) | | **Tim Kuijsten** | [**@timkuijsten**](https://github.com/timkuijsten) | [**@timkuijsten@mastodon.social**](https://mastodon.social/@timkuijsten) | | **Tim Oxley** | [**@timoxley**](https://github.com/timoxley) | [**@secoif@twitter**](https://twitter.com/secoif) | abstract-leveldown-6.3.0/LICENSE.md000066400000000000000000000021451364427107700167410ustar00rootroot00000000000000# The MIT License (MIT) **Copyright © 2013-present Rod Vagg and [Contributors](CONTRIBUTORS.md).** Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. abstract-leveldown-6.3.0/README.md000066400000000000000000000743341364427107700166250ustar00rootroot00000000000000# abstract-leveldown > An abstract prototype matching the [`leveldown`][leveldown] API. Useful for extending [`levelup`](https://github.com/Level/levelup) functionality by providing a replacement to `leveldown`. [![level badge][level-badge]](https://github.com/Level/awesome) [![npm](https://img.shields.io/npm/v/abstract-leveldown.svg?label=&logo=npm)](https://www.npmjs.com/package/abstract-leveldown) [![Node version](https://img.shields.io/node/v/abstract-leveldown.svg)](https://www.npmjs.com/package/abstract-leveldown) [![Travis](https://img.shields.io/travis/com/Level/abstract-leveldown.svg?logo=travis&label=)](https://travis-ci.com/Level/abstract-leveldown) [![Coverage Status](https://coveralls.io/repos/github/Level/abstract-leveldown/badge.svg)](https://coveralls.io/github/Level/abstract-leveldown) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) [![npm](https://img.shields.io/npm/dm/abstract-leveldown.svg?label=dl)](https://www.npmjs.com/package/abstract-leveldown) [![Backers on Open Collective](https://opencollective.com/level/backers/badge.svg?color=orange)](#backers) [![Sponsors on Open Collective](https://opencollective.com/level/sponsors/badge.svg?color=orange)](#sponsors) ## Table of Contents
Click to expand - [Background](#background) - [Example](#example) - [Browser Support](#browser-support) - [Public API For Consumers](#public-api-for-consumers) - [Private API For Implementors](#private-api-for-implementors) - [Test Suite](#test-suite) - [Spread The Word](#spread-the-word) - [Install](#install) - [Contributing](#contributing) - [Big Thanks](#big-thanks) - [Donate](#donate) - [License](#license)
## Background This module provides a simple base prototype for a key-value store. It has a public API for consumers and a private API for implementors. To implement a `abstract-leveldown` compliant store, extend its prototype and override the private underscore versions of the methods. For example, to implement `put()`, override `_put()` on your prototype. Where possible, the default private methods have sensible _noop_ defaults that essentially do nothing. For example, `_open(callback)` will invoke `callback` on a next tick. Other methods like `_clear(..)` have functional defaults. Each method listed below documents whether implementing it is mandatory. The private methods are always provided with consistent arguments, regardless of what is passed in through the public API. All public methods provide argument checking: if a consumer calls `open()` without a callback argument they'll get an `Error('open() requires a callback argument')`. Where optional arguments are involved, private methods receive sensible defaults: a `get(key, callback)` call translates to `_get(key, options, callback)` where the `options` argument is an empty object. These arguments are documented below. **If you are upgrading:** please see [UPGRADING.md](UPGRADING.md). ## Example Let's implement a simplistic in-memory [`leveldown`][leveldown] replacement: ```js var AbstractLevelDOWN = require('abstract-leveldown').AbstractLevelDOWN var util = require('util') // Constructor function FakeLevelDOWN () { AbstractLevelDOWN.call(this) } // Our new prototype inherits from AbstractLevelDOWN util.inherits(FakeLevelDOWN, AbstractLevelDOWN) FakeLevelDOWN.prototype._open = function (options, callback) { // Initialize a memory storage object this._store = {} // Use nextTick to be a nice async citizen process.nextTick(callback) } FakeLevelDOWN.prototype._serializeKey = function (key) { // As an example, prefix all input keys with an exclamation mark. // Below methods will receive serialized keys in their arguments. return '!' + key } FakeLevelDOWN.prototype._put = function (key, value, options, callback) { this._store[key] = value process.nextTick(callback) } FakeLevelDOWN.prototype._get = function (key, options, callback) { var value = this._store[key] if (value === undefined) { // 'NotFound' error, consistent with LevelDOWN API return process.nextTick(callback, new Error('NotFound')) } process.nextTick(callback, null, value) } FakeLevelDOWN.prototype._del = function (key, options, callback) { delete this._store[key] process.nextTick(callback) } ``` Now we can use our implementation with `levelup`: ```js var levelup = require('levelup') var db = levelup(new FakeLevelDOWN()) db.put('foo', 'bar', function (err) { if (err) throw err db.get('foo', function (err, value) { if (err) throw err console.log(value) // 'bar' }) }) ``` See [`memdown`](https://github.com/Level/memdown/) if you are looking for a complete in-memory replacement for `leveldown`. ## Browser Support [![Sauce Test Status](https://saucelabs.com/browser-matrix/abstract-leveldown.svg)](https://saucelabs.com/u/abstract-leveldown) ## Public API For Consumers ### `db = constructor(..)` Constructors typically take a `location` argument pointing to a location on disk where the data will be stored. Since not all implementations are disk-based and some are non-persistent, implementors are free to take zero or more arguments in their constructor. ### `db.status` A read-only property. An `abstract-leveldown` compliant store can be in one of the following states: - `'new'` - newly created, not opened or closed - `'opening'` - waiting for the store to be opened - `'open'` - successfully opened the store, available for use - `'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. The optional `options` argument may contain: - `createIfMissing` _(boolean, default: `true`)_: If `true` and the store doesn't exist it will be created. If `false` and the store doesn't exist, `callback` will receive an error. - `errorIfExists` _(boolean, default: `false`)_: If `true` and the store exists, `callback` will receive an error. Not all implementations support the above options. ### `db.close(callback)` Close the store. The `callback` function will be called with no arguments if the operation is successful or with a single `error` argument if closing failed for any reason. ### `db.get(key[, options], callback)` Get a value from the store by `key`. The optional `options` object may contain: - `asBuffer` _(boolean, default: `true`)_: Whether to return the `value` as a Buffer. If `false`, the returned type depends on the implementation. The `callback` function will be called with an `Error` if the operation failed for any reason. If successful the first argument will be `null` and the second argument will be the value. ### `db.put(key, value[, options], callback)` Store a new entry or overwrite an existing entry. There are no `options` by default but implementations may add theirs. The `callback` function will be called with no arguments if the operation is successful or with an `Error` if putting failed for any reason. ### `db.del(key[, options], callback)` Delete an entry. There are no `options` by default but implementations may add theirs. The `callback` function will be called with no arguments if the operation is successful or with an `Error` if deletion failed for any reason. ### `db.batch(operations[, options], callback)` Perform multiple _put_ and/or _del_ operations in bulk. The `operations` argument must be an `Array` containing a list of operations to be executed sequentially, although as a whole they are performed as an atomic operation. Each operation is contained in an object having the following properties: `type`, `key`, `value`, where the `type` is either `'put'` or `'del'`. In the case of `'del'` the `value` property is ignored. There are no `options` by default but implementations may add theirs. The `callback` function will be called with no arguments if the batch is successful or with an `Error` if the batch failed for any reason. ### `db.batch()` Returns a [`chainedBatch`](#chainedbatch). ### `db.iterator([options])` Returns an [`iterator`](#iterator). Accepts the following range options: - `gt` (greater than), `gte` (greater than or equal) define the lower bound of the range to be iterated. 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 iterated will be the same. - `lt` (less than), `lte` (less than or equal) define the higher bound of the range to be iterated. 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 iterated will be the same. - `reverse` _(boolean, default: `false`)_: iterate entries in reverse order. Beware that a reverse seek can be slower than a forward seek. - `limit` _(number, default: `-1`)_: limit the number of entries collected by this iterator. 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 returned instead of the lowest keys. Legacy options: - `start`: instead use `gte` - `end`: instead use `lte`. **Note** Zero-length strings, buffers and arrays as well as `null` and `undefined` are invalid as keys, yet valid as range options. These types are significant in encodings like [`bytewise`](https://github.com/deanlandolt/bytewise) and [`charwise`](https://github.com/dominictarr/charwise) as well as some underlying stores like IndexedDB. Consumers of an implementation should assume that `{ gt: undefined }` is _not_ the same as `{}`. An implementation can choose to: - [_Serialize_](#db_serializekeykey) or [_encode_][encoding-down] these types to make them meaningful - Have no defined behavior (moving the concern to a higher level) - Delegate to an underlying store (moving the concern to a lower level). If you are an implementor, a final note: the [abstract test suite](#test-suite) does not test these types. Whether they are supported or how they sort is up to you; add custom tests accordingly. In addition to range options, `iterator()` takes the following options: - `keys` _(boolean, default: `true`)_: whether to return the key of each entry. If set to `false`, calls to `iterator.next(callback)` will yield keys with a value of `undefined`. - `values` _(boolean, default: `true`)_: whether to return the value of each entry. If set to `false`, calls to `iterator.next(callback)` will yield values with a value of `undefined`. - `keyAsBuffer` _(boolean, default: `true`)_: Whether to return the key of each entry as a Buffer. If `false`, the returned type depends on the implementation. - `valueAsBuffer` _(boolean, default: `true`)_: Whether to return the value of each entry as a Buffer. Lastly, an implementation is free to add its own options. ### `db.clear([options, ]callback)` **This method is experimental. Not all implementations 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 `Error` if it failed for any reason. ### `chainedBatch` #### `chainedBatch.put(key, value)` Queue a `put` operation on this batch. This may throw if `key` or `value` is invalid. #### `chainedBatch.del(key)` Queue a `del` operation on this batch. This may throw if `key` is invalid. #### `chainedBatch.clear()` Clear all queued operations on this batch. #### `chainedBatch.write([options, ]callback)` Commit the queued operations for this batch. All operations will be written atomically, that is, they will either all succeed or fail with no partial commits. There are no `options` by default but implementations may add theirs. The `callback` function will be called with no arguments if the batch is successful or with an `Error` if the batch failed for any reason. After `write` has been called, no further operations are allowed. #### `chainedBatch.db` A reference to the `db` that created this chained batch. ### `iterator` An iterator allows you to _iterate_ the entire store or a range. It operates on a snapshot of the store, created at the time `db.iterator()` was called. This means reads on the iterator are unaffected by simultaneous writes. Most but not all implementations can offer this guarantee. An iterator keeps track of when a `next()` is in progress and when an `end()` has been called so it doesn't allow concurrent `next()` calls, it does allow `end()` while a `next()` is in progress and it doesn't allow either `next()` or `end()` after `end()` has been called. #### `iterator.next(callback)` Advance the iterator and yield the entry at that key. If an error occurs, the `callback` function will be called with an `Error`. Otherwise, the `callback` receives `null`, a `key` and a `value`. The type of `key` and `value` depends on the options passed to `db.iterator()`. If the iterator has reached its end, both `key` and `value` will be `undefined`. This happens in the following situations: - The end of the store has been reached - The end of the range has been reached - The last `iterator.seek()` was out of range. **Note:** Don't forget to call `iterator.end()`, even if you received an error. #### `iterator.seek(target)` Seek the iterator to a given key or the closest key. Subsequent calls to `iterator.next()` will yield entries with keys equal to or larger than `target`, or equal to or smaller than `target` if the `reverse` option passed to `db.iterator()` was true. If range options like `gt` were passed to `db.iterator()` and `target` does not fall within that range, the iterator will reach its end. **Note:** At the time of writing, [`leveldown`][leveldown] is the only known implementation to support `seek()`. In other implementations, it is a noop. #### `iterator.end(callback)` End iteration and free up underlying resources. The `callback` function will be called with no arguments on success or with an `Error` if ending failed for any reason. #### `iterator.db` A reference to the `db` that created this iterator. ### Type Support The following applies to any method above that takes a `key` argument or option: all implementations _must_ support a `key` of type String and _should_ support a `key` of type Buffer. A `key` may not be `null`, `undefined`, a zero-length Buffer, zero-length string or zero-length array. The following applies to any method above that takes a `value` argument or option: all implementations _must_ support a `value` of type String or Buffer. A `value` may not be `null` or `undefined` due to preexisting significance in streams and iterators. Support of other key and value types depends on the implementation as well as its underlying storage. See also [`db._serializeKey`](#db_serializekeykey) and [`db._serializeValue`](#db_serializevaluevalue). ## Private API For Implementors 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` or some other means of microtask scheduling. For convenience, the prototypes of `AbstractLevelDOWN`, `AbstractIterator` and `AbstractChainedBatch` include a `_nextTick` method that is compatible with node and browsers. ### `db = AbstractLevelDOWN([manifest])` 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)` Open the store. The `options` object will always have the following properties: `createIfMissing`, `errorIfExists`. If opening failed, call the `callback` function with an `Error`. Otherwise call `callback` without any arguments. The default `_open()` is a sensible noop and invokes `callback` on a next tick. ### `db._close(callback)` Close the store. If closing failed, call the `callback` function with an `Error`. Otherwise call `callback` without any arguments. The default `_close()` is a sensible noop and invokes `callback` on a next tick. ### `db._serializeKey(key)` Convert a `key` to a type supported by the underlying storage. All methods below that take a `key` argument or option - including `db._iterator()` with its range options and `iterator._seek()` with its `target` argument - will receive serialized keys. For example, if `_serializeKey` is implemented as: ```js FakeLevelDOWN.prototype._serializeKey = function (key) { return Buffer.isBuffer(key) ? key : String(key) } ``` Then `db.get(2, callback)` translates into `db._get('2', options, callback)`. Similarly, `db.iterator({ gt: 2 })` translates into `db._iterator({ gt: '2', ... })` and `iterator.seek(2)` translates into `iterator._seek('2')`. If the underlying storage supports any JavaScript type or if your implementation wraps another implementation, it is recommended to make `_serializeKey` an identity function (returning the key as-is). Serialization is irreversible, unlike _encoding_ as performed by implementations like [`encoding-down`][encoding-down]. This also applies to `_serializeValue`. The default `_serializeKey()` is an identity function. ### `db._serializeValue(value)` Convert a `value` to a type supported by the underlying storage. All methods below that take a `value` argument or option will receive serialized values. For example, if `_serializeValue` is implemented as: ```js FakeLevelDOWN.prototype._serializeValue = function (value) { return Buffer.isBuffer(value) ? value : String(value) } ``` Then `db.put(key, 2, callback)` translates into `db._put(key, '2', options, callback)`. The default `_serializeValue()` is an identity function. ### `db._get(key, options, callback)` Get a value by `key`. The `options` object will always have the following properties: `asBuffer`. If the key does not exist, call the `callback` function with a `new Error('NotFound')`. Otherwise call `callback` with `null` as the first argument and the value as the second. The default `_get()` invokes `callback` on a next tick with a `NotFound` error. It must be overridden. ### `db._put(key, value, options, callback)` Store a new entry or overwrite an existing entry. There are no default options but `options` will always be an object. If putting failed, call the `callback` function with an `Error`. Otherwise call `callback` without any arguments. The default `_put()` invokes `callback` on a next tick. It must be overridden. ### `db._del(key, options, callback)` Delete an entry. There are no default options but `options` will always be an object. If deletion failed, call the `callback` function with an `Error`. Otherwise call `callback` without any arguments. The default `_del()` invokes `callback` on a next tick. It must be overridden. ### `db._batch(operations, options, callback)` Perform multiple _put_ and/or _del_ operations in bulk. The `operations` argument is always an `Array` containing a list of operations to be executed sequentially, although as a whole they should be performed as an atomic operation. Each operation is guaranteed to have at least `type` and `key` properties. There are no default options but `options` will always be an object. If the batch failed, call the `callback` function with an `Error`. Otherwise call `callback` without any arguments. The default `_batch()` invokes `callback` on a next tick. It must be overridden. ### `db._chainedBatch()` The default `_chainedBatch()` returns a functional `AbstractChainedBatch` instance that uses `db._batch(array, options, callback)` under the hood. The prototype is available on the main exports for you to extend. If you want to implement chainable batch operations in a different manner then you should extend `AbstractChainedBatch` and return an instance of this prototype in the `_chainedBatch()` method: ```js var AbstractChainedBatch = require('abstract-leveldown').AbstractChainedBatch var inherits = require('util').inherits function ChainedBatch (db) { AbstractChainedBatch.call(this, db) } inherits(ChainedBatch, AbstractChainedBatch) FakeLevelDOWN.prototype._chainedBatch = function () { return new ChainedBatch(this) } ``` ### `db._iterator(options)` The default `_iterator()` returns a noop `AbstractIterator` instance. It must be overridden, by extending `AbstractIterator` (available on the main module exports) and returning an instance of this prototype in the `_iterator(options)` method. The `options` object will always have the following properties: `reverse`, `keys`, `values`, `limit`, `keyAsBuffer` and `valueAsBuffer`. ### `db._clear(options, callback)` **This method is experimental and optional for the time being. To enable its tests, set the [`clear` option of the test suite](#excluding-tests) to `true`.** Delete all entries or a range. Does not have to be atomic. It is recommended (and possibly mandatory in the future) to operate on a snapshot so that writes scheduled after a call to `clear()` will not be affected. The default `_clear()` uses `_iterator()` and `_del()` to provide a reasonable fallback, but requires binary key support. It is _recommended_ to implement `_clear()` with more performant primitives than `_iterator()` and `_del()` if the underlying storage has such primitives. Implementations that don't support binary keys _must_ implement their own `_clear()`. Implementations that wrap another `db` can typically forward the `_clear()` call to that `db`, having transformed range options if necessary. The `options` object will always have the following properties: `reverse` and `limit`. ### `iterator = AbstractIterator(db)` The first argument to this constructor must be an instance of your `AbstractLevelDOWN` implementation. The constructor will set `iterator.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. #### `iterator._next(callback)` Advance the iterator and yield the entry at that key. If nexting failed, call the `callback` function with an `Error`. Otherwise, call `callback` with `null`, a `key` and a `value`. The default `_next()` invokes `callback` on a next tick. It must be overridden. #### `iterator._seek(target)` Seek the iterator to a given key or the closest key. This method is optional. #### `iterator._end(callback)` Free up underlying resources. This method is guaranteed to only be called once. If ending failed, call the `callback` function with an `Error`. Otherwise call `callback` without any arguments. The default `_end()` invokes `callback` on a next tick. Overriding is optional. ### `chainedBatch = AbstractChainedBatch(db)` 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)` Queue a `put` operation on this batch. #### `chainedBatch._del(key)` Queue a `del` operation on this batch. #### `chainedBatch._clear()` Clear all queued operations on this batch. #### `chainedBatch._write(options, callback)` The default `_write` method uses `db._batch`. If the `_write` method is overridden it must atomically commit the queued operations. There are no default options but `options` will always be an object. If committing fails, call the `callback` function with an `Error`. Otherwise call `callback` without any arguments. ## Test Suite To prove that your implementation is `abstract-leveldown` compliant, include the abstract test suite in your `test.js` (or similar): ```js const test = require('tape') const suite = require('abstract-leveldown/test') const YourDOWN = require('.') suite({ test: test, factory: function () { return new YourDOWN() } }) ``` This is the most minimal setup. The `test` option _must_ be a function that is API-compatible with `tape`. The `factory` option _must_ be a function that returns a unique and isolated database instance. The factory will be called many times by the test suite. If your implementation is disk-based we recommend using [`tempy`](https://github.com/sindresorhus/tempy) (or similar) to create unique temporary directories. Your setup could look something like: ```js const test = require('tape') const tempy = require('tempy') const suite = require('abstract-leveldown/test') const YourDOWN = require('.') suite({ test: test, factory: function () { return new YourDOWN(tempy.directory()) } }) ``` ### Excluding tests As not every implementation can be fully compliant due to limitations of its underlying storage, some tests may be skipped. For example, to skip snapshot tests: ```js suite({ // .. snapshots: false }) ``` This also serves as a signal to users of your implementation. The following options are available: - `bufferKeys`: set to `false` if binary keys are not supported by the underlying storage - `seek`: set to `false` if your `iterator` does not implement `_seek` - `clear`: defaults to `false` until a next major release. Set to `true` if your implementation either implements `_clear()` itself or is suitable to use the default implementation of `_clear()` (which requires binary key support). - `snapshots`: set to `false` if any of the following is true: - Reads don't operate on a [snapshot](#iterator) - Snapshots are created asynchronously - `createIfMissing` and `errorIfExists`: set to `false` if `db._open()` does not support these options. - `legacyRange`: set to `false` if your iterator does not support the legacy `start` and `end` range 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: ```js suite({ // .. setUp: function (t) { t.end() }, tearDown: function (t) { t.end() } }) ``` ### Reusing `testCommon` The input to the test suite is a `testCommon` object. Should you need to reuse `testCommon` for your own (additional) tests, use the included utility to create a `testCommon` with defaults: ```js const test = require('tape') const suite = require('abstract-leveldown/test') const YourDOWN = require('.') const testCommon = suite.common({ test: test, factory: function () { return new YourDOWN() } }) suite(testCommon) ``` The `testCommon` object will have all the properties describe above: `test`, `factory`, `setUp`, `tearDown` and the skip options. You might use it like so: ```js test('setUp', testCommon.setUp) test('custom test', function (t) { var db = testCommon.factory() // .. }) test('another custom test', function (t) { var db = testCommon.factory() // .. }) test('tearDown', testCommon.tearDown) ``` ## Spread The Word If you'd like to share your awesome implementation with the world, here's what you might want to do: - Add an awesome badge to your `README`: `![level badge](https://leveljs.org/img/badge.svg)` - Publish your awesome module to [npm](https://npmjs.org) - Send a Pull Request to [Level/awesome](https://github.com/Level/awesome) to advertise your work! ## Install With [npm](https://npmjs.org) do: ``` npm install abstract-leveldown ``` ## Contributing [`Level/abstract-leveldown`](https://github.com/Level/abstract-leveldown) is an **OPEN Open Source Project**. This means that: > Individuals making significant and valuable contributions are given commit-access to the project to contribute as they see fit. This project is more like an open wiki than a standard guarded open source project. See the [Contribution Guide](https://github.com/Level/community/blob/master/CONTRIBUTING.md) for more details. ## Big Thanks Cross-browser Testing Platform and Open Source ♥ Provided by [Sauce Labs](https://saucelabs.com). [![Sauce Labs logo](./sauce-labs.svg)](https://saucelabs.com) ## Donate To sustain [`Level`](https://github.com/Level) and its activities, become a backer or sponsor on [Open Collective](https://opencollective.com/level). Your logo or avatar will be displayed on our 28+ [GitHub repositories](https://github.com/Level) and [npm](https://www.npmjs.com/) packages. 💖 ### Backers [![Open Collective backers](https://opencollective.com/level/backers.svg?width=890)](https://opencollective.com/level) ### Sponsors [![Open Collective sponsors](https://opencollective.com/level/sponsors.svg?width=890)](https://opencollective.com/level) ## License [MIT](LICENSE.md) © 2013-present Rod Vagg and [Contributors](CONTRIBUTORS.md). [level-badge]: https://leveljs.org/img/badge.svg [encoding-down]: https://github.com/Level/encoding-down [leveldown]: https://github.com/Level/leveldown abstract-leveldown-6.3.0/UPGRADING.md000066400000000000000000000263651364427107700172110ustar00rootroot00000000000000# Upgrade Guide This document describes breaking changes and how to upgrade. For a complete list of changes including minor and patch releases, please refer to the [changelog](CHANGELOG.md). ## Table of Contents
Click to expand - [v6](#v6) - [v5](#v5) - [v4](#v4) - [v3](#v3)
## v6 This release brings a major refactoring of the test suite, decouples `abstract-leveldown` from disk-based implementations and solves long-standing issues around serialization and type support. Because the changes are substantial, this guide has two sections: 1. **Changes to public API** - for consumers of any implementation. 2. **Changes to private API** - intended for implementors. ### Changes to public API #### Nullish values are rejected In addition to rejecting `null` and `undefined` as _keys_, `abstract-leveldown` now also rejects these types as _values_, due to preexisting significance in streams and iterators. Before this, the behavior of these types depended on a large number of factors: `_serializeValue` and type support of the underlying storage, whether `get()`, `iterator()` or a stream was used to retrieve values, the `keys` and `asBuffer` options of `iterator()` and finally, which encoding was selected. #### Range options are serialized Previously, range options like `lt` were passed through as-is, unlike keys. #### The rules for range options have been relaxed Because `null`, `undefined`, zero-length strings and zero-length buffers are significant types in encodings like `bytewise` and `charwise`, they became valid as range options. In fact, any type is now valid. This means `db.iterator({ gt: undefined })` is not the same as `db.iterator({})`. Furthermore, `abstract-leveldown` makes no assumptions about the meaning of these types. Range tests that assumed `null` meant "not defined" have been removed. #### Zero-length array keys are rejected Though this was already the case because `_checkKey` stringified its input before checking the length, that behavior has been replaced with an explicit `Array.isArray()` check and a new error message. #### No longer assumes support of boolean and `NaN` keys A test that asserted boolean and `NaN` keys were valid has been removed. #### Browser support IE10 has been dropped. ### Changes to private API #### `location` was removed `AbstractLevelDOWN` is no longer associated with a `location`. It's up to the implementation to handle it if it's required. If your implementation has a `location` and you previously did: ```js function YourDOWN (location) { AbstractLevelDOWN.call(this, location) } ``` You must now do: ```js function YourDOWN (location) { this.location = location AbstractLevelDOWN.call(this) } ``` Be sure to include appropriate type checks. If you relied on the default `AbstractLevelDOWN` behavior that would be: ```js if (typeof location !== 'string') { throw new Error('constructor requires a location string argument') } ``` #### Abstract test suite has moved to a single entry point Instead of including test files individually, you can and should include the test suite with one `require()` statement. If you previously did: ```js const test = require('tape') const testCommon = require('abstract-leveldown/testCommon') const YourDOWN = require('.') require('abstract-leveldown/abstract/get-test').all(YourDOWN, test, testCommon) require('abstract-leveldown/abstract/put-test').all(YourDOWN, test, testCommon) // etc ``` You must now do: ```js const test = require('tape') const suite = require('abstract-leveldown/test') const YourDOWN = require('.') suite({ test: test, factory: function () { return new YourDOWN() } }) ``` The input to the test suite is a new form of `testCommon`. Should you need to reuse `testCommon` for your own (additional) tests, use the included utility to create a `testCommon` with defaults: ```js const test = require('tape') const suite = require('abstract-leveldown/test') const YourDOWN = require('.') const testCommon = suite.common({ test: test, factory: function () { return new YourDOWN() } }) suite(testCommon) ``` As part of removing `location`, the abstract tests no longer use `testCommon.location()`. Instead an implementation _must_ implement `factory()` which _must_ return a unique and isolated database instance. This allows implementations to pass options to their constructor. The `testCommon.cleanup` method has been removed. Because `factory()` returns a unique database instance, cleanup should no longer be necessary. The `testCommon.lastLocation` method has also been removed as there is no remaining use of it in abstract tests. Previously, implementations using the default `testCommon` had to include `rimraf` in their `devDependencies` and browser-based implementations had to exclude `rimraf` from browserify builds. This is no longer the case. If your implementation is disk-based we recommend using [`tempy`](https://github.com/sindresorhus/tempy) (or similar) to create unique temporary directories. Together with `factory()` your setup could now look something like: ```js const test = require('tape') const tempy = require('tempy') const suite = require('abstract-leveldown/test') const YourDOWN = require('.') suite({ test: test, factory: function () { return new YourDOWN(tempy.directory()) } }) ``` #### The `collectEntries` utility has moved The `testCommon.collectEntries` method has moved to the npm package `level-concat-iterator`. If your (additional) tests depend on `collectEntries` and you previously did: ```js testCommon.collectEntries(iterator, function (err, entries) {}) ``` You must now do: ```js const concat = require('level-concat-iterator') concat(iterator, function (err, entries) {}) ``` #### Setup and teardown became noops Because cleanup is no longer necessary, the `testCommon.setUp` and `testCommon.tearDown` methods are now noops by default. If you do need to perform (a)synchronous work before or after each test, `setUp` and `tearDown` can be overridden: ```js suite({ // .. setUp: function (t) { t.end() }, tearDown: function (t) { t.end() } }) ``` #### Optional tests have been separated If your implementation does not support snapshots or other optional features, the relevant tests may be skipped. For example: ```js suite({ // .. snapshots: false }) ``` Please see the [README](README.md) for a list of options. Note that some of these have replaced `process.browser` checks. #### Iterator must have a `db` reference The `db` argument of the `AbstractIterator` constructor became mandatory, as well as a public `db` property on the instance. Its existence is not new; the test suite now asserts that your implementation also has it. #### Seeking became part of official API If your implementation previously defined the public `iterator.seek(target)`, it must now define the private `iterator._seek(target)`. The new public API is equal to the reference implementation of `leveldown` except for two differences: - The `target` argument is not type checked, this is up to the implementation. - The `target` argument is passed through `db._serializeKey`. Please see the [README](README.md) for details. #### Chained batch has been refactored - The default `_clear` method is no longer a noop; instead it clears the operations queued by `_put` and/or `_del` - The `_write` method now takes an `options` object as its first argument - The `db` argument of the `AbstractChainedBatch` constructor became mandatory, as well as a public `db` property on the instance, which was previously named `_db`. #### Default `_serializeKey` and `_serializeValue` became identity functions They return whatever is given. Previously they were opinionated and mostly geared towards string- and Buffer-based storages. Implementations that didn't already define their own serialization should now do so, according to the types that they support. Please refer to the [README](README.md) for recommended behavior. ## v5 Dropped support for node 4. No other breaking changes. ## v4 #### default `testCommon` parameter The `testCommon` parameter will now default to `abstract-leveldown/testCommon.js`. You can omit this parameter, unless your implementation needs a custom version. If your code today looks something like: ```js const test = require('tape') const testCommon = require('abstract-leveldown/testCommon') const leveldown = require('./your-leveldown') const abstract = require('abstract-leveldown/abstract/get-test') abstract.all(leveldown, test, testCommon) ``` You can simplify it to: ```js const test = require('tape') const leveldown = require('./your-leveldown') const abstract = require('abstract-leveldown/abstract/get-test') abstract.all(leveldown, test) ``` #### `testBuffer` parameter removed The `abstract/put-get-del-test.js` previously took a custom `testBuffer` parameter. After an [analysis](https://github.com/Level/abstract-leveldown/pull/175#issuecomment-353867144) of various implementations we came to the conclusion that the parameter has no use. If your implementation is using this abstract test, change from: ```js const test = require('tape') const testCommon = require('abstract-leveldown/testCommon') const leveldown = require('./your-leveldown') const fs = require('fs') const path = require('path') const testBuffer = fs.readFileSync(path.join(__dirname, 'data/testdata.bin')) const abstract = require('abstract-leveldown/abstract/put-get-del-test') abstract.all(leveldown, test, testBuffer, testCommon) ``` to: ```js const test = require('tape') const testCommon = require('abstract-leveldown/testCommon') const leveldown = require('./your-leveldown') const abstract = require('abstract-leveldown/abstract/put-get-del-test') abstract.all(leveldown, test, testCommon) ``` or if `testCommon` is also redundant, to: ```js const test = require('tape') const leveldown = require('./your-leveldown') const abstract = require('abstract-leveldown/abstract/put-get-del-test') abstract.all(leveldown, test) ``` #### `.approximateSize` method removed The `.approximateSize` method has been removed from the public API. It is heavily related to `LevelDB` and more often than not, other stores lack the native primitives to implement this. If you did implement the internal `_approximateSize` method, that is now dead code. To preserve the method in your public API, rename it to `approximateSize` and also take care of the initialization code. Look to `leveldown` for inspiration. Also, the corresponding abstract tests have been removed, so your implementation can no longer require `abstract/approximate-size-test`. #### `._isBuffer` method removed Because `Buffer` is available in all environments nowadays, there is no need for alternatives like typed arrays. It is preferred to use `Buffer` and `Buffer.isBuffer()` directly. #### `isLevelDOWN` function removed This was a legacy function. #### `ranges-test.js` renamed We have refactored a lot of the tests. Specifically the iterator tests were split in two and in that process we renamed `ranges-test.js` to `iterator-range-test.js`. If your implementation is using these tests then change from: ```js const abstract = require('abstract-leveldown/abstract/ranges-test') ``` to: ```js const abstract = require('abstract-leveldown/abstract/iterator-range-test') ``` ## v3 No changes to the API. New major version because support for node 0.12 was dropped. abstract-leveldown-6.3.0/abstract-chained-batch.js000066400000000000000000000037531364427107700221540ustar00rootroot00000000000000var nextTick = require('./next-tick') function AbstractChainedBatch (db) { if (typeof db !== 'object' || db === null) { throw new TypeError('First argument must be an abstract-leveldown compliant store') } this.db = db this._operations = [] this._written = false } AbstractChainedBatch.prototype._checkWritten = function () { if (this._written) { throw new Error('write() already called on this batch') } } AbstractChainedBatch.prototype.put = function (key, value) { this._checkWritten() var err = this.db._checkKey(key) || this.db._checkValue(value) if (err) throw err key = this.db._serializeKey(key) value = this.db._serializeValue(value) this._put(key, value) return this } AbstractChainedBatch.prototype._put = function (key, value) { this._operations.push({ type: 'put', key: key, value: value }) } AbstractChainedBatch.prototype.del = function (key) { this._checkWritten() var err = this.db._checkKey(key) if (err) throw err key = this.db._serializeKey(key) this._del(key) return this } AbstractChainedBatch.prototype._del = function (key) { this._operations.push({ type: 'del', key: key }) } AbstractChainedBatch.prototype.clear = function () { this._checkWritten() this._clear() return this } AbstractChainedBatch.prototype._clear = function () { this._operations = [] } AbstractChainedBatch.prototype.write = function (options, callback) { this._checkWritten() if (typeof options === 'function') { callback = options } if (typeof callback !== 'function') { throw new Error('write() requires a callback argument') } if (typeof options !== 'object' || options === null) { options = {} } this._written = true this._write(options, callback) } AbstractChainedBatch.prototype._write = function (options, callback) { this.db._batch(this._operations, options, callback) } // Expose browser-compatible nextTick for dependents AbstractChainedBatch.prototype._nextTick = nextTick module.exports = AbstractChainedBatch abstract-leveldown-6.3.0/abstract-iterator.js000066400000000000000000000034021364427107700213220ustar00rootroot00000000000000var nextTick = require('./next-tick') function AbstractIterator (db) { if (typeof db !== 'object' || db === null) { throw new TypeError('First argument must be an abstract-leveldown compliant store') } this.db = db this._ended = false this._nexting = false } AbstractIterator.prototype.next = function (callback) { var self = this if (typeof callback !== 'function') { throw new Error('next() requires a callback argument') } if (self._ended) { nextTick(callback, new Error('cannot call next() after end()')) return self } if (self._nexting) { nextTick(callback, new Error('cannot call next() before previous next() has completed')) return self } self._nexting = true self._next(function () { self._nexting = false callback.apply(null, arguments) }) return self } AbstractIterator.prototype._next = function (callback) { nextTick(callback) } AbstractIterator.prototype.seek = function (target) { if (this._ended) { throw new Error('cannot call seek() after end()') } if (this._nexting) { throw new Error('cannot call seek() before next() has completed') } target = this.db._serializeKey(target) this._seek(target) } AbstractIterator.prototype._seek = function (target) {} AbstractIterator.prototype.end = function (callback) { if (typeof callback !== 'function') { throw new Error('end() requires a callback argument') } if (this._ended) { return nextTick(callback, new Error('end() already called on iterator')) } this._ended = true this._end(callback) } AbstractIterator.prototype._end = function (callback) { nextTick(callback) } // Expose browser-compatible nextTick for dependents AbstractIterator.prototype._nextTick = nextTick module.exports = AbstractIterator abstract-leveldown-6.3.0/abstract-leveldown.js000066400000000000000000000207111364427107700214720ustar00rootroot00000000000000var xtend = require('xtend') var supports = require('level-supports') var Buffer = require('buffer').Buffer var AbstractIterator = require('./abstract-iterator') var AbstractChainedBatch = require('./abstract-chained-batch') var nextTick = require('./next-tick') var hasOwnProperty = Object.prototype.hasOwnProperty var rangeOptions = 'start end gt gte lt lte'.split(' ') function AbstractLevelDOWN (manifest) { this.status = 'new' // TODO (next major): make this mandatory this.supports = supports(manifest, { status: true }) } AbstractLevelDOWN.prototype.open = function (options, callback) { var self = this var oldStatus = this.status if (typeof options === 'function') callback = options if (typeof callback !== 'function') { throw new Error('open() requires a callback argument') } if (typeof options !== 'object' || options === null) options = {} options.createIfMissing = options.createIfMissing !== false options.errorIfExists = !!options.errorIfExists this.status = 'opening' this._open(options, function (err) { if (err) { self.status = oldStatus return callback(err) } self.status = 'open' callback() }) } AbstractLevelDOWN.prototype._open = function (options, callback) { nextTick(callback) } AbstractLevelDOWN.prototype.close = function (callback) { var self = this var oldStatus = this.status if (typeof callback !== 'function') { throw new Error('close() requires a callback argument') } this.status = 'closing' this._close(function (err) { if (err) { self.status = oldStatus return callback(err) } self.status = 'closed' callback() }) } AbstractLevelDOWN.prototype._close = function (callback) { nextTick(callback) } AbstractLevelDOWN.prototype.get = function (key, options, callback) { if (typeof options === 'function') callback = options if (typeof callback !== 'function') { throw new Error('get() requires a callback argument') } var err = this._checkKey(key) if (err) return nextTick(callback, err) key = this._serializeKey(key) if (typeof options !== 'object' || options === null) options = {} options.asBuffer = options.asBuffer !== false this._get(key, options, callback) } AbstractLevelDOWN.prototype._get = function (key, options, callback) { nextTick(function () { callback(new Error('NotFound')) }) } AbstractLevelDOWN.prototype.put = function (key, value, options, callback) { if (typeof options === 'function') callback = options if (typeof callback !== 'function') { throw new Error('put() requires a callback argument') } var err = this._checkKey(key) || this._checkValue(value) if (err) return nextTick(callback, err) key = this._serializeKey(key) value = this._serializeValue(value) if (typeof options !== 'object' || options === null) options = {} this._put(key, value, options, callback) } AbstractLevelDOWN.prototype._put = function (key, value, options, callback) { nextTick(callback) } AbstractLevelDOWN.prototype.del = function (key, options, callback) { if (typeof options === 'function') callback = options if (typeof callback !== 'function') { throw new Error('del() requires a callback argument') } var err = this._checkKey(key) if (err) return nextTick(callback, err) key = this._serializeKey(key) if (typeof options !== 'object' || options === null) options = {} this._del(key, options, callback) } AbstractLevelDOWN.prototype._del = function (key, options, callback) { nextTick(callback) } AbstractLevelDOWN.prototype.batch = function (array, options, callback) { if (!arguments.length) return this._chainedBatch() if (typeof options === 'function') callback = options if (typeof array === 'function') callback = array if (typeof callback !== 'function') { throw new Error('batch(array) requires a callback argument') } if (!Array.isArray(array)) { return nextTick(callback, new Error('batch(array) requires an array argument')) } if (array.length === 0) { return nextTick(callback) } if (typeof options !== 'object' || options === null) options = {} var serialized = new Array(array.length) for (var i = 0; i < array.length; i++) { if (typeof array[i] !== 'object' || array[i] === null) { return nextTick(callback, new Error('batch(array) element must be an object and not `null`')) } var e = xtend(array[i]) if (e.type !== 'put' && e.type !== 'del') { return nextTick(callback, new Error("`type` must be 'put' or 'del'")) } var err = this._checkKey(e.key) if (err) return nextTick(callback, err) e.key = this._serializeKey(e.key) if (e.type === 'put') { var valueErr = this._checkValue(e.value) if (valueErr) return nextTick(callback, valueErr) e.value = this._serializeValue(e.value) } serialized[i] = e } this._batch(serialized, options, callback) } AbstractLevelDOWN.prototype._batch = function (array, options, callback) { nextTick(callback) } AbstractLevelDOWN.prototype.clear = function (options, callback) { if (typeof options === 'function') { callback = options } else if (typeof callback !== 'function') { throw new Error('clear() requires a callback argument') } options = cleanRangeOptions(this, options) options.reverse = !!options.reverse options.limit = 'limit' in options ? options.limit : -1 this._clear(options, callback) } AbstractLevelDOWN.prototype._clear = function (options, callback) { // Avoid setupIteratorOptions, would serialize range options a second time. options.keys = true options.values = false options.keyAsBuffer = true options.valueAsBuffer = true var iterator = this._iterator(options) var emptyOptions = {} var self = this var next = function (err) { if (err) { return iterator.end(function () { callback(err) }) } iterator.next(function (err, key) { if (err) return next(err) if (key === undefined) return iterator.end(callback) // This could be optimized by using a batch, but the default _clear // is not meant to be fast. Implementations have more room to optimize // if they override _clear. Note: using _del bypasses key serialization. self._del(key, emptyOptions, next) }) } next() } AbstractLevelDOWN.prototype._setupIteratorOptions = function (options) { options = cleanRangeOptions(this, options) options.reverse = !!options.reverse options.keys = options.keys !== false options.values = options.values !== false options.limit = 'limit' in options ? options.limit : -1 options.keyAsBuffer = options.keyAsBuffer !== false options.valueAsBuffer = options.valueAsBuffer !== false return options } function cleanRangeOptions (db, options) { var result = {} for (var k in options) { if (!hasOwnProperty.call(options, k)) continue var opt = options[k] if (isRangeOption(k)) { // Note that we don't reject nullish and empty options here. While // those types are invalid as keys, they are valid as range options. opt = db._serializeKey(opt) } result[k] = opt } return result } function isRangeOption (k) { return rangeOptions.indexOf(k) !== -1 } AbstractLevelDOWN.prototype.iterator = function (options) { if (typeof options !== 'object' || options === null) options = {} options = this._setupIteratorOptions(options) return this._iterator(options) } AbstractLevelDOWN.prototype._iterator = function (options) { return new AbstractIterator(this) } AbstractLevelDOWN.prototype._chainedBatch = function () { return new AbstractChainedBatch(this) } AbstractLevelDOWN.prototype._serializeKey = function (key) { return key } AbstractLevelDOWN.prototype._serializeValue = function (value) { return value } AbstractLevelDOWN.prototype._checkKey = function (key) { if (key === null || key === undefined) { return new Error('key cannot be `null` or `undefined`') } else if (Buffer.isBuffer(key) && key.length === 0) { return new Error('key cannot be an empty Buffer') } else if (key === '') { return new Error('key cannot be an empty String') } else if (Array.isArray(key) && key.length === 0) { return new Error('key cannot be an empty Array') } } AbstractLevelDOWN.prototype._checkValue = function (value) { if (value === null || value === undefined) { return new Error('value cannot be `null` or `undefined`') } } // Expose browser-compatible nextTick for dependents AbstractLevelDOWN.prototype._nextTick = nextTick module.exports = AbstractLevelDOWN abstract-leveldown-6.3.0/index.js000066400000000000000000000002711364427107700170000ustar00rootroot00000000000000exports.AbstractLevelDOWN = require('./abstract-leveldown') exports.AbstractIterator = require('./abstract-iterator') exports.AbstractChainedBatch = require('./abstract-chained-batch') abstract-leveldown-6.3.0/next-tick-browser.js000066400000000000000000000000461364427107700212600ustar00rootroot00000000000000module.exports = require('immediate') abstract-leveldown-6.3.0/next-tick.js000066400000000000000000000000421364427107700175730ustar00rootroot00000000000000module.exports = process.nextTick abstract-leveldown-6.3.0/package.json000066400000000000000000000026761364427107700176340ustar00rootroot00000000000000{ "name": "abstract-leveldown", "version": "6.3.0", "description": "An abstract prototype matching the LevelDOWN API", "license": "MIT", "main": "index.js", "browser": { "./next-tick.js": "./next-tick-browser.js" }, "scripts": { "test": "standard && hallmark && nyc node test/self.js", "test-browsers": "airtap --coverage --loopback airtap.local test/self.js", "test-browser-local": "airtap --coverage --local test/self.js", "coverage": "nyc report --reporter=text-lcov | coveralls", "hallmark": "hallmark --fix", "dependency-check": "dependency-check --no-dev -i buffer -i immediate . test/*.js", "prepublishOnly": "npm run dependency-check" }, "dependencies": { "buffer": "^5.5.0", "immediate": "^3.2.3", "level-concat-iterator": "~2.0.0", "level-supports": "~1.0.0", "xtend": "~4.0.0" }, "devDependencies": { "airtap": "^3.0.0", "coveralls": "^3.0.2", "dependency-check": "^4.1.0", "hallmark": "^2.0.0", "level-community": "^3.0.0", "nyc": "^14.0.0", "sinon": "^7.2.4", "standard": "^14.0.0", "tape": "^4.10.0" }, "hallmark": { "community": "level-community" }, "repository": { "type": "git", "url": "https://github.com/Level/abstract-leveldown.git" }, "homepage": "https://github.com/Level/abstract-leveldown", "keywords": [ "level", "leveldb", "leveldown", "levelup" ], "engines": { "node": ">=6" } } abstract-leveldown-6.3.0/sauce-labs.svg000066400000000000000000000124271364427107700201010ustar00rootroot00000000000000 Sauce Labs abstract-leveldown-6.3.0/test/000077500000000000000000000000001364427107700163125ustar00rootroot00000000000000abstract-leveldown-6.3.0/test/batch-test.js000066400000000000000000000213741364427107700207150ustar00rootroot00000000000000var db var verifyNotFoundError = require('./util').verifyNotFoundError var isTypedArray = require('./util').isTypedArray exports.setUp = function (test, testCommon) { test('setUp common', testCommon.setUp) test('setUp db', function (t) { db = testCommon.factory() db.open(t.end.bind(t)) }) } exports.args = function (test, testCommon) { testCommon.promises || test('test callback-less, 2-arg, batch() throws', function (t) { t.throws( db.batch.bind(db, 'foo', {}), /Error: batch\(array\) requires a callback argument/, 'callback-less, 2-arg batch() throws' ) t.end() }) test('test batch() with missing `value`', function (t) { db.batch([{ type: 'put', key: 'foo1' }], function (err) { t.is(err.message, 'value cannot be `null` or `undefined`', 'correct error message') t.end() }) }) test('test batch() with null or undefined `value`', function (t) { var illegalValues = [null, undefined] t.plan(illegalValues.length) illegalValues.forEach(function (value) { db.batch([{ type: 'put', key: 'foo1', value: value }], function (err) { t.is(err.message, 'value cannot be `null` or `undefined`', 'correct error message') }) }) }) test('test batch() with missing `key`', function (t) { var async = false db.batch([{ type: 'put', value: 'foo1' }], function (err) { t.ok(err, 'got error') t.equal(err.message, 'key cannot be `null` or `undefined`', 'correct error message') t.ok(async, 'callback is asynchronous') t.end() }) async = true }) test('test batch() with null or undefined `key`', function (t) { var illegalKeys = [null, undefined] t.plan(illegalKeys.length * 3) illegalKeys.forEach(function (key) { var async = false db.batch([{ type: 'put', key: key, value: 'foo1' }], function (err) { t.ok(err, 'got error') t.equal(err.message, 'key cannot be `null` or `undefined`', 'correct error message') t.ok(async, 'callback is asynchronous') }) async = true }) }) test('test batch() with empty `key`', function (t) { var illegalKeys = [ { type: 'String', key: '' }, { type: 'Buffer', key: Buffer.alloc(0) }, { type: 'Array', key: [] } ] t.plan(illegalKeys.length * 3) illegalKeys.forEach(function (item) { var async = false db.batch([{ type: 'put', key: item.key, value: 'foo1' }], function (err) { t.ok(err, 'got error') t.equal(err.message, 'key cannot be an empty ' + item.type, 'correct error message') t.ok(async, 'callback is asynchronous') }) async = true }) }) test('test batch() with missing `key` and `value`', function (t) { var async = false db.batch([{ type: 'put' }], function (err) { t.ok(err, 'got error') t.equal(err.message, 'key cannot be `null` or `undefined`', 'correct error message') t.ok(async, 'callback is asynchronous') t.end() }) async = true }) test('test batch() with missing `type`', function (t) { var async = false db.batch([{ key: 'key', value: 'value' }], function (err) { t.ok(err, 'got error') t.equal(err.message, "`type` must be 'put' or 'del'", 'correct error message') t.ok(async, 'callback is asynchronous') t.end() }) async = true }) test('test batch() with wrong `type`', function (t) { var async = false db.batch([{ key: 'key', value: 'value', type: 'foo' }], function (err) { t.ok(err, 'got error') t.equal(err.message, "`type` must be 'put' or 'del'", 'correct error message') t.ok(async, 'callback is asynchronous') t.end() }) async = true }) test('test batch() with missing array', function (t) { var async = false db.batch(function (err) { t.ok(err, 'got error') t.equal(err.message, 'batch(array) requires an array argument', 'correct error message') t.ok(async, 'callback is asynchronous') t.end() }) async = true }) test('test batch() with undefined array', function (t) { var async = false db.batch(undefined, function (err) { t.ok(err, 'got error') t.equal(err.message, 'batch(array) requires an array argument', 'correct error message') t.ok(async, 'callback is asynchronous') t.end() }) async = true }) test('test batch() with null array', function (t) { var async = false db.batch(null, function (err) { t.ok(err, 'got error') t.equal(err.message, 'batch(array) requires an array argument', 'correct error message') t.ok(async, 'callback is asynchronous') t.end() }) async = true }) test('test batch() with null options', function (t) { db.batch([], null, function (err) { t.error(err) t.end() }) }) ;[null, undefined, 1, true].forEach(function (element) { var type = element === null ? 'null' : typeof element test('test batch() with ' + type + ' element', function (t) { var async = false db.batch([element], function (err) { t.ok(err, 'got error') t.equal(err.message, 'batch(array) element must be an object and not `null`', 'correct error message') t.ok(async, 'callback is asynchronous') t.end() }) async = true }) }) test('test batch() with empty array', function (t) { var async = false db.batch([], function (err) { t.error(err, 'no error from batch()') t.ok(async, 'callback is asynchronous') t.end() }) async = true }) } exports.batch = function (test, testCommon) { test('test simple batch()', function (t) { db.batch([{ type: 'put', key: 'foo', value: 'bar' }], function (err) { t.error(err) db.get('foo', function (err, value) { t.error(err) var result if (testCommon.encodings) { t.is(typeof value, 'string') result = value } else if (isTypedArray(value)) { result = String.fromCharCode.apply(null, new Uint16Array(value)) } else { t.ok(typeof Buffer !== 'undefined' && value instanceof Buffer) result = value.toString() } t.equal(result, 'bar') t.end() }) }) }) test('test multiple batch()', function (t) { db.batch([ { type: 'put', key: 'foobatch1', value: 'bar1' }, { type: 'put', key: 'foobatch2', value: 'bar2' }, { type: 'put', key: 'foobatch3', value: 'bar3' }, { type: 'del', key: 'foobatch2' } ], function (err) { t.error(err) var r = 0 var done = function () { if (++r === 3) { t.end() } } db.get('foobatch1', function (err, value) { t.error(err) var result if (testCommon.encodings) { t.is(typeof value, 'string') result = value } else if (isTypedArray(value)) { result = String.fromCharCode.apply(null, new Uint16Array(value)) } else { t.ok(typeof Buffer !== 'undefined' && value instanceof Buffer) result = value.toString() } t.equal(result, 'bar1') done() }) db.get('foobatch2', function (err, value) { t.ok(err, 'entry not found') t.ok(typeof value === 'undefined', 'value is undefined') t.ok(verifyNotFoundError(err), 'NotFound error') done() }) db.get('foobatch3', function (err, value) { t.error(err) var result if (testCommon.encodings) { t.is(typeof value, 'string') result = value } else if (isTypedArray(value)) { result = String.fromCharCode.apply(null, new Uint16Array(value)) } else { t.ok(typeof Buffer !== 'undefined' && value instanceof Buffer) result = value.toString() } t.equal(result, 'bar3') done() }) }) }) } exports.atomic = function (test, testCommon) { test('test multiple batch()', function (t) { t.plan(4) var async = false db.batch([ { type: 'put', key: 'foobah1', value: 'bar1' }, { type: 'put', value: 'bar2' }, { type: 'put', key: 'foobah3', value: 'bar3' } ], function (err) { t.ok(err, 'should error') t.ok(async, 'callback is asynchronous') db.get('foobah1', function (err) { t.ok(err, 'should not be found') }) db.get('foobah3', function (err) { t.ok(err, 'should not be found') }) }) async = true }) } exports.tearDown = function (test, testCommon) { test('tearDown', function (t) { db.close(testCommon.tearDown.bind(null, t)) }) } exports.all = function (test, testCommon) { exports.setUp(test, testCommon) exports.args(test, testCommon) exports.batch(test, testCommon) exports.atomic(test, testCommon) exports.tearDown(test, testCommon) } abstract-leveldown-6.3.0/test/chained-batch-test.js000066400000000000000000000170121364427107700223000ustar00rootroot00000000000000var collectEntries = require('level-concat-iterator') var db function collectBatchOps (batch) { var _put = batch._put var _del = batch._del var _operations = [] if (typeof _put !== 'function' || typeof _del !== 'function') { return batch._operations } batch._put = function (key, value) { _operations.push({ type: 'put', key: key, value: value }) return _put.apply(this, arguments) } batch._del = function (key) { _operations.push({ type: 'del', key: key }) return _del.apply(this, arguments) } return _operations } exports.setUp = function (test, testCommon) { test('setUp common', testCommon.setUp) test('setUp db', function (t) { db = testCommon.factory() db.open(t.end.bind(t)) }) } exports.args = function (test, testCommon) { test('test batch has db reference', function (t) { t.ok(db.batch().db === db) t.end() }) test('test batch#put() with missing `value`', function (t) { t.plan(1) try { db.batch().put('foo1') } catch (err) { t.is(err.message, 'value cannot be `null` or `undefined`', 'correct error message') } }) test('test batch#put() with missing `key`', function (t) { try { db.batch().put(undefined, 'foo1') } catch (err) { t.equal(err.message, 'key cannot be `null` or `undefined`', 'correct error message') return t.end() } t.fail('should have thrown') t.end() }) test('test batch#put() with null `key`', function (t) { try { db.batch().put(null, 'foo1') } catch (err) { t.equal(err.message, 'key cannot be `null` or `undefined`', 'correct error message') return t.end() } t.fail('should have thrown') t.end() }) test('test batch#put() with missing `key` and `value`', function (t) { try { db.batch().put() } catch (err) { t.equal(err.message, 'key cannot be `null` or `undefined`', 'correct error message') return t.end() } t.fail('should have thrown') t.end() }) test('test batch#put() with null or undefined `value`', function (t) { var illegalValues = [null, undefined] t.plan(illegalValues.length) illegalValues.forEach(function (value) { try { db.batch().put('key', value) } catch (err) { t.is(err.message, 'value cannot be `null` or `undefined`', 'correct error message') } }) }) test('test batch#del() with missing `key`', function (t) { try { db.batch().del() } catch (err) { t.equal(err.message, 'key cannot be `null` or `undefined`', 'correct error message') return t.end() } t.fail('should have thrown') t.end() }) test('test batch#del() with null or undefined `key`', function (t) { var illegalKeys = [null, undefined] t.plan(illegalKeys.length) illegalKeys.forEach(function (key) { try { db.batch().del(key) } catch (err) { t.equal(err.message, 'key cannot be `null` or `undefined`', 'correct error message') } }) }) test('test batch#clear() doesn\'t throw', function (t) { db.batch().clear() t.end() }) testCommon.promises || test('test batch#write() with no callback', function (t) { try { db.batch().write() } catch (err) { t.equal(err.message, 'write() requires a callback argument', 'correct error message') return t.end() } t.fail('should have thrown') t.end() }) test('test batch#put() after write()', function (t) { var batch = db.batch().put('foo', 'bar') batch.write(function () {}) try { batch.put('boom', 'bang') } catch (err) { t.equal(err.message, 'write() already called on this batch', 'correct error message') return t.end() } t.fail('should have thrown') t.end() }) test('test batch#del() after write()', function (t) { var batch = db.batch().put('foo', 'bar') batch.write(function () {}) try { batch.del('foo') } catch (err) { t.equal(err.message, 'write() already called on this batch', 'correct error message') return t.end() } t.fail('should have thrown') t.end() }) test('test batch#clear() after write()', function (t) { var batch = db.batch().put('foo', 'bar') batch.write(function () {}) try { batch.clear() } catch (err) { t.equal(err.message, 'write() already called on this batch', 'correct error message') return t.end() } t.fail('should have thrown') t.end() }) test('test batch#write() after write()', function (t) { var batch = db.batch().put('foo', 'bar') batch.write(function () {}) try { batch.write(function () {}) } catch (err) { t.equal(err.message, 'write() already called on this batch', 'correct error message') return t.end() } t.fail('should have thrown') t.end() }) testCommon.serialize && test('test serialize object', function (t) { var batch = db.batch() var ops = collectBatchOps(batch) batch .put({ foo: 'bar' }, { beep: 'boop' }) .del({ bar: 'baz' }) ops.forEach(function (op) { t.ok(op.key, '.key is set for .put and .del operations') if (op.type === 'put') { t.ok(op.value, '.value is set for .put operation') } }) t.end() }) testCommon.serialize && test('test custom _serialize*', function (t) { t.plan(4) var _db = Object.create(db) var batch = _db.batch() var ops = collectBatchOps(batch) _db._serializeKey = function (key) { t.same(key, { foo: 'bar' }) return 'key1' } _db._serializeValue = function (value) { t.same(value, { beep: 'boop' }) return 'value1' } batch.put({ foo: 'bar' }, { beep: 'boop' }) _db._serializeKey = function (key) { t.same(key, { bar: 'baz' }) return 'key2' } batch.del({ bar: 'baz' }) t.deepEqual(ops, [ { type: 'put', key: 'key1', value: 'value1' }, { type: 'del', key: 'key2' } ]) }) test('test batch#write() with no operations', function (t) { var async = false db.batch().write(function (err) { t.ifError(err, 'no error from write()') t.ok(async, 'callback is asynchronous') t.end() }) async = true }) } exports.batch = function (test, testCommon) { test('test basic batch', function (t) { db.batch([ { type: 'put', key: 'one', value: '1' }, { type: 'put', key: 'two', value: '2' }, { type: 'put', key: 'three', value: '3' } ], function (err) { t.error(err) db.batch() .put('1', 'one') .del('2', 'two') .put('3', 'three') .clear() .put('one', 'I') .put('two', 'II') .del('three') .put('foo', 'bar') .write(function (err) { t.error(err) collectEntries( db.iterator({ keyAsBuffer: false, valueAsBuffer: false }), function (err, data) { t.error(err) t.equal(data.length, 3, 'correct number of entries') var expected = [ { key: 'foo', value: 'bar' }, { key: 'one', value: 'I' }, { key: 'two', value: 'II' } ] t.deepEqual(data, expected) t.end() } ) }) }) }) } exports.tearDown = function (test, testCommon) { test('tearDown', function (t) { db.close(testCommon.tearDown.bind(null, t)) }) } exports.all = function (test, testCommon) { exports.setUp(test, testCommon) exports.args(test, testCommon) exports.batch(test, testCommon) exports.tearDown(test, testCommon) } abstract-leveldown-6.3.0/test/clear-range-test.js000066400000000000000000000123241364427107700220070ustar00rootroot00000000000000var concat = require('level-concat-iterator') var data = (function () { var d = [] var i = 0 var k for (; i < 100; i++) { k = (i < 10 ? '0' : '') + i d.push({ key: k, value: String(Math.random()) }) } return d }()) exports.setUp = function (test, testCommon) { test('setUp common', testCommon.setUp) } exports.range = function (test, testCommon) { function rangeTest (name, opts, expected) { test('db#clear() with ' + name, function (t) { prepare(t, function (db) { db.clear(opts, function (err) { t.ifError(err, 'no clear error') verify(t, db, expected) }) }) }) } function prepare (t, callback) { var db = testCommon.factory() db.open(function (err) { t.ifError(err, 'no open error') db.batch(data.map(function (d) { return { type: 'put', key: d.key, value: d.value } }), function (err) { t.ifError(err, 'no batch error') callback(db) }) }) } function verify (t, db, expected) { var it = db.iterator({ keyAsBuffer: false, valueAsBuffer: false }) concat(it, function (err, result) { t.ifError(err, 'no concat error') t.is(result.length, expected.length, 'correct number of entries') t.same(result, expected) db.close(t.end.bind(t)) }) } function exclude (data, start, end, expectedLength) { data = data.slice() var removed = data.splice(start, end - start + 1) // Inclusive if (expectedLength != null) checkLength(removed, expectedLength) return data } // For sanity checks on test arguments function checkLength (arr, length) { if (arr.length !== length) { throw new RangeError('Expected ' + length + ' elements, got ' + arr.length) } return arr } rangeTest('full range', {}, []) // Reversing has no effect without limit rangeTest('reverse=true', { reverse: true }, []) rangeTest('gte=00', { gte: '00' }, []) rangeTest('gte=50', { gte: '50' }, data.slice(0, 50)) rangeTest('lte=50 and reverse=true', { lte: '50', reverse: true }, data.slice(51)) rangeTest('gte=49.5 (midway)', { gte: '49.5' }, data.slice(0, 50)) rangeTest('gte=49999 (midway)', { gte: '49999' }, data.slice(0, 50)) rangeTest('lte=49.5 (midway) and reverse=true', { lte: '49.5', reverse: true }, data.slice(50)) rangeTest('lt=49.5 (midway) and reverse=true', { lt: '49.5', reverse: true }, data.slice(50)) rangeTest('lt=50 and reverse=true', { lt: '50', reverse: true }, data.slice(50)) rangeTest('lte=50', { lte: '50' }, data.slice(51)) rangeTest('lte=50.5 (midway)', { lte: '50.5' }, data.slice(51)) rangeTest('lte=50555 (midway)', { lte: '50555' }, data.slice(51)) rangeTest('lt=50555 (midway)', { lt: '50555' }, data.slice(51)) rangeTest('gte=50.5 (midway) and reverse=true', { gte: '50.5', reverse: true }, data.slice(0, 51)) rangeTest('gt=50.5 (midway) and reverse=true', { gt: '50.5', reverse: true }, data.slice(0, 51)) rangeTest('gt=50 and reverse=true', { gt: '50', reverse: true }, data.slice(0, 51)) // Starting key is actually '00' so it should avoid it rangeTest('lte=0', { lte: '0' }, data) // Starting key is actually '00' so it should avoid it rangeTest('lt=0', { lt: '0' }, data) rangeTest('gte=30 and lte=70', { gte: '30', lte: '70' }, exclude(data, 30, 70)) rangeTest('gt=29 and lt=71', { gt: '29', lt: '71' }, exclude(data, 30, 70)) rangeTest('gte=30 and lte=70 and reverse=true', { lte: '70', gte: '30', reverse: true }, exclude(data, 30, 70)) rangeTest('gt=29 and lt=71 and reverse=true', { lt: '71', gt: '29', reverse: true }, exclude(data, 30, 70)) rangeTest('limit=20', { limit: 20 }, data.slice(20)) rangeTest('limit=20 and gte=20', { limit: 20, gte: '20' }, exclude(data, 20, 39, 20)) rangeTest('limit=20 and reverse=true', { limit: 20, reverse: true }, data.slice(0, -20)) rangeTest('limit=20 and lte=79 and reverse=true', { limit: 20, lte: '79', reverse: true }, exclude(data, 60, 79, 20)) rangeTest('limit=-1 should clear whole database', { limit: -1 }, []) rangeTest('limit=0 should not clear anything', { limit: 0 }, data) rangeTest('lte after limit', { limit: 20, lte: '50' }, data.slice(20)) rangeTest('lte before limit', { limit: 50, lte: '19' }, data.slice(20)) rangeTest('gte after database end', { gte: '9a' }, data) rangeTest('gt after database end', { gt: '9a' }, data) rangeTest('lte after database end and reverse=true', { lte: '9a', reverse: true }, []) rangeTest('lte and gte after database and reverse=true', { lte: '9b', gte: '9a', reverse: true }, data) rangeTest('lt and gt after database and reverse=true', { lt: '9b', gt: '9a', reverse: true }, data) } exports.tearDown = function (test, testCommon) { test('tearDown', testCommon.tearDown) } exports.all = function (test, testCommon) { exports.setUp(test, testCommon) exports.range(test, testCommon) exports.tearDown(test, testCommon) } abstract-leveldown-6.3.0/test/clear-test.js000066400000000000000000000043061364427107700207160ustar00rootroot00000000000000var concat = require('level-concat-iterator') var db exports.setUp = function (test, testCommon) { test('setUp common', testCommon.setUp) test('setUp db', function (t) { db = testCommon.factory() db.open(t.end.bind(t)) }) } exports.args = function (test, testCommon) { testCommon.promises || test('test argument-less clear() throws', function (t) { t.throws( db.clear.bind(db), /Error: clear\(\) requires a callback argument/, 'no-arg clear() throws' ) t.end() }) } exports.clear = function (test, testCommon) { makeTest('string', ['a', 'b']) if (testCommon.bufferKeys) { makeTest('buffer', [Buffer.from('a'), Buffer.from('b')]) makeTest('mixed', [Buffer.from('a'), 'b']) // These keys would be equal when compared as utf8 strings makeTest('non-utf8 buffer', [Buffer.from('80', 'hex'), Buffer.from('c0', 'hex')]) } function makeTest (type, keys) { test('test simple clear() on ' + type + ' keys', function (t) { t.plan(8) var db = testCommon.factory() var ops = keys.map(function (key) { return { type: 'put', key: key, value: 'foo' } }) db.open(function (err) { t.ifError(err, 'no open error') db.batch(ops, function (err) { t.ifError(err, 'no batch error') concat(db.iterator(), function (err, entries) { t.ifError(err, 'no concat error') t.is(entries.length, keys.length, 'has entries') db.clear(function (err) { t.ifError(err, 'no clear error') concat(db.iterator(), function (err, entries) { t.ifError(err, 'no concat error') t.is(entries.length, 0, 'has no entries') db.close(function (err) { t.ifError(err, 'no close error') }) }) }) }) }) }) }) } } exports.tearDown = function (test, testCommon) { test('tearDown', function (t) { db.close(testCommon.tearDown.bind(null, t)) }) } exports.all = function (test, testCommon) { exports.setUp(test, testCommon) exports.args(test, testCommon) exports.clear(test, testCommon) exports.tearDown(test, testCommon) } abstract-leveldown-6.3.0/test/close-test.js000066400000000000000000000016271364427107700207400ustar00rootroot00000000000000var db exports.setUp = function (test, testCommon) { test('setUp common', testCommon.setUp) test('setUp db', function (t) { db = testCommon.factory() db.open(t.end.bind(t)) }) } exports.close = function (test, testCommon) { test('test close()', function (t) { testCommon.promises || t.throws( db.close.bind(db), /Error: close\(\) requires a callback argument/, 'no-arg close() throws' ) testCommon.promises || t.throws( db.close.bind(db, 'foo'), /Error: close\(\) requires a callback argument/, 'non-callback close() throws' ) db.close(function (err) { t.error(err) t.end() }) }) } exports.tearDown = function (test, testCommon) { test('tearDown', testCommon.tearDown) } exports.all = function (test, testCommon) { exports.setUp(test, testCommon) exports.close(test, testCommon) exports.tearDown(test, testCommon) } abstract-leveldown-6.3.0/test/common.js000066400000000000000000000031271364427107700201430ustar00rootroot00000000000000function testCommon (options) { var factory = options.factory var test = options.test if (typeof factory !== 'function') { throw new TypeError('factory must be a function') } if (typeof test !== 'function') { throw new TypeError('test must be a function') } 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, snapshots: options.snapshots !== false, seek: options.seek !== false, clear: !!options.clear, // Allow skipping 'start' and 'end' tests // TODO (next major): drop legacy range options legacyRange: options.legacyRange !== false, // Support running test suite on a levelup db. All options below this line // are undocumented and should not be used by abstract-leveldown db's (yet). promises: !!options.promises, status: options.status !== false, serialize: options.serialize !== false, // If true, the test suite assumes a default encoding of utf8 (like levelup) // and that operations return strings rather than buffers by default. encodings: !!options.encodings, // Not yet used, only here for symmetry with levelup's test suite. deferredOpen: !!options.deferredOpen, streams: !!options.streams } } function noopTest () { return function (t) { t.end() } } module.exports = testCommon abstract-leveldown-6.3.0/test/del-test.js000066400000000000000000000045661364427107700204040ustar00rootroot00000000000000var db var verifyNotFoundError = require('./util').verifyNotFoundError exports.setUp = function (test, testCommon) { test('setUp common', testCommon.setUp) test('setUp db', function (t) { db = testCommon.factory() db.open(t.end.bind(t)) }) } exports.args = function (test, testCommon) { testCommon.promises || test('test argument-less del() throws', function (t) { t.throws( db.del.bind(db), /Error: del\(\) requires a callback argument/, 'no-arg del() throws' ) t.end() }) testCommon.promises || test('test callback-less, 1-arg, del() throws', function (t) { t.throws( db.del.bind(db, 'foo'), /Error: del\(\) requires a callback argument/, 'callback-less, 1-arg del() throws' ) t.end() }) testCommon.promises || test('test callback-less, 3-arg, del() throws', function (t) { t.throws( db.del.bind(db, 'foo', {}), /Error: del\(\) requires a callback argument/, 'callback-less, 2-arg del() throws' ) t.end() }) testCommon.serialize && test('test custom _serialize*', function (t) { t.plan(3) var db = testCommon.factory() db._serializeKey = function (data) { return data } db._del = function (key, options, callback) { t.deepEqual(key, { foo: 'bar' }) process.nextTick(callback) } db.open(function () { db.del({ foo: 'bar' }, function (err) { t.error(err) db.close(t.error.bind(t)) }) }) }) } exports.del = function (test, testCommon) { test('test simple del()', function (t) { db.put('foo', 'bar', function (err) { t.error(err) db.del('foo', function (err) { t.error(err) db.get('foo', function (err, value) { t.ok(err, 'entry properly deleted') t.ok(typeof value === 'undefined', 'value is undefined') t.ok(verifyNotFoundError(err), 'NotFound error') t.end() }) }) }) }) test('test del on non-existent key', function (t) { db.del('blargh', function (err) { t.error(err) t.end() }) }) } exports.tearDown = function (test, testCommon) { test('tearDown', function (t) { db.close(testCommon.tearDown.bind(null, t)) }) } exports.all = function (test, testCommon) { exports.setUp(test, testCommon) exports.args(test, testCommon) exports.del(test, testCommon) exports.tearDown(test, testCommon) } abstract-leveldown-6.3.0/test/factory-test.js000066400000000000000000000020211364427107700212670ustar00rootroot00000000000000var concat = require('level-concat-iterator') module.exports = function (test, testCommon) { test('setUp common', testCommon.setUp) test('testCommon.factory() returns a unique database', function (t) { var db1 = testCommon.factory() var db2 = testCommon.factory() function close () { db1.close(function (err) { t.error(err, 'no error while closing db1') db2.close(function (err) { t.error(err, 'no error while closing db2') t.end() }) }) } db1.open(function (err) { t.error(err, 'no error while opening db1') db2.open(function (err) { t.error(err, 'no error while opening db2') db1.put('key', 'value', function (err) { t.error(err, 'put key in db1') concat(db2.iterator(), function (err, entries) { t.error(err, 'got items from db2') t.same(entries, [], 'db2 should be empty') close() }) }) }) }) }) test('tearDown', testCommon.tearDown) } abstract-leveldown-6.3.0/test/get-test.js000066400000000000000000000114351364427107700204100ustar00rootroot00000000000000var db var verifyNotFoundError = require('./util').verifyNotFoundError var isTypedArray = require('./util').isTypedArray exports.setUp = function (test, testCommon) { test('setUp common', testCommon.setUp) test('setUp db', function (t) { db = testCommon.factory() db.open(t.end.bind(t)) }) } exports.args = function (test, testCommon) { testCommon.promises || test('test argument-less get() throws', function (t) { t.throws( db.get.bind(db), /Error: get\(\) requires a callback argument/, 'no-arg get() throws' ) t.end() }) testCommon.promises || test('test callback-less, 1-arg, get() throws', function (t) { t.throws( db.get.bind(db, 'foo'), /Error: get\(\) requires a callback argument/, 'callback-less, 1-arg get() throws' ) t.end() }) testCommon.promises || test('test callback-less, 3-arg, get() throws', function (t) { t.throws( db.get.bind(db, 'foo', {}), /Error: get\(\) requires a callback argument/, 'callback-less, 2-arg get() throws' ) t.end() }) testCommon.serialize && test('test custom _serialize*', function (t) { t.plan(3) var db = testCommon.factory() db._serializeKey = function (data) { return data } db._get = function (key, options, callback) { t.deepEqual(key, { foo: 'bar' }) process.nextTick(callback) } db.open(function () { db.get({ foo: 'bar' }, function (err) { t.error(err) db.close(t.error.bind(t)) }) }) }) } exports.get = function (test, testCommon) { test('test simple get()', function (t) { db.put('foo', 'bar', function (err) { t.error(err) db.get('foo', function (err, value) { t.error(err) if (!testCommon.encodings) { t.ok(typeof value !== 'string', 'should not be string by default') if (isTypedArray(value)) { var result = String.fromCharCode.apply(null, new Uint16Array(value)) } else { t.ok(typeof Buffer !== 'undefined' && value instanceof Buffer) try { result = value.toString() } catch (e) { t.error(e, 'should not throw when converting value to a string') } } } else { result = value } t.equal(result, 'bar') db.get('foo', {}, function (err, value) { // same but with {} t.error(err) if (!testCommon.encodings) { t.ok(typeof value !== 'string', 'should not be string by default') if (isTypedArray(value)) { var result = String.fromCharCode.apply(null, new Uint16Array(value)) } else { t.ok(typeof Buffer !== 'undefined' && value instanceof Buffer) try { result = value.toString() } catch (e) { t.error(e, 'should not throw when converting value to a string') } } } else { result = value } t.equal(result, 'bar') db.get('foo', { asBuffer: false }, function (err, value) { t.error(err) t.ok(typeof value === 'string', 'should be string if not buffer') t.equal(value, 'bar') t.end() }) }) }) }) }) test('test simultaniously get()', function (t) { db.put('hello', 'world', function (err) { t.error(err) var r = 0 var done = function () { if (++r === 20) { t.end() } } var i = 0 var j = 0 for (; i < 10; ++i) { db.get('hello', function (err, value) { t.error(err) t.equal(value.toString(), 'world') done() }) } for (; j < 10; ++j) { db.get('not found', function (err, value) { t.ok(err, 'should error') t.ok(verifyNotFoundError(err), 'should have correct error message') t.ok(typeof value === 'undefined', 'value is undefined') done() }) } }) }) test('test get() not found error is asynchronous', function (t) { t.plan(5) db.put('hello', 'world', function (err) { t.error(err) var async = false db.get('not found', function (err, value) { t.ok(err, 'should error') t.ok(verifyNotFoundError(err), 'should have correct error message') t.ok(typeof value === 'undefined', 'value is undefined') t.ok(async, 'callback is asynchronous') }) async = true }) }) } exports.tearDown = function (test, testCommon) { test('tearDown', function (t) { db.close(testCommon.tearDown.bind(null, t)) }) } exports.all = function (test, testCommon) { exports.setUp(test, testCommon) exports.args(test, testCommon) exports.get(test, testCommon) exports.tearDown(test, testCommon) } abstract-leveldown-6.3.0/test/index.js000066400000000000000000000026241364427107700177630ustar00rootroot00000000000000var common = require('./common') function suite (options) { var testCommon = common(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) require('./close-test').all(test, testCommon) if (testCommon.createIfMissing) { require('./open-create-if-missing-test').all(test, testCommon) } if (testCommon.errorIfExists) { require('./open-error-if-exists-test').all(test, testCommon) } require('./put-test').all(test, testCommon) require('./get-test').all(test, testCommon) require('./del-test').all(test, testCommon) require('./put-get-del-test').all(test, testCommon) require('./batch-test').all(test, testCommon) require('./chained-batch-test').all(test, testCommon) require('./iterator-test').all(test, testCommon) require('./iterator-range-test').all(test, testCommon) if (testCommon.seek) { require('./iterator-seek-test').all(test, testCommon) } if (testCommon.snapshots) { require('./iterator-snapshot-test').all(test, testCommon) } else { require('./iterator-no-snapshot-test').all(test, testCommon) } if (testCommon.clear) { require('./clear-test').all(test, testCommon) require('./clear-range-test').all(test, testCommon) } } suite.common = common module.exports = suite abstract-leveldown-6.3.0/test/iterator-no-snapshot-test.js000066400000000000000000000037221364427107700237310ustar00rootroot00000000000000var collectEntries = require('level-concat-iterator') exports.setUp = function (test, testCommon) { test('setUp common', testCommon.setUp) } exports.noSnapshot = function (test, testCommon) { function make (run) { return function (t) { var db = testCommon.factory() var operations = [ { type: 'put', key: 'a', value: 'a' }, { type: 'put', key: 'b', value: 'b' }, { type: 'put', key: 'c', value: 'c' } ] db.open(function (err) { t.ifError(err, 'no open error') db.batch(operations, function (err) { t.ifError(err, 'no batch error') // For this test it is important that we don't read eagerly. // NOTE: highWaterMark is not an abstract option atm, but // it is supported by leveldown, rocksdb and others. var it = db.iterator({ highWaterMark: 0 }) run(db, function (err) { t.ifError(err, 'no run error') verify(t, it, db) }) }) }) } } function verify (t, it, db) { collectEntries(it, function (err, entries) { t.ifError(err, 'no iterator error') var kv = entries.map(function (entry) { return entry.key.toString() + entry.value.toString() }) if (kv.length === 3) { t.same(kv, ['aa', 'bb', 'cc'], 'maybe supports snapshots') } else { t.same(kv, ['aa', 'cc'], 'ignores keys that have been deleted in the mean time') } db.close(t.end.bind(t)) }) } test('delete key after creating iterator', make(function (db, done) { db.del('b', done) })) test('batch delete key after creating iterator', make(function (db, done) { db.batch([{ type: 'del', key: 'b' }], done) })) } exports.tearDown = function (test, testCommon) { test('tearDown', testCommon.tearDown) } exports.all = function (test, testCommon) { exports.setUp(test, testCommon) exports.noSnapshot(test, testCommon) exports.tearDown(test, testCommon) } abstract-leveldown-6.3.0/test/iterator-range-test.js000066400000000000000000000230331364427107700225510ustar00rootroot00000000000000var collectEntries = require('level-concat-iterator') var xtend = require('xtend') var db var data = (function () { var d = [] var i = 0 var k for (; i < 100; i++) { k = (i < 10 ? '0' : '') + i d.push({ key: k, value: String(Math.random()) }) } return d }()) exports.setUp = function (test, testCommon) { test('setUp common', testCommon.setUp) test('setUp db', function (t) { db = testCommon.factory() db.open(function () { db.batch(data.map(function (d) { return { type: 'put', key: d.key, value: d.value } }), t.end.bind(t)) }) }) } exports.range = function (test, testCommon) { function rangeTest (name, opts, expected) { if (!testCommon.legacyRange && ('start' in opts || 'end' in opts)) { return } opts.keyAsBuffer = false opts.valueAsBuffer = false test(name, function (t) { collectEntries(db.iterator(opts), function (err, result) { t.error(err) t.is(result.length, expected.length, 'correct number of entries') t.same(result, expected) t.end() }) }) // Test the documented promise that in reverse mode, // "the returned entries are the same, but in reverse". if (!opts.reverse && !('limit' in opts)) { var reverseOpts = xtend(opts, { reverse: true }) // Swap start & end options if (('start' in opts) && ('end' in opts)) { reverseOpts.end = opts.start reverseOpts.start = opts.end } else if ('start' in opts) { reverseOpts.end = opts.start delete reverseOpts.start } else if ('end' in opts) { reverseOpts.start = opts.end delete reverseOpts.end } rangeTest( name + ' (flipped)', reverseOpts, expected.slice().reverse() ) } } rangeTest('test full data collection', {}, data) rangeTest('test iterator with reverse=true', { reverse: true }, data.slice().reverse()) rangeTest('test iterator with gte=00', { gte: '00' }, data) rangeTest('test iterator with start=00 - legacy', { start: '00' }, data) rangeTest('test iterator with gte=50', { gte: '50' }, data.slice(50)) rangeTest('test iterator with start=50 - legacy', { start: '50' }, data.slice(50)) rangeTest('test iterator with lte=50 and reverse=true', { lte: '50', reverse: true }, data.slice().reverse().slice(49)) rangeTest('test iterator with start=50 and reverse=true - legacy', { start: '50', reverse: true }, data.slice().reverse().slice(49)) rangeTest('test iterator with gte=49.5 (midway)', { gte: '49.5' }, data.slice(50)) rangeTest('test iterator with start=49.5 (midway) - legacy', { start: '49.5' }, data.slice(50)) rangeTest('test iterator with gte=49999 (midway)', { gte: '49999' }, data.slice(50)) rangeTest('test iterator with start=49999 (midway) - legacy', { start: '49999' }, data.slice(50)) rangeTest('test iterator with lte=49.5 (midway) and reverse=true', { lte: '49.5', reverse: true }, data.slice().reverse().slice(50)) rangeTest('test iterator with lt=49.5 (midway) and reverse=true', { lt: '49.5', reverse: true }, data.slice().reverse().slice(50)) rangeTest('test iterator with lt=50 and reverse=true', { lt: '50', reverse: true }, data.slice().reverse().slice(50)) rangeTest('test iterator with start=49.5 (midway) and reverse=true - legacy', { start: '49.5', reverse: true }, data.slice().reverse().slice(50)) rangeTest('test iterator with lte=50', { lte: '50' }, data.slice(0, 51)) rangeTest('test iterator with end=50 - legacy', { end: '50' }, data.slice(0, 51)) rangeTest('test iterator with lte=50.5 (midway)', { lte: '50.5' }, data.slice(0, 51)) rangeTest('test iterator with end=50.5 (midway) - legacy', { end: '50.5' }, data.slice(0, 51)) rangeTest('test iterator with lte=50555 (midway)', { lte: '50555' }, data.slice(0, 51)) rangeTest('test iterator with lt=50555 (midway)', { lt: '50555' }, data.slice(0, 51)) rangeTest('test iterator with end=50555 (midway) - legacy', { end: '50555' }, data.slice(0, 51)) rangeTest('test iterator with gte=50.5 (midway) and reverse=true', { gte: '50.5', reverse: true }, data.slice().reverse().slice(0, 49)) rangeTest('test iterator with gt=50.5 (midway) and reverse=true', { gt: '50.5', reverse: true }, data.slice().reverse().slice(0, 49)) rangeTest('test iterator with end=50.5 (midway) and reverse=true - legacy', { end: '50.5', reverse: true }, data.slice().reverse().slice(0, 49)) rangeTest('test iterator with gt=50 and reverse=true', { gt: '50', reverse: true }, data.slice().reverse().slice(0, 49)) // end='0', starting key is actually '00' so it should avoid it rangeTest('test iterator with lte=0', { lte: '0' }, []) // end='0', starting key is actually '00' so it should avoid it rangeTest('test iterator with lt=0', { lt: '0' }, []) // end='0', starting key is actually '00' so it should avoid it rangeTest('test iterator with end=0 - legacy', { end: '0' }, []) rangeTest('test iterator with gte=30 and lte=70', { gte: '30', lte: '70' }, data.slice(30, 71)) rangeTest('test iterator with gt=29 and lt=71', { gt: '29', lt: '71' }, data.slice(30, 71)) rangeTest('test iterator with start=30 and end=70 - legacy', { start: '30', end: '70' }, data.slice(30, 71)) rangeTest('test iterator with gte=30 and lte=70 and reverse=true', { lte: '70', gte: '30', reverse: true }, data.slice().reverse().slice(29, 70)) rangeTest('test iterator with gt=29 and lt=71 and reverse=true', { lt: '71', gt: '29', reverse: true }, data.slice().reverse().slice(29, 70)) rangeTest('test iterator with start=70 and end=30 and reverse=true - legacy', { start: '70', end: '30', reverse: true }, data.slice().reverse().slice(29, 70)) rangeTest('test iterator with limit=20', { limit: 20 }, data.slice(0, 20)) rangeTest('test iterator with limit=20 and gte=20', { limit: 20, gte: '20' }, data.slice(20, 40)) rangeTest('test iterator with limit=20 and start=20 - legacy', { limit: 20, start: '20' }, data.slice(20, 40)) rangeTest('test iterator with limit=20 and reverse=true', { limit: 20, reverse: true }, data.slice().reverse().slice(0, 20)) rangeTest('test iterator with limit=20 and lte=79 and reverse=true', { limit: 20, lte: '79', reverse: true }, data.slice().reverse().slice(20, 40)) rangeTest('test iterator with limit=20 and start=79 and reverse=true - legacy', { limit: 20, start: '79', reverse: true }, data.slice().reverse().slice(20, 40)) // the default limit value from levelup is -1 rangeTest('test iterator with limit=-1 should iterate over whole database', { limit: -1 }, data) rangeTest('test iterator with limit=0 should not iterate over anything', { limit: 0 }, []) rangeTest('test iterator with lte after limit', { limit: 20, lte: '50' }, data.slice(0, 20)) rangeTest('test iterator with end after limit - legacy', { limit: 20, end: '50' }, data.slice(0, 20)) rangeTest('test iterator with lte before limit', { limit: 50, lte: '19' }, data.slice(0, 20)) rangeTest('test iterator with end before limit - legacy', { limit: 50, end: '19' }, data.slice(0, 20)) rangeTest('test iterator with gte after database end', { gte: '9a' }, []) rangeTest('test iterator with gt after database end', { gt: '9a' }, []) rangeTest('test iterator with start after database end - legacy', { start: '9a' }, []) rangeTest('test iterator with lte after database end and reverse=true', { lte: '9a', reverse: true }, data.slice().reverse()) rangeTest('test iterator with start after database end and reverse=true - legacy', { start: '9a', reverse: true }, data.slice().reverse()) rangeTest('test iterator with lt after database end', { lt: 'a' }, data.slice()) rangeTest('test iterator with end after database end - legacy', { end: 'a' }, data.slice()) rangeTest('test iterator with lt at database end', { lt: data[data.length - 1].key }, data.slice(0, -1)) rangeTest('test iterator with lte at database end', { lte: data[data.length - 1].key }, data.slice()) rangeTest('test iterator with end at database end - legacy', { end: data[data.length - 1].key }, data.slice()) rangeTest('test iterator with lt before database end', { lt: data[data.length - 2].key }, data.slice(0, -2)) rangeTest('test iterator with lte before database end', { lte: data[data.length - 2].key }, data.slice(0, -1)) rangeTest('test iterator with end before database end - legacy', { end: data[data.length - 2].key }, data.slice(0, -1)) rangeTest('test iterator with lte and gte after database and reverse=true', { lte: '9b', gte: '9a', reverse: true }, []) rangeTest('test iterator with lt and gt after database and reverse=true', { lt: '9b', gt: '9a', reverse: true }, []) rangeTest('test iterator with start and end after database and reverse=true - legacy', { start: '9b', end: '9a', reverse: true }, []) } exports.tearDown = function (test, testCommon) { test('tearDown', function (t) { db.close(testCommon.tearDown.bind(null, t)) }) } exports.all = function (test, testCommon) { exports.setUp(test, testCommon) exports.range(test, testCommon) exports.tearDown(test, testCommon) } abstract-leveldown-6.3.0/test/iterator-seek-test.js000066400000000000000000000176361364427107700224200ustar00rootroot00000000000000exports.all = function (test, testCommon) { exports.setUp(test, testCommon) exports.sequence(test, testCommon) exports.seek(test, testCommon) exports.tearDown(test, testCommon) } exports.setUp = function (test, testCommon) { test('setUp common', testCommon.setUp) } exports.sequence = function (test, testCommon) { function make (name, testFn) { test(name, function (t) { var db = testCommon.factory() var done = function (err) { t.error(err, 'no error from done()') db.close(function (err) { t.error(err, 'no error from close()') t.end() }) } db.open(function (err) { t.error(err, 'no error from open()') testFn(db, t, done) }) }) } make('iterator#seek() throws if next() has not completed', function (db, t, done) { var ite = db.iterator() var error var async = false ite.next(function (err, key, value) { t.error(err, 'no error from next()') t.ok(async, 'next is asynchronous') ite.end(done) }) async = true try { ite.seek('two') } catch (err) { error = err.message } t.is(error, 'cannot call seek() before next() has completed', 'got error') }) make('iterator#seek() throws after end()', function (db, t, done) { var ite = db.iterator() // TODO: why call next? Can't we end immediately? ite.next(function (err, key, value) { t.error(err, 'no error from next()') ite.end(function (err) { t.error(err, 'no error from end()') var error try { ite.seek('two') } catch (err) { error = err.message } t.is(error, 'cannot call seek() after end()', 'got error') done() }) }) }) } exports.seek = function (test, testCommon) { function make (name, testFn) { test(name, function (t) { var db = testCommon.factory() var done = function (err) { t.error(err, 'no error from done()') db.close(function (err) { t.error(err, 'no error from close()') t.end() }) } db.open(function (err) { t.error(err, 'no error from open()') db.batch([ { type: 'put', key: 'one', value: '1' }, { type: 'put', key: 'two', value: '2' }, { type: 'put', key: 'three', value: '3' } ], function (err) { t.error(err, 'no error from batch()') testFn(db, t, done) }) }) }) } make('iterator#seek() to string target', function (db, t, done) { var ite = db.iterator() ite.seek('two') ite.next(function (err, key, value) { t.error(err, 'no error') t.same(key.toString(), 'two', 'key matches') t.same(value.toString(), '2', 'value matches') ite.next(function (err, key, value) { t.error(err, 'no error') t.same(key, undefined, 'end of iterator') t.same(value, undefined, 'end of iterator') ite.end(done) }) }) }) if (testCommon.bufferKeys) { make('iterator#seek() to buffer target', function (db, t, done) { var ite = db.iterator() ite.seek(Buffer.from('two')) ite.next(function (err, key, value) { t.error(err, 'no error from next()') t.equal(key.toString(), 'two', 'key matches') t.equal(value.toString(), '2', 'value matches') ite.next(function (err, key, value) { t.error(err, 'no error from next()') t.equal(key, undefined, 'end of iterator') t.equal(value, undefined, 'end of iterator') ite.end(done) }) }) }) } make('iterator#seek() on reverse iterator', function (db, t, done) { var ite = db.iterator({ reverse: true, limit: 1 }) ite.seek('three!') ite.next(function (err, key, value) { t.error(err, 'no error') t.same(key.toString(), 'three', 'key matches') t.same(value.toString(), '3', 'value matches') ite.end(done) }) }) make('iterator#seek() to out of range target', function (db, t, done) { var ite = db.iterator() ite.seek('zzz') ite.next(function (err, key, value) { t.error(err, 'no error') t.same(key, undefined, 'end of iterator') t.same(value, undefined, 'end of iterator') ite.end(done) }) }) make('iterator#seek() on reverse iterator to out of range target', function (db, t, done) { var ite = db.iterator({ reverse: true }) ite.seek('zzz') ite.next(function (err, key, value) { t.error(err, 'no error') t.same(key.toString(), 'two') t.same(value.toString(), '2') ite.end(done) }) }) test('iterator#seek() respects range', function (t) { var db = testCommon.factory() db.open(function (err) { t.error(err, 'no error from open()') // Can't use Array.fill() because IE var ops = [] for (var i = 0; i < 10; i++) { ops.push({ type: 'put', key: String(i), value: String(i) }) } db.batch(ops, function (err) { t.error(err, 'no error from batch()') var pending = 0 expect({ gt: '5' }, '4', undefined) expect({ gt: '5' }, '5', undefined) expect({ gt: '5' }, '6', '6') expect({ gte: '5' }, '4', undefined) expect({ gte: '5' }, '5', '5') expect({ gte: '5' }, '6', '6') expect({ start: '5' }, '4', undefined) expect({ start: '5' }, '5', '5') expect({ start: '5' }, '6', '6') expect({ lt: '5' }, '4', '4') expect({ lt: '5' }, '5', undefined) expect({ lt: '5' }, '6', undefined) expect({ lte: '5' }, '4', '4') expect({ lte: '5' }, '5', '5') expect({ lte: '5' }, '6', undefined) expect({ end: '5' }, '4', '4') expect({ end: '5' }, '5', '5') expect({ end: '5' }, '6', undefined) expect({ lt: '5', reverse: true }, '4', '4') expect({ lt: '5', reverse: true }, '5', undefined) expect({ lt: '5', reverse: true }, '6', undefined) expect({ lte: '5', reverse: true }, '4', '4') expect({ lte: '5', reverse: true }, '5', '5') expect({ lte: '5', reverse: true }, '6', undefined) expect({ start: '5', reverse: true }, '4', '4') expect({ start: '5', reverse: true }, '5', '5') expect({ start: '5', reverse: true }, '6', undefined) expect({ gt: '5', reverse: true }, '4', undefined) expect({ gt: '5', reverse: true }, '5', undefined) expect({ gt: '5', reverse: true }, '6', '6') expect({ gte: '5', reverse: true }, '4', undefined) expect({ gte: '5', reverse: true }, '5', '5') expect({ gte: '5', reverse: true }, '6', '6') expect({ end: '5', reverse: true }, '4', undefined) expect({ end: '5', reverse: true }, '5', '5') expect({ end: '5', reverse: true }, '6', '6') expect({ gt: '7', lt: '8' }, '7', undefined) expect({ gte: '7', lt: '8' }, '7', '7') expect({ gte: '7', lt: '8' }, '8', undefined) expect({ gt: '7', lte: '8' }, '8', '8') function expect (range, target, expected) { pending++ var ite = db.iterator(range) ite.seek(target) ite.next(function (err, key, value) { t.error(err, 'no error from next()') var json = JSON.stringify(range) var msg = 'seek(' + target + ') on ' + json + ' yields ' + expected if (expected === undefined) { t.equal(value, undefined, msg) } else { t.equal(value.toString(), expected, msg) } ite.end(function (err) { t.error(err, 'no error from end()') if (!--pending) done() }) }) } function done () { db.close(function (err) { t.error(err, 'no error from close()') t.end() }) } }) }) }) } exports.tearDown = function (test, testCommon) { test('tearDown', testCommon.tearDown) } abstract-leveldown-6.3.0/test/iterator-snapshot-test.js000066400000000000000000000046411364427107700233200ustar00rootroot00000000000000exports.setUp = function (test, testCommon) { test('setUp common', testCommon.setUp) } exports.snapshot = function (test, testCommon) { function make (run) { return function (t) { var db = testCommon.factory() db.open(function (err) { t.ifError(err, 'no open error') db.put('z', 'from snapshot', function (err) { t.ifError(err, 'no put error') // For this test it is important that we don't read eagerly. // NOTE: highWaterMark is not an abstract option atm, but // it is supported by leveldown, rocksdb and others. var it = db.iterator({ highWaterMark: 0 }) run(t, db, it, function end (err) { t.ifError(err, 'no run error') it.end(function (err) { t.ifError(err, 'no iterator end error') db.close(t.end.bind(t)) }) }) }) }) } } test('delete key after snapshotting', make(function (t, db, it, end) { db.del('z', function (err) { t.ifError(err, 'no del error') it.next(function (err, key, value) { t.ifError(err, 'no next error') t.ok(key, 'got a key') t.is(key.toString(), 'z', 'correct key') t.is(value.toString(), 'from snapshot', 'correct value') end() }) }) })) test('overwrite key after snapshotting', make(function (t, db, it, end) { db.put('z', 'not from snapshot', function (err) { t.ifError(err, 'no put error') it.next(function (err, key, value) { t.ifError(err, 'no next error') t.ok(key, 'got a key') t.is(key.toString(), 'z', 'correct key') t.is(value.toString(), 'from snapshot', 'correct value') end() }) }) })) test('add key after snapshotting that sorts first', make(function (t, db, it, end) { db.put('a', 'not from snapshot', function (err) { t.ifError(err, 'no put error') it.next(function (err, key, value) { t.ifError(err, 'no next error') t.ok(key, 'got a key') t.is(key.toString(), 'z', 'correct key') t.is(value.toString(), 'from snapshot', 'correct value') end() }) }) })) } exports.tearDown = function (test, testCommon) { test('tearDown', testCommon.tearDown) } exports.all = function (test, testCommon) { exports.setUp(test, testCommon) exports.snapshot(test, testCommon) exports.tearDown(test, testCommon) } abstract-leveldown-6.3.0/test/iterator-test.js000066400000000000000000000116351364427107700214640ustar00rootroot00000000000000var db exports.setUp = function (test, testCommon) { test('setUp common', testCommon.setUp) test('setUp db', function (t) { db = testCommon.factory() db.open(t.end.bind(t)) }) } exports.args = function (test, testCommon) { test('test iterator has db reference', function (t) { var iterator = db.iterator() // For levelup compat: may return iterator of an underlying db, that's okay. t.ok(iterator.db === db || iterator.db) iterator.end(t.end.bind(t)) }) test('test argument-less iterator#next() throws', function (t) { var iterator = db.iterator() t.throws( iterator.next.bind(iterator), /Error: next\(\) requires a callback argument/, 'no-arg iterator#next() throws' ) iterator.end(t.end.bind(t)) }) test('test argument-less iterator#end() after next() throws', function (t) { var iterator = db.iterator() iterator.next(function () { t.throws( iterator.end.bind(iterator), /Error: end\(\) requires a callback argument/, 'no-arg iterator#end() throws' ) iterator.end(t.end.bind(t)) }) }) test('test argument-less iterator#end() throws', function (t) { var iterator = db.iterator() t.throws( iterator.end.bind(iterator), /Error: end\(\) requires a callback argument/, 'no-arg iterator#end() throws' ) iterator.end(t.end.bind(t)) }) test('test iterator#next returns this', function (t) { var iterator = db.iterator() var self = iterator.next(function () {}) t.ok(iterator === self) iterator.end(t.end.bind(t)) }) } exports.sequence = function (test, testCommon) { test('test twice iterator#end() callback with error', function (t) { var iterator = db.iterator() iterator.end(function (err) { t.error(err) var async = false iterator.end(function (err2) { t.ok(err2, 'returned error') t.is(err2.name, 'Error', 'correct error') t.is(err2.message, 'end() already called on iterator') t.ok(async, 'callback is asynchronous') t.end() }) async = true }) }) test('test iterator#next after iterator#end() callback with error', function (t) { var iterator = db.iterator() iterator.end(function (err) { t.error(err) var async = false iterator.next(function (err2) { t.ok(err2, 'returned error') t.is(err2.name, 'Error', 'correct error') t.is(err2.message, 'cannot call next() after end()', 'correct message') t.ok(async, 'callback is asynchronous') t.end() }) async = true }) }) test('test twice iterator#next() throws', function (t) { var iterator = db.iterator() iterator.next(function (err) { t.error(err) iterator.end(function (err) { t.error(err) t.end() }) }) var async = false iterator.next(function (err) { t.ok(err, 'returned error') t.is(err.name, 'Error', 'correct error') t.is(err.message, 'cannot call next() before previous next() has completed') t.ok(async, 'callback is asynchronous') }) async = true }) } exports.iterator = function (test, testCommon) { test('test simple iterator()', function (t) { var data = [ { type: 'put', key: 'foobatch1', value: 'bar1' }, { type: 'put', key: 'foobatch2', value: 'bar2' }, { type: 'put', key: 'foobatch3', value: 'bar3' } ] var idx = 0 db.batch(data, function (err) { t.error(err) var iterator = db.iterator() var fn = function (err, key, value) { t.error(err) if (key && value) { if (testCommon.encodings) { t.is(typeof key, 'string', 'key argument is a string') t.is(typeof value, 'string', 'value argument is a string') } else { t.ok(Buffer.isBuffer(key), 'key argument is a Buffer') t.ok(Buffer.isBuffer(value), 'value argument is a Buffer') } t.is(key.toString(), data[idx].key, 'correct key') t.is(value.toString(), data[idx].value, 'correct value') process.nextTick(next) idx++ } else { // end t.ok(err == null, 'err argument is nullish') t.ok(typeof key === 'undefined', 'key argument is undefined') t.ok(typeof value === 'undefined', 'value argument is undefined') t.is(idx, data.length, 'correct number of entries') iterator.end(function () { t.end() }) } } var next = function () { iterator.next(fn) } next() }) }) } exports.tearDown = function (test, testCommon) { test('tearDown', function (t) { db.close(testCommon.tearDown.bind(null, t)) }) } exports.all = function (test, testCommon) { exports.setUp(test, testCommon) exports.args(test, testCommon) exports.sequence(test, testCommon) exports.iterator(test, testCommon) exports.tearDown(test, testCommon) } abstract-leveldown-6.3.0/test/leveldown-test.js000066400000000000000000000005341364427107700216260ustar00rootroot00000000000000module.exports = function (test, testCommon) { test('setUp common', testCommon.setUp) test('test database open method exists', function (t) { var db = testCommon.factory() t.ok(db, 'database object returned') t.ok(typeof db.open === 'function', 'open() function exists') t.end() }) test('tearDown', testCommon.tearDown) } abstract-leveldown-6.3.0/test/manifest-test.js000066400000000000000000000011101364427107700214240ustar00rootroot00000000000000var suite = require('level-supports/test') module.exports = function (test, testCommon) { test('setUp common', testCommon.setUp) suite(test, testCommon) testCommon.status && test('manifest has status', function (t) { var db = testCommon.factory() t.is(db.supports.status, true) // The semantics of not opening or closing a new db are unclear // atm, so let's open it before closing, like every other test. db.open(function (err) { t.ifError(err, 'no open error') db.close(t.end.bind(t)) }) }) test('tearDown', testCommon.tearDown) } abstract-leveldown-6.3.0/test/open-create-if-missing-test.js000066400000000000000000000014041364427107700240710ustar00rootroot00000000000000exports.setUp = function (test, testCommon) { test('setUp', testCommon.setUp) } exports.createIfMissing = function (test, testCommon) { test('test database open createIfMissing:false', function (t) { var db = testCommon.factory() var async = false db.open({ createIfMissing: false }, function (err) { t.ok(err, 'error') t.ok(/does not exist/.test(err.message), 'error is about dir not existing') t.ok(async, 'callback is asynchronous') t.end() }) async = true }) } exports.tearDown = function (test, testCommon) { test('tearDown', testCommon.tearDown) } exports.all = function (test, testCommon) { exports.setUp(test, testCommon) exports.createIfMissing(test, testCommon) exports.tearDown(test, testCommon) } abstract-leveldown-6.3.0/test/open-error-if-exists-test.js000066400000000000000000000016451364427107700236340ustar00rootroot00000000000000exports.setUp = function (test, testCommon) { test('setUp', testCommon.setUp) } exports.errorIfExists = function (test, testCommon) { test('test database open errorIfExists:true', function (t) { var db = testCommon.factory() db.open({}, function (err) { t.error(err) db.close(function (err) { t.error(err) var async = false db.open({ createIfMissing: false, errorIfExists: true }, function (err) { t.ok(err, 'error') t.ok(/exists/.test(err.message), 'error is about already existing') t.ok(async, 'callback is asynchronous') t.end() }) async = true }) }) }) } exports.tearDown = function (test, testCommon) { test('tearDown', testCommon.tearDown) } exports.all = function (test, testCommon) { exports.setUp(test, testCommon) exports.errorIfExists(test, testCommon) exports.tearDown(test, testCommon) } abstract-leveldown-6.3.0/test/open-test.js000066400000000000000000000035411364427107700205710ustar00rootroot00000000000000exports.setUp = function (test, testCommon) { test('setUp', testCommon.setUp) } exports.args = function (test, testCommon) { testCommon.promises || test('test database open no-arg throws', function (t) { var db = testCommon.factory() t.throws( db.open.bind(db), /Error: open\(\) requires a callback argument/, 'no-arg open() throws' ) t.end() }) testCommon.promises || test('test callback-less, 1-arg, open() throws', function (t) { var db = testCommon.factory() t.throws( db.open.bind(db, {}), /Error: open\(\) requires a callback argument/, 'callback-less, 1-arg open() throws' ) t.end() }) } exports.open = function (test, testCommon) { test('test database open, no options', function (t) { var db = testCommon.factory() // default createIfMissing=true, errorIfExists=false db.open(function (err) { t.error(err) db.close(function () { t.end() }) }) }) test('test database open, options and callback', function (t) { var db = testCommon.factory() // default createIfMissing=true, errorIfExists=false db.open({}, function (err) { t.error(err) db.close(function () { t.end() }) }) }) test('test database open, close and open', function (t) { var db = testCommon.factory() db.open(function (err) { t.error(err) db.close(function (err) { t.error(err) db.open(function (err) { t.error(err) db.close(function () { t.end() }) }) }) }) }) } exports.tearDown = function (test, testCommon) { test('tearDown', testCommon.tearDown) } exports.all = function (test, testCommon) { exports.setUp(test, testCommon) exports.args(test, testCommon) exports.open(test, testCommon) exports.tearDown(test, testCommon) } abstract-leveldown-6.3.0/test/put-get-del-test.js000066400000000000000000000136121364427107700217570ustar00rootroot00000000000000'use strict' var db var verifyNotFoundError = require('./util').verifyNotFoundError var testBuffer = Buffer.from('testbuffer') function makeGetDelErrorTests (test, type, key, expectedError) { test('test get() with ' + type + ' causes error', function (t) { var async = false db.get(key, function (err) { t.ok(err, 'has error') t.ok(err instanceof Error) t.ok(err.message.match(expectedError), 'correct error message') t.ok(async, 'callback is asynchronous') t.end() }) async = true }) test('test del() with ' + type + ' causes error', function (t) { var async = false db.del(key, function (err) { t.ok(err, 'has error') t.ok(err instanceof Error) t.ok(err.message.match(expectedError), 'correct error message') t.ok(async, 'callback is asynchronous') t.end() }) async = true }) } function makePutErrorTest (test, type, key, value, expectedError) { test('test put() with ' + type + ' causes error', function (t) { var async = false db.put(key, value, function (err) { t.ok(err, 'has error') t.ok(err instanceof Error) t.ok(err.message.match(expectedError), 'correct error message') t.ok(async, 'callback is asynchronous') t.end() }) async = true }) } function makePutGetDelSuccessfulTest (test, testCommon, type, key, value, expectedResult) { var hasExpectedResult = arguments.length === 6 test('test put()/get()/del() with ' + type, function (t) { db.put(key, value, function (err) { t.error(err) db.get(key, function (err, _value) { t.error(err, 'no error, has key/value for `' + type + '`') if (!testCommon.encodings) { t.ok(Buffer.isBuffer(_value), 'is a Buffer') var result = _value } else { t.is(typeof _value, 'string', 'is a string') result = _value } if (hasExpectedResult) { t.equal(result.toString(), expectedResult) } else { if (result != null) { result = _value.toString() } if (value != null) { value = value.toString() } t.equals(result, value) } db.del(key, function (err) { t.error(err, 'no error, deleted key/value for `' + type + '`') var async = false db.get(key, function (err, value) { t.ok(err, 'entry properly deleted') t.ok(verifyNotFoundError(err), 'should have correct error message') t.equal(typeof value, 'undefined', 'value is undefined') t.ok(async, 'callback is asynchronous') t.end() }) async = true }) }) }) }) } function makeErrorKeyTest (test, type, key, expectedError) { makeGetDelErrorTests(test, type, key, expectedError) makePutErrorTest(test, type, key, 'foo', expectedError) } exports.setUp = function (test, testCommon) { test('setUp common', testCommon.setUp) test('setUp db', function (t) { db = testCommon.factory() db.open(t.end.bind(t)) }) } exports.errorKeys = function (test, testCommon) { makeErrorKeyTest(test, 'null key', null, /key cannot be `null` or `undefined`/) makeErrorKeyTest(test, 'undefined key', undefined, /key cannot be `null` or `undefined`/) makeErrorKeyTest(test, 'empty String key', '', /key cannot be an empty String/) makeErrorKeyTest(test, 'empty Buffer key', Buffer.alloc(0), /key cannot be an empty \w*Buffer/) makeErrorKeyTest(test, 'empty Array key', [], /key cannot be an empty Array/) } exports.errorValues = function (test, testCommon) { makePutErrorTest(test, 'null value', 'key', null, /value cannot be `null` or `undefined`/) makePutErrorTest(test, 'undefined value', 'key', undefined, /value cannot be `null` or `undefined`/) } exports.nonErrorKeys = function (test, testCommon) { // valid falsey keys makePutGetDelSuccessfulTest(test, testCommon, '`0` key', 0, 'foo 0') // standard String key makePutGetDelSuccessfulTest( test , testCommon , 'long String key' , 'some long string that I\'m using as a key for this unit test, cross your fingers human, we\'re going in!' , 'foo' ) if (testCommon.bufferKeys) { makePutGetDelSuccessfulTest(test, testCommon, 'Buffer key', testBuffer, 'foo') } // non-empty Array as a value makePutGetDelSuccessfulTest(test, testCommon, 'Array value', 'foo', [1, 2, 3, 4]) } exports.nonErrorValues = function (test, testCommon) { // valid falsey values makePutGetDelSuccessfulTest(test, testCommon, '`false` value', 'foo false', false) makePutGetDelSuccessfulTest(test, testCommon, '`0` value', 'foo 0', 0) makePutGetDelSuccessfulTest(test, testCommon, '`NaN` value', 'foo NaN', NaN) // all of the following result in an empty-string value: makePutGetDelSuccessfulTest(test, testCommon, 'empty String value', 'foo', '', '') makePutGetDelSuccessfulTest(test, testCommon, 'empty Buffer value', 'foo', Buffer.alloc(0), '') // note that an implementation may return the value as an array makePutGetDelSuccessfulTest(test, testCommon, 'empty Array value', 'foo', [], '') // standard String value makePutGetDelSuccessfulTest( test , testCommon , 'long String value' , 'foo' , 'some long string that I\'m using as a key for this unit test, cross your fingers human, we\'re going in!' ) // standard Buffer value makePutGetDelSuccessfulTest(test, testCommon, 'Buffer value', 'foo', testBuffer) // non-empty Array as a key makePutGetDelSuccessfulTest(test, testCommon, 'Array key', [1, 2, 3, 4], 'foo') } exports.tearDown = function (test, testCommon) { test('tearDown', function (t) { db.close(testCommon.tearDown.bind(null, t)) }) } exports.all = function (test, testCommon) { exports.setUp(test, testCommon) exports.errorKeys(test, testCommon) exports.errorValues(test, testCommon) exports.nonErrorKeys(test, testCommon) exports.nonErrorValues(test, testCommon) exports.tearDown(test, testCommon) } abstract-leveldown-6.3.0/test/put-test.js000066400000000000000000000055351364427107700204450ustar00rootroot00000000000000var db var isTypedArray = require('./util').isTypedArray exports.setUp = function (test, testCommon) { test('setUp common', testCommon.setUp) test('setUp db', function (t) { db = testCommon.factory() db.open(t.end.bind(t)) }) } exports.args = function (test, testCommon) { testCommon.promises || test('test argument-less put() throws', function (t) { t.throws( db.put.bind(db), /Error: put\(\) requires a callback argument/, 'no-arg put() throws' ) t.end() }) testCommon.promises || test('test callback-less, 1-arg, put() throws', function (t) { t.throws( db.put.bind(db, 'foo'), /Error: put\(\) requires a callback argument/, 'callback-less, 1-arg put() throws' ) t.end() }) testCommon.promises || test('test callback-less, 2-arg, put() throws', function (t) { t.throws( db.put.bind(db, 'foo', 'bar'), /Error: put\(\) requires a callback argument/, 'callback-less, 2-arg put() throws' ) t.end() }) testCommon.promises || test('test callback-less, 3-arg, put() throws', function (t) { t.throws( db.put.bind(db, 'foo', 'bar', {}), /Error: put\(\) requires a callback argument/, 'callback-less, 3-arg put() throws' ) t.end() }) testCommon.serialize && test('test _serialize object', function (t) { t.plan(3) var db = testCommon.factory() db._put = function (key, value, opts, callback) { t.ok(key) t.ok(value) process.nextTick(callback) } db.put({}, {}, function (err, val) { t.error(err) }) }) testCommon.serialize && test('test custom _serialize*', function (t) { t.plan(4) var db = testCommon.factory() db._serializeKey = db._serializeValue = function (data) { return data } db._put = function (key, value, options, callback) { t.deepEqual(key, { foo: 'bar' }) t.deepEqual(value, { beep: 'boop' }) process.nextTick(callback) } db.open(function () { db.put({ foo: 'bar' }, { beep: 'boop' }, function (err) { t.error(err) db.close(t.error.bind(t)) }) }) }) } exports.put = function (test, testCommon) { test('test simple put()', function (t) { db.put('foo', 'bar', function (err) { t.error(err) db.get('foo', function (err, value) { t.error(err) var result = value.toString() if (isTypedArray(value)) { result = String.fromCharCode.apply(null, new Uint16Array(value)) } t.equal(result, 'bar') t.end() }) }) }) } exports.tearDown = function (test, testCommon) { test('tearDown', function (t) { db.close(testCommon.tearDown.bind(null, t)) }) } exports.all = function (test, testCommon) { exports.setUp(test, testCommon) exports.args(test, testCommon) exports.put(test, testCommon) exports.tearDown(test, testCommon) } abstract-leveldown-6.3.0/test/self.js000066400000000000000000000754261364427107700176170ustar00rootroot00000000000000'use strict' var test = require('tape') var sinon = require('sinon') var inherits = require('util').inherits var AbstractLevelDOWN = require('../').AbstractLevelDOWN var AbstractIterator = require('../').AbstractIterator var AbstractChainedBatch = require('../').AbstractChainedBatch var testCommon = require('./common')({ test: test, clear: true, factory: function () { return new AbstractLevelDOWN() } }) var rangeOptions = ['gt', 'gte', 'lt', 'lte'] var legacyRangeOptions = ['start', 'end'] // Test the suite itself as well as the default implementation, // 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) require('./open-create-if-missing-test').tearDown(test, testCommon) require('./open-error-if-exists-test').setUp(test, testCommon) require('./open-error-if-exists-test').tearDown(test, testCommon) require('./del-test').setUp(test, testCommon) require('./del-test').args(test, testCommon) require('./get-test').setUp(test, testCommon) require('./get-test').args(test, testCommon) require('./put-test').setUp(test, testCommon) require('./put-test').args(test, testCommon) require('./put-get-del-test').setUp(test, testCommon) require('./put-get-del-test').errorKeys(test, testCommon) require('./put-get-del-test').tearDown(test, testCommon) require('./batch-test').setUp(test, testCommon) require('./batch-test').args(test, testCommon) require('./chained-batch-test').setUp(test, testCommon) require('./chained-batch-test').args(test, testCommon) require('./chained-batch-test').tearDown(test, testCommon) require('./close-test').all(test, testCommon) require('./iterator-test').setUp(test, testCommon) require('./iterator-test').args(test, testCommon) require('./iterator-test').sequence(test, testCommon) require('./iterator-test').tearDown(test, testCommon) require('./iterator-range-test').setUp(test, testCommon) require('./iterator-range-test').tearDown(test, testCommon) require('./iterator-snapshot-test').setUp(test, testCommon) require('./iterator-snapshot-test').tearDown(test, testCommon) require('./iterator-no-snapshot-test').setUp(test, testCommon) require('./iterator-no-snapshot-test').tearDown(test, testCommon) require('./iterator-seek-test').setUp(test, testCommon) require('./iterator-seek-test').sequence(test, testCommon) require('./iterator-seek-test').tearDown(test, testCommon) require('./clear-test').setUp(test, testCommon) require('./clear-test').args(test, testCommon) require('./clear-test').tearDown(test, testCommon) require('./clear-range-test').setUp(test, testCommon) require('./clear-range-test').tearDown(test, testCommon) function implement (ctor, methods) { function Test () { ctor.apply(this, arguments) } inherits(Test, ctor) for (var k in methods) { Test.prototype[k] = methods[k] } return Test } /** * Extensibility */ test('test core extensibility', function (t) { var Test = implement(AbstractLevelDOWN) var test = new Test() t.equal(test.status, 'new', 'status is new') t.end() }) test('test key/value serialization', function (t) { var Test = implement(AbstractLevelDOWN) var test = new Test() ;['', {}, null, undefined, Buffer.alloc(0)].forEach(function (v) { t.ok(test._serializeKey(v) === v, '_serializeKey is an identity function') t.ok(test._serializeValue(v) === v, '_serializeValue is an identity function') }) t.end() }) test('test open() extensibility', function (t) { var spy = sinon.spy() var expectedCb = function () {} var expectedOptions = { createIfMissing: true, errorIfExists: false } var Test = implement(AbstractLevelDOWN, { _open: spy }) var test = new Test('foobar') test.open(expectedCb) t.equal(spy.callCount, 1, 'got _open() call') t.equal(spy.getCall(0).thisValue, test, '`this` on _open() was correct') t.equal(spy.getCall(0).args.length, 2, 'got two arguments') t.deepEqual(spy.getCall(0).args[0], expectedOptions, 'got default options argument') test.open({ options: 1 }, expectedCb) expectedOptions.options = 1 t.equal(spy.callCount, 2, 'got _open() call') t.equal(spy.getCall(1).thisValue, test, '`this` on _open() was correct') t.equal(spy.getCall(1).args.length, 2, 'got two arguments') t.deepEqual(spy.getCall(1).args[0], expectedOptions, 'got expected options argument') t.end() }) test('test close() extensibility', function (t) { var spy = sinon.spy() var expectedCb = function () {} var Test = implement(AbstractLevelDOWN, { _close: spy }) var test = new Test('foobar') test.close(expectedCb) t.equal(spy.callCount, 1, 'got _close() call') t.equal(spy.getCall(0).thisValue, test, '`this` on _close() was correct') t.equal(spy.getCall(0).args.length, 1, 'got one arguments') t.end() }) test('test get() extensibility', function (t) { var spy = sinon.spy() var expectedCb = function () {} var expectedOptions = { asBuffer: true } var expectedKey = 'a key' var Test = implement(AbstractLevelDOWN, { _get: spy }) var test = new Test('foobar') test.get(expectedKey, expectedCb) t.equal(spy.callCount, 1, 'got _get() call') t.equal(spy.getCall(0).thisValue, test, '`this` on _get() was correct') t.equal(spy.getCall(0).args.length, 3, 'got three arguments') t.equal(spy.getCall(0).args[0], expectedKey, 'got expected key argument') t.deepEqual(spy.getCall(0).args[1], expectedOptions, 'got default options argument') t.equal(spy.getCall(0).args[2], expectedCb, 'got expected cb argument') test.get(expectedKey, { options: 1 }, expectedCb) expectedOptions.options = 1 t.equal(spy.callCount, 2, 'got _get() call') t.equal(spy.getCall(1).thisValue, test, '`this` on _get() was correct') t.equal(spy.getCall(1).args.length, 3, 'got three arguments') t.equal(spy.getCall(1).args[0], expectedKey, 'got expected key argument') t.deepEqual(spy.getCall(1).args[1], expectedOptions, 'got expected options argument') t.equal(spy.getCall(1).args[2], expectedCb, 'got expected cb argument') t.end() }) test('test del() extensibility', function (t) { var spy = sinon.spy() var expectedCb = function () {} var expectedOptions = { options: 1 } var expectedKey = 'a key' var Test = implement(AbstractLevelDOWN, { _del: spy }) var test = new Test('foobar') test.del(expectedKey, expectedCb) 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, 3, 'got three arguments') t.equal(spy.getCall(0).args[0], expectedKey, 'got expected key argument') t.deepEqual(spy.getCall(0).args[1], {}, 'got blank options argument') t.equal(spy.getCall(0).args[2], expectedCb, 'got expected cb argument') test.del(expectedKey, expectedOptions, expectedCb) t.equal(spy.callCount, 2, 'got _del() call') t.equal(spy.getCall(1).thisValue, test, '`this` on _del() was correct') t.equal(spy.getCall(1).args.length, 3, 'got three arguments') t.equal(spy.getCall(1).args[0], expectedKey, 'got expected key argument') t.deepEqual(spy.getCall(1).args[1], expectedOptions, 'got expected options argument') t.equal(spy.getCall(1).args[2], expectedCb, 'got expected cb argument') t.end() }) test('test put() extensibility', function (t) { var spy = sinon.spy() var expectedCb = function () {} var expectedOptions = { options: 1 } var expectedKey = 'a key' var expectedValue = 'a value' var Test = implement(AbstractLevelDOWN, { _put: spy }) var test = new Test('foobar') test.put(expectedKey, expectedValue, expectedCb) 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, 4, 'got four 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.deepEqual(spy.getCall(0).args[2], {}, 'got blank options argument') t.equal(spy.getCall(0).args[3], expectedCb, 'got expected cb argument') test.put(expectedKey, expectedValue, expectedOptions, expectedCb) t.equal(spy.callCount, 2, 'got _put() call') t.equal(spy.getCall(1).thisValue, test, '`this` on _put() was correct') t.equal(spy.getCall(1).args.length, 4, 'got four arguments') t.equal(spy.getCall(1).args[0], expectedKey, 'got expected key argument') t.equal(spy.getCall(1).args[1], expectedValue, 'got expected value argument') t.deepEqual(spy.getCall(1).args[2], expectedOptions, 'got blank options argument') t.equal(spy.getCall(1).args[3], expectedCb, 'got expected cb argument') t.end() }) test('test batch([]) (array-form) extensibility', function (t) { var spy = sinon.spy() var expectedCb = function () {} var expectedOptions = { options: 1 } var expectedArray = [ { type: 'put', key: '1', value: '1' }, { type: 'del', key: '2' } ] var Test = implement(AbstractLevelDOWN, { _batch: spy }) var test = new Test('foobar') test.batch(expectedArray, expectedCb) t.equal(spy.callCount, 1, 'got _batch() call') t.equal(spy.getCall(0).thisValue, test, '`this` on _batch() was correct') t.equal(spy.getCall(0).args.length, 3, 'got three arguments') t.deepEqual(spy.getCall(0).args[0], expectedArray, 'got expected array argument') 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(expectedArray, 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.deepEqual(spy.getCall(1).args[0], expectedArray, 'got expected array argument') t.deepEqual(spy.getCall(1).args[1], expectedOptions, 'got expected options argument') t.equal(spy.getCall(1).args[2], expectedCb, 'got expected callback argument') test.batch(expectedArray, null, expectedCb) t.equal(spy.callCount, 3, 'got _batch() call') t.equal(spy.getCall(2).thisValue, test, '`this` on _batch() was correct') t.equal(spy.getCall(2).args.length, 3, 'got three arguments') t.deepEqual(spy.getCall(2).args[0], expectedArray, 'got expected array argument') t.ok(spy.getCall(2).args[1], 'options should not be null') t.equal(spy.getCall(2).args[2], expectedCb, 'got expected callback argument') t.end() }) test('test batch([]) (array-form) with empty array is asynchronous', function (t) { var spy = sinon.spy() var Test = implement(AbstractLevelDOWN, { _batch: spy }) var test = new Test() var async = false test.batch([], function (err) { t.ifError(err, 'no error') t.ok(async, 'callback is asynchronous') // Assert that asynchronicity is provided by batch() rather than _batch() t.is(spy.callCount, 0, '_batch() call was bypassed') t.end() }) async = true }) test('test chained batch() extensibility', function (t) { var spy = sinon.spy() var expectedCb = function () {} var expectedOptions = { options: 1 } var Test = implement(AbstractLevelDOWN, { _batch: spy }) var test = new Test('foobar') test.batch().put('foo', 'bar').del('bang').write(expectedCb) t.equal(spy.callCount, 1, 'got _batch() call') t.equal(spy.getCall(0).thisValue, test, '`this` on _batch() was correct') t.equal(spy.getCall(0).args.length, 3, 'got three arguments') t.equal(spy.getCall(0).args[0].length, 2, 'got expected array argument') t.deepEqual(spy.getCall(0).args[0][0], { type: 'put', key: 'foo', value: 'bar' }, 'got expected array argument[0]') t.deepEqual(spy.getCall(0).args[0][1], { type: 'del', key: 'bang' }, 'got expected array argument[1]') 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) 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[1], expectedOptions, 'got expected options argument') t.equal(spy.getCall(1).args[2], expectedCb, 'got expected callback argument') t.end() }) test('test chained batch() with no operations is asynchronous', function (t) { var Test = implement(AbstractLevelDOWN, {}) var test = new Test() var async = false test.batch().write(function (err) { t.ifError(err, 'no error') t.ok(async, 'callback is asynchronous') t.end() }) async = true }) test('test chained batch() (custom _chainedBatch) extensibility', function (t) { var spy = sinon.spy() var Test = implement(AbstractLevelDOWN, { _chainedBatch: spy }) var test = new Test('foobar') test.batch() t.equal(spy.callCount, 1, 'got _chainedBatch() call') t.equal(spy.getCall(0).thisValue, test, '`this` on _chainedBatch() was correct') test.batch() t.equal(spy.callCount, 2, 'got _chainedBatch() call') t.equal(spy.getCall(1).thisValue, test, '`this` on _chainedBatch() was correct') t.end() }) test('test AbstractChainedBatch extensibility', function (t) { var Test = implement(AbstractChainedBatch) var db = {} var test = new Test(db) t.ok(test.db === db, 'instance has db reference') t.end() }) test('test AbstractChainedBatch expects a db', function (t) { t.plan(1) var Test = implement(AbstractChainedBatch) try { Test() } catch (err) { t.is(err.message, 'First argument must be an abstract-leveldown compliant store') } }) test('test AbstractChainedBatch#write() extensibility', function (t) { var spy = sinon.spy() var spycb = sinon.spy() var Test = implement(AbstractChainedBatch, { _write: spy }) var test = new Test({ test: true }) test.write(spycb) t.equal(spy.callCount, 1, 'got _write() call') t.equal(spy.getCall(0).thisValue, test, '`this` on _write() was correct') t.equal(spy.getCall(0).args.length, 2, 'got two arguments') t.same(spy.getCall(0).args[0], {}, 'got options') // awkward here cause of nextTick & an internal wrapped cb t.equal(typeof spy.getCall(0).args[1], 'function', 'got a callback function') t.equal(spycb.callCount, 0, 'spycb not called') spy.getCall(0).args[1]() t.equal(spycb.callCount, 1, 'spycb called, i.e. was our cb argument') t.end() }) test('test AbstractChainedBatch#write() extensibility with null options', function (t) { var spy = sinon.spy() var Test = implement(AbstractChainedBatch, { _write: spy }) var test = new Test({ test: true }) test.write(null, function () {}) t.equal(spy.callCount, 1, 'got _write() call') t.same(spy.getCall(0).args[0], {}, 'got options') t.end() }) test('test AbstractChainedBatch#write() extensibility with options', function (t) { var spy = sinon.spy() var Test = implement(AbstractChainedBatch, { _write: spy }) var test = new Test({ test: true }) test.write({ test: true }, function () {}) t.equal(spy.callCount, 1, 'got _write() call') t.same(spy.getCall(0).args[0], { test: true }, 'got options') t.end() }) test('test AbstractChainedBatch#put() extensibility', function (t) { var spy = sinon.spy() var expectedKey = 'key' var expectedValue = 'value' var Test = implement(AbstractChainedBatch, { _put: spy }) var test = new Test(testCommon.factory()) var returnValue = test.put(expectedKey, expectedValue) 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[0], expectedKey, 'got expected key argument') t.equal(spy.getCall(0).args[1], expectedValue, 'got expected value argument') t.equal(returnValue, test, 'get expected return value') t.end() }) test('test AbstractChainedBatch#del() extensibility', function (t) { var spy = sinon.spy() var expectedKey = 'key' var Test = implement(AbstractChainedBatch, { _del: spy }) var test = new Test(testCommon.factory()) var returnValue = test.del(expectedKey) 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[0], expectedKey, 'got expected key argument') t.equal(returnValue, test, 'get expected return value') t.end() }) test('test AbstractChainedBatch#clear() extensibility', function (t) { var spy = sinon.spy() var Test = implement(AbstractChainedBatch, { _clear: spy }) var test = new Test(testCommon.factory()) var returnValue = test.clear() t.equal(spy.callCount, 1, 'got _clear call') t.equal(spy.getCall(0).thisValue, test, '`this` on _clear() was correct') t.equal(spy.getCall(0).args.length, 0, 'got zero arguments') t.equal(returnValue, test, 'get expected return value') t.end() }) test('test iterator() extensibility', function (t) { var spy = sinon.spy() var expectedOptions = { options: 1, reverse: false, keys: true, values: true, limit: -1, keyAsBuffer: true, valueAsBuffer: true } var Test = implement(AbstractLevelDOWN, { _iterator: spy }) var test = new Test('foobar') test.iterator({ options: 1 }) t.equal(spy.callCount, 1, 'got _iterator() call') t.equal(spy.getCall(0).thisValue, test, '`this` on _iterator() was correct') t.equal(spy.getCall(0).args.length, 1, 'got one arguments') t.deepEqual(spy.getCall(0).args[0], expectedOptions, 'got expected options argument') t.end() }) test('test AbstractIterator extensibility', function (t) { var Test = implement(AbstractIterator) var db = {} var test = new Test(db) t.ok(test.db === db, 'instance has db reference') t.end() }) test('test AbstractIterator#next() extensibility', function (t) { var spy = sinon.spy() var spycb = sinon.spy() var Test = implement(AbstractIterator, { _next: spy }) var test = new Test({}) test.next(spycb) t.equal(spy.callCount, 1, 'got _next() call') t.equal(spy.getCall(0).thisValue, test, '`this` on _next() was correct') t.equal(spy.getCall(0).args.length, 1, 'got one arguments') // awkward here cause of nextTick & an internal wrapped cb t.equal(typeof spy.getCall(0).args[0], 'function', 'got a callback function') t.equal(spycb.callCount, 0, 'spycb not called') spy.getCall(0).args[0]() t.equal(spycb.callCount, 1, 'spycb called, i.e. was our cb argument') t.end() }) test('test AbstractIterator#end() extensibility', function (t) { var spy = sinon.spy() var expectedCb = function () {} var Test = implement(AbstractIterator, { _end: spy }) var test = new Test({}) test.end(expectedCb) t.equal(spy.callCount, 1, 'got _end() call') t.equal(spy.getCall(0).thisValue, test, '`this` on _end() was correct') t.equal(spy.getCall(0).args.length, 1, 'got one arguments') t.equal(spy.getCall(0).args[0], expectedCb, 'got expected cb argument') t.end() }) test('test clear() extensibility', function (t) { var spy = sinon.spy() var Test = implement(AbstractLevelDOWN, { _clear: spy }) var db = new Test() var callback = function () {} call([callback], { reverse: false, limit: -1 }) call([null, callback], { reverse: false, limit: -1 }) call([undefined, callback], { reverse: false, limit: -1 }) call([{ custom: 1 }, callback], { custom: 1, reverse: false, limit: -1 }) call([{ reverse: true, limit: 0 }, callback], { reverse: true, limit: 0 }) call([{ reverse: 1 }, callback], { reverse: true, limit: -1 }) call([{ reverse: null }, callback], { reverse: false, limit: -1 }) function call (args, expectedOptions) { db.clear.apply(db, args) t.is(spy.callCount, 1, 'got _clear() call') t.is(spy.getCall(0).thisValue, db, '`this` on _clear() was correct') t.is(spy.getCall(0).args.length, 2, 'got two arguments') t.same(spy.getCall(0).args[0], expectedOptions, 'got expected options argument') t.is(spy.getCall(0).args[1], callback, 'got expected callback argument') spy.resetHistory() } t.end() }) test('test serialization extensibility (put)', function (t) { t.plan(5) var spy = sinon.spy() var Test = implement(AbstractLevelDOWN, { _put: spy, _serializeKey: function (key) { t.equal(key, 'no') return 'foo' }, _serializeValue: function (value) { t.equal(value, 'nope') return 'bar' } }) var test = new Test('foobar') test.put('no', 'nope', function () {}) t.equal(spy.callCount, 1, 'got _put() call') t.equal(spy.getCall(0).args[0], 'foo', 'got expected key argument') t.equal(spy.getCall(0).args[1], 'bar', 'got expected value argument') }) test('test serialization extensibility (del)', function (t) { t.plan(3) var spy = sinon.spy() var Test = implement(AbstractLevelDOWN, { _del: spy, _serializeKey: function (key) { t.equal(key, 'no') return 'foo' }, _serializeValue: function (value) { t.fail('should not be called') } }) var test = new Test('foobar') test.del('no', function () {}) t.equal(spy.callCount, 1, 'got _del() call') t.equal(spy.getCall(0).args[0], 'foo', 'got expected key argument') t.end() }) test('test serialization extensibility (batch array put)', function (t) { t.plan(5) var spy = sinon.spy() var Test = implement(AbstractLevelDOWN, { _batch: spy, _serializeKey: function (key) { t.equal(key, 'no') return 'foo' }, _serializeValue: function (value) { t.equal(value, 'nope') return 'bar' } }) var test = new Test('foobar') test.batch([{ type: 'put', key: 'no', value: 'nope' }], function () {}) t.equal(spy.callCount, 1, 'got _batch() call') t.equal(spy.getCall(0).args[0][0].key, 'foo', 'got expected key') t.equal(spy.getCall(0).args[0][0].value, 'bar', 'got expected value') }) test('test serialization extensibility (batch chain put)', function (t) { t.plan(5) var spy = sinon.spy() var Test = implement(AbstractLevelDOWN, { _batch: spy, _serializeKey: function (key) { t.equal(key, 'no') return 'foo' }, _serializeValue: function (value) { t.equal(value, 'nope') return 'bar' } }) var test = new Test('foobar') test.batch().put('no', 'nope').write(function () {}) t.equal(spy.callCount, 1, 'got _batch() call') t.equal(spy.getCall(0).args[0][0].key, 'foo', 'got expected key') t.equal(spy.getCall(0).args[0][0].value, 'bar', 'got expected value') }) test('test serialization extensibility (batch array del)', function (t) { t.plan(3) var spy = sinon.spy() var Test = implement(AbstractLevelDOWN, { _batch: spy, _serializeKey: function (key) { t.equal(key, 'no') return 'foo' }, _serializeValue: function (value) { t.fail('should not be called') } }) var test = new Test('foobar') test.batch([{ type: 'del', key: 'no' }], function () {}) t.equal(spy.callCount, 1, 'got _batch() call') t.equal(spy.getCall(0).args[0][0].key, 'foo', 'got expected key') }) test('test serialization extensibility (batch chain del)', function (t) { t.plan(3) var spy = sinon.spy() var Test = implement(AbstractLevelDOWN, { _batch: spy, _serializeKey: function (key) { t.equal(key, 'no') return 'foo' }, _serializeValue: function (value) { t.fail('should not be called') } }) var test = new Test('foobar') test.batch().del('no').write(function () {}) t.equal(spy.callCount, 1, 'got _batch() call') t.equal(spy.getCall(0).args[0][0].key, 'foo', 'got expected key') }) test('test serialization extensibility (batch array is not mutated)', function (t) { t.plan(7) var spy = sinon.spy() var Test = implement(AbstractLevelDOWN, { _batch: spy, _serializeKey: function (key) { t.equal(key, 'no') return 'foo' }, _serializeValue: function (value) { t.equal(value, 'nope') return 'bar' } }) var test = new Test('foobar') var op = { type: 'put', key: 'no', value: 'nope' } test.batch([op], function () {}) t.equal(spy.callCount, 1, 'got _batch() call') t.equal(spy.getCall(0).args[0][0].key, 'foo', 'got expected key') t.equal(spy.getCall(0).args[0][0].value, 'bar', 'got expected value') t.equal(op.key, 'no', 'did not mutate input key') t.equal(op.value, 'nope', 'did not mutate input value') }) test('test serialization extensibility (iterator range options)', function (t) { t.plan(2) function Test () { AbstractLevelDOWN.call(this) } inherits(Test, AbstractLevelDOWN) Test.prototype._serializeKey = function (key) { t.is(key, 'input') return 'output' } Test.prototype._iterator = function (options) { return new Iterator(this, options) } function Iterator (db, options) { AbstractIterator.call(this, db) t.is(options.gt, 'output') } inherits(Iterator, AbstractIterator) var test = new Test() test.iterator({ gt: 'input' }) }) test('test serialization extensibility (iterator seek)', function (t) { t.plan(3) var spy = sinon.spy() var TestIterator = implement(AbstractIterator, { _seek: spy }) var Test = implement(AbstractLevelDOWN, { _iterator: function () { return new TestIterator(this) }, _serializeKey: function (key) { t.equal(key, 'target') return 'serialized' } }) var test = new Test('foobar') var it = test.iterator() it.seek('target') t.equal(spy.callCount, 1, 'got _seek() call') t.equal(spy.getCall(0).args[0], 'serialized', 'got expected target argument') }) test('test serialization extensibility (clear range options)', function (t) { t.plan(rangeOptions.length * 2) rangeOptions.forEach(function (key) { var Test = implement(AbstractLevelDOWN, { _serializeKey: function (key) { t.is(key, 'input') return 'output' }, _clear: function (options, callback) { t.is(options[key], 'output') } }) var db = new Test() var options = {} options[key] = 'input' db.clear(options, function () {}) }) }) test('clear() does not delete empty or nullish range options', function (t) { var rangeValues = [Buffer.alloc(0), '', null, undefined] t.plan(rangeOptions.length * rangeValues.length) rangeValues.forEach(function (value) { var Test = implement(AbstractLevelDOWN, { _clear: function (options, callback) { rangeOptions.forEach(function (key) { t.ok(key in options, key + ' option should not be deleted') }) } }) var db = new Test() var options = {} rangeOptions.forEach(function (key) { options[key] = value }) db.clear(options, function () {}) }) }) test('.status', function (t) { t.plan(5) t.test('empty prototype', function (t) { var Test = implement(AbstractLevelDOWN) var test = new Test('foobar') t.equal(test.status, 'new') test.open(function (err) { t.error(err) t.equal(test.status, 'open') test.close(function (err) { t.error(err) t.equal(test.status, 'closed') t.end() }) }) }) t.test('open error', function (t) { var Test = implement(AbstractLevelDOWN, { _open: function (options, cb) { cb(new Error()) } }) var test = new Test('foobar') test.open(function (err) { t.ok(err) t.equal(test.status, 'new') t.end() }) }) t.test('close error', function (t) { var Test = implement(AbstractLevelDOWN, { _close: function (cb) { cb(new Error()) } }) var test = new Test('foobar') test.open(function () { test.close(function (err) { t.ok(err) t.equal(test.status, 'open') t.end() }) }) }) t.test('open', function (t) { var Test = implement(AbstractLevelDOWN, { _open: function (options, cb) { process.nextTick(cb) } }) var test = new Test('foobar') test.open(function (err) { t.error(err) t.equal(test.status, 'open') t.end() }) t.equal(test.status, 'opening') }) t.test('close', function (t) { var Test = implement(AbstractLevelDOWN, { _close: function (cb) { process.nextTick(cb) } }) var test = new Test('foobar') test.open(function (err) { t.error(err) test.close(function (err) { t.error(err) t.equal(test.status, 'closed') t.end() }) t.equal(test.status, 'closing') }) }) }) test('_setupIteratorOptions', function (t) { var keys = legacyRangeOptions.concat(rangeOptions) var db = new AbstractLevelDOWN() function setupOptions (constrFn) { var options = {} keys.forEach(function (key) { options[key] = constrFn() }) return options } function verifyOptions (t, options) { keys.forEach(function (key) { t.ok(key in options, key + ' option should not be deleted') }) t.end() } t.plan(6) t.test('default options', function (t) { t.same(db._setupIteratorOptions(), { reverse: false, keys: true, values: true, limit: -1, keyAsBuffer: true, valueAsBuffer: true }, 'correct defaults') t.end() }) t.test('set options', function (t) { t.same(db._setupIteratorOptions({ reverse: false, keys: false, values: false, limit: 20, keyAsBuffer: false, valueAsBuffer: false }), { reverse: false, keys: false, values: false, limit: 20, keyAsBuffer: false, valueAsBuffer: false }, 'options set correctly') t.end() }) t.test('does not delete empty buffers', function (t) { var options = setupOptions(function () { return Buffer.from('') }) keys.forEach(function (key) { t.is(Buffer.isBuffer(options[key]), true, 'should be buffer') t.is(options[key].length, 0, 'should be empty') }) verifyOptions(t, db._setupIteratorOptions(options)) }) t.test('does not delete empty strings', function (t) { var options = setupOptions(function () { return '' }) keys.forEach(function (key) { t.is(typeof options[key], 'string', 'should be string') t.is(options[key].length, 0, 'should be empty') }) verifyOptions(t, db._setupIteratorOptions(options)) }) t.test('does not delete null', function (t) { var options = setupOptions(function () { return null }) keys.forEach(function (key) { t.is(options[key], null, 'should be null') }) verifyOptions(t, db._setupIteratorOptions(options)) }) t.test('does not delete undefined', function (t) { var options = setupOptions(function () { return undefined }) keys.forEach(function (key) { t.is(options[key], undefined, 'should be undefined') }) verifyOptions(t, db._setupIteratorOptions(options)) }) }) abstract-leveldown-6.3.0/test/util.js000066400000000000000000000005461364427107700176320ustar00rootroot00000000000000var nfre = /NotFound/i exports.verifyNotFoundError = function verifyNotFoundError (err) { return nfre.test(err.message) || nfre.test(err.name) } exports.isTypedArray = function isTypedArray (value) { return (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) || (typeof Uint8Array !== 'undefined' && value instanceof Uint8Array) }