Skip to content

Commit 7cb27b3

Browse files
committed
Compile on_writable_violation map into multiple clauses
1 parent 0ff27f8 commit 7cb27b3

3 files changed

Lines changed: 26 additions & 9 deletions

File tree

lib/ecto/repo/schema.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -638,7 +638,7 @@ defmodule Ecto.Repo.Schema do
638638
end
639639

640640
defp handle_writable_violation(field, schema, action) do
641-
on_writable_violation = schema.__schema__(:on_writable_violation)[field]
641+
on_writable_violation = schema.__schema__(:on_writable_violation, field)
642642

643643
message = "attempted to write to non-writable field #{inspect(field)} during #{action}"
644644

lib/ecto/schema.ex

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2028,9 +2028,7 @@ defmodule Ecto.Schema do
20282028
writable = opts[:writable] || :always
20292029
put_struct_field(mod, name, Keyword.get(opts, :default))
20302030

2031-
on_writable_violation = Keyword.get_lazy(opts, :on_writable_violation, fn ->
2032-
Module.get_attribute(mod, :on_writable_violation, :nothing)
2033-
end)
2031+
on_writable_violation = Keyword.get(opts, :on_writable_violation)
20342032

20352033
redact_field? =
20362034
Keyword.get_lazy(opts, :redact, fn ->
@@ -2086,7 +2084,9 @@ defmodule Ecto.Schema do
20862084
raise ArgumentError, "autogenerated fields must always be writable"
20872085
end
20882086

2089-
Module.put_attribute(mod, :ecto_on_writable_violation, {name, on_writable_violation})
2087+
if on_writable_violation do
2088+
Module.put_attribute(mod, :ecto_on_writable_violation, {name, on_writable_violation})
2089+
end
20902090

20912091
if pk? do
20922092
Module.put_attribute(mod, :ecto_primary_keys, name)
@@ -2387,6 +2387,7 @@ defmodule Ecto.Schema do
23872387
read_after_writes = Module.get_attribute(module, :ecto_raw) |> Enum.reverse()
23882388
autogenerate_id = Module.get_attribute(module, :ecto_autogenerate_id)
23892389
on_writable_violation = Module.get_attribute(module, :ecto_on_writable_violation)
2390+
on_writable_violation_default = Module.get_attribute(module, :on_writable_violation, :nothing)
23902391

23912392
struct_fields = Module.get_attribute(module, :ecto_struct_fields) |> Enum.reverse()
23922393
derive = Module.get_attribute(module, :derive)
@@ -2470,7 +2471,6 @@ defmodule Ecto.Schema do
24702471
{[:embeds], embed_names},
24712472
{[:updatable_fields], updatable},
24722473
{[:insertable_fields], insertable},
2473-
{[:on_writable_violation], on_writable_violation |> Map.new() |> Macro.escape()},
24742474
{[:redact_fields], redacted_fields},
24752475
{[:autogenerate_fields], Enum.flat_map(autogenerate, &elem(&1, 0))},
24762476
{[:virtual_fields], Enum.map(virtual_fields, &elem(&1, 0))},
@@ -2490,12 +2490,19 @@ defmodule Ecto.Schema do
24902490
{[:type, quote(do: _)], nil},
24912491
{[:virtual_type, quote(do: _)], nil},
24922492
{[:association, quote(do: _)], nil},
2493-
{[:embed, quote(do: _)], nil}
2493+
{[:embed, quote(do: _)], nil},
2494+
{[:on_writable_violation, quote(do: _)], on_writable_violation_default}
24942495
]
24952496

2497+
on_writable_violation_quoted =
2498+
for {name, value} <- on_writable_violation do
2499+
{[:on_writable_violation, name], value}
2500+
end
2501+
24962502
bags_of_clauses =
24972503
[
24982504
single_arg,
2505+
on_writable_violation_quoted,
24992506
field_sources_quoted,
25002507
types_quoted,
25012508
virtual_types_quoted,

test/ecto/schema_test.exs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -542,11 +542,21 @@ defmodule Ecto.SchemaTest do
542542
end
543543

544544
test "schema with @on_writable_violation defaults :on_writable_violation" do
545-
%{a: :raise, b: :raise, c: :nothing, d: :warn} = SchemaWithOnWritableViolation.__schema__(:on_writable_violation)
545+
assert SchemaWithOnWritableViolation.__schema__(:on_writable_violation, :a) == :raise
546+
assert SchemaWithOnWritableViolation.__schema__(:on_writable_violation, :b) == :raise
547+
assert SchemaWithOnWritableViolation.__schema__(:on_writable_violation, :c) == :nothing
548+
assert SchemaWithOnWritableViolation.__schema__(:on_writable_violation, :d) == :warn
549+
assert SchemaWithOnWritableViolation.__schema__(:on_writable_violation, :unknown) == :raise
546550
end
547551

548552
test "schema without @on_writable_violation uses the field-level default (:nothing)" do
549-
%{a: :nothing, b: :nothing, c: :warn, d: :raise} = SchemaWithoutOnWritableViolation.__schema__(:on_writable_violation)
553+
assert SchemaWithoutOnWritableViolation.__schema__(:on_writable_violation, :a) == :nothing
554+
assert SchemaWithoutOnWritableViolation.__schema__(:on_writable_violation, :b) == :nothing
555+
assert SchemaWithoutOnWritableViolation.__schema__(:on_writable_violation, :c) == :warn
556+
assert SchemaWithoutOnWritableViolation.__schema__(:on_writable_violation, :d) == :raise
557+
558+
assert SchemaWithoutOnWritableViolation.__schema__(:on_writable_violation, :unknown) ==
559+
:nothing
550560
end
551561

552562
## Errors

0 commit comments

Comments
 (0)