defmodule Manganese.CoreKit.Structs.Version do @moduledoc """ A SemVer version. ## Deserialization *See `from_string/1`* ## Serialization The version struct implements the `String.Chars` protocol. ## Manipulation - see `increment/2` """ alias Manganese.CoreKit.Structs alias Manganese.CoreKit.Enumerations @typedoc """ """ @type t :: %Structs.Version{ major: non_neg_integer, minor: non_neg_integer, patch: non_neg_integer } defstruct [ major: 0, minor: 0, patch: 0 ] # Deserialization @doc """ """ @spec from_string(String.t) :: t def from_string(string) do components = String.split(string, ".") |> Enum.map(&Integer.parse/1) [ major, minor, patch ] = components %Structs.Version{ major: major, minor: minor, patch: patch } end # Serialization @type t_external :: String.t # Manipulation @doc """ """ @spec increment(t, Enumerations.VersionType.t) :: t def increment(version, version_type \\ :patch) do case version_type do :major -> %Structs.Version{ major: version.major + 1 } :minor -> %Structs.Version{ major: version.major, minor: version.minor + 1 } :patch -> %Structs.Version{ major: version.major, minor: version.minor, patch: version.patch + 1 } end end # Ecto type @behaviour Ecto.Type @doc """ The PostgreSQL type used to represent a version. """ @spec type :: :string def type, do: :string @doc false def cast(%Structs.Version{} = version) do { :ok, version } end @doc false def cast(string) when is_binary(string) do { :ok, from_string string } end @doc false def cast(nil) do { :ok, nil } end @doc false def cast(_), do: :error @doc false def load(string) when is_binary(string) do { :ok, from_string string } end @doc false def dump(%Structs.Version{} = version) do { :ok, to_string version } end end defimpl String.Chars, for: Manganese.CoreKit.Structs.Version do def to_string(version) do "#{version.major}.#{version.minor}.#{version.patch}" end end