question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Current functionality and the future (hoping on support for all use cases)

See original GitHub issue

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 https://github.com/Level/subleveldown/pull/7#issuecomment-367958457) 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).

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:2
  • Comments:13 (13 by maintainers)

github_iconTop GitHub Comments

1reaction
ralphtheninjacommented, May 31, 2018

@vweevers Had to tweak the first subdb check to this.leveldown = down(subdb.db) since calling this.leveldown = down(subdb) will result back in subdb.

1reaction
vweeverscommented, May 30, 2018

That line calls levelup#down(). What would that implementation look like?

return this.db.down(type). It doesn’t matter if this.db is deferred-leveldown or the open db, the result would be the same.

I’m wondering what we can do as minimal change to get this working, without having to rewrite the whole world

I was thinking about that too. We might be able to get by with while (db.db) db = db.db with some additional check that db.db is an abstract-leveldown (and not an underlying IndexedDB, for example).

Read more comments on GitHub >

github_iconTop Results From Across the Web

2. Hopes for the future of the digital life - Pew Research Center
The core question guiding this study explores experts' attitudes about the future of people's well-being. A plurality of the participants ...
Read more >
The Future of Customer Service Technology: 5 Key Trends
Check out the five big technology trends that give you a glimpse of how the future of customer service is changing in 2021....
Read more >
Nine keys to becoming a future ready company - McKinsey
To better organize for a postpandemic future, leaders should embrace nine imperatives that collectively explain “who we are” as an ...
Read more >
The Promise of Digital Health: Then, Now, and the Future
Digital health technologies are also developing new use cases to address various environmental factors, including air pollution and climate ...
Read more >
14 Ways Technology Will Affect the Future of Customer Service
There's a steep learning curve when it comes to learning to use and adapt to new technologies, they can be costly for businesses...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found