Mediate.Adapter behaviour (mediate v0.1.0)

Copy Markdown View Source

The contract every adapter implements. The port calls each callback with a subject, an operation, an object or an object type, the environment, and the adapter's validated options. The adapter answers and never raises on the request path. around_query/3, options_schema/0, and settle/0 are optional. The port and the seam check at runtime whether the adapter exports them, so one build serves every adapter. What produced an answer travels on the answer's meta, where the adapter can say.

Two declarations hold for an adapter in any domain. scope_cap/0 is the cap on the number of objects scope can return, or :none where the rule is a query the database runs. settle/0 says whether the adapter has state of its own to settle. An adapter that reads the application's own tables has none.

An adapter is domain-free. It names no schema and no rule of the application, and the coverage test each adapter package carries holds it to that.

Summary

Types

What a callback returns when it cannot answer.

The options the port hands the adapter, unchanged.

What scope/5 answers: the rule as a dynamic, and the answer that goes with it.

Callbacks

Wrap a mediated call. The arguments are the query or changeset, the decision in force, and the zero-arity function that runs the call. An adapter that needs session state at execution, such as row-level security settings, sets it here and then calls the function. Every other adapter leaves this undefined, and the seam calls the function directly.

Decide for one object. The port records it, whether the caller asked authorize or check.

The schema for the adapter's entry in Mediate.Config. When absent, the entry must be the bare module.

The rule that narrows a query over an object type to what the subject can see.

The cap on objects scope can return, or :none.

Bring the state the adapter keeps of its own into step with the application's tables. Answer :ok when nothing is outstanding. Answer :none for an adapter that keeps no state, which is what an adapter that leaves this callback undefined says. A caller that has written facts and is about to ask about them settles first. Mediate.Test.settle/0 is that caller in the suite.

Types

failure()

@type failure() :: {:error, Mediate.Error.t()}

What a callback returns when it cannot answer.

options()

@type options() :: keyword()

The options the port hands the adapter, unchanged.

scoped()

@type scoped() :: {Ecto.Query.dynamic_expr(), Mediate.Answer.t()}

What scope/5 answers: the rule as a dynamic, and the answer that goes with it.

Callbacks

around_query(arg1, t, function)

(optional)
@callback around_query(
  Ecto.Query.t() | Ecto.Changeset.t(),
  Mediate.Decision.t(),
  (-> term())
) :: term()

Wrap a mediated call. The arguments are the query or changeset, the decision in force, and the zero-arity function that runs the call. An adapter that needs session state at execution, such as row-level security settings, sets it here and then calls the function. Every other adapter leaves this undefined, and the seam calls the function directly.

decide(subject, atom, object, environment, options)

@callback decide(
  Mediate.subject(),
  atom(),
  Mediate.object(),
  Mediate.environment(),
  options()
) ::
  {:ok, Mediate.Answer.t()} | failure()

Decide for one object. The port records it, whether the caller asked authorize or check.

options_schema()

(optional)
@callback options_schema() :: NimbleOptions.t()

The schema for the adapter's entry in Mediate.Config. When absent, the entry must be the bare module.

scope(subject, atom, atom, environment, options)

@callback scope(Mediate.subject(), atom(), atom(), Mediate.environment(), options()) ::
  {:ok, scoped()} | failure()

The rule that narrows a query over an object type to what the subject can see.

scope_cap()

@callback scope_cap() :: pos_integer() | :none

The cap on objects scope can return, or :none.

settle()

(optional)
@callback settle() :: :ok | :none | {:error, Mediate.Error.t()}

Bring the state the adapter keeps of its own into step with the application's tables. Answer :ok when nothing is outstanding. Answer :none for an adapter that keeps no state, which is what an adapter that leaves this callback undefined says. A caller that has written facts and is about to ask about them settles first. Mediate.Test.settle/0 is that caller in the suite.

A caller settles in place of a wait. An application in production has a process that brings the same state into step on its own interval. Nothing on the request path calls this.