-
-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
plugin extension points: merge level-hooks / level-sublevel #44
Comments
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 |
I can re-open and move to community. |
One part of this (sublevels) is code complete: Level/abstract-level#8. As for hooks, let's define some requirements:
High-level, I see three ways to implement hooks:
|
cc @bcomnes as the author of |
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:
|
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 Such a class might also give hooks and events access to lazily encoded keys/values, roughly like so: Click to expandconst kKey = Symbol('key')
const kEncodedKey = Symbol('encodedKey')
const kNone = Symbol('none')
// Skipping values for brevity
class Operation {
constructor (type, key, keyEncoding) {
this.type = type
this.key = key
this.keyEncoding = keyEncoding
}
get key () {
return this[kKey]
}
set key (key) {
if (key === null || key === undefined) {
// throw
}
this[kKey] = key
this[kEncodedKey] = kNone
}
get encodedKey () {
let encodedKey = this[kEncodedKey]
if (encodedKey === kNone) {
encodedKey = this[kEncodedKey] = this.keyEncoding.encode(this[kKey])
}
return encodedKey
}
} Plus, in scenarios where a db is wrapped (like sublevels) we can possibly skip work if we see that Edit: I'm not gonna do that, hurts userland options and modularity. |
Adds postopen, prewrite and newsub hooks that allow userland "hook functions" to customize behavior of the database. See README for details. A quick example: ```js db.hooks.prewrite.add(function (op, batch) { if (op.type === 'put') { batch.add({ type: 'put', key: op.value.foo, value: op.key, sublevel: fooIndex }) } }) ``` More generally, this is a move towards "renewed modularity". Our ecosystem is old and many modules no longer work because they had no choice but to monkeypatch database methods, of which the signature has changed since then. So in addition to hooks, this: - Introduces a new `write` event that is emitted on `db.batch()`, `db.put()` and `db.del()` and has richer data: userland options, encoded data, keyEncoding and valueEncoding. The `batch`, `put` and `del` events are now deprecated and will be removed in a future version. Related to Level/level#222. - Restores support of userland options on batch operations. In particular, to copy options in `db.batch(ops, options)` to ops, allowing for code like `db.batch(ops, { ttl: 123 })` to apply a default userland `ttl` option to all ops. No breaking changes, yet. Using hooks means opting-in to new behaviors (like the new write event) and disables some old behaviors (like the deprecated events). Later on we can make those the default behavior, regardless of whether hooks are used. TODO: benchmarks, tests and optionally some light refactoring. Closes Level/community#44.
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.
The text was updated successfully, but these errors were encountered: