Packages
zoi
0.5.0
0.18.6
0.18.5
0.18.4
0.18.3
0.18.2
0.18.1
0.18.0
0.17.4
0.17.3
0.17.2
0.17.1
0.17.0
0.16.1
0.16.0
0.15.0
0.14.1
0.14.0
0.13.1
0.13.0
0.12.1
0.12.0
0.11.1
0.11.0
0.10.7
0.10.6
0.10.5
0.10.4
0.10.3
0.10.2
0.10.1
0.10.0
0.9.1
0.9.0
0.9.0-rc.1
0.9.0-rc.0
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.6
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.0
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.3
0.2.2
0.2.1
0.2.0
0.1.3
0.1.2
0.1.1
0.1.0
Zoi is a schema validation library for Elixir, designed to provide a simple and flexible way to define and validate data.
Current section
74 Versions
Jump to
Current section
74 Versions
Compare versions
11
files changed
+202
additions
-53
deletions
| @@ -2,6 +2,20 @@ | |
| 2 2 | |
| 3 3 | All notable changes to this project will be documented in this file. |
| 4 4 | |
| 5 | + ## Unreleased |
| 6 | + |
| 7 | + ### Added |
| 8 | + |
| 9 | + - `Zoi.atom/1` type |
| 10 | + - `Zoi.string_boolean/1` type |
| 11 | + - `Zoi.union/2` custom error messages |
| 12 | + - `Zoi.intersection/2` custom error messages |
| 13 | + - `Zoi.to_struct/2` transform |
| 14 | + |
| 15 | + ### Changed |
| 16 | + |
| 17 | + - `Zoi.boolean/1` does not coerce values besides "true" and "false" anymore. For coercion of other values, use `Zoi.string_boolean/1` type. |
| 18 | + |
| 5 19 | ## 0.4.0 - 2025-08-14 |
| 6 20 | |
| 7 21 | ### Added |
| @@ -118,16 +132,16 @@ Zoi.object(schema, %{"name" => "John", "age" => 30}, coerce: true) | |
| 118 132 | |
| 119 133 | ### Changed |
| 120 134 | |
| 121 | - - `number/2` now returns proper error message |
| 135 | + - `Zoi.number/2` now returns proper error message |
| 122 136 | |
| 123 137 | ## 0.2.0 - 2025-08-05 |
| 124 138 | |
| 125 139 | ### Added |
| 126 140 | |
| 127 | - - `mfa` to `refine` and `transform` functions |
| 128 | - - accumulator errors to `refine` and `transform` functions |
| 129 | - - `array` type |
| 130 | - - `length`, `min` and `max` validators for arrays |
| 141 | + - `mfa` to `Zoi.refine/2` and `Zoi.transform/2` functions |
| 142 | + - accumulator errors to `Zoi.refine/2` and `Zoi.transform/2` functions |
| 143 | + - `Zoi.array/2` type |
| 144 | + - `Zoi.length/2`, `Zoi.min/2` and `Zoi.max/2` validators for arrays |
| 131 145 | |
| 132 146 | ### Changed |
| @@ -15,7 +15,7 @@ | |
| 15 15 | ```elixir |
| 16 16 | def deps do |
| 17 17 | [ |
| 18 | - {:zoi, "~> 0.4"} |
| 18 | + {:zoi, "~> 0.5"} |
| 19 19 | ] |
| 20 20 | end |
| 21 21 | ``` |
| @@ -2,7 +2,7 @@ | |
| 2 2 | [{<<"Changelog">>,<<"https://hexdocs.pm/zoi/changelog.html">>}, |
| 3 3 | {<<"GitHub">>,<<"https://github.com/phcurado/zoi">>}]}. |
| 4 4 | {<<"name">>,<<"zoi">>}. |
| 5 | - {<<"version">>,<<"0.4.0">>}. |
| 5 | + {<<"version">>,<<"0.5.0">>}. |
| 6 6 | {<<"description">>, |
| 7 7 | <<"Zoi is a schema validation library for Elixir, designed to provide a simple and flexible way to define and validate data.">>}. |
| 8 8 | {<<"elixir">>,<<"~> 1.14">>}. |
| @@ -10,24 +10,25 @@ | |
| 10 10 | {<<"licenses">>,[<<"Apache-2.0">>]}. |
| 11 11 | {<<"files">>, |
| 12 12 | [<<".formatter.exs">>,<<"lib">>,<<"lib/zoi.ex">>,<<"lib/zoi">>, |
| 13 | - <<"lib/zoi/iso">>,<<"lib/zoi/iso/time.ex">>,<<"lib/zoi/iso/date.ex">>, |
| 13 | + <<"lib/zoi/error.ex">>,<<"lib/zoi/regexes.ex">>,<<"lib/zoi/iso">>, |
| 14 14 | <<"lib/zoi/iso/naive_datetime.ex">>,<<"lib/zoi/iso/datetime.ex">>, |
| 15 | - <<"lib/zoi/error.ex">>,<<"lib/zoi/refinements.ex">>,<<"lib/zoi/type">>, |
| 16 | - <<"lib/zoi/type/def.ex">>,<<"lib/zoi/types">>,<<"lib/zoi/types/time.ex">>, |
| 17 | - <<"lib/zoi/types/integer.ex">>,<<"lib/zoi/types/default.ex">>, |
| 18 | - <<"lib/zoi/types/date.ex">>,<<"lib/zoi/types/intersection.ex">>, |
| 19 | - <<"lib/zoi/types/decimal.ex">>,<<"lib/zoi/types/number.ex">>, |
| 20 | - <<"lib/zoi/types/nullable.ex">>,<<"lib/zoi/types/object.ex">>, |
| 21 | - <<"lib/zoi/types/naive_datetime.ex">>,<<"lib/zoi/types/optional.ex">>, |
| 22 | - <<"lib/zoi/types/tuple.ex">>,<<"lib/zoi/types/float.ex">>, |
| 23 | - <<"lib/zoi/types/string.ex">>,<<"lib/zoi/types/map.ex">>, |
| 24 | - <<"lib/zoi/types/boolean.ex">>,<<"lib/zoi/types/enum.ex">>, |
| 25 | - <<"lib/zoi/types/array.ex">>,<<"lib/zoi/types/datetime.ex">>, |
| 26 | - <<"lib/zoi/types/union.ex">>,<<"lib/zoi/types/meta.ex">>, |
| 27 | - <<"lib/zoi/types/any.ex">>,<<"lib/zoi/iso.ex">>,<<"lib/zoi/type.ex">>, |
| 28 | - <<"lib/zoi/context.ex">>,<<"lib/zoi/regexes.ex">>,<<"lib/zoi/errors.ex">>, |
| 29 | - <<"lib/zoi/transforms.ex">>,<<"mix.exs">>,<<"README.md">>, |
| 30 | - <<"CHANGELOG.md">>]}. |
| 15 | + <<"lib/zoi/iso/date.ex">>,<<"lib/zoi/iso/time.ex">>,<<"lib/zoi/type.ex">>, |
| 16 | + <<"lib/zoi/context.ex">>,<<"lib/zoi/refinements.ex">>,<<"lib/zoi/types">>, |
| 17 | + <<"lib/zoi/types/string.ex">>,<<"lib/zoi/types/atom.ex">>, |
| 18 | + <<"lib/zoi/types/enum.ex">>,<<"lib/zoi/types/default.ex">>, |
| 19 | + <<"lib/zoi/types/any.ex">>,<<"lib/zoi/types/nullable.ex">>, |
| 20 | + <<"lib/zoi/types/decimal.ex">>,<<"lib/zoi/types/object.ex">>, |
| 21 | + <<"lib/zoi/types/array.ex">>,<<"lib/zoi/types/integer.ex">>, |
| 22 | + <<"lib/zoi/types/float.ex">>,<<"lib/zoi/types/tuple.ex">>, |
| 23 | + <<"lib/zoi/types/naive_datetime.ex">>,<<"lib/zoi/types/boolean.ex">>, |
| 24 | + <<"lib/zoi/types/meta.ex">>,<<"lib/zoi/types/datetime.ex">>, |
| 25 | + <<"lib/zoi/types/map.ex">>,<<"lib/zoi/types/string_boolean.ex">>, |
| 26 | + <<"lib/zoi/types/optional.ex">>,<<"lib/zoi/types/date.ex">>, |
| 27 | + <<"lib/zoi/types/intersection.ex">>,<<"lib/zoi/types/time.ex">>, |
| 28 | + <<"lib/zoi/types/number.ex">>,<<"lib/zoi/types/union.ex">>, |
| 29 | + <<"lib/zoi/iso.ex">>,<<"lib/zoi/type">>,<<"lib/zoi/type/def.ex">>, |
| 30 | + <<"lib/zoi/errors.ex">>,<<"lib/zoi/transforms.ex">>,<<"mix.exs">>, |
| 31 | + <<"README.md">>,<<"CHANGELOG.md">>]}. |
| 31 32 | {<<"requirements">>, |
| 32 33 | [[{<<"name">>,<<"decimal">>}, |
| 33 34 | {<<"app">>,<<"decimal">>}, |
| @@ -176,6 +176,44 @@ defmodule Zoi do | |
| 176 176 | @doc group: "Basic Types" |
| 177 177 | defdelegate boolean(opts \\ []), to: Zoi.Types.Boolean, as: :new |
| 178 178 | |
| 179 | + @doc """ |
| 180 | + Defines a string boolean type schema. |
| 181 | + |
| 182 | + This type parses "boolish" string values: |
| 183 | + # thruthy values: true, "true", "1", "yes", "on", "y", "enabled" |
| 184 | + # falsy values: false, "false", "0", "no", "off", "n", "disabled" |
| 185 | + |
| 186 | + |
| 187 | + ## Example |
| 188 | + |
| 189 | + iex> schema = Zoi.string_boolean() |
| 190 | + iex> Zoi.parse(schema, "true") |
| 191 | + {:ok, true} |
| 192 | + iex> Zoi.parse(schema, "false") |
| 193 | + {:ok, false} |
| 194 | + iex> Zoi.parse(schema, "yes") |
| 195 | + {:ok, true} |
| 196 | + iex> Zoi.parse(schema, "no") |
| 197 | + {:ok, false} |
| 198 | + |
| 199 | + You can also specify custom truthy and falsy values using the `:truthy` and `:falsy` options: |
| 200 | + iex> schema = Zoi.string_boolean(truthy: ["yes", "y"], falsy: ["no", "n"]) |
| 201 | + iex> Zoi.parse(schema, "yes") |
| 202 | + {:ok, true} |
| 203 | + iex> Zoi.parse(schema, "no") |
| 204 | + {:ok, false} |
| 205 | + |
| 206 | + By default the string boolean type is case insensitive and the input is converted to lowercase during the comparison. You can change this behavior using the `:case` option: |
| 207 | + |
| 208 | + iex> schema = Zoi.string_boolean(case: "sensitive") |
| 209 | + iex> Zoi.parse(schema, "True") |
| 210 | + {:error, [%Zoi.Error{message: "invalid type: must be a string boolean"}]} |
| 211 | + iex> Zoi.parse(schema, "true") |
| 212 | + {:ok, true} |
| 213 | + """ |
| 214 | + @doc group: "Basic Types" |
| 215 | + defdelegate string_boolean(opts \\ []), to: Zoi.Types.StringBoolean, as: :new |
| 216 | + |
| 179 217 | @doc """ |
| 180 218 | Defines a schema that accepts any type of input. |
| 181 219 | |
| @@ -194,6 +232,19 @@ defmodule Zoi do | |
| 194 232 | @doc group: "Basic Types" |
| 195 233 | defdelegate any(opts \\ []), to: Zoi.Types.Any, as: :new |
| 196 234 | |
| 235 | + @doc """ |
| 236 | + Defines an atom type schema. |
| 237 | + |
| 238 | + ## Examples |
| 239 | + iex> schema = Zoi.atom() |
| 240 | + iex> Zoi.parse(schema, :atom) |
| 241 | + {:ok, :atom} |
| 242 | + iex> Zoi.parse(schema, "not_an_atom") |
| 243 | + {:error, [%Zoi.Error{message: "invalid type: must be an atom"}]} |
| 244 | + """ |
| 245 | + @doc group: "Basic Types" |
| 246 | + defdelegate atom(opts \\ []), to: Zoi.Types.Atom, as: :new |
| 247 | + |
| 197 248 | @doc """ |
| 198 249 | Makes the schema optional for the `Zoi.object/2` type. |
| 199 250 | |
| @@ -901,6 +952,32 @@ defmodule Zoi do | |
| 901 952 | |> transform({Zoi.Transforms, :transform, [[:to_upcase]]}) |
| 902 953 | end |
| 903 954 | |
| 955 | + @doc """ |
| 956 | + Converts a schema to a struct of the given module. |
| 957 | + This is useful for transforming parsed data into a specific struct type. |
| 958 | + |
| 959 | + ## Example |
| 960 | + |
| 961 | + defmodule User do |
| 962 | + defstruct [:name, :age] |
| 963 | + end |
| 964 | + |
| 965 | + schema = Zoi.object(%{ |
| 966 | + name: Zoi.string() |> Zoi.required(), |
| 967 | + age: Zoi.integer() |> Zoi.required() |
| 968 | + }) |
| 969 | + |> Zoi.to_struct(User) |
| 970 | + |
| 971 | + Zoi.parse(schema, %{name: "Alice", age: 30}) |
| 972 | + #=> {:ok, %User{name: "Alice", age: 30}} |
| 973 | + """ |
| 974 | + @doc group: "Transforms" |
| 975 | + @spec to_struct(schema :: Zoi.Type.t(), struct :: module()) :: Zoi.Type.t() |
| 976 | + def to_struct(schema, module) do |
| 977 | + schema |
| 978 | + |> transform({Zoi.Transforms, :transform, [[struct: module]]}) |
| 979 | + end |
| 980 | + |
| 904 981 | @doc ~S""" |
| 905 982 | Adds a custom validation function to the schema. |
| @@ -17,6 +17,10 @@ defmodule Zoi.Transforms do | |
| 17 17 | String.upcase(input) |
| 18 18 | end |
| 19 19 | |
| 20 | + defp do_transform(%Zoi.Types.Object{}, input, [struct: struct], _opts) do |
| 21 | + struct!(struct, input) |
| 22 | + end |
| 23 | + |
| 20 24 | defp do_transform(_schema, input, _args, _opts) do |
| 21 25 | # Default to the input if there is no type pattern match |
| 22 26 | {:ok, input} |
Loading more files…