diff --git a/app/models/fragment.rb b/app/models/fragment.rb index bd22935..35785c6 100644 --- a/app/models/fragment.rb +++ b/app/models/fragment.rb @@ -11,7 +11,7 @@ class Fragment < ApplicationRecord validates :descendent_rank, presence: true, numericality: { only_integer: true } def previous_fragment - Fragment.find_by(document: document, parent: parent, level: level, rank: rank - 1) + Fragment.where(document: document, level: level, rank: -Float::INFINITY...rank).order(:rank).last end def previous_range(stop_fragment) @@ -21,7 +21,7 @@ def previous_range(stop_fragment) end def next_fragment - Fragment.find_by(document: document, parent: parent, level: level, rank: rank + 1) + Fragment.where(document: document, level: level, rank: (rank + 1)..Float::INFINITY).order(:rank).first end def next_range(stop_fragment) @@ -31,7 +31,7 @@ def next_range(stop_fragment) end def first_fragment - Fragment.where(document: document, parent: parent, level: level).order(:rank).first + Fragment.where(document: document, level: level).order(:rank).first end def first_range(stop_fragment) @@ -41,7 +41,7 @@ def first_range(stop_fragment) end def last_fragment - Fragment.where(document: document, parent: parent, level: level).order(:rank).last + Fragment.where(document: document, level: level).order(:rank).last end def last_range(stop_fragment) diff --git a/spec/models/fragment_spec.rb b/spec/models/fragment_spec.rb index f7a1726..8a611cb 100644 --- a/spec/models/fragment_spec.rb +++ b/spec/models/fragment_spec.rb @@ -28,4 +28,216 @@ it { should validate_uniqueness_of(:ref).scoped_to(:document_id) } it { should validate_uniqueness_of(:rank).scoped_to(:document_id) } end + + describe 'navigation methods' do + let!(:collection) do + Collection.create(urn: 'urn', title: 'title', display_type: 'resource', cite_structure: %w[book chapter]) + end + let!(:document) { Document.create(urn: 'urn', xml: '', collection: collection) } + + let!(:parent1) do + Fragment.create( + ref: 'p1', + xml: '', + level: 1, + rank: 1, + descendent_rank: 4, + document: document, + ) + end + let!(:child11) do + Fragment.create( + ref: 'c11', + xml: '', + level: 2, + rank: 2, + descendent_rank: 2, + parent: parent1, + document: document, + ) + end + let!(:child12) do + Fragment.create( + ref: 'c12', + xml: '', + level: 2, + rank: 3, + descendent_rank: 3, + parent: parent1, + document: document, + ) + end + let!(:child13) do + Fragment.create( + ref: 'c13', + xml: '', + level: 2, + rank: 4, + descendent_rank: 4, + parent: parent1, + document: document, + ) + end + + let!(:parent2) do + Fragment.create(ref: 'p2', xml: '', level: 1, rank: 5, descendent_rank: 8, document: document) + end + let!(:child21) do + Fragment.create( + ref: 'c21', + xml: '', + level: 2, + rank: 6, + descendent_rank: 6, + parent: parent2, + document: document, + ) + end + let!(:child22) do + Fragment.create( + ref: 'c22', + xml: '', + level: 2, + rank: 7, + descendent_rank: 7, + parent: parent2, + document: document, + ) + end + let!(:child23) do + Fragment.create( + ref: 'c23', + xml: '', + level: 2, + rank: 8, + descendent_rank: 8, + parent: parent2, + document: document, + ) + end + + let!(:parent3) do + Fragment.create(ref: 'p3', xml: '', level: 1, rank: 9, descendent_rank: 9, document: document) + end + + describe '#previous_fragment' do + it 'gets the previous passage of a parent fragment' do + expect(parent2.previous_fragment).to eq(parent1) + end + + it 'returns nil if there is no previous passage' do + expect(parent1.previous_fragment).to be_nil + end + + it 'gets the previous passage of a child fragment' do + expect(child12.previous_fragment).to eq(child11) + end + + it 'gets the last fragment of the previous parent' do + expect(child21.previous_fragment).to eq(child13) + end + end + + describe '#previous_range' do + it 'gets the previous range of a parent fragment' do + expect(parent3.previous_range(parent3)).to eq([parent2, parent2]) + end + + it 'is empty if there is no previous range' do + expect(parent1.previous_range(parent2)).to be_empty + end + + it 'gets the previous range of a child fragment' do + expect(child21.previous_range(child22)).to eq([child12, child13]) + end + + it 'squishes the previous range if there are not enough children' do + expect(child12.previous_range(child13)).to eq([child11, child11]) + end + + it 'creates a range that straddles the two parents' do + expect(child22.previous_range(child23)).to eq([child13, child21]) + end + end + + describe '#next_fragment' do + it 'gets the next passage of a parent fragment' do + expect(parent1.next_fragment).to eq(parent2) + end + + it 'returns nil if there is no next passage' do + expect(parent3.next_fragment).to be_nil + end + + it 'gets the next passage of a child fragment' do + expect(child12.next_fragment).to eq(child13) + end + + it 'gets the first fragment of the next parent' do + expect(child13.next_fragment).to eq(child21) + end + end + + describe '#next_range' do + it 'gets the next range of a parent fragment' do + expect(parent1.next_range(parent1)).to eq([parent2, parent2]) + end + + it 'is empty if there is no next range' do + expect(parent2.next_range(parent3)).to be_empty + end + + it 'gets the next range of a child fragment' do + expect(child12.next_range(child13)).to eq([child21, child22]) + end + + it 'squishes the next range if there are not enough children' do + expect(child21.next_range(child22)).to eq([child23, child23]) + end + + it 'creates a range that straddles the two parents' do + expect(child11.next_range(child12)).to eq([child13, child21]) + end + end + + describe '#first_fragment' do + it 'gets the first passage for a parent fragment' do + expect(parent2.first_fragment).to eq(parent1) + end + + it 'gets the first passage for a child fragment' do + expect(child21.first_fragment).to eq(child11) + end + end + + describe '#first_range' do + it 'gets the first range for a parent fragment' do + expect(parent2.first_range(parent3)).to eq([parent1, parent2]) + end + + it 'gets the first range for a child fragment' do + expect(child21.first_range(child23)).to eq([child11, child13]) + end + end + + describe '#last_fragment' do + it 'gets the last passage for a parent fragment' do + expect(parent1.last_fragment).to eq(parent3) + end + + it 'gets the last passage for a child fragment' do + expect(child13.last_fragment).to eq(child23) + end + end + + describe '#last_range' do + it 'gets the last range for a parent fragment' do + expect(parent1.last_range(parent2)).to eq([parent2, parent3]) + end + + it 'gets the last range for a child fragment' do + expect(child11.last_range(child13)).to eq([child21, child23]) + end + end + end end