Skip to content

Commit eea054f

Browse files
committed
address credo warnings
1 parent 0693a57 commit eea054f

2 files changed

Lines changed: 97 additions & 80 deletions

File tree

lib/polymorphic_embed.ex

Lines changed: 94 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
defmodule PolymorphicEmbed do
22
use Ecto.ParameterizedType
33

4+
alias Ecto.Changeset
5+
46
defmacro polymorphic_embeds_one(field_name, opts) do
57
quote do
68
field(unquote(field_name), PolymorphicEmbed, unquote(opts))
@@ -70,28 +72,9 @@ defmodule PolymorphicEmbed do
7072
required = Keyword.get(cast_options, :required, false)
7173
with = Keyword.get(cast_options, :with, nil)
7274

73-
changeset_fun = fn
74-
struct, params when is_nil(with) ->
75-
struct.__struct__.changeset(struct, params)
76-
77-
struct, params when is_list(with) ->
78-
type = do_get_polymorphic_type(struct, types_metadata)
79-
80-
case Keyword.get(with, type) do
81-
{module, function_name, args} ->
82-
apply(module, function_name, [struct, params | args])
75+
changeset_fun = &changeset_fun(&1, &2, with, types_metadata)
8376

84-
nil ->
85-
struct.__struct__.changeset(struct, params)
86-
87-
fun ->
88-
apply(fun, [struct, params])
89-
end
90-
end
91-
92-
(changeset.params || %{})
93-
|> Map.fetch(to_string(field))
94-
|> case do
77+
case Map.fetch(changeset.params || %{}, to_string(field)) do
9578
:error when required ->
9679
if data_for_field = Map.fetch!(changeset.data, field) do
9780
data_for_field = autogenerate_id(data_for_field, changeset.action)
@@ -144,6 +127,25 @@ defmodule PolymorphicEmbed do
144127
raise "cast_polymorphic_embed/3 only accepts a changeset as first argument"
145128
end
146129

130+
defp changeset_fun(struct, params, with, types_metadata) when is_list(with) do
131+
type = do_get_polymorphic_type(struct, types_metadata)
132+
133+
case Keyword.get(with, type) do
134+
{module, function_name, args} ->
135+
apply(module, function_name, [struct, params | args])
136+
137+
nil ->
138+
struct.__struct__.changeset(struct, params)
139+
140+
fun ->
141+
apply(fun, [struct, params])
142+
end
143+
end
144+
145+
defp changeset_fun(struct, params, nil, _) do
146+
struct.__struct__.changeset(struct, params)
147+
end
148+
147149
defp cast_polymorphic_embeds_one(changeset, field, changeset_fun, params, field_options) do
148150
%{
149151
types_metadata: types_metadata,
@@ -155,27 +157,8 @@ defmodule PolymorphicEmbed do
155157

156158
# We support partial update of the embed. If the type cannot be inferred from the parameters, or if the found type
157159
# hasn't changed, pass the data to the changeset.
158-
action_and_struct =
159-
case do_get_polymorphic_module_from_map(params, type_field, types_metadata) do
160-
nil ->
161-
if data_for_field do
162-
{:update, data_for_field}
163-
else
164-
:type_not_found
165-
end
166-
167-
module when is_nil(data_for_field) ->
168-
{:insert, struct(module)}
169160

170-
module ->
171-
if data_for_field.__struct__ != module do
172-
{:insert, struct(module)}
173-
else
174-
{:update, data_for_field}
175-
end
176-
end
177-
178-
case action_and_struct do
161+
case action_and_struct(params, type_field, types_metadata, data_for_field) do
179162
:type_not_found when on_type_not_found == :raise ->
180163
raise_cannot_infer_type_from_data(params)
181164

@@ -203,6 +186,27 @@ defmodule PolymorphicEmbed do
203186
end
204187
end
205188

189+
defp action_and_struct(params, type_field, types_metadata, data_for_field) do
190+
case do_get_polymorphic_module_from_map(params, type_field, types_metadata) do
191+
nil ->
192+
if data_for_field do
193+
{:update, data_for_field}
194+
else
195+
:type_not_found
196+
end
197+
198+
module when is_nil(data_for_field) ->
199+
{:insert, struct(module)}
200+
201+
module ->
202+
if data_for_field.__struct__ != module do
203+
{:insert, struct(module)}
204+
else
205+
{:update, data_for_field}
206+
end
207+
end
208+
end
209+
206210
defp cast_polymorphic_embeds_many(changeset, field, changeset_fun, list_params, field_options) do
207211
%{
208212
types_metadata: types_metadata,
@@ -225,16 +229,7 @@ defmodule PolymorphicEmbed do
225229
module ->
226230
embed_changeset = changeset_fun.(struct(module), params)
227231
embed_changeset = %{embed_changeset | action: :insert}
228-
229-
case embed_changeset do
230-
%{valid?: true} = embed_changeset ->
231-
embed_changeset
232-
|> Ecto.Changeset.apply_changes()
233-
|> autogenerate_id(embed_changeset.action)
234-
235-
%{valid?: false} = embed_changeset ->
236-
embed_changeset
237-
end
232+
maybe_apply_changes(embed_changeset)
238233
end
239234
end)
240235

@@ -259,6 +254,14 @@ defmodule PolymorphicEmbed do
259254
end
260255
end
261256

257+
defp maybe_apply_changes(%{valid?: true} = embed_changeset) do
258+
embed_changeset
259+
|> Ecto.Changeset.apply_changes()
260+
|> autogenerate_id(embed_changeset.action)
261+
end
262+
263+
defp maybe_apply_changes(%Changeset{valid?: false} = changeset), do: changeset
264+
262265
@impl true
263266
def cast(_data, _params),
264267
do:
@@ -393,7 +396,7 @@ defmodule PolymorphicEmbed do
393396
schema.__schema__(:type, field)
394397
rescue
395398
_ in UndefinedFunctionError ->
396-
raise ArgumentError, "#{inspect(schema)} is not an Ecto schema"
399+
reraise ArgumentError, "#{inspect(schema)} is not an Ecto schema", __STACKTRACE__
397400
else
398401
{:parameterized, PolymorphicEmbed, options} -> Map.put(options, :array?, false)
399402
{:array, {:parameterized, PolymorphicEmbed, options}} -> Map.put(options, :array?, true)
@@ -438,38 +441,49 @@ defmodule PolymorphicEmbed do
438441
end
439442

440443
defp merge_polymorphic_keys(map, changes, types, msg_func) do
441-
Enum.reduce(types, map, fn
442-
{field, {:parameterized, PolymorphicEmbed, _opts}}, acc ->
443-
if changeset = Map.get(changes, field) do
444-
case traverse_errors(changeset, msg_func) do
445-
errors when errors == %{} -> acc
446-
errors -> Map.put(acc, field, errors)
447-
end
448-
else
449-
acc
450-
end
444+
Enum.reduce(types, map, &polymorphic_key_reducer(&1, &2, changes, msg_func))
445+
end
451446

452-
{field, {:array, {:parameterized, PolymorphicEmbed, _opts}}}, acc ->
453-
if changesets = Map.get(changes, field) do
454-
{errors, all_empty?} =
455-
Enum.map_reduce(changesets, true, fn changeset, all_empty? ->
456-
errors = traverse_errors(changeset, msg_func)
457-
{errors, all_empty? and errors == %{}}
458-
end)
459-
460-
case all_empty? do
461-
true -> acc
462-
false -> Map.put(acc, field, errors)
463-
end
464-
else
465-
acc
466-
end
447+
defp polymorphic_key_reducer(
448+
{field, {:parameterized, PolymorphicEmbed, _opts}},
449+
acc,
450+
changes,
451+
msg_func
452+
) do
453+
if changeset = Map.get(changes, field) do
454+
case traverse_errors(changeset, msg_func) do
455+
errors when errors == %{} -> acc
456+
errors -> Map.put(acc, field, errors)
457+
end
458+
else
459+
acc
460+
end
461+
end
467462

468-
{_, _}, acc ->
469-
acc
470-
end)
463+
defp polymorphic_key_reducer(
464+
{field, {:array, {:parameterized, PolymorphicEmbed, _opts}}},
465+
acc,
466+
changes,
467+
msg_func
468+
) do
469+
if changesets = Map.get(changes, field) do
470+
{errors, all_empty?} =
471+
Enum.map_reduce(changesets, true, fn changeset, all_empty? ->
472+
errors = traverse_errors(changeset, msg_func)
473+
{errors, all_empty? and errors == %{}}
474+
end)
475+
476+
case all_empty? do
477+
true -> acc
478+
false -> Map.put(acc, field, errors)
479+
end
480+
else
481+
acc
482+
end
471483
end
472484

485+
defp polymorphic_key_reducer({_, _}, acc, _, _), do: acc
486+
473487
defp autogenerate_id([], _action), do: []
474488

475489
defp autogenerate_id([schema | rest], action) do

lib/polymorphic_embed/html/form.ex

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
if Code.ensure_loaded?(Phoenix.HTML) && Code.ensure_loaded?(Phoenix.HTML.Form) &&
22
Code.ensure_loaded?(PhoenixHTMLHelpers.Form) do
33
defmodule PolymorphicEmbed.HTML.Form do
4+
@moduledoc """
5+
Defines functions for using PolymorphicEmbed with `Phoenix.HTML.Form`.
6+
"""
47
import Phoenix.HTML, only: [html_escape: 1]
58
import Phoenix.HTML.Form, only: [input_value: 2]
69
import PhoenixHTMLHelpers.Form, only: [hidden_inputs_for: 1]

0 commit comments

Comments
 (0)