Closed dominictarr closed 1 year ago
I realize that this could be construed as going against the modularity principle, but I think this may be worthwile, because A) we already have the core separated into leveldown B) this would provide a firm standard basis for more modularity.
Also, I don't want to suggest we merge immediately, but we should put it on the table.
those 2 plugins you suggest to go into core will be crucial for the future development of levelUp.
With hooks multilevel will work with more plugins or e.g. a middleware layer can easily be implemented.
SubLevel will come in handy when we decide to give each plugin its own meta db.
see also #97
@ralphtheninja I think a new issue is in order (in community
perhaps), because the hooks of level-sublevel
are a powerful concept, and we don't have a replacement atm.
I can re-open and move to community.
One part of this (sublevels) is code complete: https://github.com/Level/abstract-level/pull/8. As for hooks, let's define some requirements:
level-hooks
did, because sublevels are builtinlevel-hooksdown
).db.batch(..)
calls contains operations with a sublevel
property, execute the hooks of that sublevel, instead of hooks of the db? TBD.High-level, I see three ways to implement hooks:
abstract-level
layer (similar to level-hooksdown
).
put()
instead of _put()
- but I'd really like to avoid that pattern.abstract-level
, and executed before encoding (of keys and values) and prefixing (of sublevel keys).
put()
and del()
should internally use a batch()
. Initially we can do that eagerly, later on perhaps only if one of the hooks wants to add operations.abstract-level
, and executed after encoding and before prefixing.
cc @bcomnes as the author of level-hooksdown
: if hooks were builtin, which features are a must for you?
Let me think about ideas for a bit. The only reason I wrote hookdown was to better support hooks and indexes when working with sub level downs at the time.
Areas for simplification should definitely be welcomed (eg if only pre or post hooks can do the job of both, why have the other). Simplifying the order hooks run in (series) is also probably a better api for community plugins in order to clarify behavior when various hooks are combined in unanticipated ways. You can always combine actions to run in parallel in a single hook. I believe this option was added mainly because I wasn't sure what the best approach was at the time.
So +1 to those changes if the functionality can be built in.
Further reducing the scope of this feature, to make it easier to land something:
abstract-level
and run before encoding and prefixing.put()
, del()
and batch()
. But not clear()
for now, because that will require deeper integration (especially on abstract-level
implementations that clear natively meaning the deleted keys are not exposed to JS).Sounds good
After implementing an initial version, I realized that I reduced the scope too much. It would box us into a corner by adding hooks in the wrong place - serving one use case but being unable to extend it later without breaking changes. That's vague, but long story short I'm gonna take another use case into account: modifying operations. This has to consider encodings, options, events, sublevels and validation, so as a result the hook will be more future-proof.
As for performance, specifically on db.batch([])
, I may have found a way to even increase performance when no hooks are present, by internally using a class instead of a plain object for operations. That's faster to create and clone, compared to Object.assign({}, operation)
. Will have to find a place for userland options though (the foo
in { type, key, foo: 2 }
).
Such a class might also give hooks and events access to lazily encoded keys/values, roughly like so:
Plus, in scenarios where a db is wrapped (like sublevels) we can possibly skip work if we see that op instanceof Operation
, meaning we already validated and normalized the operation.
Edit: I'm not gonna do that, hurts userland options and modularity.
I'm not suggesting we do this right away, but I am suggesting this is something worth considering.
Also, I don't want to merge this, unless there is a consensus that this is an easy and effective way to build plugins.
I'd also intend to refactor the code style, etc, to match levelup.
I think that given these base features, and maybe one or two more, a wide array of plugins could be developed.