Skip to content

Commit

Permalink
Feat: Movies Catalog (#13)
Browse files Browse the repository at this point in the history
* feat: add CreateMovies migration

* feat: implement MoviesRepository and UCs

* test: write MoviesRepository spec

* test: write Movie model spec

* test: write Movies:Create spec

* test: write Movies:Find spec

* feat: implement index and create endpoints + tests

* chore: update movie create use case

* feat: delete movie use case

* feat: find by id movie use case

* chore: update movie find use case

* feat: implement update movie use case

* feat: implement show, update and delete endpoints

* test: write tests

* chore: code review I
  • Loading branch information
joaoGabriel55 committed Dec 12, 2023
1 parent d24c79d commit 292a302
Show file tree
Hide file tree
Showing 23 changed files with 630 additions and 1 deletion.
47 changes: 47 additions & 0 deletions backend/app/controllers/movies_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
class MoviesController < ApplicationController
rescue_from ActiveRecord::RecordNotFound, with: :movie_not_found

def index
render json: Movies::Find.new.call
end

def create
movie = Movies::Create.new(params: movie_params).call!

render json: movie, status: :created
rescue ActiveRecord::RecordInvalid
render json: { error: "Could not create a movie" }, status: :unprocessable_entity
end

def update
Movies::Update.new(params: movie_params.merge(id: params[:id]), movie: Movie).call!

render status: :no_content
rescue ActiveRecord::RecordInvalid
render json: { error: "Could not update a movie" }, status: :unprocessable_entity
end

def show
movie = Movies::FindById.new(id: params[:id]).call

render json: movie
end

def destroy
Movies::Delete.new(id: params[:id]).call

render status: :no_content
end

private

def movie_params
params
.require(:movie)
.permit(:director, :writer, :title, :producer, :production_company, :year, cast: [])
end

def movie_not_found
render json: { error: "Movie not found" }, status: :not_found
end
end
31 changes: 31 additions & 0 deletions backend/app/models/movie.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
class Movie
attr_accessor :id, :director, :writer, :title, :producer, :production_company, :cast, :year, :created_at, :updated_at

def initialize(id: nil, director:, writer:, title:, producer:, production_company:, cast:, year:, created_at: nil, updated_at: nil)
@id = id
@director = director
@writer = writer
@title = title
@producer = producer
@production_company = production_company
@cast = cast
@year = year
@created_at = created_at
@updated_at = updated_at
end

def to_hash
{
id: @id,
director: @director,
writer: @writer,
title: @title,
producer: @producer,
production_company: @production_company,
cast: @cast,
year: @year,
created_at: @created_at,
updated_at: @updated_at
}.compact
end
end
7 changes: 7 additions & 0 deletions backend/app/repositories/movies_repository.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

class MoviesRepository < ActiveRecord::Base
self.table_name = 'movies'

validates_presence_of :director, :writer, :title, :producer, :cast, :year
end
26 changes: 26 additions & 0 deletions backend/app/usecases/movies/create.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
class Movies::Create
def initialize(params:, movie: Movie, repository: MoviesRepository)
@params = params
@movie = movie
@repository = repository
end

def call!
movie = @movie.new(
director: @params[:director],
writer: @params[:writer],
title: @params[:title],
producer: @params[:producer],
production_company: @params[:production_company],
cast: @params[:cast],
year: @params[:year]
)

result = @repository.create!(movie.to_hash)
movie.id = result.id
movie.created_at = result.created_at
movie.updated_at = result.updated_at

movie
end
end
10 changes: 10 additions & 0 deletions backend/app/usecases/movies/delete.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class Movies::Delete
def initialize(id:, repository: MoviesRepository)
@id = id
@repository = repository
end

def call
@repository.delete(@id)
end
end
22 changes: 22 additions & 0 deletions backend/app/usecases/movies/find.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
class Movies::Find
def initialize(repository: MoviesRepository)
@repository = repository
end

def call
@repository.all.map do |movie|
Movie.new(
id: movie.id,
director: movie.director,
writer: movie.writer,
title: movie.title,
producer: movie.producer,
production_company: movie.production_company,
cast: JSON.parse(movie.cast),
year: movie.year,
created_at: movie.created_at,
updated_at: movie.updated_at
)
end
end
end
23 changes: 23 additions & 0 deletions backend/app/usecases/movies/find_by_id.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
class Movies::FindById
def initialize(id:, repository: MoviesRepository)
@id = id
@repository = repository
end

def call
movie = @repository.find(@id)

Movie.new(
id: movie.id,
director: movie.director,
writer: movie.writer,
title: movie.title,
producer: movie.producer,
production_company: movie.production_company,
cast: JSON.parse(movie.cast),
year: movie.year,
created_at: movie.created_at,
updated_at: movie.updated_at
)
end
end
23 changes: 23 additions & 0 deletions backend/app/usecases/movies/update.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
class Movies::Update
def initialize(params:, movie: Movie, repository: MoviesRepository)
@params = params
@movie = movie
@repository = repository
end

def call!
movie = @movie.new(
id: @params[:id],
director: @params[:director],
writer: @params[:writer],
title: @params[:title],
producer: @params[:producer],
production_company: @params[:production_company],
cast: @params[:cast],
year: @params[:year]
)

current_movie = @repository.find(movie.id)
current_movie.update!(movie.to_hash)
end
end
1 change: 1 addition & 0 deletions backend/config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
get "/health", to: "health#index"

resources :games, only: [:index, :create, :show, :update, :destroy]
resources :movies, only: [:index, :create, :show, :update, :destroy]
end
end
15 changes: 15 additions & 0 deletions backend/db/migrate/20231129121220_create_movies.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class CreateMovies < ActiveRecord::Migration[7.0]
def change
create_table :movies do |t|
t.string :director
t.string :writer
t.string :title
t.string :producer
t.string :production_company
t.string :cast, array: true
t.integer :year

t.timestamps
end
end
end
14 changes: 13 additions & 1 deletion backend/db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

50 changes: 50 additions & 0 deletions backend/spec/models/movie_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
require "rails_helper"

RSpec.describe Movie do
describe '.to_hash' do
let(:movie_id) { 1 }
let(:movie) {
described_class.new(
id: movie_id,
director: "George Lucas",
writer: "George Lucas",
title: "Star Wars",
producer: "George Lucas",
production_company: "Lucasfilm",
cast: ["Han Solo", "Princess Leia"],
year: 1977
)
}

context 'when movie id is present' do
it 'returns movie hash' do
expect(movie.to_hash).to eq({
id: movie_id,
director: "George Lucas",
writer: "George Lucas",
title: "Star Wars",
producer: "George Lucas",
production_company: "Lucasfilm",
cast: ["Han Solo", "Princess Leia"],
year: 1977
})
end
end

context 'when movie id is not present' do
let(:movie_id) { nil }

it 'returns movie hash without id' do
expect(movie.to_hash).to eq({
director: "George Lucas",
writer: "George Lucas",
title: "Star Wars",
producer: "George Lucas",
production_company: "Lucasfilm",
cast: ["Han Solo", "Princess Leia"],
year: 1977
})
end
end
end
end
10 changes: 10 additions & 0 deletions backend/spec/repositories/movies_repository_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
require "rails_helper"

RSpec.describe MoviesRepository, type: :model do
it { is_expected.to validate_presence_of(:title) }
it { is_expected.to validate_presence_of(:year) }
it { is_expected.to validate_presence_of(:director) }
it { is_expected.to validate_presence_of(:writer) }
it { is_expected.to validate_presence_of(:producer) }
it { is_expected.to validate_presence_of(:cast) }
end
39 changes: 39 additions & 0 deletions backend/spec/requests/movies/create_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
require "rails_helper"

RSpec.describe "Movies", type: :request do
let(:response_json) { JSON.parse(response.body) }

let(:params) do
{
"movie" => {
"director" => "George Lucas",
"writer" => "George Lucas",
"title" => "Star Wars",
"producer" => "George Lucas",
"production_company" => "Lucasfilm",
"cast" => ["Han Solo", "Princess Leia"],
"year" => 1977
}
}
end

describe "POST /api/movies" do
context "when create params are valid" do
it "responds with 201" do
expect { post "/api/movies", params: params }
.to change { MoviesRepository.count }.by(1)

expect(response).to have_http_status(:created)
end
end

context "when create params are invalid" do
it "responds with 422" do
post "/api/movies", params: { "movie" => { "title" => "", "year" => "" } }

expect(response_json).to eq({ "error" => "Could not create a movie" })
expect(response).to have_http_status(:unprocessable_entity)
end
end
end
end
36 changes: 36 additions & 0 deletions backend/spec/requests/movies/destroy_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
require "rails_helper"

RSpec.describe "Movies", type: :request do
describe "DELETE /api/movies/:id" do
context "when movie exists" do
let!(:movie) {
Movies::Create.new(
params: {
director: "George Lucas",
writer: "George Lucas",
title: "Star Wars",
producer: "George Lucas",
production_company: "Lucasfilm",
cast: ["Han Solo", "Princess Leia"],
year: 1977
}
).call!
}

it "responds with 204" do
expect { delete "/api/movies/#{movie.id}" }
.to change { MoviesRepository.count }.by(-1)

expect(response).to have_http_status(:no_content)
end
end

context "when movie does not exist" do
it "responds with 204" do
delete "/api/movies/123"

expect(response).to have_http_status(:no_content)
end
end
end
end

0 comments on commit 292a302

Please sign in to comment.