Skip to content

Commit

Permalink
Add #one to HasMany (hanami#550)
Browse files Browse the repository at this point in the history
Per hanami#550, the HasMany interface
does not line up with Hanami's guides. Prior to this commit, the
following is invalid as HasMany does not implement #one.

```ruby
class AuthorRepository < Hanami::Repository
  associations do
    has_many :books
  end

  def find_book(author, id)
    book_for(author, id).one
  end

  private

  def book_for(author, id)
    assoc(:books, author).where(id: id)
  end
end
```

This implementation is based on a couple of others, notably ROM's and
Ecto's (Elixir). I opted to name the raised error MultipleResultsError,
which is the exact name used by Ecto, because I feel it bears a semantic
relationship to the name of the method from which raises it.
  • Loading branch information
landongrindheim committed Oct 2, 2019
1 parent 3ac27f7 commit 870f7af
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 0 deletions.
10 changes: 10 additions & 0 deletions lib/hanami/model/associations/has_many.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions lib/hanami/model/error.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
29 changes: 29 additions & 0 deletions spec/integration/hanami/model/associations/has_many_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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: 'Umberto Eco')
book = books.create(author_id: author.id, title: 'Foucault Pendulum')
book = books.create(author_id: author.id, title: 'Foucault Pendulum')

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: 'Umberto Eco')
book = books.create(author_id: author.id, title: 'Foucault Pendulum')

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
8 changes: 8 additions & 0 deletions spec/support/fixtures.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 870f7af

Please sign in to comment.