-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Description
Intro
Modifier functions are the first proposal out of two, which together will allow users to set up expiration / TTL (#746). I'll post the second part shortly.
A modifier function is a ReQL function that can be configured on a given table. A modifier function is applied to each write, and can:
- perform schema validation
- rewrite documents or add additional fields, for example a
lastModificationTsfield to implement expiration (TTL) - implement security rules, such as insert-only tables. In the future, we can extend this concept to expose a user context with the user name and user groups to the modifier function.
Specification
The modifier function has the signature (oldVal : object, newVal : object) -> object. Each of the objects can also be null.
A modifier function has to be deterministic.
Whenever a write operation on the table inserts, deletes or modifies a given document, the modifier function will be called with the old value of the document (or null on inserts) and the new value of the document (or null on deletes). It then returns the value that should actually be inserted and/or replaced instead of newVal. It can also return r.error(...) to abort the write.
To simplify things, I think we should require the modifier function to return null exactly iff newVal is null. That way we make sure that it doesn't turn an insert/update into a deletion, and doesn't turn a deletion into an update, which could be confusing and might break some assumptions in our code.
Configuration API
Proposal for an API for setting a modifier function on a given table:
tbl.setModifier(function)sets the modifier function or overwrites it if one already existstbl.setModifier(null)deletes the modifier functiontbl.getModifier()gets a string representation of the current modifier function, ornull
The setModifier term requires "config" permissions on tbl.
This API could be more straight-forward if we had a ReQL query pseudo-type ( #3636 ), but I think that would become too much for 2.4. The current API therefore is loosely inspired by the secondary index API.
Examples for modifier functions:
// Inject a `lastModified` timestamp
tbl.setModifier(function(oldVal, newVal) {
return newVal.merge({lastModified: r.now}).default(null);
})(Note that r.now is the deterministic r.now that's filled in when the write query triggering this is compiled, not when the modifier is set. This might require some extra plumbing to work.)
// Verify that the documents have certain fields.
tbl.setModifier(function(oldVal, newVal) {
return r.branch(newVal.hasFields("field1", "field2"), newVal, r.error("Missing fields")).default(null);
})