Skip to content

Proposal: Modifier functions #5813

@danielmewes

Description

@danielmewes

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 lastModificationTs field 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 exists
  • tbl.setModifier(null) deletes the modifier function
  • tbl.getModifier() gets a string representation of the current modifier function, or null

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);
  })

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions