Skip to content

Commit

Permalink
add some good stuff!
Browse files Browse the repository at this point in the history
  • Loading branch information
andrepiske committed Dec 17, 2024
1 parent f17f043 commit 72fa3ad
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 16 deletions.
4 changes: 4 additions & 0 deletions lib/iron_trail/change_model_concern.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ def reify
Reifier.reify(self)
end

def insert_operation? = (operation == 'i')
def update_operation? = (operation == 'u')
def delete_operation? = (operation == 'd')

module ClassMethods
def where_object_changes_to(args = {})
_where_object_changes(1, args)
Expand Down
26 changes: 20 additions & 6 deletions lib/iron_trail/reifier.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
module IronTrail
module Reifier
def self.reify(trail)
klass = model_from_table_name(trail.rec_table)
source_attributes = (trail.delete_operation? ? trail.rec_old : trail.rec_new)
klass = model_from_table_name(trail.rec_table, source_attributes['type'])

record = klass.where(id: trail.rec_id).first || klass.new
source_attributes = (trail.operation == 'd' ? trail.rec_old : trail.rec_new)

source_attributes.each do |name, value|
if record.has_attribute?(name)
Expand All @@ -26,13 +26,27 @@ def self.reify(trail)
record
end

def self.model_from_table_name(table_name)
# TODO: this won't work with STI models.
index = ActiveRecord::Base.descendants.reject(&:abstract_class).index_by(&:table_name)
def self.model_from_table_name(table_name, sti_type=nil)
index = ActiveRecord::Base.descendants.reject(&:abstract_class).chunk(&:table_name).to_h do |key, val|
v = \
if val.length == 1
val[0]
else
val.to_h { |k| [k.to_s, k] }
end

[key, v]
end

klass = index[table_name]
raise "Cannot infer model from table named '#{table_name}'" unless klass

klass
return klass unless klass.is_a?(Hash)
klass = klass[sti_type]

return klass if klass

raise "Cannot infer STI model for table #{table_name} and type '#{sti_type}'"
end
end
end
4 changes: 4 additions & 0 deletions spec/dummy_app/app/models/irontrail_change.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@ class IrontrailChange < ApplicationRecord
include IronTrail::ChangeModelConcern

range_partition_by { :created_at }

scope :inserts, -> { where(operation: 'i') }
scope :updates, -> { where(operation: 'u') }
scope :deletes, -> { where(operation: 'd') }
end
1 change: 1 addition & 0 deletions spec/dummy_app/app/models/matrix_pill.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@

# An STI model
class MatrixPill < ApplicationRecord
include IronTrail::Model
end
8 changes: 2 additions & 6 deletions spec/dummy_app/app/services/morpheus.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,8 @@
class Morpheus
def just_like_in_the_movie
{
red: RedPill.create!,
blue: PillBlue.create!
red: RedPill.create!(pill_size: 10),
blue: PillBlue.create!(pill_size: 11)
}
end

def guitar_hero
end

end
32 changes: 32 additions & 0 deletions spec/models/guitar_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,38 @@
RSpec.describe Guitar do
let(:person) { Person.create!(first_name: 'Arthur', last_name: 'Schopenhauer') }

describe 'IronTrail::ChangeModelConcern' do
describe 'helper methods' do
before do
person.update!(first_name: 'Joe')
person.update!(first_name: 'Joey')
person.destroy!
end

it 'correctly classifies operations' do
expect(person.iron_trails.length).to eq(4)
expect(person.iron_trails.inserts.length).to eq(1)
expect(person.iron_trails.updates.length).to eq(2)
expect(person.iron_trails.deletes.length).to eq(1)

expect(person.iron_trails.inserts[0].insert_operation?).to be(true)
expect(person.iron_trails.inserts[0].update_operation?).to be(false)
expect(person.iron_trails.inserts[0].delete_operation?).to be(false)

expect(person.iron_trails.updates[0].insert_operation?).to be(false)
expect(person.iron_trails.updates[0].update_operation?).to be(true)
expect(person.iron_trails.updates[0].delete_operation?).to be(false)
expect(person.iron_trails.updates[1].insert_operation?).to be(false)
expect(person.iron_trails.updates[1].update_operation?).to be(true)
expect(person.iron_trails.updates[1].delete_operation?).to be(false)

expect(person.iron_trails.deletes[0].insert_operation?).to be(false)
expect(person.iron_trails.deletes[0].update_operation?).to be(false)
expect(person.iron_trails.deletes[0].delete_operation?).to be(true)
end
end
end

describe 'iron_trails.version_at' do
let(:guitar) { Guitar.create!(description: 'the guitar', person:) }

Expand Down
33 changes: 29 additions & 4 deletions spec/services/morpheus_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,37 @@

RSpec.describe Morpheus do
subject(:instance) { described_class.new }
subject(:pills) { instance.just_like_in_the_movie }

describe '#just_like_in_the_movie' do
xit 'offers two pills' do
3.times { described_class.new.just_like_in_the_movie }
it 'has the type attribute serialized' do
red = pills[:red]

pills = described_class.new.just_like_in_the_movie
red.update!(pill_size: 44)
trails = red.reload.iron_trails.order(id: :asc)

expect(trails.length).to eq(2)
expect(trails[0].rec_new['type']).to eq('RedPill')
expect(trails[1].rec_new['type']).to eq('RedPill')
end

describe 'object morphing' do
it 'morphs colors' do
blue = pills[:blue]
pills[:red].destroy!

blue.update!(pill_size: 15)
blue.update!(pill_size: 25)

trail = blue.iron_trails.where_object_changes_to(pill_size: 15).first
trail.rec_new['type'] = 'RedPill' # likely invalid case in the real world, but good for testing.
trail.save!
blue.reload

red = blue.iron_trails.where_object_changes_to(pill_size: 15).first.reify
expect(red).to be_a(RedPill)

blue_again = blue.iron_trails.where_object_changes_to(pill_size: 25).first.reify
expect(blue_again).to be_a(PillBlue)
end
end
end

0 comments on commit 72fa3ad

Please sign in to comment.