subleveldown
Advanced tools
Comparing version 2.1.0 to 3.0.0-rc1
var subdown = require('./leveldown') | ||
var levelup = require('levelup') | ||
var encoding = require('encoding-down') | ||
@@ -8,7 +9,3 @@ module.exports = function (db, prefix, opts) { | ||
opts.db = function () { | ||
return subdown(db, prefix, opts) | ||
} | ||
return levelup(opts) | ||
return levelup(encoding(subdown(db, prefix, opts), opts), opts) | ||
} |
108
leveldown.js
@@ -1,21 +0,27 @@ | ||
var util = require('util') | ||
var inherits = require('inherits') | ||
var abstract = require('abstract-leveldown') | ||
var wrap = require('level-option-wrap') | ||
var END = new Buffer([0xff]) | ||
var END = Buffer.from([0xff]) | ||
var concat = function (prefix, key, force) { | ||
function concat (prefix, key, force) { | ||
if (typeof key === 'string' && (force || key.length)) return prefix + key | ||
if (Buffer.isBuffer(key) && (force || key.length)) return Buffer.concat([new Buffer(prefix), key]) | ||
if (Buffer.isBuffer(key) && (force || key.length)) { | ||
return Buffer.concat([Buffer.from(prefix), key]) | ||
} | ||
return key | ||
} | ||
var SubIterator = function (ite, prefix) { | ||
function SubIterator (ite, prefix) { | ||
this.iterator = ite | ||
this.prefix = prefix | ||
abstract.AbstractIterator.call(this) | ||
} | ||
SubIterator.prototype.next = function (cb) { | ||
inherits(SubIterator, abstract.AbstractIterator) | ||
SubIterator.prototype._next = function (cb) { | ||
var self = this | ||
this.iterator.next(cb && function (err, key, value) { | ||
this.iterator.next(function (err, key, value) { | ||
if (err) return cb(err) | ||
@@ -27,7 +33,7 @@ if (key) key = key.slice(self.prefix.length) | ||
SubIterator.prototype.end = function (cb) { | ||
SubIterator.prototype._end = function (cb) { | ||
this.iterator.end(cb) | ||
} | ||
var SubDown = function (db, prefix, opts) { | ||
function SubDown (db, prefix, opts) { | ||
if (!(this instanceof SubDown)) return new SubDown(db, prefix, opts) | ||
@@ -64,5 +70,5 @@ if (typeof opts === 'string') opts = {separator: opts} | ||
util.inherits(SubDown, abstract.AbstractLevelDOWN) | ||
inherits(SubDown, abstract.AbstractLevelDOWN) | ||
SubDown.prototype.type = 'subdown' | ||
SubDown.prototype.type = 'subleveldown' | ||
@@ -72,41 +78,35 @@ SubDown.prototype._open = function (opts, cb) { | ||
if (this.db.isOpen()) { | ||
if (this.db.db.type === 'subdown' && this.db.db.prefix) { | ||
this.prefix = this.db.db.prefix + this.prefix | ||
this.leveldown = this.db.db.leveldown | ||
this.db.open(function (err) { | ||
if (err) return cb(err) | ||
var subdb = down(self.db, 'subleveldown') | ||
if (subdb && subdb.prefix) { | ||
self.prefix = subdb.prefix + self.prefix | ||
self.leveldown = down(subdb.db) | ||
} else { | ||
this.leveldown = this.db.db | ||
self.leveldown = down(self.db) | ||
} | ||
return done() | ||
} | ||
this.db.on('open', this.open.bind(this, opts, done)) | ||
function done (err) { | ||
if (err || !self._beforeOpen) return cb(err) | ||
self._beforeOpen(cb) | ||
} | ||
if (self._beforeOpen) self._beforeOpen(cb) | ||
else cb() | ||
}) | ||
} | ||
SubDown.prototype.close = function () { | ||
this.leveldown.close.apply(this.leveldown, arguments) | ||
SubDown.prototype._close = function (cb) { | ||
this.leveldown.close(cb) | ||
} | ||
SubDown.prototype.setDb = function () { | ||
this.leveldown.setDb.apply(this.leveldown, arguments) | ||
} | ||
SubDown.prototype.put = function (key, value, opts, cb) { | ||
SubDown.prototype._put = function (key, value, opts, cb) { | ||
this.leveldown.put(concat(this.prefix, key), value, opts, cb) | ||
} | ||
SubDown.prototype.get = function (key, opts, cb) { | ||
SubDown.prototype._get = function (key, opts, cb) { | ||
this.leveldown.get(concat(this.prefix, key), opts, cb) | ||
} | ||
SubDown.prototype.del = function (key, opts, cb) { | ||
SubDown.prototype._del = function (key, opts, cb) { | ||
this.leveldown.del(concat(this.prefix, key), opts, cb) | ||
} | ||
SubDown.prototype.batch = | ||
SubDown.prototype._batch = function (operations, opts, cb) { | ||
@@ -125,19 +125,3 @@ if (arguments.length === 0) return new abstract.AbstractChainedBatch(this) | ||
SubDown.prototype.approximateSize = function (start, end, cb) { | ||
this.leveldown.approximateSize.apply(this.leveldown, arguments) | ||
} | ||
SubDown.prototype.getProperty = function () { | ||
return this.leveldown.getProperty.apply(this.leveldown, arguments) | ||
} | ||
SubDown.prototype.destroy = function () { | ||
return this.leveldown.destroy.apply(this.leveldown, arguments) | ||
} | ||
SubDown.prototype.repair = function () { | ||
return this.leveldown.repair.apply(this.leveldown, arguments) | ||
} | ||
var extend = function (xopts, opts) { | ||
function extend (xopts, opts) { | ||
xopts.keys = opts.keys | ||
@@ -158,8 +142,7 @@ xopts.values = opts.values | ||
var fixRange = function (opts) { | ||
function fixRange (opts) { | ||
return (!opts.reverse || (!opts.end && !opts.start)) ? opts : {start: opts.end, end: opts.start} | ||
} | ||
SubDown.prototype.iterator = function (opts) { | ||
if (!opts) opts = {} | ||
SubDown.prototype._iterator = function (opts) { | ||
var xopts = extend(wrap(fixRange(opts), this._wrap), opts) | ||
@@ -170,1 +153,18 @@ return new SubIterator(this.leveldown.iterator(xopts), this.prefix) | ||
module.exports = SubDown | ||
function down (db, type) { | ||
if (typeof db.down === 'function') return db.down(type) | ||
if (type && db.type === type) return db | ||
if (isAbstract(db.db)) return down(db.db, type) | ||
if (isAbstract(db._db)) return down(db._db, type) | ||
return type ? null : db | ||
} | ||
function isAbstract (db) { | ||
if (!db || typeof db !== 'object') { return false } | ||
return Object.keys(abstract.AbstractLevelDOWN.prototype).filter(function (name) { | ||
return name[0] !== '_' | ||
}).every(function (name) { | ||
return typeof db[name] === 'function' | ||
}) | ||
} |
{ | ||
"name": "subleveldown", | ||
"version": "2.1.0", | ||
"version": "3.0.0-rc1", | ||
"description": "sublevels implemented using leveldowns", | ||
"main": "index.js", | ||
"dependencies": { | ||
"abstract-leveldown": "^2.4.1", | ||
"abstract-leveldown": "^5.0.0", | ||
"encoding-down": "^5.0.3", | ||
"inherits": "^2.0.3", | ||
"level-option-wrap": "^1.1.0", | ||
"levelup": "^1.2.1" | ||
"levelup": "^3.0.1" | ||
}, | ||
"devDependencies": { | ||
"memdown": "^1.1.0", | ||
"standard": "^5.3.1", | ||
"tape": "^4.2.2" | ||
"memdown": "^3.0.0", | ||
"standard": "^11.0.1", | ||
"tape": "^4.9.0" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/mafintosh/subleveldown.git" | ||
"url": "https://github.com/level/subleveldown.git" | ||
}, | ||
@@ -23,5 +25,5 @@ "author": "Mathias Buus (@mafintosh)", | ||
"bugs": { | ||
"url": "https://github.com/mafintosh/subleveldown/issues" | ||
"url": "https://github.com/level/subleveldown/issues" | ||
}, | ||
"homepage": "https://github.com/mafintosh/subleveldown", | ||
"homepage": "https://github.com/level/subleveldown", | ||
"directories": { | ||
@@ -32,3 +34,6 @@ "test": "test" | ||
"test": "standard && node test" | ||
}, | ||
"engines": { | ||
"node": ">=6" | ||
} | ||
} |
# subleveldown | ||
Sublevels implemented using leveldowns | ||
> Sublevels on top of [`levelup`][levelup] with different encodings for each sublevel. | ||
``` | ||
npm install subleveldown | ||
``` | ||
[![level badge][level-badge]](https://github.com/level/awesome) | ||
[![npm](https://img.shields.io/npm/v/subleveldown.svg)](https://www.npmjs.com/package/subleveldown) | ||
![Node version](https://img.shields.io/node/v/subleveldown.svg) | ||
[![Travis](https://img.shields.io/travis/Level/subleveldown.svg?style=flat)](http://travis-ci.org/Level/subleveldown) | ||
[![dependencies](https://img.shields.io/david/Level/subleveldown.svg)](https://david-dm.org/level/subleveldown) | ||
[![npm](https://img.shields.io/npm/dm/subleveldown.svg)](https://www.npmjs.com/package/subleveldown) | ||
[![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) | ||
[![build status](http://img.shields.io/travis/mafintosh/subleveldown.svg?style=flat)](http://travis-ci.org/mafintosh/subleveldown) | ||
## Table of Contents | ||
<details><summary>Click to expand</summary> | ||
- [Usage](#usage) | ||
- [Background](#background) | ||
- [API](#api) | ||
- [Install](#install) | ||
- [License](#license) | ||
</details> | ||
## Usage | ||
**If you are upgrading:** please see [UPGRADING.md](UPGRADING.md). | ||
``` js | ||
@@ -31,11 +47,49 @@ var sub = require('subleveldown') | ||
## Background | ||
`subleveldown` separates a [`levelup`][levelup] database into sections - or *sublevels* from here on out. Think SQL tables, but evented, ranged and realtime! | ||
Each sublevel is a `levelup` of its own. This means it has the exact same interface as its parent database, but its own keyspace and [events](https://github.com/Level/levelup#events). In addition, sublevels are individually wrapped with [`encoding-down`][encoding-down], giving us per-sublevel encodings. For example, it's possible to have one sublevel with Buffer keys and another with `'utf8'` encoded keys. The same goes for values. Like so: | ||
```js | ||
sub(db, 'one', { valueEncoding: 'json' }) | ||
sub(db, 'two', { keyEncoding: 'binary' }) | ||
``` | ||
There is one limitation, however: keys must *encode to* either strings or Buffers. This is not likely to affect you, unless you use custom encodings or the `id` encoding (which bypasses encodings and thus makes it your responsibility to ensure keys are either strings or Buffers). | ||
Authored by [@mafintosh](https://github.com/mafintosh) and inspired by [`level-sublevel`][level-sublevel] by [@dominictarr](https://github.com/dominictarr), `subleveldown` has become an official part of [Level][level-org]. As `level-sublevel` is no longer under active development, we recommend switching to `subleveldown` to get the latest and greatest of the Level ecosystem. These two modules largely offer the same functionality, except for [hooks](https://github.com/dominictarr/level-sublevel#hooks) and [per-batch prefixes](https://github.com/dominictarr/level-sublevel#batches). | ||
## API | ||
#### `subdb = sub(db, [prefix], [options])` | ||
### `subdb = sub(db[, prefix][, options])` | ||
Returns a levelup instance that uses the subleveldown with `prefix`. | ||
The `options` argument is passed to the [levelup](https://github.com/rvagg/node-levelup) constructor | ||
Returns a `levelup` instance that uses subleveldown to prefix the keys of the underlying store of `db`. The required `db` parameter must be a `levelup` instance. Any layers that this instance may have (like `encoding-down` or `subleveldown` itself) are peeled off to get to the innermost [`abstract-leveldown`][abstract-leveldown] compliant store (like `leveldown`). This ensures there is no double encoding step. | ||
The `prefix` must be a string. If omitted, the effective prefix is two separators, e.g. `'!!'`. If `db` is already a subleveldown-powered instance, the effective prefix is a combined prefix, e.g. `'!one!!two!'`. | ||
The optional `options` parameter has the following `subleveldown` specific properties: | ||
* `separator` *(string, default: `'!'`)* Character for separating sublevel prefixes from user keys and each other. Should be outside the character (or byte) range of user keys. | ||
* `open` *(function)* Optional open hook called when the underlying `levelup` instance has been opened. The hook receives a callback which must be called to finish opening. | ||
Any other `options` are passed along to the underlying [`levelup`][levelup] and [`encoding-down`][encoding-down] constructors. See their documentation for further details. | ||
## Install | ||
With [npm](https://npmjs.org) do: | ||
``` | ||
npm i subleveldown -S | ||
``` | ||
## License | ||
MIT | ||
MIT © 2014-present [Mathias Buus](https://github.com/mafintosh) and [contributors](https://github.com/Level/subleveldown/graphs/contributors). See the included [LICENSE](./LICENSE.md) file for more details. | ||
[level-badge]: http://leveldb.org/img/badge.svg | ||
[levelup]: https://github.com/level/levelup | ||
[encoding-down]: https://github.com/level/encoding-down | ||
[abstract-leveldown]: https://github.com/level/abstract-leveldown | ||
[level-sublevel]: https://github.com/dominictarr/level-sublevel | ||
[level-org]: https://github.com/Level |
var test = require('tape') | ||
var memdown = require('memdown') | ||
var encoding = require('encoding-down') | ||
var subdown = require('../leveldown') | ||
var subdb = require('..') | ||
var levelup = require('levelup') | ||
var testCommon = require('./common') | ||
var testBuffer = new Buffer('this-is-test-data') | ||
@@ -13,3 +14,3 @@ require('abstract-leveldown/abstract/open-test').args(down, test, testCommon) | ||
require('abstract-leveldown/abstract/put-test').all(down, test, testCommon) | ||
require('abstract-leveldown/abstract/put-get-del-test').all(down, test, testCommon, testBuffer) | ||
require('abstract-leveldown/abstract/put-get-del-test').all(down, test, testCommon) | ||
require('abstract-leveldown/abstract/batch-test').all(down, test, testCommon) | ||
@@ -19,6 +20,128 @@ require('abstract-leveldown/abstract/chained-batch-test').all(down, test, testCommon) | ||
require('abstract-leveldown/abstract/iterator-test').all(down, test, testCommon) | ||
require('abstract-leveldown/abstract/ranges-test').all(down, test, testCommon) | ||
require('abstract-leveldown/abstract/iterator-range-test').all(down, test, testCommon) | ||
test('SubDown constructor', function (t) { | ||
t.test('can be called without new', function (t) { | ||
var sub = subdown() | ||
t.is(sub instanceof subdown, true, 'instanceof subdown') | ||
t.end() | ||
}) | ||
t.test('missing prefix and missing separator', function (t) { | ||
var sub = subdown() | ||
t.is(sub.prefix, '!!') | ||
t.end() | ||
}) | ||
t.test('prefix and missing separator', function (t) { | ||
var sub = subdown({}, 'prefix') | ||
t.is(sub.prefix, '!prefix!') | ||
t.end() | ||
}) | ||
t.test('prefix and separator (as string)', function (t) { | ||
var sub = subdown({}, 'prefix', '%') | ||
t.is(sub.prefix, '%prefix%') | ||
t.end() | ||
}) | ||
t.test('prefix and separator (as options)', function (t) { | ||
var sub = subdown({}, 'prefix', { separator: '%' }) | ||
t.is(sub.prefix, '%prefix%') | ||
t.end() | ||
}) | ||
t.test('prefix with same initial character as separator is sliced', function (t) { | ||
var sub = subdown({}, '!prefix') | ||
t.is(sub.prefix, '!prefix!') | ||
t.end() | ||
}) | ||
t.test('prefix with same ending character as separator is sliced', function (t) { | ||
var sub = subdown({}, 'prefix!') | ||
t.is(sub.prefix, '!prefix!') | ||
t.end() | ||
}) | ||
// TODO we're currently not guarded by multiple separators in the prefix | ||
// t.test('repeated separator is slices off from prefix parameter', function (t) { | ||
// var sub = subdown({}, '!!prefix!!') | ||
// t.is(sub.prefix, '!prefix!') | ||
// t.end() | ||
// }) | ||
}) | ||
test('SubDb main function', function (t) { | ||
t.test('opts.open hook', function (t) { | ||
t.plan(1) | ||
subdb(levelup(memdown()), 'test', { | ||
open: function (cb) { | ||
t.pass('opts.open called') | ||
} | ||
}) | ||
}) | ||
t.test('levelup *down is set to subdown which has correct storage', function (t) { | ||
var db = levelup(memdown()) | ||
var sub = subdb(db, 'test') | ||
sub.once('open', function () { | ||
t.is(sub.db instanceof encoding, true, 'is encoding-down instance') | ||
t.is(sub.db.db instanceof subdown, true, 'is subdown instance') | ||
t.is(sub.db.db.type, 'subleveldown', '.type is subleveldown') | ||
t.is(sub.db.db.leveldown instanceof memdown, true, 'memdown') | ||
t.end() | ||
}) | ||
}) | ||
t.test('different sub levels can have different encodings', function (t) { | ||
t.plan(6) | ||
var db = levelup(memdown()) | ||
var sub1 = subdb(db, 'test1', { | ||
valueEncoding: 'json' | ||
}) | ||
var sub2 = subdb(db, 'test2', { | ||
keyEncoding: 'binary', | ||
valueEncoding: 'binary' | ||
}) | ||
sub1.put('foo', { some: 'json' }, function (err) { | ||
t.error(err, 'no error') | ||
sub1.get('foo', function (err, value) { | ||
t.error(err, 'no error') | ||
t.same(value, { some: 'json' }) | ||
}) | ||
}) | ||
sub2.put(Buffer.from([1, 2]), Buffer.from([2, 3]), function (err) { | ||
t.error(err, 'no error') | ||
sub2.get(Buffer.from([1, 2]), function (err, value) { | ||
t.error(err, 'no error') | ||
t.deepEqual(value, Buffer.from([2, 3])) | ||
}) | ||
}) | ||
}) | ||
t.test('wrap a closed levelup and re-open levelup', function (t) { | ||
t.plan(3) | ||
var db = levelup(memdown()) | ||
db.once('open', function () { | ||
db.close(function (err) { | ||
t.error(err, 'no error') | ||
var sub = subdb(db, 'test') | ||
sub.once('open', function () { | ||
t.pass('subdb openen') | ||
}) | ||
db.open(function (err) { | ||
t.error(err, 'no error') | ||
}) | ||
}) | ||
}) | ||
}) | ||
t.test('wrapping a sub level', function (t) { | ||
var db = levelup(memdown()) | ||
var sub1 = subdb(db, 'test1') | ||
var sub2 = subdb(sub1, 'test2') | ||
sub2.once('open', function () { | ||
t.is(sub1.db instanceof encoding, true, 'sub1 encoding-down') | ||
t.is(sub1.db.db.prefix, '!test1!', 'sub1 prefix ok') | ||
t.is(sub1.db.db.leveldown instanceof memdown, true, 'memdown') | ||
t.is(sub2.db instanceof encoding, true, 'sub2 encoding-down') | ||
t.is(sub2.db.db.prefix, '!test1!!test2!', 'sub2 prefix ok') | ||
t.is(sub2.db.db.type, 'subleveldown', '.type is subleveldown') | ||
t.is(sub2.db.db.leveldown instanceof memdown, true, 'memdown') | ||
t.end() | ||
}) | ||
}) | ||
}) | ||
function down (loc) { | ||
return subdown(levelup(loc, {db: memdown}), 'test') | ||
return subdown(levelup(memdown()), 'test') | ||
} |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
24123
11
361
95
5
1
1
+ Addedencoding-down@^5.0.3
+ Addedinherits@^2.0.3
+ Addedabstract-leveldown@5.0.0(transitive)
+ Addedbase64-js@1.5.1(transitive)
+ Addedbuffer@5.7.1(transitive)
+ Addeddeferred-leveldown@4.0.2(transitive)
+ Addedencoding-down@5.0.4(transitive)
+ Addedieee754@1.2.1(transitive)
+ Addedisarray@1.0.0(transitive)
+ Addedlevel-codec@9.0.2(transitive)
+ Addedlevel-errors@2.0.1(transitive)
+ Addedlevel-iterator-stream@3.0.1(transitive)
+ Addedlevelup@3.1.1(transitive)
+ Addedprocess-nextick-args@2.0.1(transitive)
+ Addedreadable-stream@2.3.8(transitive)
+ Addedsafe-buffer@5.1.2(transitive)
+ Addedstring_decoder@1.1.1(transitive)
+ Addedutil-deprecate@1.0.2(transitive)
- Removedabstract-leveldown@2.6.32.7.2(transitive)
- Removeddeferred-leveldown@1.2.2(transitive)
- Removedisarray@0.0.1(transitive)
- Removedlevel-codec@7.0.1(transitive)
- Removedlevel-errors@1.0.5(transitive)
- Removedlevel-iterator-stream@1.3.1(transitive)
- Removedlevelup@1.3.9(transitive)
- Removedreadable-stream@1.1.14(transitive)
- Removedsemver@5.4.1(transitive)
- Removedstring_decoder@0.10.31(transitive)
Updatedabstract-leveldown@^5.0.0
Updatedlevelup@^3.0.1