Skip to content

Commit

Permalink
Use reachdown package (Level/community#82) (#75)
Browse files Browse the repository at this point in the history
  • Loading branch information
vweevers authored Sep 17, 2019
1 parent 992353b commit 10ee4d9
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 17 deletions.
21 changes: 5 additions & 16 deletions leveldown.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
var inherits = require('inherits')
var abstract = require('abstract-leveldown')
var wrap = require('level-option-wrap')
var reachdown = require('reachdown')
var matchdown = require('./matchdown')

var rangeOptions = 'start end gt gte lt lte'.split(' ')
var defaultClear = abstract.AbstractLevelDOWN.prototype._clear
Expand Down Expand Up @@ -83,13 +85,13 @@ SubDown.prototype._open = function (opts, cb) {
this.db.open(function (err) {
if (err) return cb(err)

var subdb = down(self.db, 'subleveldown')
var subdb = reachdown(self.db, 'subleveldown')

if (subdb && subdb.prefix) {
self.prefix = subdb.prefix + self.prefix
self.leveldown = down(subdb.db)
self.leveldown = reachdown(subdb.db, matchdown, false)
} else {
self.leveldown = down(self.db)
self.leveldown = reachdown(self.db, matchdown, false)
}

if (self._beforeOpen) self._beforeOpen(cb)
Expand Down Expand Up @@ -179,16 +181,3 @@ SubDown.prototype._iterator = function (opts) {
}

module.exports = SubDown

function down (db, type) {
if (typeof db.down === 'function') return db.down(type)
if (type && db.type === type) return db
if (isLooseAbstract(db.db)) return down(db.db, type)
if (isLooseAbstract(db._db)) return down(db._db, type)
return type ? null : db
}

function isLooseAbstract (db) {
if (!db || typeof db !== 'object') { return false }
return typeof db._batch === 'function' && typeof db._iterator === 'function'
}
8 changes: 8 additions & 0 deletions matchdown.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = function matchdown (db, type) {
// Skip layers that we handle ourselves
if (type === 'levelup') return false
if (type === 'encoding-down') return false
if (type === 'deferred-leveldown') return false

return true
}
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
"encoding-down": "^6.2.0",
"inherits": "^2.0.3",
"level-option-wrap": "^1.1.0",
"levelup": "^4.2.0"
"levelup": "^4.2.0",
"reachdown": "^1.0.0"
},
"devDependencies": {
"after": "^0.8.2",
Expand All @@ -30,6 +31,7 @@
"hallmark": "^2.0.0",
"level-community": "^3.0.0",
"level-concat-iterator": "^2.0.1",
"memdb": "^1.3.1",
"memdown": "^5.0.0",
"nyc": "^14.0.0",
"standard": "^14.0.0",
Expand Down
76 changes: 76 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ var after = require('after')
var subdown = require('../leveldown')
var subdb = require('..')
var levelup = require('levelup')
var reachdown = require('reachdown')
var memdb = require('memdb')
var abstract = require('abstract-leveldown')
var inherits = require('util').inherits

// Test abstract-leveldown compliance
suite({
Expand Down Expand Up @@ -359,6 +363,78 @@ test('SubDb main function', function (t) {
}
})

// Test that we peel off the levelup, deferred-leveldown and encoding-down
// layers from db, but stop at any other intermediate layer like encrypt-down,
// cachedown, etc.
test('subleveldown on intermediate layer', function (t) {
t.plan(7)

function Intermediate (db) {
abstract.AbstractLevelDOWN.call(this)
this.db = db
}

inherits(Intermediate, abstract.AbstractLevelDOWN)

Intermediate.prototype._put = function (key, value, options, callback) {
t.pass('got _put call')
this.db._put('mitm' + key, value, options, callback)
}

Intermediate.prototype._get = function (key, options, callback) {
t.pass('got _get call')
this.db._get('mitm' + key, options, callback)
}

var db = levelup(encoding(new Intermediate(memdown())))
var sub = subdb(db, 'test')

sub.put('key', 'value', function (err) {
t.error(err, 'no err')

db.get('!test!key', function (err, value) {
t.ifError(err, 'no levelup get error')
t.is(value, 'value')
})

reachdown(db).get('mitm!test!key', { asBuffer: false }, function (err, value) {
t.ifError(err, 'no memdown get error')
t.is(value, 'value')
})
})
})

test('legacy memdb (old levelup)', function (t) {
t.plan(7)

// Should not result in double json encoding
var db = memdb({ valueEncoding: 'json' })
var sub = subdb(db, 'test', { valueEncoding: 'json' })

// Integration with memdb still works because subleveldown waits to reachdown
// until the (old levelup) db is open. Reaching down then correctly lands on
// the memdown db. If subleveldown were to reachdown immediately it'd land on
// the old deferred-leveldown (which when unopened doesn't have a reference to
// the memdown db yet) so we'd be unable to persist anything.
t.is(Object.getPrototypeOf(reachdown(db)).constructor.name, 'DeferredLevelDOWN')

sub.put('key', { a: 1 }, function (err) {
t.ifError(err, 'no put error')

sub.get('key', function (err, value) {
t.ifError(err, 'no get error')
t.same(value, { a: 1 })
})

t.is(Object.getPrototypeOf(reachdown(db)).constructor.name, 'MemDOWN')

reachdown(db).get('!test!key', { asBuffer: false }, function (err, value) {
t.ifError(err, 'no get error')
t.is(value, '{"a":1}')
})
})
})

function getKey (entry) {
return entry.key
}

0 comments on commit 10ee4d9

Please sign in to comment.