-
-
Notifications
You must be signed in to change notification settings - Fork 11
Current functionality and the future (hoping on support for all use cases) #34
Description
Just wanted to jot down how it actually works but with words. Mostly for my own processing but also to explain to others that might be interested.
What I like the most with this module, is that it allows you to create sub levels (duh) but also with their specific encodings and it does this quite cleverly by peeling off the levelup layer, adding one down layer (SubDb) on top of the current down (leveldown, memdown etc wrapped by levelup) and then finishes off by adding back a levelup layer.
This trickery happens in ._open() (with some added comments):
SubDown.prototype._open = function (opts, cb) {
var self = this
if (this.db.isOpen()) {
if (this.db.db.type === 'subdown' && this.db.db.prefix) {
// This happens when we do a nested sub level
// this.db is a levelup and this.db.db is the SubDown and
// this.db.db.leveldown is the original down (see else case below)
this.prefix = this.db.db.prefix + this.prefix
this.leveldown = this.db.db.leveldown
} else {
// this.db is a levelup and this.db.db is the *down it's wrapping
this.leveldown = this.db.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)
}
}The reason this works is because older versions of levelup takes care of the encodings and just applies them to a *down (SubDown in this case).
From index.js:
module.exports = function (db, prefix, opts) {
if (typeof prefix === 'object' && !opts) return module.exports(db, null, prefix)
if (!opts) opts = {}
opts.db = function () {
return subdown(db, prefix, opts)
}
return levelup(opts)
}The problem we face now is that levelup was rewritten and encodings moved out into encoding-down so if we want to support encodings in the same way we can no longer rely on levelup alone.
So what if we in index.js finish off with:
module.exports = function (db, prefix, opts) {
// ..
return levelup(encoding(subdown(db, prefix, opts), opts), opts)
}That should take care of the current functionality of levelup. But it's not enough. What if we want to create a sub level out of a level? This will not work (as @emilbayes pointed out here #7 (comment)) since it would mean double decodings (and encodings I guess).
So what I propose is that we continue with this trickery a bit and tweak ._open() to peel off two layers if there's an encoding-down:
SubDown.prototype._open = function (opts, cb) {
var self = this
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
} else if (encDown.isEncodingDown(this.db.db)) { // <-- HERE!
this.leveldown = this.db.db.db
} else {
this.leveldown = this.db.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)
}
}It's a bit hacky, but I think it should work well. We need to implement a proper static encDown.isEncodingDown() function though which should support cross realms (using Symbol.for() etc).