Visualize.Data.Schema (Visualize v0.4.0)

Copy Markdown View Source

A feed's schema: what each of its fields means (spec/08 §10.1, D-136).

A schema maps a field — named as the feed's rows name it, an atom or a string — to a description: its type, and as much of unit, quantity, label, order, status, polarity, target, continuity, window, metric_kind and bounds as the feed knows. It says what the numbers are, whoever draws them, and never how they are drawn: a description has no colour key, since colour is the theme's to choose from the meaning (#533). A :time field holds instants; a feed whose clock is a number describes it :number and window: true, the field its windows are over (D-154). A numeric field may say how it was measured, metric_kind: :gauge | :counter | :rate, which refines what its quantity's additivity allows, and where its values lie, bounds: [min, max], a display hint over its quantity's (D-155). A unit is a UCUM code Visualize.Unit reads and a quantity one of Visualize.Quantity.all/0, and when both are given the unit measures the quantity (D-157).

A schema is identified by its version, a content hash (spec/08 §10.2): the same schema has the same version on every node and under every release, and any change of content is a new version. A Visualize.Data.Delivery names the version its rows were produced under; Visualize.Data.Schema.Cache holds schemas by {feed, version}.

Examples

iex> {:ok, schema} =
...>   Visualize.Data.Schema.new(%{
...>     t: %{type: :time},
...>     latency: %{type: :number, unit: "s", quantity: :duration, label: "Request time"},
...>     state: %{type: :category, order: ["ok", "warn", "fail"],
...>              status: %{"ok" => :good, "warn" => :warning, "fail" => :bad}}
...>   })
iex> Visualize.Data.Schema.fetch(schema, "latency", :unit)
{:ok, "s"}
iex> String.length(Visualize.Data.Schema.version(schema))
64
iex> Visualize.Data.Schema.new(%{state: %{type: :category, colors: %{"ok" => "#0a0"}}})
{:error, [{[:state, :colors], {:colour_key, :colors}}]}

Summary

Types

What one field means (spec/08 §10.1).

A fault of new/1: the path from the schema to the value, and why.

A field name, as the feed's rows spell it.

t()

Functions

The twelve description keys, :type first (spec/08 §10.1).

A field's description, by either spelling of its name (spec/08 §6.2).

One attribute of a field's description; :error when the field or the attribute is absent.

One fault of new/1 as a line a person reads.

The schema of a map of field descriptions, or every fault of it by path (spec/08 §10.1).

The schema of a map of field descriptions, or ArgumentError naming every fault.

The schema's version: the SHA-256 of its canonical encoding as 64 lowercase hex digits (spec/08 §10.2), computed once by new/1.

Types

description()

@type description() :: %{
  :type => :time | :number | :category | :text,
  optional(:unit) => String.t(),
  optional(:quantity) => atom(),
  optional(:label) => String.t(),
  optional(:order) => [String.t() | atom() | number(), ...],
  optional(:status) => %{required(term()) => atom()},
  optional(:polarity) => :higher_is_better | :lower_is_better | :neutral,
  optional(:target) => number(),
  optional(:continuity) => number(),
  optional(:window) => boolean(),
  optional(:metric_kind) => :gauge | :counter | :rate,
  optional(:bounds) => [number() | nil]
}

What one field means (spec/08 §10.1).

error()

@type error() :: {[name() | atom() | non_neg_integer() | term()], term()}

A fault of new/1: the path from the schema to the value, and why.

name()

@type name() :: atom() | String.t()

A field name, as the feed's rows spell it.

t()

@type t() :: %Visualize.Data.Schema{
  fields: %{required(name()) => description()},
  version: String.t()
}

Functions

attributes()

@spec attributes() :: [atom(), ...]

The twelve description keys, :type first (spec/08 §10.1).

fetch(schema, name)

@spec fetch(t(), name()) :: {:ok, description()} | :error

A field's description, by either spelling of its name (spec/08 §6.2).

iex> schema = Visualize.Data.Schema.new!(%{"v" => %{type: :number}})
iex> Visualize.Data.Schema.fetch(schema, :v)
{:ok, %{type: :number}}
iex> Visualize.Data.Schema.fetch(schema, :w)
:error

fetch(schema, name, key)

@spec fetch(t(), name(), atom()) :: {:ok, term()} | :error

One attribute of a field's description; :error when the field or the attribute is absent.

format_error(arg)

@spec format_error(error()) :: String.t()

One fault of new/1 as a line a person reads.

iex> Visualize.Data.Schema.format_error({[:latency, :unit], {:invalid_for, :category}})
"latency.unit: is not a key a :category field takes"

new(fields)

@spec new(term()) :: {:ok, t()} | {:error, [error(), ...]}

The schema of a map of field descriptions, or every fault of it by path (spec/08 §10.1).

iex> Visualize.Data.Schema.new(%{v: %{type: :category, unit: "s"}})
{:error, [{[:v, :unit], {:invalid_for, :category}}]}

iex> Visualize.Data.Schema.new(%{v: %{type: :number, unit: "By", quantity: :duration}})
{:error, [{[:v, :quantity], {:quantity, :duration, "By"}}]}

new!(fields)

@spec new!(term()) :: t()

The schema of a map of field descriptions, or ArgumentError naming every fault.

version(schema)

@spec version(t()) :: String.t()

The schema's version: the SHA-256 of its canonical encoding as 64 lowercase hex digits (spec/08 §10.2), computed once by new/1.