Reading a document through the gates, in order (spec/01 §5).
A document type implements this behavior and Macaw.Layers.Version: its version line
and steps, and validate/1, which judges a document at the current version. Whatever
the document came from (a file, a database, an object store), it is read the same way,
by read/3, and nothing in it is evaluated:
- bytes: an encoded document longer than the
byteslimit is refused; - decode with the
depthanditemslimits, byMacaw.Layers.Scan, which stops at a limit before any value is built; only then is it decoded, with Elixir'sJSON; - version: a newer stamp is refused by name before anything else is read;
- migrate, step by step;
- validate, and count
depthanditemsagain, since a migration can grow a document.
Faults from one gate stop the gates after it. Within the last, the type's faults and the recount's are all reported, ordered by path.
Summary
Callbacks
:ok, or every fault of a document at the type's current version. Unknown keys are
refused by name (see unknown_keys/3).
Functions
The canonical digest of a document's map form (Macaw.Layers.Form.to_map/2): 64
lowercase hex characters, the SHA-256 of its canonical encoding (spec/01 §7).
The document, read through every gate, at the type's current version: {:ok, map}, or
every fault of the first gate that refuses it.
The faults of map's keys that are not among known, each at its own spelling under
path: {path ++ [key], :unknown_key}, ordered by path.
Types
Callbacks
@callback validate(document :: map()) :: :ok | {:error, [Macaw.Layers.Fault.t(), ...]}
:ok, or every fault of a document at the type's current version. Unknown keys are
refused by name (see unknown_keys/3).
Functions
The canonical digest of a document's map form (Macaw.Layers.Form.to_map/2): 64
lowercase hex characters, the SHA-256 of its canonical encoding (spec/01 §7).
The encoding is JSON with objects' keys sorted bytewise, no insignificant whitespace,
each string as JSON encodes it, an integer in decimal, and a float in its shortest
spelling that reads back as the same float. Reordering keys, at any depth, does not
change the digest; a document and its JSON round trip have the same one. The encoding is
part of the kernel's contract: changing it changes every digest, so it changes only with
a new major version.
Raises ArgumentError for a term that is not a map form: an atom key, a tuple, any
value JSON has no form for. Write the value's map form first.
iex> Macaw.Layers.Document.digest(%{"b" => 1, "a" => [true, nil]}) ==
...> Macaw.Layers.Document.digest(%{"a" => [true, nil], "b" => 1})
true
@spec read(binary() | map(), module(), [option()]) :: {:ok, map()} | {:error, [Macaw.Layers.Fault.t(), ...]}
The document, read through every gate, at the type's current version: {:ok, map}, or
every fault of the first gate that refuses it.
input is the JSON form, a binary, or the map form, which skips the bytes gate and is
walked for depth and items instead of scanned. type implements this behavior and
Macaw.Layers.Version. limits: tightens the limits, as Macaw.Layers.Limits.new/1
takes them.
@spec unknown_keys(map(), [String.t()], Macaw.Layers.Fault.path()) :: [ Macaw.Layers.Fault.t() ]
The faults of map's keys that are not among known, each at its own spelling under
path: {path ++ [key], :unknown_key}, ordered by path.
known is the type's keys as the document spells them, strings. A key the type knows
stays the type's to read; one it does not is refused by name, never dropped.
iex> Macaw.Layers.Document.unknown_keys(%{"title" => "t", "ttle" => "x"}, ["title"], [:page])
[{[:page, "ttle"], :unknown_key}]