@@ -69,9 +69,10 @@ defmodule Ecto.Repo.Schema do
6969 on_conflict = Keyword . get ( opts , :on_conflict , :raise )
7070 conflict_target = Keyword . get ( opts , :conflict_target , [ ] )
7171 conflict_target = conflict_target ( conflict_target , dumper )
72+ replace_changed? = Keyword . get ( opts , :replace_changed , true )
7273
7374 { on_conflict , conflict_cast_params } =
74- on_conflict ( on_conflict , conflict_target , schema_meta , counter , dumper , adapter )
75+ on_conflict ( on_conflict , conflict_target , replace_changed? , schema_meta , counter , dumper , adapter )
7576
7677 opts =
7778 Keyword . put (
@@ -445,6 +446,7 @@ defmodule Ecto.Repo.Schema do
445446 on_conflict = Keyword . get ( opts , :on_conflict , :raise )
446447 conflict_target = Keyword . get ( opts , :conflict_target , [ ] )
447448 conflict_target = conflict_target ( conflict_target , dumper )
449+ replace_changed? = Keyword . get ( opts , :replace_changed , true )
448450
449451 # On insert, we always merge the whole struct into the
450452 # changeset as changes, except the primary key if it is nil.
@@ -479,6 +481,7 @@ defmodule Ecto.Repo.Schema do
479481 on_conflict (
480482 on_conflict ,
481483 conflict_target ,
484+ replace_changed? ,
482485 schema_meta ,
483486 fn -> length ( dump_changes ) end ,
484487 dumper ,
@@ -889,7 +892,7 @@ defmodule Ecto.Repo.Schema do
889892 end
890893 end
891894
892- defp on_conflict ( on_conflict , conflict_target , schema_meta , counter_fun , dumper , adapter ) do
895+ defp on_conflict ( on_conflict , conflict_target , replace_changed? , schema_meta , counter_fun , dumper , adapter ) do
893896 % { source: source , schema: schema , prefix: prefix } = schema_meta
894897
895898 case on_conflict do
@@ -913,15 +916,15 @@ defmodule Ecto.Repo.Schema do
913916 # Remove the conflict targets from the replacing fields
914917 # since the values don't change and this allows postgres to
915918 # possibly perform a HOT optimization: https://www.postgresql.org/docs/current/storage-hot.html
916- to_remove = List . wrap ( conflict_target )
919+ to_remove = if replace_changed? , do: List . wrap ( conflict_target ) , else: [ ]
917920 replace = replace_all_fields! ( :replace_all , schema , to_remove )
918921
919922 if replace == [ ] , do: raise ( ArgumentError , "empty list of fields to update, use the `:replace` option instead" )
920923
921924 { { replace , [ ] , conflict_target } , [ ] }
922925
923926 { :replace_all_except , fields } ->
924- to_remove = List . wrap ( conflict_target ) ++ fields
927+ to_remove = if replace_changed? , do: List . wrap ( conflict_target ) ++ fields , else: fields
925928 replace = replace_all_fields! ( :replace_all_except , schema , to_remove )
926929
927930 if replace == [ ] , do: raise ( ArgumentError , "empty list of fields to update, use the `:replace` option instead" )
0 commit comments