diff --git a/lib/active_graph/node/query_methods.rb b/lib/active_graph/node/query_methods.rb index 5f52a1e7d..984f9ebe8 100644 --- a/lib/active_graph/node/query_methods.rb +++ b/lib/active_graph/node/query_methods.rb @@ -11,14 +11,46 @@ def exists?(node_condition = nil) !!result end - # Returns the first node of this class, sorted by ID. Note that this may not be the first node created since Neo4j recycles IDs. - def first - self.query_as(:n).limit(1).order(n: primary_key).pluck(:n).first + # Returns the first node (or first N nodes if a parameter is supplied) of this class, sorted by ID. + # Note that this may not be the first node created since Neo4j recycles IDs. + def first(limit = 1) + find_nth(0, limit) end - # Returns the last node of this class, sorted by ID. Note that this may not be the first node created since Neo4j recycles IDs. - def last - self.query_as(:n).limit(1).order(n: {primary_key => :desc}).pluck(:n).first + # Returns the last node (or last N nodes if a parameter is supplied) of this class, sorted by ID. + # Note that this may not be the first node created since Neo4j recycles IDs. + def last(limit = 1) + find_nth_from_last(0, limit) + end + + # Returns the second node of this class, sorted by ID. Note that this may not be the first node created since Neo4j recycles IDs. + def second + find_nth(1) + end + + # Returns the third node of this class, sorted by ID. Note that this may not be the first node created since Neo4j recycles IDs. + def third + find_nth(2) + end + + # Returns the fourth node of this class, sorted by ID. Note that this may not be the first node created since Neo4j recycles IDs. + def fourth + find_nth(3) + end + + # Returns the fifth node of this class, sorted by ID. Note that this may not be the first node created since Neo4j recycles IDs. + def fifth + find_nth(4) + end + + # Returns the third to last node of this class, sorted by ID. Note that this may not be the first node created since Neo4j recycles IDs. + def third_to_last + find_nth_from_last(2) + end + + # Returns the second to last node of this class, sorted by ID. Note that this may not be the first node created since Neo4j recycles IDs. + def second_to_last + find_nth_from_last(1) end # @return [Integer] number of nodes of this class @@ -63,6 +95,18 @@ def exists_query_start(node_condition) self.query_as(:n) end end + + def find_nth(index, limit = 1, order = primary_key) + if limit == 1 + self.query_as(:n).order(n: order).limit(limit).skip(index).pluck(:n).first + else + self.query_as(:n).order(n: order).limit(limit).skip(index).pluck(:n).first(limit) + end + end + + def find_nth_from_last(index, limit = 1) + find_nth(index, limit, {primary_key => :desc}) + end end end end diff --git a/spec/e2e/query_proxy_methods_spec.rb b/spec/e2e/query_proxy_methods_spec.rb index 387d10b9a..4d5186763 100644 --- a/spec/e2e/query_proxy_methods_spec.rb +++ b/spec/e2e/query_proxy_methods_spec.rb @@ -177,11 +177,21 @@ def destroy_called end end - describe 'first and last' do + describe 'numeral finder methods (first, last, etc.)' do it 'returns different objects' do - Student.create + 5.times { Student.create } expect(Student.all.count).to be > 1 expect(Student.all.first).to_not eq(Student.all.last) + expect(Student.all.second).to_not eq(Student.all.second_to_last) + expect(Student.all.third).to_not eq(Student.all.third_to_last) + expect(Student.all.fourth).to_not eq(Student.all.fifth) + end + + it 'allows to specify limit for first and last methods' do + Student.create + expect(Student.all.count).to be > 1 + expect(Student.first(2)).to eq([Student.all.first, Student.all.second]) + expect(Student.last(2)).to eq([Student.all.last, Student.all.second_to_last]) end it 'returns objects across multiple associations' do