Skip to content
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

Apply irrelevant changes caused by touch #140

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lib/activerecord-bitemporal/bitemporal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,10 @@ def _update_row(attribute_names, attempted_action = 'update')
self.transaction_from = after_instance.transaction_from
self.transaction_to = after_instance.transaction_to

if attempted_action == 'touch'
@_touch_attr_names += Set.new(['valid_from', 'valid_to', 'transaction_from', 'transaction_to'])
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Append to an instance variable used by ActiveRecord::AttributeMethods::Dirty#_touch_row.
https://github.com/rails/rails/blob/v7.0.6/activerecord/lib/active_record/attribute_methods/dirty.rb#L187

This is probably not a good approach, but it's the only way to write out to the saved_changes at once with minimal changes.

end

1
# MEMO: Must return false instead of nil, if `#_update_row` failure.
end || false
Expand Down
41 changes: 38 additions & 3 deletions spec/activerecord-bitemporal/bitemporal_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,13 @@
it {
is_expected.to have_attributes(
bitemporal_id: subject.id,
# changes: be_empty,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps the expected is be_empty, but unfortunately that is not the case at this time. This will be fixed in another PR.

previous_changes: include(
"id" => [nil, subject.swapped_id],
"valid_from" => [nil, be_present],
"valid_to" => [nil, "2019/10/01".in_time_zone],
"transaction_from" => [nil, be_present],
"transaction_to" => [nil, ActiveRecord::Bitemporal::DEFAULT_TRANSACTION_TO],
"name" => [nil, "Tom"]
)
)
Expand All @@ -42,10 +45,13 @@
it {
is_expected.to have_attributes(
bitemporal_id: subject.id,
changes: be_empty,
previous_changes: include(
"id" => [nil, subject.id],
"valid_from" => [nil, be_present],
"valid_to" => [nil, ActiveRecord::Bitemporal::DEFAULT_VALID_TO],
"transaction_from" => [nil, be_present],
"transaction_to" => [nil, ActiveRecord::Bitemporal::DEFAULT_TRANSACTION_TO],
"name" => [nil, "Tom"]
),
previously_force_updated?: false
Expand Down Expand Up @@ -654,7 +660,7 @@ def self.bitemporal_id_key
let(:from) { time_current }
let(:to) { from + 10.days }
let(:finish) { Time.utc(9999, 12, 31).in_time_zone }
let!(:employee) { Employee.create!(name: "Jone", valid_from: from, valid_to: to) }
let!(:employee) { Timecop.freeze(from - 1.month) { Employee.create!(name: "Jone", valid_from: from, valid_to: to) } }
let!(:swapped_id) { employee.swapped_id }
let(:count) { -> { Employee.where(bitemporal_id: employee.id).ignore_valid_datetime.count } }
let(:old_jone) { Employee.ignore_valid_datetime.within_deleted.find_by(bitemporal_id: employee.id, name: "Jone") }
Expand Down Expand Up @@ -684,6 +690,13 @@ def self.bitemporal_id_key
let(:now) { from + 5.days }
it { expect { subject }.to change(&count).by(1) }
it { expect { subject }.to change(employee, :name).from("Jone").to("Tom") }
it { expect { subject }.to change(employee, :valid_from).from(from).to(now) }
it { expect { subject }.not_to change(employee, :valid_to) }
it { expect { subject }.to change(employee, :transaction_from).to(now) }
it { expect { subject }.not_to change(employee, :transaction_to) }
it { expect(employee.changes).to be_empty }
it { expect { subject }.not_to change(employee, :changes) }
it { expect { subject }.to change { employee.saved_changes.keys }.to(contain_exactly("name", "valid_from", "transaction_from", "updated_at")) }
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_behaves_like "updated Jone" do
Expand All @@ -707,6 +720,13 @@ def self.bitemporal_id_key
let(:now) { from - 5.days }
it { expect { subject }.to change(&count).by(1) }
it { expect { subject }.to change(employee, :name).from("Jone").to("Tom") }
it { expect { subject }.to change(employee, :valid_from).from(from).to(now) }
it { expect { subject }.to change(employee, :valid_to).from(to).to(from) }
it { expect { subject }.to change(employee, :transaction_from).to(now) }
it { expect { subject }.not_to change(employee, :transaction_to) }
it { expect(employee.changes).to be_empty }
it { expect { subject }.not_to change(employee, :changes) }
it { expect { subject }.to change { employee.saved_changes.keys }.to contain_exactly("name", "valid_from", "valid_to", "transaction_from", "updated_at") }
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_behaves_like "updated Jone" do
Expand Down Expand Up @@ -1052,6 +1072,8 @@ class EmployeeWithUniquness < Employee
it { expect { subject }.to change { Employee.ignore_valid_datetime.within_deleted.count }.by(1) }
it { expect { subject }.to change(employee, :swapped_id).from(@swapped_id_before_destroy).to(kind_of(Integer)) }
it { expect { subject }.to change(employee, :swapped_id_previously_was).from(kind_of(Integer)).to(@swapped_id_before_destroy) }
xit { expect { subject }.to change(employee, :changes).to(be_empty) }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps the expected is be_empty, but unfortunately that is not the case at this time. This will be fixed in another PR.

it { expect { subject }.not_to change(employee, :saved_changes) }
it { expect(subject).to eq employee }

it do
Expand Down Expand Up @@ -1223,14 +1245,27 @@ class EmployeeWithUniquness < Employee
end

describe "#touch" do
let!(:employee) { Employee.create(name: "Jane").tap { |it| it.update!(name: "Tom") } }
let!(:employee) { Timecop.freeze(created_time) { Employee.create(name: "Tom") } }
let(:employee_count) { -> { Employee.ignore_valid_datetime.bitemporal_for(employee.id).count } }
subject { employee.touch(:archived_at) }
let(:created_time) { time_current - 10.seconds }
let(:touched_time) { time_current - 5.seconds }
subject { Timecop.freeze(touched_time) { employee.touch(:archived_at) } }

before { @swapped_id_before_touch = employee.swapped_id }

it { expect(employee).to have_attributes(name: "Tom", id: employee.id) }
it { expect(subject).to eq true }
it { expect { subject }.to change(&employee_count).by(1) }
it { expect { subject }.to change { employee.reload.archived_at }.from(nil) }
it { expect { subject }.to change(employee, :valid_from).from(created_time).to(touched_time) }
it { expect { subject }.not_to change(employee, :valid_to) }
it { expect { subject }.to change(employee, :transaction_from).from(created_time).to(touched_time) }
it { expect { subject }.not_to change(employee, :transaction_to) }
it { expect { subject }.to change(employee, :swapped_id).from(@swapped_id_before_touch).to(kind_of(Integer)) }
it { expect { subject }.to change(employee, :swapped_id_previously_was).from(nil).to(@swapped_id_before_touch) }
it { expect(employee.changes).to be_empty }
it { expect { subject }.not_to change(employee, :changes) }
it { expect { subject }.to change { employee.saved_changes.keys }.to(contain_exactly("archived_at", "valid_from", "transaction_from", "updated_at")) }
end

describe "validation" do
Expand Down