Skip to content
This repository has been archived by the owner on Dec 2, 2024. It is now read-only.

Use reachdown #75

Merged
merged 4 commits into from
Sep 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
}