-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Do not reflect changes ignored due to :writable in returned struct #4736
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
greg-rychlewski
merged 11 commits into
elixir-ecto:master
from
green-david:dg-fix-ignored-writable-changes-in-struct
Jun 18, 2026
+71
−34
Merged
Changes from 4 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
401efa8
Do not reflect changes ignored due to :writable in returned struct
green-david bfe9ab7
Fix incorrect docs
green-david 58413a6
Ensure that the returned struct from an insert with surfaced changes …
green-david 73fac16
Simplify tests and test that the returned struct values are accurate …
green-david 51183d8
Optimize non-writable field processing
green-david f4bb632
Remove extraneous test assertions
green-david 241b3ee
Special handle non-writable fields in data for insert
green-david f397115
Manipulate changeset within subfunction rather than using update_in
green-david 5f72973
Short-circuit non-writable logic if there are no non-writable fields
green-david 7337183
Restore previous behavior of reflecting surfaced changes in returned …
green-david c74527b
Remove outdated comment
green-david File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -2440,18 +2440,20 @@ defmodule Ecto.RepoTest do | |||||||||||||||||||
| end | ||||||||||||||||||||
|
|
||||||||||||||||||||
| test "update with on_writable_violation: :nothing saves changes for writable: :always and ignores changes for writable: :insert/:never" do | ||||||||||||||||||||
| %MySchemaWritable{id: 1} | ||||||||||||||||||||
| |> Ecto.Changeset.change(%{always: 10, never: 11, insert: 12}) | ||||||||||||||||||||
| |> TestRepo.update() | ||||||||||||||||||||
| %{always: 10, never: nil, insert: nil} = | ||||||||||||||||||||
| %MySchemaWritable{id: 1} | ||||||||||||||||||||
| |> Ecto.Changeset.change(%{always: 10, never: 11, insert: 12}) | ||||||||||||||||||||
| |> TestRepo.update!() | ||||||||||||||||||||
|
|
||||||||||||||||||||
| assert_received {:update, %{changes: [always: 10]}} | ||||||||||||||||||||
| end | ||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
I think this is enough and then you can also make this minimal change to the existing insert test. |
||||||||||||||||||||
|
|
||||||||||||||||||||
| test "update with on_writable_violation: :warn saves changes for writable: :always, ignores changes for writable: :insert/:never, and logs a warning" do | ||||||||||||||||||||
| log = capture_log(fn -> | ||||||||||||||||||||
| %MySchemaWritableWarn{id: 1} | ||||||||||||||||||||
| |> Ecto.Changeset.change(%{always: 10, never: 11, insert: 12}) | ||||||||||||||||||||
| |> TestRepo.update() | ||||||||||||||||||||
| %{always: 10, never: nil, insert: nil} = | ||||||||||||||||||||
| %MySchemaWritableWarn{id: 1} | ||||||||||||||||||||
| |> Ecto.Changeset.change(%{always: 10, never: 11, insert: 12}) | ||||||||||||||||||||
| |> TestRepo.update!() | ||||||||||||||||||||
|
|
||||||||||||||||||||
| assert_received {:update, %{changes: [always: 10]}} | ||||||||||||||||||||
| end) | ||||||||||||||||||||
|
|
@@ -2464,18 +2466,19 @@ defmodule Ecto.RepoTest do | |||||||||||||||||||
| assert_raise ArgumentError, "attempted to write to non-writable field :never during update", fn -> | ||||||||||||||||||||
| %MySchemaWritableRaise{id: 1} | ||||||||||||||||||||
| |> Ecto.Changeset.change(%{never: 10}) | ||||||||||||||||||||
| |> TestRepo.update() | ||||||||||||||||||||
| |> TestRepo.update!() | ||||||||||||||||||||
| end | ||||||||||||||||||||
|
|
||||||||||||||||||||
| assert_raise ArgumentError, "attempted to write to non-writable field :insert during update", fn -> | ||||||||||||||||||||
| %MySchemaWritableRaise{id: 2} | ||||||||||||||||||||
| |> Ecto.Changeset.change(%{insert: 11}) | ||||||||||||||||||||
| |> TestRepo.update() | ||||||||||||||||||||
| |> TestRepo.update!() | ||||||||||||||||||||
| end | ||||||||||||||||||||
|
|
||||||||||||||||||||
| %MySchemaWritableRaise{id: 3} | ||||||||||||||||||||
| |> Ecto.Changeset.change(%{always: 12}) | ||||||||||||||||||||
| |> TestRepo.update() | ||||||||||||||||||||
| %{always: 12, never: nil, insert: nil} = | ||||||||||||||||||||
| %MySchemaWritableRaise{id: 3} | ||||||||||||||||||||
| |> Ecto.Changeset.change(%{always: 12}) | ||||||||||||||||||||
| |> TestRepo.update!() | ||||||||||||||||||||
|
greg-rychlewski marked this conversation as resolved.
Outdated
|
||||||||||||||||||||
|
|
||||||||||||||||||||
| assert_received {:update, %{changes: [always: 12]}} | ||||||||||||||||||||
| end | ||||||||||||||||||||
|
|
@@ -2514,28 +2517,31 @@ defmodule Ecto.RepoTest do | |||||||||||||||||||
| end | ||||||||||||||||||||
|
|
||||||||||||||||||||
| test "insert with surfaced changes on_writable_violation: :nothing saves changes for writable: :always/:insert and ignores changes for writable: :never" do | ||||||||||||||||||||
| %MySchemaWritable{id: 1, always: 10, never: 11, insert: 12} | ||||||||||||||||||||
| |> Ecto.Changeset.change(%{}) | ||||||||||||||||||||
| |> TestRepo.insert() | ||||||||||||||||||||
| %{always: 10, never: nil, insert: 12} = | ||||||||||||||||||||
| %MySchemaWritable{id: 1, always: 10, never: 11, insert: 12} | ||||||||||||||||||||
| |> Ecto.Changeset.change(%{}) | ||||||||||||||||||||
| |> TestRepo.insert!() | ||||||||||||||||||||
|
|
||||||||||||||||||||
| assert_received {:insert, %{fields: inserted_fields}} | ||||||||||||||||||||
| assert Enum.sort(inserted_fields) == [always: 10, id: 1, insert: 12] | ||||||||||||||||||||
| end | ||||||||||||||||||||
|
|
||||||||||||||||||||
| test "insert with on_writable_violation: :nothing saves changes for writable: :always/:insert and ignores changes for writable: :never" do | ||||||||||||||||||||
| %MySchemaWritable{id: 1} | ||||||||||||||||||||
| |> Ecto.Changeset.change(%{always: 10, never: 11, insert: 12}) | ||||||||||||||||||||
| |> TestRepo.insert() | ||||||||||||||||||||
| %{always: 10, never: nil, insert: 12} = | ||||||||||||||||||||
| %MySchemaWritable{id: 1} | ||||||||||||||||||||
| |> Ecto.Changeset.change(%{always: 10, never: 11, insert: 12}) | ||||||||||||||||||||
| |> TestRepo.insert!() | ||||||||||||||||||||
|
|
||||||||||||||||||||
| assert_received {:insert, %{fields: inserted_fields}} | ||||||||||||||||||||
| assert Enum.sort(inserted_fields) == [always: 10, id: 1, insert: 12] | ||||||||||||||||||||
| end | ||||||||||||||||||||
|
|
||||||||||||||||||||
| 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 | ||||||||||||||||||||
| test "insert with surfaced changes and on_writable_violation: :warn saves changes for writable: :always/:insert, ignores changes for writable: :never, and logs a warning" do | ||||||||||||||||||||
| log = capture_log(fn -> | ||||||||||||||||||||
| %MySchemaWritableWarn{id: 1, always: 10, never: 11, insert: 12} | ||||||||||||||||||||
| |> Ecto.Changeset.change(%{}) | ||||||||||||||||||||
| |> TestRepo.insert() | ||||||||||||||||||||
| %{always: 10, never: nil, insert: 12} = | ||||||||||||||||||||
| %MySchemaWritableWarn{id: 1, always: 10, never: 11, insert: 12} | ||||||||||||||||||||
| |> Ecto.Changeset.change(%{}) | ||||||||||||||||||||
| |> TestRepo.insert!() | ||||||||||||||||||||
|
|
||||||||||||||||||||
| assert_received {:insert, %{fields: inserted_fields}} | ||||||||||||||||||||
| assert Enum.sort(inserted_fields) == [always: 10, id: 1, insert: 12] | ||||||||||||||||||||
|
|
@@ -2546,9 +2552,10 @@ defmodule Ecto.RepoTest do | |||||||||||||||||||
|
|
||||||||||||||||||||
| test "insert with on_writable_violation: :warn saves changes for writable: :always/:insert, ignores changes for writable: :never, and logs a warning" do | ||||||||||||||||||||
| log = capture_log(fn -> | ||||||||||||||||||||
| %MySchemaWritableWarn{id: 1} | ||||||||||||||||||||
| |> Ecto.Changeset.change(%{always: 10, never: 11, insert: 12}) | ||||||||||||||||||||
| |> TestRepo.insert() | ||||||||||||||||||||
| %{always: 10, never: nil, insert: 12} = | ||||||||||||||||||||
| %MySchemaWritableWarn{id: 1} | ||||||||||||||||||||
| |> Ecto.Changeset.change(%{always: 10, never: 11, insert: 12}) | ||||||||||||||||||||
| |> TestRepo.insert!() | ||||||||||||||||||||
|
|
||||||||||||||||||||
| assert_received {:insert, %{fields: inserted_fields}} | ||||||||||||||||||||
| assert Enum.sort(inserted_fields) == [always: 10, id: 1, insert: 12] | ||||||||||||||||||||
|
|
@@ -2561,12 +2568,13 @@ defmodule Ecto.RepoTest do | |||||||||||||||||||
| assert_raise ArgumentError, "attempted to write to non-writable field :never during insert", fn -> | ||||||||||||||||||||
| %MySchemaWritableRaise{id: 1, never: 10} | ||||||||||||||||||||
| |> Ecto.Changeset.change(%{}) | ||||||||||||||||||||
| |> TestRepo.insert() | ||||||||||||||||||||
| |> TestRepo.insert!() | ||||||||||||||||||||
| end | ||||||||||||||||||||
|
|
||||||||||||||||||||
| %MySchemaWritableRaise{id: 2, insert: 11, always: 12} | ||||||||||||||||||||
| |> Ecto.Changeset.change(%{}) | ||||||||||||||||||||
| |> TestRepo.insert() | ||||||||||||||||||||
| %{always: 12, never: nil, insert: 11} = | ||||||||||||||||||||
| %MySchemaWritableRaise{id: 2, insert: 11, always: 12} | ||||||||||||||||||||
| |> Ecto.Changeset.change(%{}) | ||||||||||||||||||||
| |> TestRepo.insert!() | ||||||||||||||||||||
|
|
||||||||||||||||||||
| assert_received {:insert, %{fields: inserted_fields}} | ||||||||||||||||||||
| assert Enum.sort(inserted_fields) == [always: 12, id: 2, insert: 11] | ||||||||||||||||||||
|
|
@@ -2576,12 +2584,13 @@ defmodule Ecto.RepoTest do | |||||||||||||||||||
| assert_raise ArgumentError, "attempted to write to non-writable field :never during insert", fn -> | ||||||||||||||||||||
| %MySchemaWritableRaise{id: 1} | ||||||||||||||||||||
| |> Ecto.Changeset.change(%{never: 10}) | ||||||||||||||||||||
| |> TestRepo.insert() | ||||||||||||||||||||
| |> TestRepo.insert!() | ||||||||||||||||||||
| end | ||||||||||||||||||||
|
|
||||||||||||||||||||
| %MySchemaWritableRaise{id: 2} | ||||||||||||||||||||
| |> Ecto.Changeset.change(%{insert: 11, always: 12}) | ||||||||||||||||||||
| |> TestRepo.insert() | ||||||||||||||||||||
| %{always: 12, never: nil, insert: 11} = | ||||||||||||||||||||
|
greg-rychlewski marked this conversation as resolved.
Outdated
|
||||||||||||||||||||
| %MySchemaWritableRaise{id: 2} | ||||||||||||||||||||
| |> Ecto.Changeset.change(%{insert: 11, always: 12}) | ||||||||||||||||||||
| |> TestRepo.insert!() | ||||||||||||||||||||
|
|
||||||||||||||||||||
| assert_received {:insert, %{fields: inserted_fields}} | ||||||||||||||||||||
| assert Enum.sort(inserted_fields) == [always: 12, id: 2, insert: 11] | ||||||||||||||||||||
|
|
||||||||||||||||||||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.