@@ -3,6 +3,7 @@ defmodule Ecto.RepoTest do
33
44 import Ecto.Query
55 import Ecto , only: [ put_meta: 2 ]
6+ import ExUnit.CaptureLog
67 alias Ecto.TestRepo
78
89 defmodule MyParent do
@@ -181,6 +182,26 @@ defmodule Ecto.RepoTest do
181182 end
182183 end
183184
185+ defmodule MySchemaWritableWarn do
186+ use Ecto.Schema
187+
188+ schema "my_schema" do
189+ field :never , :integer , writable: :never , on_writable_violation: :warn
190+ field :always , :integer , writable: :always
191+ field :insert , :integer , writable: :insert , on_writable_violation: :warn
192+ end
193+ end
194+
195+ defmodule MySchemaWritableRaise do
196+ use Ecto.Schema
197+
198+ schema "my_schema" do
199+ field :never , :integer , writable: :never , on_writable_violation: :raise
200+ field :always , :integer , writable: :always
201+ field :insert , :integer , writable: :insert , on_writable_violation: :raise
202+ end
203+ end
204+
184205 defmodule MySchemaOneField do
185206 use Ecto.Schema
186207
@@ -2418,14 +2439,47 @@ defmodule Ecto.RepoTest do
24182439 ]
24192440 end
24202441
2421- test "update only saves changes for writable: :always" do
2442+ test "update with on_writable_violation: :nothing saves changes for writable: :always and ignores changes for writable: :insert/:never " do
24222443 % MySchemaWritable { id: 1 }
24232444 |> Ecto.Changeset . change ( % { always: 10 , never: 11 , insert: 12 } )
24242445 |> TestRepo . update ( )
24252446
24262447 assert_received { :update , % { changes: [ always: 10 ] } }
24272448 end
24282449
2450+ test "update with on_writable_violation: :warn saves changes for writable: :always, ignores changes for writable: :insert/:never, and logs a warning" do
2451+ log = capture_log ( fn ->
2452+ % MySchemaWritableWarn { id: 1 }
2453+ |> Ecto.Changeset . change ( % { always: 10 , never: 11 , insert: 12 } )
2454+ |> TestRepo . update ( )
2455+
2456+ assert_received { :update , % { changes: [ always: 10 ] } }
2457+ end )
2458+
2459+ assert log =~ "attempted to write to non-writable field :insert during update"
2460+ assert log =~ "attempted to write to non-writable field :never during update"
2461+ end
2462+
2463+ test "update with on_writable_violation: :raise saves changes for writable: :always and raises for changes for writable: :insert/:never" do
2464+ assert_raise ArgumentError , "attempted to write to non-writable field :never during update" , fn ->
2465+ % MySchemaWritableRaise { id: 1 }
2466+ |> Ecto.Changeset . change ( % { never: 10 } )
2467+ |> TestRepo . update ( )
2468+ end
2469+
2470+ assert_raise ArgumentError , "attempted to write to non-writable field :insert during update" , fn ->
2471+ % MySchemaWritableRaise { id: 2 }
2472+ |> Ecto.Changeset . change ( % { insert: 11 } )
2473+ |> TestRepo . update ( )
2474+ end
2475+
2476+ % MySchemaWritableRaise { id: 3 }
2477+ |> Ecto.Changeset . change ( % { always: 12 } )
2478+ |> TestRepo . update ( )
2479+
2480+ assert_received { :update , % { changes: [ always: 12 ] } }
2481+ end
2482+
24292483 test "update is a no-op when updatable fields are not changed" do
24302484 % MySchemaWritable { id: 1 }
24312485 |> Ecto.Changeset . change ( % { never: "can't update" , insert: "can't update either" } )
@@ -2459,7 +2513,16 @@ defmodule Ecto.RepoTest do
24592513 end
24602514 end
24612515
2462- test "insert only saves changes for writable: :always/:insert" do
2516+ test "insert with surfaced changes on_writable_violation: :nothing saves changes for writable: :always/:insert and ignores changes for writable: :never" do
2517+ % MySchemaWritable { id: 1 , always: 10 , never: 11 , insert: 12 }
2518+ |> Ecto.Changeset . change ( % { } )
2519+ |> TestRepo . insert ( )
2520+
2521+ assert_received { :insert , % { fields: inserted_fields } }
2522+ assert Enum . sort ( inserted_fields ) == [ always: 10 , id: 1 , insert: 12 ]
2523+ end
2524+
2525+ test "insert with on_writable_violation: :nothing saves changes for writable: :always/:insert and ignores changes for writable: :never" do
24632526 % MySchemaWritable { id: 1 }
24642527 |> Ecto.Changeset . change ( % { always: 10 , never: 11 , insert: 12 } )
24652528 |> TestRepo . insert ( )
@@ -2468,6 +2531,62 @@ defmodule Ecto.RepoTest do
24682531 assert Enum . sort ( inserted_fields ) == [ always: 10 , id: 1 , insert: 12 ]
24692532 end
24702533
2534+ test "insert with with surfaced changes and on_writable_violation: :warn saves changes for writable: :always/:insert, ignores changes for writable: :never, and logs a warning" do
2535+ log = capture_log ( fn ->
2536+ % MySchemaWritableWarn { id: 1 , always: 10 , never: 11 , insert: 12 }
2537+ |> Ecto.Changeset . change ( % { } )
2538+ |> TestRepo . insert ( )
2539+
2540+ assert_received { :insert , % { fields: inserted_fields } }
2541+ assert Enum . sort ( inserted_fields ) == [ always: 10 , id: 1 , insert: 12 ]
2542+ end )
2543+
2544+ assert log =~ "attempted to write to non-writable field :never during insert"
2545+ end
2546+
2547+ test "insert with on_writable_violation: :warn saves changes for writable: :always/:insert, ignores changes for writable: :never, and logs a warning" do
2548+ log = capture_log ( fn ->
2549+ % MySchemaWritableWarn { id: 1 }
2550+ |> Ecto.Changeset . change ( % { always: 10 , never: 11 , insert: 12 } )
2551+ |> TestRepo . insert ( )
2552+
2553+ assert_received { :insert , % { fields: inserted_fields } }
2554+ assert Enum . sort ( inserted_fields ) == [ always: 10 , id: 1 , insert: 12 ]
2555+ end )
2556+
2557+ assert log =~ "attempted to write to non-writable field :never during insert"
2558+ end
2559+
2560+ test "insert with surfaced changes and on_writable_violation: :raise saves changes for writable: :always/:insert and raises for changes for writable: :never" do
2561+ assert_raise ArgumentError , "attempted to write to non-writable field :never during insert" , fn ->
2562+ % MySchemaWritableRaise { id: 1 , never: 10 }
2563+ |> Ecto.Changeset . change ( % { } )
2564+ |> TestRepo . insert ( )
2565+ end
2566+
2567+ % MySchemaWritableRaise { id: 2 , insert: 11 , always: 12 }
2568+ |> Ecto.Changeset . change ( % { } )
2569+ |> TestRepo . insert ( )
2570+
2571+ assert_received { :insert , % { fields: inserted_fields } }
2572+ assert Enum . sort ( inserted_fields ) == [ always: 12 , id: 2 , insert: 11 ]
2573+ end
2574+
2575+ test "insert with on_writable_violation: :raise saves changes for writable: :always/:insert and raises for changes for writable: :never" do
2576+ assert_raise ArgumentError , "attempted to write to non-writable field :never during insert" , fn ->
2577+ % MySchemaWritableRaise { id: 1 }
2578+ |> Ecto.Changeset . change ( % { never: 10 } )
2579+ |> TestRepo . insert ( )
2580+ end
2581+
2582+ % MySchemaWritableRaise { id: 2 }
2583+ |> Ecto.Changeset . change ( % { insert: 11 , always: 12 } )
2584+ |> TestRepo . insert ( )
2585+
2586+ assert_received { :insert , % { fields: inserted_fields } }
2587+ assert Enum . sort ( inserted_fields ) == [ always: 12 , id: 2 , insert: 11 ]
2588+ end
2589+
24712590 test "insert with returning" do
24722591 % MySchemaWritable { id: 1 }
24732592 |> Ecto.Changeset . change ( % { always: 10 , never: 11 , insert: 12 } )
0 commit comments