Skip to content

Commit 16670ce

Browse files
committed
Simplify :on_writable_violation handling
1 parent 3e33f42 commit 16670ce

3 files changed

Lines changed: 32 additions & 24 deletions

File tree

lib/ecto/repo/schema.ex

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@ defmodule Ecto.Repo.Schema do
434434
struct = struct_from_changeset!(:insert, changeset)
435435
schema = struct.__struct__
436436
dumper = schema.__schema__(:dump)
437-
{insertable_fields, non_insertable} = schema.__schema__(:insertable)
437+
{keep_fields, drop_fields} = schema.__schema__(:insertable_fields)
438438
assocs = schema.__schema__(:associations)
439439
embeds = schema.__schema__(:embeds)
440440

@@ -452,8 +452,8 @@ defmodule Ecto.Repo.Schema do
452452
# On insert, we always merge the whole struct into the
453453
# changeset as changes, except the primary key if it is nil.
454454
changeset = put_repo_and_action(changeset, :insert, repo, tuplet)
455-
changeset = Relation.surface_changes(changeset, struct, insertable_fields ++ assocs)
456-
changeset = update_in(changeset.changes, &drop_non_writable_changes!(&1, non_insertable, :insert))
455+
changeset = Relation.surface_changes(changeset, struct, keep_fields ++ assocs)
456+
changeset = update_in(changeset.changes, &drop_non_writable_changes!(&1, drop_fields, schema, :insert))
457457

458458
wrap_in_transaction(adapter, adapter_meta, opts, changeset, assocs, embeds, prepare, fn ->
459459
assoc_opts = assoc_opts(assocs, opts)
@@ -472,7 +472,7 @@ defmodule Ecto.Repo.Schema do
472472
{changes, cast_extra, dump_extra, return_types, return_sources} =
473473
autogenerate_id(autogen_id, changes, return_types, return_sources, adapter)
474474

475-
changes = Map.take(changes, insertable_fields)
475+
changes = Map.take(changes, keep_fields)
476476
autogen = autogenerate_changes(schema, :insert, changes)
477477

478478
dump_changes =
@@ -544,7 +544,7 @@ defmodule Ecto.Repo.Schema do
544544
struct = struct_from_changeset!(:update, changeset)
545545
schema = struct.__struct__
546546
dumper = schema.__schema__(:dump)
547-
{updatable_fields, non_updatable} = schema.__schema__(:updatable)
547+
{keep_fields, drop_fields} = schema.__schema__(:updatable_fields)
548548
assocs = schema.__schema__(:associations)
549549
embeds = schema.__schema__(:embeds)
550550

@@ -561,7 +561,7 @@ defmodule Ecto.Repo.Schema do
561561
# fields into the changeset. All changes must be in the
562562
# changeset before hand.
563563
changeset = put_repo_and_action(changeset, :update, repo, tuplet)
564-
changeset = update_in(changeset.changes, &drop_non_writable_changes!(&1, non_updatable, :update))
564+
changeset = update_in(changeset.changes, &drop_non_writable_changes!(&1, drop_fields, schema, :update))
565565

566566
if changeset.changes != %{} or force? do
567567
wrap_in_transaction(adapter, adapter_meta, opts, changeset, assocs, embeds, prepare, fn ->
@@ -576,7 +576,7 @@ defmodule Ecto.Repo.Schema do
576576
if changeset.valid? do
577577
embeds = Ecto.Embedded.prepare(changeset, embeds, adapter, :update)
578578

579-
changes = changeset.changes |> Map.merge(embeds) |> Map.take(updatable_fields)
579+
changes = changeset.changes |> Map.merge(embeds) |> Map.take(keep_fields)
580580
autogen = autogenerate_changes(schema, :update, changes)
581581
dump_changes = dump_changes!(:update, changes, autogen, schema, [], dumper, adapter)
582582

@@ -625,20 +625,22 @@ defmodule Ecto.Repo.Schema do
625625
{:error, put_repo_and_action(changeset, :update, repo, tuplet)}
626626
end
627627

628-
defp drop_non_writable_changes!(changes, non_writable, action) do
629-
Enum.reduce(non_writable, changes, fn {name, on_writable_violation}, changes ->
630-
case Map.pop(changes, name) do
628+
defp drop_non_writable_changes!(changes, non_writable_fields, schema, action) do
629+
Enum.reduce(non_writable_fields, changes, fn field, changes ->
630+
case Map.pop(changes, field) do
631631
{nil, changes} ->
632632
changes
633633
{_change, changes} ->
634-
handle_writable_violation(name, on_writable_violation, action)
634+
handle_writable_violation(field, schema, action)
635635
changes
636636
end
637637
end)
638638
end
639639

640-
defp handle_writable_violation(name, on_writable_violation, action) do
641-
message = "attempted to write to non-writable field #{inspect(name)} during #{action}"
640+
defp handle_writable_violation(field, schema, action) do
641+
on_writable_violation = schema.__schema__(:on_writable_violation)[field]
642+
643+
message = "attempted to write to non-writable field #{inspect(field)} during #{action}"
642644

643645
case on_writable_violation do
644646
:raise ->
@@ -990,7 +992,7 @@ defmodule Ecto.Repo.Schema do
990992
end
991993

992994
defp replace_all_fields!(_kind, schema, to_remove) do
993-
{updatable_fields, _} = schema.__schema__(:updatable)
995+
{updatable_fields, _} = schema.__schema__(:updatable_fields)
994996
Enum.map(updatable_fields -- to_remove, &field_source!(schema, &1))
995997
end
996998

lib/ecto/schema.ex

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2439,30 +2439,36 @@ defmodule Ecto.Schema do
24392439
embed_names = Enum.map(embeds, &elem(&1, 0))
24402440

24412441
updatable =
2442-
for {name, {_, {writable, on_writable_violation}}} <- fields, reduce: {[], []} do
2442+
for {name, {_, {writable, _on_writable_violation}}} <- fields, reduce: {[], []} do
24432443
{keep, drop} ->
24442444
case writable do
24452445
:always -> {[name | keep], drop}
2446-
_ -> {keep, [{name, on_writable_violation} | drop]}
2446+
_ -> {keep, [name | drop]}
24472447
end
24482448
end
24492449

24502450
insertable =
2451-
for {name, {_, {writable, on_writable_violation}}} <- fields, reduce: {[], []} do
2451+
for {name, {_, {writable, _on_writable_violation}}} <- fields, reduce: {[], []} do
24522452
{keep, drop} ->
24532453
case writable do
2454-
:never -> {keep, [{name, on_writable_violation} | drop]}
2454+
:never -> {keep, [name | drop]}
24552455
_ -> {[name | keep], drop}
24562456
end
24572457
end
24582458

2459+
on_writable_violation =
2460+
for {name, {_, {_writable, on_writable_violation}}} <- fields do
2461+
{name, on_writable_violation}
2462+
end
2463+
24592464
single_arg = [
24602465
{[:dump], dump |> Map.new() |> Macro.escape()},
24612466
{[:load], load |> Macro.escape()},
24622467
{[:associations], assoc_names},
24632468
{[:embeds], embed_names},
2464-
{[:updatable], updatable},
2465-
{[:insertable], insertable},
2469+
{[:updatable_fields], updatable},
2470+
{[:insertable_fields], insertable},
2471+
{[:on_writable_violation], on_writable_violation |> Map.new() |> Macro.escape()},
24662472
{[:redact_fields], redacted_fields},
24672473
{[:autogenerate_fields], Enum.flat_map(autogenerate, &elem(&1, 0))},
24682474
{[:virtual_fields], Enum.map(virtual_fields, &elem(&1, 0))},

test/ecto/schema_test.exs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ defmodule Ecto.SchemaTest do
4141
:comment_id
4242
]
4343

44-
assert Schema.__schema__(:insertable) ==
44+
assert Schema.__schema__(:insertable_fields) ==
4545
{[
4646
:comment_id,
4747
:non_updatable,
@@ -53,11 +53,11 @@ defmodule Ecto.SchemaTest do
5353
:email,
5454
:name,
5555
:id
56-
], [{:unwritable, :nothing}]}
56+
], [:unwritable]}
5757

58-
assert Schema.__schema__(:updatable) ==
58+
assert Schema.__schema__(:updatable_fields) ==
5959
{[:comment_id, :no_query_load, :uuid, :array, :count, :password, :email, :name, :id],
60-
[{:non_updatable, :nothing}, {:unwritable, :nothing}]}
60+
[:non_updatable, :unwritable]}
6161

6262
assert Schema.__schema__(:virtual_fields) == [:temp]
6363

0 commit comments

Comments
 (0)