Skip to content

Commit

Permalink
feat: add defaults to schemas (#120)
Browse files Browse the repository at this point in the history
  • Loading branch information
laraujo7 authored Dec 10, 2024
1 parent a31f0f8 commit d6e0c54
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 3 deletions.
18 changes: 15 additions & 3 deletions lib/goal.ex
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,9 @@ defmodule Goal do
Returns the validated parameters or an error changeset.
"""
@spec validate(Ecto.Changeset.t()) :: {:ok, map()} | {:error, Ecto.Changeset.t()}
def validate(%Changeset{valid?: true, changes: changes}), do: {:ok, changes}
def validate(%Changeset{valid?: true} = changeset),
do: {:ok, Changeset.apply_changes(changeset)}

def validate(%Changeset{valid?: false} = changeset), do: {:error, changeset}

@doc """
Expand Down Expand Up @@ -660,7 +662,7 @@ defmodule Goal do
|> build_changeset(params)
|> Map.put(:action, :validate)
|> case do
%Changeset{valid?: true, changes: changes} -> {:ok, changes}
%Changeset{valid?: true} = changes -> {:ok, Changeset.apply_changes(changes)}
%Changeset{valid?: false} = changeset -> {:error, changeset}
end
end
Expand All @@ -680,8 +682,9 @@ defmodule Goal do
@spec build_changeset(schema(), params()) :: Changeset.t()
def build_changeset(schema, params) do
types = get_types(schema)
defaults = build_defaults(schema)

{%{}, types}
{defaults, types}
|> Changeset.cast(params, Map.keys(types), force_changes: true)
|> validate_required_fields(schema)
|> validate_basic_fields(schema)
Expand Down Expand Up @@ -793,6 +796,15 @@ defmodule Goal do
end)
end

defp build_defaults(schema) do
Enum.reduce(schema, %{}, fn {field, rules}, acc ->
case Keyword.get(rules, :default) do
nil -> acc
default -> Map.put_new(acc, field, default)
end
end)
end

defp validate_required_fields(%Changeset{} = changeset, schema) do
required_fields =
Enum.reduce(schema, [], fn {field, rules}, acc ->
Expand Down
32 changes: 32 additions & 0 deletions test/goal_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ defmodule GoalTest do
optional(:status, :enum, values: @statuses)
end

defparams :defaults do
required(:status, :enum, values: @statuses, default: :pending)
optional(:name, :string, default: "The one who shall not be named")
end

describe "__using__/1" do
test "schema/0" do
assert schema() == %{id: [type: :integer, required: true]}
Expand Down Expand Up @@ -292,6 +297,14 @@ defmodule GoalTest do
fields2: %{"hello" => "world"},
fields4: [%{"bye" => "world"}]
}}

assert validate(:defaults, %{}) == {
:ok,
%{status: :pending, name: "The one who shall not be named"}
}

assert validate(:defaults, %{status: :done, name: "Voldemort"}) ==
{:ok, %{status: :done, name: "Voldemort"}}
end
end

Expand Down Expand Up @@ -344,6 +357,12 @@ defmodule GoalTest do

assert Goal.validate_params(schema, params, opts) == {:ok, %{}}
end

test "includes default value when one is not provider" do
schema = %{name: [type: :string, default: "Harry Potter"]}

assert Goal.validate_params(schema, %{}) == {:ok, %{name: "Harry Potter"}}
end
end

describe "build_changeset/2" do
Expand Down Expand Up @@ -948,6 +967,19 @@ defmodule GoalTest do
assert errors_on(changeset_4) == %{status: ["is invalid"]}
end

test "default" do
schema = %{
status: [type: :enum, values: [:active, :inactive], default: :active, required: true],
name: [type: :string]
}

data_5 = %{}

changeset_5 = Goal.build_changeset(schema, data_5)

assert data_on(changeset_5) == %{status: :active}
end

test "enum, string-based" do
schema = %{status: [type: :enum, values: ["active", "inactive"]]}

Expand Down
2 changes: 2 additions & 0 deletions test/test_helper.exs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ defmodule Goal.Helpers do
end)
end)
end

def data_on(%Ecto.Changeset{data: data}), do: data
end

defmodule Goal.DemoSchema do
Expand Down

0 comments on commit d6e0c54

Please sign in to comment.