diff --git a/.gitignore b/.gitignore index e941da68..27e6018e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ .bundle vendor/bundle .DS_Store +.gems + diff --git a/Gemfile b/Gemfile index f4b5c425..63c1e33f 100644 --- a/Gemfile +++ b/Gemfile @@ -1,5 +1,5 @@ source 'https://rubygems.org' -ruby '2.0.0' +ruby '2.1.3' gem 'rspec', '~> 2.14.1' gem 'pry-byebug' diff --git a/lib/library_plus.rb b/lib/library_plus.rb index 9148018a..b66ff02b 100644 --- a/lib/library_plus.rb +++ b/lib/library_plus.rb @@ -2,13 +2,14 @@ module Library def self.create_db_connection(dbname) - PG.connect(host: 'localhost', dbname: dbname) + PG.connect(dbname: dbname) end def self.clear_db(db) db.exec <<-SQL - DELETE FROM users; - /* TODO: Clear rest of the tables (books, etc.) */ + DELETE FROM users cascade; + DELETE FROM books cascade; + DELETE FROM checkouts; SQL end @@ -18,17 +19,35 @@ def self.create_tables(db) id SERIAL PRIMARY KEY, name VARCHAR ); - /* TODO: Create rest of the tables (books, etc.) */ + + create table books( + id SERIAL PRIMARY KEY, + title VARCHAR, + author VARCHAR + ); + + create table checkouts( + book_id integer + references books(id) on delete cascade, + user_id integer + references users(id) on delete cascade + ); SQL end def self.drop_tables(db) db.exec <<-SQL - DROP TABLE users; - /* TODO: Drop rest of the tables (books, etc.) */ + DROP TABLE if exists users cascade; + DROP TABLE if exists books cascade; + DROP TABLE if exists checkouts SQL end + end require_relative 'library_plus/book_repo' require_relative 'library_plus/user_repo' + +# db = Library.create_db_connection "library_test" +# Library.drop_tables db +# Library.create_tables db diff --git a/lib/library_plus/book_repo.rb b/lib/library_plus/book_repo.rb index 46409041..0bbb69ca 100644 --- a/lib/library_plus/book_repo.rb +++ b/lib/library_plus/book_repo.rb @@ -1 +1,80 @@ -# TODO +module Library + class BookRepo + def self.all(db) + # Other code should not have to deal with the PG:Result. + # Therefore, convert the results into a plain array. + db.exec("SELECT * FROM books").to_a + end + + def self.find(db, book_data) + # find book by id + sql = %Q[ + select * + from books + where id = $1 + ] + result = db.exec(sql, [book_data]) + + result.first + end + + def self.save(db, book_data) + # update book data if book exists, otherwise create new book + if book_data.include?(:id) + sql_users = %Q[ + UPDATE books + set title =$1, author = $2 + where id = $3 + returning * + ] + result = db.exec(sql_users, [book_data[:title], book_data[:author], book_data[:id]]) + else + sql_insert_user = %Q[ + insert into books + (title, author) + values ($1, $2) + returning * + ] + result = db.exec(sql_insert_user, [book_data[:title], book_data[:author]]) + end + + result.first + end + + def self.check_out(db, check_out_data) + check_out_data.each {|c| puts c} + sql = %Q[ + insert into checkouts + (book_id, user_id) + values ($1, $2) + returning * + ] + result = db.exec(sql, [check_out_data[:book_id], check_out_data[:user_id]]) + end + + def self.get_check_outs(db) + sql = %Q[ + SELECT + books.title, + books.author, + books.id, + users.name + FROM + books, + checkouts, + users + WHERE + books.id = checkouts.book_id AND + users.id = checkouts.user_id + ] + db.exec(sql).to_a + end + + def self.destroy(db, book_data) + sql = %Q[ + delete from books + ] + db.exec(sql) + end + end +end diff --git a/lib/library_plus/user_repo.rb b/lib/library_plus/user_repo.rb index ef6ee87c..d290d9a2 100644 --- a/lib/library_plus/user_repo.rb +++ b/lib/library_plus/user_repo.rb @@ -8,20 +8,47 @@ def self.all(db) end def self.find(db, user_data) - # TODO: Insert SQL statement + # find user by id + sql = %Q[ + select * + from users + where id = $1 + ] + result = db.exec(sql, [user_data]) + + return result.first end def self.save(db, user_data) - if user_data['id'] - # TODO: Update SQL statement + # update user data if user exists, otherwise create new user + if user_data.include?(:id) + sql_users = %Q[ + UPDATE users + set name =$1 + where id = $2 + returning * + ] + result = db.exec(sql_users, [user_data[:name], user_data[:id]]) else - # TODO: Insert SQL statement + sql_insert_user = %Q[ + insert into users + (name) + values ($1) + returning * + ] + result = db.exec(sql_insert_user, [user_data[:name]]) end + + return result.first end def self.destroy(db, user_data) - # TODO: Delete SQL statement + sql = %Q[ + delete from users + ] + db.exec(sql) end end end + diff --git a/server.rb b/server.rb index 91a87bcd..b3f74a1f 100644 --- a/server.rb +++ b/server.rb @@ -4,5 +4,63 @@ # set :bind, '0.0.0.0' # This is needed for Vagrant get '/' do - erb :index + erb :"index" end + +get "/users" do + db = Library.create_db_connection('library_dev') + @users = Library::UserRepo.all(db) + + erb :"users/index" +end + +post "/users" do + db = Library.create_db_connection('library_dev') + @name = params[:user_name] + + Library::UserRepo.save(db, :name => @name) + + redirect back +end + +get "/books" do + db = Library.create_db_connection('library_dev') + @books = Library::BookRepo.all(db) + + erb :"books/index" +end + +post "/books" do + db = Library.create_db_connection('library_dev') + @title = params[:title] + @author = params[:author] + + Library::BookRepo.save(db, :title => @title, :author => @author) + + redirect back +end + +get "/checkouts" do + db = Library.create_db_connection('library_dev') + @books = Library::BookRepo.all(db) + @users = Library::UserRepo.all(db) + + erb :"checkouts/index" +end + +post "/checkouts" do + db = Library.create_db_connection('library_dev') + @book_id = params[:book_id] + @user_id = params[:user_id] + + Library::BookRepo.check_out(db, :book_id => @book_id, :user_id => @user_id) + + redirect back +end + +get "/checkouts/books-out" do + db = Library.create_db_connection("library_dev") + @checkouts = Library::BookRepo.get_check_outs(db) + + erb :"checkouts/books-out" +end \ No newline at end of file diff --git a/spec/repos/book_repo_spec.rb b/spec/repos/book_repo_spec.rb new file mode 100644 index 00000000..32fad81d --- /dev/null +++ b/spec/repos/book_repo_spec.rb @@ -0,0 +1,78 @@ +require 'spec_helper' +require "./lib/library_plus/user_repo" + +describe Library::BookRepo do + + def book_count(db) + db.exec("SELECT COUNT(*) FROM books")[0]["count"].to_i + end + + let(:db) { Library.create_db_connection('library_test') } + + before(:each) do + Library.clear_db(db) + end + + it "gets all books" do + db.exec("INSERT INTO books (title, author) VALUES ($1, $2)", ["To Kill a Mockingbird", "Harper Lee"]) + db.exec("INSERT INTO books (title, author) VALUES ($1, $2)", ["Fellowship of the Ring", "J.R.R. Tolkien"]) + + books = Library::BookRepo.all(db) + expect(books).to be_a Array + expect(books.count).to eq 2 + + books = books.map {|u| u['title']} + expect(books).to include "To Kill a Mockingbird", "Fellowship of the Ring" + end + + it "creates books" do + expect(book_count(db)).to eq 0 + + book = Library::BookRepo.save(db, :title => "To Kill a Mockingbird", :author => "Harper Lee") + expect(book['id']).to_not be_nil + expect(book['title']).to eq "To Kill a Mockingbird" + expect(book["author"]).to eq "Harper Lee" + + # Check for persistence + expect(book_count(db)).to eq 1 + + book = db.exec("SELECT * FROM books")[0] + expect(book['title']).to eq "To Kill a Mockingbird" + end + + it "finds books" do + book = Library::BookRepo.save(db, :title => "To Kill a Mockingbird", :author => "Harper Lee") + retrieved_book = Library::BookRepo.find(db, book['id']) + expect(retrieved_book['title']).to eq "To Kill a Mockingbird" + expect(retrieved_book["author"]).to eq "Harper Lee" + end + + it "updates books" do + book1 = Library::BookRepo.save(db, :title => "To Kill a Raven", :author => "Harper Lee") + book2 = Library::BookRepo.save(db, { :id => book1['id'], :title => "To Kill a Mockingbird", :author => book1["author"] }) + + expect(book2['id']).to eq(book1['id']) + expect(book2['title']).to eq "To Kill a Mockingbird" + + # Check for persistence + book3 = Library::BookRepo.find(db, book1['id']) + expect(book3['title']).to eq "To Kill a Mockingbird" + end + + it "destroys books" do + book = Library::BookRepo.save(db, :title => "To Kill a Mockingbird", :author => "Harper Lee") + expect(book_count(db)).to eq 1 + + Library::BookRepo.destroy(db, book['id']) + expect(book_count(db)).to eq 0 + end + + it "checks out books" do + user = Library::UserRepo.save(db, :name => "Alice") + book = Library::BookRepo.save(db, :title => "Foundation", :author => "Isaac Asimov") + + checkout = Library::BookRepo.check_out(db, :book_id => book['id'], :user_id => user["id"]) + expect(checkout["user_id"]).to_not be_nil + expect(checkout["book_id"]).to_not be_nil + end +end diff --git a/spec/repos/user_repo_spec.rb b/spec/repos/user_repo_spec.rb index 94028dde..f66b422b 100644 --- a/spec/repos/user_repo_spec.rb +++ b/spec/repos/user_repo_spec.rb @@ -38,24 +38,25 @@ def user_count(db) expect(user['name']).to eq "Alice" end - xit "finds users" do + it "finds users" do user = Library::UserRepo.save(db, :name => "Alice") retrieved_user = Library::UserRepo.find(db, user['id']) expect(retrieved_user['name']).to eq "Alice" end - xit "updates users" do + it "updates users" do user1 = Library::UserRepo.save(db, :name => "Alice") - user2 = Library::UserRepo.save(db, :name => "Alicia") + user2 = Library::UserRepo.save(db, { :id => user1['id'], :name => "Alicia" }) + expect(user2['id']).to eq(user1['id']) expect(user2['name']).to eq "Alicia" # Check for persistence - user3 = Library::UserRepo.find(user1['id']) + user3 = Library::UserRepo.find(db, user1['id']) expect(user3['name']).to eq "Alicia" end - xit "destroys users" do + it "destroys users" do user = Library::UserRepo.save(db, :name => "Alice") expect(user_count(db)).to eq 1 diff --git a/views/checkouts/index.erb b/views/checkouts/index.erb new file mode 100644 index 00000000..ba4b1cce --- /dev/null +++ b/views/checkouts/index.erb @@ -0,0 +1,26 @@ +
Book ID - Book Title/Author
+User ID - User Name
+Welcome to your freedom!
+