Visualize.Feed behaviour (Visualize v0.6.0)

Copy Markdown View Source

The feed behaviour: what fills a chart's source slot, asked for rows (spec/08 §11, D-140).

A feed is a struct whose module implements this behaviour. describe/1 answers the feed's schema, its version and supports, the capabilities it honours among [:window, :region, :latest, :budget, :push]; fetch/3 answers a Visualize.Data.Delivery for a window and a budget; subscribe/2 and unsubscribe/2 are for a feed that pushes. Only rows are required. A window — nil, [from, to] or a box of ranges that may ask for each identity's latest row (spec/08 §11.1, D-168) — and a budget are requests: where a feed does not honour one, finish/3 trims and reduces for it, and a budget reduction records reduced_by: :visualize. Every callback answers {:error, reason} rather than raising, so a feed that is down is a value a cell shows.

A push feed sends {:visualize_feed, ref, {:schema, version, schema}} before the first delivery naming version, then {:visualize_feed, ref, {:delivery, delivery}}, each a delivery of the rows new since the last (spec/08 §11.3). Visualize.Feed.Monitor runs the loop over many feeds; Visualize.Feed.Combine makes one feed of several by window.

Examples

iex> alias Visualize.Data.{Delivery, Schema}
iex> schema = Schema.new!(%{t: %{type: :number, window: true}, v: %{type: :number}, s: %{type: :category}})
iex> rows = for t <- 1..10, s <- ["a", "b"], do: %{t: t, v: rem(t * 7, 5), s: s}
iex> delivery = Visualize.Feed.finish(Delivery.new(rows), schema, supports: [], budget: 8)
iex> {length(delivery.rows), delivery.reduced_by}
{8, :visualize}

Summary

Types

nil, or the most rows a cell wants.

What a feed honours (spec/08 §11.1).

t()

A feed: a struct whose module implements Visualize.Feed.

nil, [from, to] over the feed's window field, either bound nil for open, or a box of ranges that may ask for each identity's latest row (spec/08 §11.1, D-168).

Callbacks

The feed's present schema, its version and the capabilities it honours.

The rows for a window and a budget, both requests.

The feed's pushes sent to pid, tagged with the answered reference.

A subscription stopped.

Functions

The five capabilities a feed may honour, in the order of spec/08 §11.1.

The feed's {version, schema, supports}, or {:error, reason}.

A map of feeds by name as the describe function of spec/08 §10.3, for Visualize.Data.Schema.Cache.resolve/4 and Visualize.Chart.apply/2's describe:. A name not in the map is {:error, :no_feed}.

fetch(feed, window, budget): {:ok, delivery} or {:error, reason}.

A delivery finished for a request (spec/08 §11.2), each part where supports: lacks it: trimmed to the window field's range of window: (:window) and to a box's other ranges (:region), reduced to each identity's latest row (:latest, spec/08 §11.1), and reduced to budget: by reduce: (:lttb or :m4) when there are more rows than the budget (:budget), recording reduced_by: :visualize. A delivery that needs none of them comes back as it is.

The feed's pushes sent to pid (spec/08 §11.3): {:ok, ref}, or {:error, :no_push} for a feed whose module does not implement subscribe/2.

A subscription stopped; :ok for a feed that does not push.

The schema's window field (spec/08 §10.1, §11.2, D-154): the field a window is over, by which rows are ordered, trimmed and routed. It is the field described window: true, else the schema's one :time field when it does not say window: false; nil when there is neither.

The type of the schema's window field, :time or :number, or nil when it has none: the kind of window that applies to it (Visualize.Feed.Window.applies?/2).

Types

budget()

@type budget() :: pos_integer() | nil

nil, or the most rows a cell wants.

capability()

@type capability() :: :window | :region | :latest | :budget | :push

What a feed honours (spec/08 §11.1).

t()

@type t() :: struct()

A feed: a struct whose module implements Visualize.Feed.

window()

@type window() ::
  Visualize.Feed.Window.t()
  | %{optional(:ranges) => map(), optional(:latest) => boolean()}

nil, [from, to] over the feed's window field, either bound nil for open, or a box of ranges that may ask for each identity's latest row (spec/08 §11.1, D-168).

Callbacks

describe(feed)

@callback describe(feed :: t()) ::
  {String.t(), Visualize.Data.Schema.t(), [capability()]} | {:error, term()}

The feed's present schema, its version and the capabilities it honours.

fetch(feed, window, budget)

@callback fetch(feed :: t(), window(), budget()) ::
  {:ok, Visualize.Data.Delivery.t()} | {:error, term()}

The rows for a window and a budget, both requests.

subscribe(feed, pid)

(optional)
@callback subscribe(feed :: t(), pid()) :: {:ok, reference()} | {:error, term()}

The feed's pushes sent to pid, tagged with the answered reference.

unsubscribe(feed, reference)

(optional)
@callback unsubscribe(feed :: t(), reference()) :: :ok

A subscription stopped.

Functions

capabilities()

@spec capabilities() :: [capability(), ...]

The five capabilities a feed may honour, in the order of spec/08 §11.1.

describe(feed)

@spec describe(t()) ::
  {String.t(), Visualize.Data.Schema.t(), [capability()]} | {:error, term()}

The feed's {version, schema, supports}, or {:error, reason}.

describer(feeds)

@spec describer(%{required(term()) => t()}) :: (term() ->
                                            {:ok, Visualize.Data.Schema.t()}
                                            | {:error, term()})

A map of feeds by name as the describe function of spec/08 §10.3, for Visualize.Data.Schema.Cache.resolve/4 and Visualize.Chart.apply/2's describe:. A name not in the map is {:error, :no_feed}.

fetch(feed, window, budget)

@spec fetch(t(), window(), budget()) ::
  {:ok, Visualize.Data.Delivery.t()} | {:error, term()}

fetch(feed, window, budget): {:ok, delivery} or {:error, reason}.

finish(delivery, schema, opts)

A delivery finished for a request (spec/08 §11.2), each part where supports: lacks it: trimmed to the window field's range of window: (:window) and to a box's other ranges (:region), reduced to each identity's latest row (:latest, spec/08 §11.1), and reduced to budget: by reduce: (:lttb or :m4) when there are more rows than the budget (:budget), recording reduced_by: :visualize. A delivery that needs none of them comes back as it is.

Raises ArgumentError for a box Visualize.Feed.Window.check/2 refuses against the schema: the request is the caller's.

subscribe(feed, pid)

@spec subscribe(t(), pid()) :: {:ok, reference()} | {:error, term()}

The feed's pushes sent to pid (spec/08 §11.3): {:ok, ref}, or {:error, :no_push} for a feed whose module does not implement subscribe/2.

unsubscribe(feed, ref)

@spec unsubscribe(t(), reference()) :: :ok

A subscription stopped; :ok for a feed that does not push.

window_field(schema)

@spec window_field(Visualize.Data.Schema.t()) :: Visualize.Data.Schema.name() | nil

The schema's window field (spec/08 §10.1, §11.2, D-154): the field a window is over, by which rows are ordered, trimmed and routed. It is the field described window: true, else the schema's one :time field when it does not say window: false; nil when there is neither.

iex> alias Visualize.Data.Schema
iex> Visualize.Feed.window_field(Schema.new!(%{t: %{type: :time}, v: %{type: :number}}))
:t
iex> Visualize.Feed.window_field(Schema.new!(%{tick: %{type: :number, window: true}, v: %{type: :number}}))
:tick
iex> Visualize.Feed.window_field(Schema.new!(%{a: %{type: :time}, b: %{type: :time}}))
nil

window_type(schema)

@spec window_type(Visualize.Data.Schema.t()) :: :time | :number | nil

The type of the schema's window field, :time or :number, or nil when it has none: the kind of window that applies to it (Visualize.Feed.Window.applies?/2).