Permalink
Browse files

Wrap association exceptions (#434)

  • Loading branch information...
mereghost authored and jodosha committed Aug 11, 2017
1 parent e44f3f1 commit cab9bbc9ce550275e250b01eda6dcac91ef52445
@@ -49,17 +49,19 @@ def initialize(repository, source, target, subject, scope = nil)
# @since 0.7.0
# @api private
def create(data)
entity.new(
command(:create, aggregate(target), use: [:timestamps])
.call(data)
)
entity.new(command(:create, aggregate(target), use: [:timestamps])
.call(data))
rescue => e
raise Hanami::Model::Error.for(e)
end

# @since 0.7.0
# @api private
def add(data)
command(:create, relation(target), use: [:timestamps])
.call(associate(data))
rescue => e
raise Hanami::Model::Error.for(e)
end

# @since 0.7.0
@@ -51,23 +51,33 @@ def create(data)
entity.new(
command(:create, aggregate(target), use: [:timestamps]).call(data)
)
rescue => e
raise Hanami::Model::Error.for(e)
end

def add(data)
command(:create, relation(target), use: [:timestamps]).call(associate(data))
rescue => e
raise Hanami::Model::Error.for(e)
end

def update(data)
command(:update, relation(target), use: [:timestamps]).call(associate(data))
command(:update, relation(target), use: [:timestamps])
.by_pk(
one.public_send(relation(target).primary_key)
).call(data)
rescue => e
raise Hanami::Model::Error.for(e)
end

def remove
command(:delete, relation(target)).by_pk(scope.one.id).call
def delete
scope.delete
end
alias remove delete

def replace(data)
repository.transaction do
remove
delete
add(data)
end
end
@@ -70,18 +70,25 @@ def where(condition)
# @since x.x.x
# @api private
# Return the association table object. Would need an aditional query to return the entity
def add(*data) # Can receive an array of hashes with pks.
def add(*data)
command(:create, relation(through), use: [:timestamps])
.call(associate(data.map(&:to_h)))
rescue => e
raise Hanami::Model::Error.for(e)
end

# @since x.x.x
# @api private
def delete
relation(through).where(source_foreign_key => subject.fetch(source_primary_key)).delete
end

# @since x.x.x
# @api private
# disabled until I figure out a better way to do this
# rubocop:disable Metrics/AbcSize
def remove(id)
def remove(target_id)
association_record = relation(through)
.where(target_foreign_key => id, source_foreign_key => subject.fetch(source_primary_key))
.where(target_foreign_key => target_id, source_foreign_key => subject.fetch(source_primary_key))
.one
if association_record
ar_id = association_record.public_send relation(through).primary_key
@@ -1,27 +1,26 @@
RSpec.describe 'Associations (has_many)' do
let(:authors) { AuthorRepository.new }
let(:books) { BookRepository.new }

it "returns nil if association wasn't preloaded" do
repository = AuthorRepository.new
author = repository.create(name: 'L')
found = repository.find(author.id)
author = authors.create(name: 'L')
found = authors.find(author.id)

expect(found.books).to be_nil
end

it 'preloads associated records' do
repository = AuthorRepository.new

author = repository.create(name: 'Umberto Eco')
book = BookRepository.new.create(author_id: author.id, title: 'Foucault Pendulum')
author = authors.create(name: 'Umberto Eco')
book = books.create(author_id: author.id, title: 'Foucault Pendulum')

found = repository.find_with_books(author.id)
found = authors.find_with_books(author.id)

expect(found).to eq(author)
expect(found.books).to eq([book])
end

it 'creates an object with a collection of associated objects' do
repository = AuthorRepository.new
author = repository.create_with_books(name: 'Henry Thoreau', books: [{ title: 'Walden' }])
author = authors.create_with_books(name: 'Henry Thoreau', books: [{ title: 'Walden' }])

expect(author).to be_an_instance_of(Author)
expect(author.name).to eq('Henry Thoreau')
@@ -38,10 +37,8 @@
# ADD
#
it 'adds an object to the collection' do
repository = AuthorRepository.new

author = repository.create(name: 'Alexandre Dumas')
book = repository.add_book(author, title: 'The Count of Monte Cristo')
author = authors.create(name: 'Alexandre Dumas')
book = authors.add_book(author, title: 'The Count of Monte Cristo')

expect(book.id).to_not be_nil
expect(book.title).to eq('The Count of Monte Cristo')
@@ -53,25 +50,25 @@
#
it 'removes an object from the collection'
# it 'removes an object from the collection' do
# repository = AuthorRepository.new
# authors = AuthorRepository.new
# books = BookRepository.new

# # Book under test
# author = repository.create(name: 'Douglas Adams')
# author = authors.create(name: 'Douglas Adams')
# book = books.create(author_id: author.id, title: "The Hitchhiker's Guide to the Galaxy")

# # Different book
# a = repository.create(name: 'William Finnegan')
# a = authors.create(name: 'William Finnegan')
# b = books.create(author_id: a.id, title: 'Barbarian Days: A Surfing Life')

# repository.remove_book(author, book.id)
# authors.remove_book(author, book.id)

# # Check the book under test has removed foreign key
# found_book = books.find(book.id)
# expect(found_book).to_not be_nil
# expect(found_book.author_id).to be_nil

# found_author = repository.find_with_books(author.id)
# found_author = authors.find_with_books(author.id)
# expect(found_author.books.map(&:id)).to_not include(found_book.id)

# # Check that the other book was left untouched
@@ -83,29 +80,23 @@
# TO_A
#
it 'returns an array of books' do
repository = AuthorRepository.new
books = BookRepository.new

author = repository.create(name: 'Nikolai Gogol')
author = authors.create(name: 'Nikolai Gogol')
expected = books.create(author_id: author.id, title: 'Dead Souls')
expect(expected).to be_an_instance_of(Book)

actual = repository.books_for(author).to_a
actual = authors.books_for(author).to_a
expect(actual).to eq([expected])
end

##
# EACH
#
it 'iterates through the books' do
repository = AuthorRepository.new
books = BookRepository.new

author = repository.create(name: 'José Saramago')
author = authors.create(name: 'José Saramago')
expected = books.create(author_id: author.id, title: 'The Cave')

actual = []
repository.books_for(author).each do |book|
authors.books_for(author).each do |book|
expect(book).to be_an_instance_of(Book)
actual << book
end
@@ -117,67 +108,70 @@
# MAP
#
it 'iterates through the books and returns an array' do
repository = AuthorRepository.new
books = BookRepository.new

author = repository.create(name: 'José Saramago')
author = authors.create(name: 'José Saramago')
expected = books.create(author_id: author.id, title: 'The Cave')
expect(expected).to be_an_instance_of(Book)

actual = repository.books_for(author).map { |book| book }
actual = authors.books_for(author).map { |book| book }
expect(actual).to eq([expected])
end

##
# COUNT
#
it 'returns the count of the associated books' do
repository = AuthorRepository.new
books = BookRepository.new

author = repository.create(name: 'Fyodor Dostoevsky')
author = authors.create(name: 'Fyodor Dostoevsky')
books.create(author_id: author.id, title: 'Crime and Punishment')
books.create(author_id: author.id, title: 'The Brothers Karamazov')

expect(repository.books_count(author)).to eq(2)
expect(authors.books_count(author)).to eq(2)
end

it 'returns the count of on sale associated books' do
repository = AuthorRepository.new
books = BookRepository.new

author = repository.create(name: 'Steven Pinker')
author = authors.create(name: 'Steven Pinker')
books.create(author_id: author.id, title: 'The Sense of Style', on_sale: true)

expect(repository.on_sales_books_count(author)).to eq(1)
expect(authors.on_sales_books_count(author)).to eq(1)
end

##
# DELETE
#
it 'deletes all the books' do
repository = AuthorRepository.new
books = BookRepository.new

author = repository.create(name: 'Grazia Deledda')
author = authors.create(name: 'Grazia Deledda')
book = books.create(author_id: author.id, title: 'Reeds In The Wind')

repository.delete_books(author)
authors.delete_books(author)

expect(books.find(book.id)).to be_nil
end

it 'deletes scoped books' do
repository = AuthorRepository.new
books = BookRepository.new

author = repository.create(name: 'Harper Lee')
author = authors.create(name: 'Harper Lee')
book = books.create(author_id: author.id, title: 'To Kill A Mockingbird')
on_sale = books.create(author_id: author.id, title: 'Go Set A Watchman', on_sale: true)

repository.delete_on_sales_books(author)
authors.delete_on_sales_books(author)

expect(books.find(book.id)).to eq(book)
expect(books.find(on_sale.id)).to be_nil
end

context 'raises a Hanami::Model::Error wrapped exception on' do
it '#create' do
expect do
authors.create_with_books(name: 'Noam Chomsky')
end.to raise_error Hanami::Model::Error
end

it '#add' do
author = authors.create(name: 'Machado de Assis')
expect do
authors.add_book(author, title: 'O Alienista', on_sale: nil)
end.to raise_error Hanami::Model::NotNullConstraintViolationError
end

# skipped spec
it '#remove'
end
end
Oops, something went wrong.

0 comments on commit cab9bbc

Please sign in to comment.