diff --git a/lib/hanami/model/associations/has_many.rb b/lib/hanami/model/associations/has_many.rb index f8724237..e8bb161b 100644 --- a/lib/hanami/model/associations/has_many.rb +++ b/lib/hanami/model/associations/has_many.rb @@ -46,6 +46,16 @@ def initialize(repository, source, target, subject, scope = nil) freeze end + # @raise [MultipleResultsError] if more than one record is available + # + # @since 1.3.3 + # @api private + def one + raise Hanami::Model::MultipleResultsError, "#{count} results returned" if count > 1 + + scope.one + end + # @since 0.7.0 # @api private def create(data) diff --git a/lib/hanami/model/error.rb b/lib/hanami/model/error.rb index 21fe379f..231f3c35 100644 --- a/lib/hanami/model/error.rb +++ b/lib/hanami/model/error.rb @@ -127,5 +127,8 @@ def initialize(url) super("Unknown database adapter for URL: #{url.inspect}. Please check your database configuration (hint: ENV['DATABASE_URL']).") end end + + class MultipleResultsError < Error + end end end diff --git a/spec/integration/hanami/model/associations/has_many_spec.rb b/spec/integration/hanami/model/associations/has_many_spec.rb index 617aba21..57e8378f 100644 --- a/spec/integration/hanami/model/associations/has_many_spec.rb +++ b/spec/integration/hanami/model/associations/has_many_spec.rb @@ -192,4 +192,33 @@ # skipped spec it '#remove' end + + describe '#one' do + it 'raises an error if more than one record exists' do + author = authors.create(name: 'Cormac McCarthy') + book = books.create(author_id: author.id, title: 'Blood Meridian') + book = books.create(author_id: author.id, title: 'Blood Meridian') + + expect do + authors.find_book_by_title(author, book.title) + end.to raise_error(Hanami::Model::MultipleResultsError) + end + + it 'returns an individual record if only one record exists' do + author = authors.create(name: 'Toni Morrison') + book = books.create(author_id: author.id, title: 'Song of Solomon') + + found = authors.find_book(author, book.id) + + expect(found).to eq(book) + end + + it 'returns nil if no records exist' do + author = authors.create(name: 'Aspiring Author') + + found = authors.find_book(author, nil) + + expect(found).to eq(nil) + end + end end diff --git a/spec/support/fixtures.rb b/spec/support/fixtures.rb index 1b75c949..260571ac 100644 --- a/spec/support/fixtures.rb +++ b/spec/support/fixtures.rb @@ -258,12 +258,20 @@ def find_book(author, id) book_for(author, id).one end + def find_book_by_title(author, title) + book_by_title(author, title).one + end + def book_exists?(author, id) book_for(author, id).exists? end private + def book_by_title(author, title) + assoc(:books, author).where(title: title) + end + def book_for(author, id) assoc(:books, author).where(id: id) end