This is just an experiment, might not be worthwhile to actually merge this. This is a pretty major refactor that pushes as much of the logic into redis as possible by using LUA scripts. Models generate LUA scripts to perform the operations, and each operation becomes a redis EVAL call.
Some naive benchmarks seem to suggest this is more performant, although I need to test this further. Also, now that every command is just an atomic EVAL call, pipelining becomes trivial. Will likely implement a pipelining feature before taking off the [WIP] tag.
Breaking Changes:
Constructor must be called from a root connection. i.e. you must say const DB = radredis(opts); const Model = DB.Model(schema, { beforeSave: '--', afterSave: '--' })
No more before/after save hooks. Instead, there are places where you can drop a before/after save LUA script to perform transformations on the server side
No more HGETALL. Radredis now expects rigid schemas and an explicit properties parameter for accessor methods, defaulting to a list of all properties. HMGET is a constant factor more efficient, and this prevents unexpected behaviour with setting fields that shouldn't exist
RFC: Update retrieves missing values from the existing model. In the previous implementation, update just called an HMSET and returned the serialized attributes. When attempting a partial update, this means only some of the attributes would be returned. This also makes explicit the fact that a partial update (note that undefined is not the same as null) only updates a part of the model, rather than deleting unset fields.
Notice that the new constructor is to encourage sharing a connection between models to allow pipelining. Furthermore, I'm playing around with integrating radgraph into the core radredis library becomes it seems to be a natural extension of radredis indices. This lends itself to encouraging code re-use, as well as providing nice features like true associations (retrieving related objects) rather than just an edge store for a graph.
All of this stuff is experimental though. This would mostly eliminate the boilerplate/wrappers on the radql end.
TODO:
refactor LUA scripts to be less ugly, performance was prioritized here but the code smells terrible
revisit radgraph so that edges do not store data attributes, only weights. This is the main rationale behind this change. By bringing radgraph and radredis together, there's room for heavy optimizations for 1-to-many and 1-to-1 relationships, encouraging intermediate data types rather than decorator edges. This makes all of the GraphQL stuff a lot cleaner
allow for custom ordering of edges and edge constraints (i.e. reverse chron vs chron, and limited length association lists)
This is just an experiment, might not be worthwhile to actually merge this. This is a pretty major refactor that pushes as much of the logic into redis as possible by using LUA scripts. Models generate LUA scripts to perform the operations, and each operation becomes a redis EVAL call.
Some naive benchmarks seem to suggest this is more performant, although I need to test this further. Also, now that every command is just an atomic EVAL call, pipelining becomes trivial. Will likely implement a pipelining feature before taking off the [WIP] tag.
Breaking Changes:
const DB = radredis(opts); const Model = DB.Model(schema, { beforeSave: '--', afterSave: '--' })
properties
parameter for accessor methods, defaulting to a list of all properties.HMGET
is a constant factor more efficient, and this prevents unexpected behaviour with setting fields that shouldn't existNotice that the new constructor is to encourage sharing a connection between models to allow pipelining. Furthermore, I'm playing around with integrating
radgraph
into the coreradredis
library becomes it seems to be a natural extension ofradredis
indices. This lends itself to encouraging code re-use, as well as providing nice features like true associations (retrieving related objects) rather than just an edge store for a graph.All of this stuff is experimental though. This would mostly eliminate the boilerplate/wrappers on the
radql
end.TODO: