Visualize.Chart.Migration (Visualize v0.8.1)

Copy Markdown View Source

Schema versions and the migrations between them (spec/14 §9).

current/0 is the version this library writes. migrate/1 steps an older design forward one version at a time through the migration registered for each step, so a stored design never goes stale. Version 2 is the first step: a design holds its frames by name (spec/14 §2.1, §4.1, #383), so a version 1 design's singular frame becomes frames: %{main: …} and the size it may still carry is dropped, the render giving one now (§4.2, #427). A stored version 1 design therefore keeps working through Visualize.Chart.from_map/1, which migrates before it validates.

Summary

Functions

The design in the shape this library writes, within the current version: a :text given as a list of parts — the form an earlier draft wrote — becomes the string with interpolation (spec/14 §7.1), walking the map by the schema so a text is known to be one. Every other value passes through as it is.

canonical/1 of a node of kind alone: a fragment of that kind (spec/14 §19.6).

The schema version this library writes: 3.

The type a flat style key of an earlier version had (spec/14 §9, D-172), nil for any other key: fill, stroke, curve and effect are flat when their value is not a part, and are read by these types then.

The type a key had in an earlier version, for a key of a kind node that the current schema no longer has; nil for any other key.

The design at the current version.

The styles of a node of kind in their parts and nothing else rewritten (spec/14 §3.1, §9, D-172): what the validator reads, so a design or a fragment written in the flat keys validates as the parts it means, while a text given as parts keeps the paths its faults are reported at.

The version gate of spec/14 §9.1 alone: {:error, {:newer_schema, version, current}} for an integer above current/0, else :ok.

Functions

canonical(map)

@spec canonical(map()) :: map()

The design in the shape this library writes, within the current version: a :text given as a list of parts — the form an earlier draft wrote — becomes the string with interpolation (spec/14 §7.1), walking the map by the schema so a text is known to be one. Every other value passes through as it is.

iex> Visualize.Chart.Migration.canonical(%{version: 2, labels: [%{anchor: :title, text: ["u: ", Visualize.Chart.var(:unit)]}]})
%{version: 2, labels: [%{anchor: :title, text: "u: \#{var(:unit)}"}]}

canonical(map, kind)

@spec canonical(map(), Visualize.Chart.Schema.kind()) :: map()

canonical/1 of a node of kind alone: a fragment of that kind (spec/14 §19.6).

iex> Visualize.Chart.Migration.canonical(%{fill: :red, fill_opacity: 0.5}, :style)
%{fill: %{type: :solid, color: {:color, :red}, opacity: 0.5}}

current()

@spec current() :: pos_integer()

The schema version this library writes: 3.

flat_type(key)

@spec flat_type(atom()) :: Visualize.Chart.Schema.type() | nil

The type a flat style key of an earlier version had (spec/14 §9, D-172), nil for any other key: fill, stroke, curve and effect are flat when their value is not a part, and are read by these types then.

iex> Visualize.Chart.Migration.flat_type(:stroke_width)
:size

legacy_type(kind, key)

@spec legacy_type(atom(), atom()) :: Visualize.Chart.Schema.type() | nil

The type a key had in an earlier version, for a key of a kind node that the current schema no longer has; nil for any other key.

The codec reads a document by the current schema, so a key only an earlier version had would be read untyped and its values left as strings. This is what it reads such a key by instead, so a document from that version is typed before migrate/1 reshapes it (spec/14 §9, #479). Each entry belongs to the step that removed the key: version 1's design-level frame is one :frame node, which the 1 → 2 step moves to frames.main.

iex> Visualize.Chart.Migration.legacy_type(:design, :frame)
{:node, :frame}

iex> Visualize.Chart.Migration.legacy_type(:design, :frames)
nil

migrate(map)

@spec migrate(term()) ::
  {:ok, map()} | {:error, [Visualize.Chart.Validator.error(), ...]}

The design at the current version.

A design already there passes through unchanged; an older one is migrated step by step; a version above current/0 is {:newer_schema, v, current} (spec/14 §9.1), and one below 1, missing or not an integer is an error at [:version] too.

parts(map, kind)

@spec parts(map(), Visualize.Chart.Schema.kind()) :: map()

The styles of a node of kind in their parts and nothing else rewritten (spec/14 §3.1, §9, D-172): what the validator reads, so a design or a fragment written in the flat keys validates as the parts it means, while a text given as parts keeps the paths its faults are reported at.

iex> Visualize.Chart.Migration.parts(%{styles: %{s: %{stroke_width: 2}}}, :design)
%{styles: %{"s" => %{stroke: %{width: 2}}}}

readable(v)

@spec readable(term()) ::
  :ok | {:error, {:newer_schema, pos_integer(), pos_integer()}}

The version gate of spec/14 §9.1 alone: {:error, {:newer_schema, version, current}} for an integer above current/0, else :ok.

It is for a reader that holds a version before it holds a design — a parsed JSON document, a fragment document's "$version", a bundle's provenance — so a newer document is refused before anything of it is read. Any other version is :ok here and left to migrate/1 to judge.

iex> Visualize.Chart.Migration.readable(4)
{:error, {:newer_schema, 4, 3}}

iex> Visualize.Chart.Migration.readable(1)
:ok