diff --git a/lib/active_graph/node/query/query_proxy_methods.rb b/lib/active_graph/node/query/query_proxy_methods.rb index cc0b1f659..3893e119a 100644 --- a/lib/active_graph/node/query/query_proxy_methods.rb +++ b/lib/active_graph/node/query/query_proxy_methods.rb @@ -270,6 +270,11 @@ def first_and_last(func, target) end.first end + # @return [Array] An array of primary key values + def ids + query.pluck(identity => association_id_key) + end + # @return [String] The primary key of a the current QueryProxy's model or target class def association_id_key self.association.nil? ? model.primary_key : self.association.target_class.primary_key diff --git a/lib/active_graph/node/query_methods.rb b/lib/active_graph/node/query_methods.rb index 508a304c4..38f1c7ef7 100644 --- a/lib/active_graph/node/query_methods.rb +++ b/lib/active_graph/node/query_methods.rb @@ -49,6 +49,13 @@ def find_each(options = {}) end end + # Returns an array of all the IDs (primary key values) of the model's nodes. + # ActiveRecord-compatible shortcut for `pluck(primary_key)`. + # @return [Array] An array of primary key values + def ids + self.all.ids + end + private def exists_query_start(condition) diff --git a/spec/e2e/query_proxy_methods_spec.rb b/spec/e2e/query_proxy_methods_spec.rb index acd34d2ad..8493b0693 100644 --- a/spec/e2e/query_proxy_methods_spec.rb +++ b/spec/e2e/query_proxy_methods_spec.rb @@ -444,6 +444,62 @@ def destroy_called end end + describe 'ids' do + before(:each) do + [Student, Lesson].each(&:delete_all) + + @john = Student.create(name: 'John') + @history = Lesson.create(name: 'history') + @math2 = Lesson.create(name: 'math2') + @john.lessons << @history + @john.lessons << @math2 + end + + it 'returns the ids of nodes on the class' do + expect(Lesson.ids).to match_array([@history.id, @math2.id]) + end + + it 'returns the ids of nodes on a query proxy association' do + expect(@john.lessons.ids).to match_array([@history.id, @math2.id]) + end + + it 'returns the ids of nodes on a where chain' do + expect(Lesson.where(name: 'history').ids).to eq([@history.id]) + end + + it 'returns an empty array when there are no matches' do + expect(Lesson.where(name: 'nope').ids).to eq([]) + end + + context 'when the association target uses a custom id_property' do + before(:each) do + stub_node_class('Book') do + id_property :book_id, on: :generate_book_id + property :title + has_many :in, :owners, model_class: 'Reader', origin: :books + def generate_book_id + "book-#{SecureRandom.hex(4)}" + end + end + + stub_node_class('Reader') do + property :name + has_many :out, :books, model_class: 'Book', type: 'OWNS' + end + + @reader = Reader.create(name: 'Ada') + @b1 = Book.create(title: 'A') + @b2 = Book.create(title: 'B') + @reader.books << @b1 + @reader.books << @b2 + end + + it 'uses the target class primary key when traversing an association' do + expect(@reader.books.ids).to match_array([@b1.book_id, @b2.book_id]) + end + end + end + describe 'distinct' do let(:frank) { Student.create(name: 'Frank') } let(:bill) { Teacher.create(name: 'Bill') }