From ca269d58a850edbfaebcbc105263c42be571074f Mon Sep 17 00:00:00 2001 From: wata727 Date: Fri, 28 Jul 2023 18:52:56 +0900 Subject: [PATCH] Add `previously_force_updated?` --- lib/activerecord-bitemporal.rb | 6 +++++ lib/activerecord-bitemporal/bitemporal.rb | 8 ++++++- .../bitemporal_spec.rb | 23 ++++++++++++++++++- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/lib/activerecord-bitemporal.rb b/lib/activerecord-bitemporal.rb index c812c56..6e98a32 100644 --- a/lib/activerecord-bitemporal.rb +++ b/lib/activerecord-bitemporal.rb @@ -104,6 +104,10 @@ def id_in_database swapped_id.presence || super end + def previously_force_updated? + @previously_force_updated + end + def valid_from_cannot_be_greater_equal_than_valid_to if valid_from && valid_to && valid_from >= valid_to errors.add(:valid_from, "can't be greater equal than valid_to") @@ -141,10 +145,12 @@ def bitemporalize( # MEMO: #update_columns is not call #_update_row (and validations, callbacks) update_columns(bitemporal_id_key => swapped_id) unless send(bitemporal_id_key) swap_id!(without_clear_changes_information: true) + @previously_force_updated = false end after_find do self.swap_id! if self.send(bitemporal_id_key).present? + @previously_force_updated = false end # Callback hook to `validates :xxx, uniqueness: true` diff --git a/lib/activerecord-bitemporal/bitemporal.rb b/lib/activerecord-bitemporal/bitemporal.rb index 8c15447..f7d5898 100644 --- a/lib/activerecord-bitemporal/bitemporal.rb +++ b/lib/activerecord-bitemporal/bitemporal.rb @@ -277,12 +277,13 @@ def update_transaction_to(value) end refine ActiveRecord::Base do - # MEMO: Do not copy `swapped_id` + # MEMO: Do not copy bitemporal internal status def dup(*) super.tap { |itself| itself.instance_exec do @_swapped_id_previously_was = nil @_swapped_id = nil + @previously_force_updated = false end unless itself.frozen? } end @@ -320,6 +321,7 @@ def _update_row(attribute_names, attempted_action = 'update') before_instance&.save_without_bitemporal_callbacks!(validate: false) # NOTE: after_instance always exists after_instance.save_without_bitemporal_callbacks!(validate: false) + @previously_force_updated = self.force_update? # update 後に新しく生成したインスタンスのデータを移行する @_swapped_id_previously_was = swapped_id @@ -345,6 +347,7 @@ def destroy(force_delete: false, operated_at: Time.current) @destroyed = false _run_destroy_callbacks { @destroyed = update_transaction_to(operated_at) + @previously_force_updated = force_update? # force_update の場合は削除時の状態の履歴を残さない unless force_update? @@ -397,6 +400,7 @@ def reload(options = nil) # NOTE: Hook to copying swapped_id @_swapped_id_previously_was = nil @_swapped_id = fresh_object.swapped_id + @previously_force_updated = false self end elsif Gem::Version.new("6.1.0") <= ActiveRecord.version @@ -420,6 +424,7 @@ def reload(options = nil) # NOTE: Hook to copying swapped_id @_swapped_id_previously_was = nil @_swapped_id = fresh_object.swapped_id + @previously_force_updated = false self end else @@ -442,6 +447,7 @@ def reload(options = nil) # NOTE: Hook to copying swapped_id @_swapped_id_previously_was = nil @_swapped_id = fresh_object.swapped_id + @previously_force_updated = false self end end diff --git a/spec/activerecord-bitemporal/bitemporal_spec.rb b/spec/activerecord-bitemporal/bitemporal_spec.rb index 113dfc3..1e8f88b 100644 --- a/spec/activerecord-bitemporal/bitemporal_spec.rb +++ b/spec/activerecord-bitemporal/bitemporal_spec.rb @@ -47,7 +47,8 @@ "valid_from" => [nil, be_present], "valid_to" => [nil, ActiveRecord::Bitemporal::DEFAULT_VALID_TO], "name" => [nil, "Tom"] - ) + ), + previously_force_updated?: false ) } end @@ -918,6 +919,7 @@ def employee.wrapped_name it { expect { subject }.not_to change(employee, :id) } it { expect { subject }.to change(employee, :swapped_id).from(swapped_id).to(kind_of(Integer)) } it { expect { subject }.to change(employee, :swapped_id_previously_was).from(nil).to(swapped_id) } + it { expect { subject }.to change(employee, :previously_force_updated?).from(false).to(true) } context "with `#valid_at`" do let!(:employee) { Timecop.freeze("2019/1/1") { Employee.create!(name: "Jane") } } @@ -1215,6 +1217,7 @@ class EmployeeWithUniquness < Employee it { expect { subject }.not_to change { Employee.ignore_valid_datetime.within_deleted.count } } it { expect { subject }.not_to change(employee, :swapped_id) } it { expect { subject }.not_to change(employee, :swapped_id_previously_was) } + it { expect { subject }.to change(employee, :previously_force_updated?).from(false).to(true) } it { expect(subject).to eq employee } end end @@ -2723,6 +2726,24 @@ class EmployeeWithUniquness < Employee end end + describe "#previously_force_updated?" do + let(:employee) { Employee.create!(name: "Jone") } + + it "sets previously_force_updated after find" do + expect(Employee.find(employee.id)).not_to be_previously_force_updated + end + + it "reverts the previously_force_updated after updating" do + employee.force_update { |e| e.update!(name: "Tom") } + expect { employee.update!(name: "Kevin") }.to change(employee, :previously_force_updated?).from(true).to(false) + end + + it "reverts the previously_force_updated after reloading" do + employee.force_update { |e| e.update!(name: "Tom") } + expect { employee.reload }.to change(employee, :previously_force_updated?).from(true).to(false) + end + end + describe "ActiveRecord" do context "[Bug fix] https://github.com/rails/rails/pull/38583 in Rails 5.x" do it { expect { Employee.where(Arel.sql("name").eq("Tom")).except_bitemporal_default_scope.to_sql }.not_to raise_error }