StatifierDatamodel.Coverage (StatifierDatamodel v0.1.0)

Copy Markdown View Source

ADR-0001 decision 10: which required fields of a shape a map does not fill.

missing/3 is given the declarations, the name of a shape and a map, and answers {:ok, names} - the name of every required field of that shape the map does not fill, in declaration order - or :error.

Only a shape has coverage

A shape is the constraint a read places on a path, so does this map cover it is a question a shape has an answer to. A record is a fact about what a write puts somewhere, and an undeclared name is nothing at all; neither is a shape, and both are :error rather than {:ok, []}. Answering nothing is missing for a name that declares no requirements would read as coverage achieved, which is the one wrong answer here.

Fill is presence with a value

A field is filled when the map carries its name as a key with a non-nil value. The value's type is not checked against the field's: a map here is data a host handed in, and the type of a value is the expression language's question, not the document's. A key spelled as an atom is not the field's key - a document's names are strings, and the map is read with the string it declares.

The order is the shape's own field order, so a pane may render the answer as the shape reads. Nothing raises: an input that is not a map fills nothing, and every required field of the shape is named.

Summary

Functions

The required field names of the shape name that map does not fill.

Functions

missing(declarations, name, map)

@spec missing(StatifierDatamodel.Declarations.t(), term(), term()) ::
  {:ok, [String.t()]} | :error

The required field names of the shape name that map does not fill.

iex> alias StatifierDatamodel.{Coverage, Declarations}
iex> declarations = Declarations.from_document(%{"types" => [
...>   %{"name" => "Settleable", "kind" => "shape", "label" => "Settleable", "fields" => [
...>     %{"name" => "amount_cents", "type" => "integer", "required?" => true},
...>     %{"name" => "currency", "type" => "string", "required?" => true},
...>     %{"name" => "note", "type" => "string"}]},
...>   %{"name" => "cards.card", "kind" => "record", "label" => "Card", "fields" => []}]})
iex> Coverage.missing(declarations, "Settleable", %{"amount_cents" => 1250, "currency" => "USD"})
{:ok, []}
iex> Coverage.missing(declarations, "Settleable", %{"currency" => nil})
{:ok, ["amount_cents", "currency"]}
iex> Coverage.missing(declarations, "cards.card", %{})
:error
iex> Coverage.missing(declarations, "Refundable", %{})
:error