diff --git a/lib/library_plus.rb b/lib/library_plus.rb index 9148018a..54f3f592 100644 --- a/lib/library_plus.rb +++ b/lib/library_plus.rb @@ -1,31 +1,50 @@ require 'pg' +require 'pry-byebug' module Library + + def self.create_db(dbname) + success = system("createdb #{dbname}") + end + def self.create_db_connection(dbname) PG.connect(host: 'localhost', dbname: dbname) end def self.clear_db(db) db.exec <<-SQL - DELETE FROM users; - /* TODO: Clear rest of the tables (books, etc.) */ + DROP TABLE IF EXISTS checkouts; + DROP TABLE IF EXISTS users; + DROP TABLE IF EXISTS books; SQL end def self.create_tables(db) db.exec <<-SQL - CREATE TABLE users( + CREATE TABLE IF NOT EXISTS users( id SERIAL PRIMARY KEY, name VARCHAR ); - /* TODO: Create rest of the tables (books, etc.) */ + CREATE TABLE IF NOT EXISTS books( + id SERIAL PRIMARY KEY, + title VARCHAR, + author VARCHAR, + status VARCHAR + ); + CREATE TABLE IF NOT EXISTS checkouts( + book_id INTEGER references books(id), + user_id INTEGER references users(id), + status VARCHAR, + checkout_date VARCHAR + ); 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 checkouts; # Drop Dependent Tables First + DROP TABLE IF EXISTS users; + DROP TABLE IF EXISTS books; SQL end end diff --git a/lib/library_plus/book_repo.rb b/lib/library_plus/book_repo.rb index 46409041..3fc203ad 100644 --- a/lib/library_plus/book_repo.rb +++ b/lib/library_plus/book_repo.rb @@ -1 +1,90 @@ -# TODO +require 'pry-byebug' + +module Library + class BookRepo + def self.all(db) + db.exec("SELECT * FROM books").to_a + end + + def self.find(db, book_id) + db.exec("SELECT * FROM books WHERE id = #{book_id}").entries.last + end + + def self.checkout(db, book_id, user_id) + book = db.exec("SELECT * FROM books WHERE id = #{book_id}").entries.last + if book['status'] == 'available' + # Update Status to 'checked-out' + db.exec("UPDATE books SET status = 'checked_out' WHERE id = #{book_id}") + + # Add book to checkout history table + db.exec("INSERT INTO checkouts (book_id, user_id, status, checkout_date) VALUES (#{book_id}, #{user_id}, 'checked_out', '#{Time.now}')") + end + find(db, book_id) + end + + def self.checkin(db, book_id) + book = db.exec("SELECT * FROM books WHERE id = #{book_id}").entries.last + if book['status'] == 'checked_out' + + # Update books table to 'available' + db.exec("UPDATE books SET status = 'available' WHERE id = #{book_id}") + + # Update checkout table to 'returned' + db.exec("UPDATE checkouts SET status = 'returned' WHERE book_id = #{book_id} AND status = 'checked_out'") + end + find(db, book_id) + end + + def self.save(db, book_data) + if book_data['id'] + # Update Title + if book_data['title'] + db.exec("UPDATE books SET title = '#{book_data['title']}' WHERE id = #{book_data['id']}") + end + if book_data['author'] + db.exec("UPDATE books SET author = '#{book_data['author']}' WHERE id = #{book_data['id']}") + end + else + # Enter book_data['title'], book_data['author'] and Status / Unique ID gets assigned automatically + db.exec("INSERT INTO books (title, author, status) VALUES ('#{book_data['title']}', '#{book_data['author']}', 'available')") + end + # puts get_users(db, user_data) + get_books(db, book_data).last + end + + def self.lose(db, book_id) + # Update books table to 'available' + db.exec("UPDATE checkouts SET status = 'lost' WHERE book_id = #{book_id} AND status = 'checked_out'") + db.exec("UPDATE books SET status = 'lost' WHERE id = #{book_id}") + end + + def self.get_books(db, book_data) + if book_data['id'] + db.exec("SELECT * FROM books WHERE id = #{book_data['id']}").entries + elsif book_data['title'] && book_data['author'] + db.exec("SELECT * FROM books WHERE title = '#{book_data['title']}' AND author = '#{book_data['author']}'").entries + elsif book_data['title'] + db.exec("SELECT * FROM books WHERE title = '#{book_data['title']}'").entries + elsif book_data['author'] + db.exec("SELECT * FROM books WHERE title = '#{book_data['author']}'").entries + end + end + + def self.get_status(db, book_id) + find(db, book_id)['status'] + end + + def self.get_history(db, id) + if id['book_id'] + db.exec("SELECT * FROM checkouts WHERE book_id = #{id['book_id']}").entries + elsif id['user_id'] + db.exec("SELECT * FROM checkouts WHERE user_id = #{id['user_id']}").entries + end + end + + def self.get_checkedOutBooks(db, user_id) + get_history(db, user_id).select{ |entry| entry['status'] == 'checked_out'} + end + + end +end diff --git a/lib/library_plus/user_repo.rb b/lib/library_plus/user_repo.rb index f293fe6a..8dcf6db7 100644 --- a/lib/library_plus/user_repo.rb +++ b/lib/library_plus/user_repo.rb @@ -1,3 +1,5 @@ +require 'pry-byebug' + module Library class UserRepo @@ -8,19 +10,30 @@ def self.all(db) end def self.find(db, user_id) - # TODO: Insert SQL statement + db.exec("SELECT * FROM users WHERE id = #{user_id}").entries.last end def self.save(db, user_data) if user_data['id'] - # TODO: Update SQL statement + # Update Name + db.exec("UPDATE users SET name = '#{user_data['name']}' WHERE id = #{user_data['id']}") else - # TODO: Insert SQL statement + # Enter Name and Unique ID gets assigned automatically + db.exec("INSERT INTO users (name) VALUES ('#{user_data['name']}')") end + get_users(db, user_data).last end def self.destroy(db, user_id) - # TODO: Delete SQL statement + db.exec("DELETE FROM users WHERE id = #{user_id}") + end + + def self.get_users(db, user_data) + if user_data['id'] + db.exec("SELECT * FROM users WHERE id = #{user_data['id']}").entries + else + db.exec("SELECT * FROM users WHERE name = '#{user_data['name']}'").entries + end end end diff --git a/server.rb b/server.rb index 91a87bcd..4075ee74 100644 --- a/server.rb +++ b/server.rb @@ -1,8 +1,93 @@ require 'sinatra' require './lib/library_plus' +require 'pry-byebug' -# set :bind, '0.0.0.0' # This is needed for Vagrant +set :bind, '0.0.0.0' # This is needed for Vagrant + +Library.create_db('library_dev') +db = Library.create_db_connection('library_dev') +Library.create_tables(db) get '/' do erb :index end + +# User Index +get '/users' do + db = Library.create_db_connection('library_dev') + @users = Library::UserRepo.all(db) + erb :"users/index" +end + +post '/users' do + # puts params + username = params[:user_name] + db = Library.create_db_connection('library_dev') + Library::UserRepo.save(db, { 'name' => username }) + @users = Library::UserRepo.all(db) + erb :"users/index" +end + +get '/users/*' do + user_id = params[:splat][0] + db = Library.create_db_connection('library_dev') + @checked_out_books = Library::BookRepo.get_checkedOutBooks(db, { 'user_id' => user_id }) + erb :"users/summary" +end + +# Book Index +get '/books' do + db = Library.create_db_connection('library_dev') + @books = Library::BookRepo.all(db) + erb :"books/index" +end + +post '/books' do + # puts params + title = params[:title] + author = params[:author] + db = Library.create_db_connection('library_dev') + Library::BookRepo.save(db, { 'title' => title, 'author' => author }) + @books = Library::BookRepo.all(db) + erb :"books/index" +end + +get '/books/:book_id' do + # We need to choose a User that will checkout the book + book_id = params[:book_id] + db = Library.create_db_connection('library_dev') + @book_history = Library::BookRepo.get_history(db, book_id) + erb :"books/summary" +end + +get '/books/:book_id/checkout' do + # We need to choose a User that will checkout the book + @book_id = params[:book_id] + db = Library.create_db_connection('library_dev') + @users = Library::UserRepo.all(db) + erb :"books/checkout/index" +end + +post '/books/:book_id/checkout/:user_id' do + # We need to choose a User that will checkout the book + book_id = params[:book_id] + user_id = params[:user_id] + db = Library.create_db_connection('library_dev') + Library::BookRepo.checkout(db, book_id, user_id) + checkout_log = Library::BookRepo.get_checkedOutBooks(db, { 'user_id' => user_id }) + books = Library::BookRepo.all(db) + @checked_out_books = [] + checkout_log.each do |log| + book = Library::BookRepo.find(db, log['book_id']) + @checked_out_books.push(book) + end + binding.pry + erb :"users/summary" +end + +post '/books/*/return' do + book_id = params[:splat][0] + db = Library.create_db_connection('library_dev') + Library::BookRepo.checkin(db, book_id) + erb :"books/index" +end diff --git a/spec/repos/book_repo_spec.rb b/spec/repos/book_repo_spec.rb new file mode 100644 index 00000000..8e959ca8 --- /dev/null +++ b/spec/repos/book_repo_spec.rb @@ -0,0 +1,182 @@ +require 'spec_helper' +require 'pg' + +describe Library::BookRepo do + + def book_count(db) + db.exec("SELECT COUNT(*) FROM books")[0]["count"].to_i + end + + def checkout_history_count(db) + db.exec("SELECT COUNT(*) FROM checkouts")[0]["count"].to_i + end + + # A let(:db) define means you can use db in an it statement below + # Also, the code in {} does not run until it sees a 'db' statement in an 'it' block + # Therefore, the code will run for each 'it' block + let(:db) { + Library.create_db('library_test') + Library.create_db_connection('library_test') + } + + # Before each 'it' block we are clearing the data base + # That way when we crete users we know exactly how many should be in the db + before(:each) do + Library.clear_db(db) + Library.create_tables(db) + end + + it "gets all books" do + db.exec("INSERT INTO books (title, author) VALUES ($1, $2)", ["Alices Adventures in Wonderland", "Lewis Carrol"]) + db.exec("INSERT INTO books (title, author) VALUES ($1, $2)", ["The Prophet", "Kahlil Gibran"]) + + books = Library::BookRepo.all(db) + expect(books).to be_a Array + expect(books.count).to eq 2 + + titles = books.map {|u| u['title'] } + expect(titles).to include "Alices Adventures in Wonderland", "The Prophet" + end + + it "creates books" do + expect(book_count(db)).to eq 0 + expect(checkout_history_count(db)).to eq 0 + + book = Library::BookRepo.save(db, { 'title' => "Alices Adventures in Wonderland", 'author' => "Lewis Carrol" }) + expect(book['id']).to_not be_nil + expect(book['title']).to eq "Alices Adventures in Wonderland" + expect(book['author']).to eq "Lewis Carrol" + expect(book['status']).to eq "available" + + # Check for persistence + expect(book_count(db)).to eq 1 + expect(checkout_history_count(db)).to eq 0 + + book = db.exec("SELECT * FROM books")[0] + expect(book['title']).to eq "Alices Adventures in Wonderland" + end + + it "finds books" do + book = Library::BookRepo.save(db, { 'title' => "Alices Adventures in Wonderland", 'author' => "Lewis Carrol" }) + retrieved_book = Library::BookRepo.find(db, book['id']) + expect(retrieved_book['title']).to eq "Alices Adventures in Wonderland" + end + + it "updates books" do + book1 = Library::BookRepo.save(db, { 'title' => "Alices Adventures in Wonderland", 'author' => "Lewis Carrol" }) + book2 = Library::BookRepo.save(db, { 'id' => book1['id'], 'title' => "Alicias Adventures in Wonderland", 'author' => "Louis CK" }) + expect(book2['id']).to eq(book1['id']) + expect(book2['title']).to include "Alicia" + expect(book2['author']).to eq "Louis CK" + + # Check for persistence + book3 = Library::BookRepo.find(db, book1['id']) + expect(book3['title']).to include "Alicia" + end + + it "check-out books" do + book = Library::BookRepo.save(db, { 'title' => "Alices Adventures in Wonderland", 'author' => "Lewis Carrol" }) + user = Library::UserRepo.save(db, { 'name' => "Alice" }) + + # Checkout Book and Check Book Status + book = Library::BookRepo.checkout(db, book['id'], user['id']) + expect(book['status']).to eq('checked_out') + + # Check Checkouts Table Status from book_id + checkout = Library::BookRepo.get_history(db, { 'book_id' => book['id'] })[0] + expect(checkout['status']).to eq('checked_out') + + # Check Checkouts Table Status from user_id + checkout_log = Library::BookRepo.get_history(db, { 'user_id' => user['id'] })[0] + expect(checkout_log['status']).to eq('checked_out') + expect(checkout_log['book_id']).to eq(book['id']) + + checkout_log = Library::BookRepo.get_history(db, { 'book_id' => book['id'] })[0] + expect(checkout_log['status']).to eq('checked_out') + expect(checkout_log['user_id']).to eq(user['id']) + end + + it "check-in books" do + book = Library::BookRepo.save(db, { 'title' => "Alices Adventures in Wonderland", 'author' => "Lewis Carrol" }) + user = Library::UserRepo.save(db, { 'name' => "Alice" }) + + # Check-out Book and Check-In Book + book = Library::BookRepo.checkout(db, book['id'], user['id']) + book = Library::BookRepo.checkin(db, book['id']) + + checkout_log = Library::BookRepo.get_history(db, { 'user_id' => user['id'] })[0] + expect(checkout_log['status']).to eq('returned') + expect(checkout_log['book_id']).to eq(book['id']) + expect(checkout_log['user_id']).to eq(user['id']) + + checkout = Library::BookRepo.get_history(db, { 'book_id' => book['id'] })[0] + expect(checkout_log['status']).to eq('returned') + expect(checkout_log['book_id']).to eq(book['id']) + expect(checkout_log['user_id']).to eq(user['id']) + + end + + it "lose books" do + book = Library::BookRepo.save(db, { 'title' => "Alices Adventures in Wonderland", 'author' => "Lewis Carrol" }) + expect(book_count(db)).to eq 1 + + Library::BookRepo.lose(db, book['id']) + lost_book = Library::BookRepo.find(db, book['id']) + expect(lost_book['status']).to eq "lost" + end + + it "list of checked-out books" do + book1 = Library::BookRepo.save(db, { 'title' => "Alices Adventures in Wonderland", 'author' => "Lewis Carrol" }) + book2 = Library::BookRepo.save(db, { 'title' => "The Prophet", 'author' => "Kahlil Gibran" }) + user = Library::UserRepo.save(db, { 'name' => "Alice" }) + + # Checkout Book and Check Book Status + Library::BookRepo.checkout(db, book1['id'], user['id']) + Library::BookRepo.checkout(db, book2['id'], user['id']) + + # Check Checkouts Table Status from user_id + user_checkout_log = Library::BookRepo.get_checkedOutBooks(db, { 'user_id' => user['id'] }) + expect(user_checkout_log.count).to eq 2 + user_checkout_log.each do |entry| + expect(entry['status']).to eq('checked_out') + end + + # Check book1 Back In + Library::BookRepo.checkin(db, book1['id']) + + user_checkout_log = Library::BookRepo.get_checkedOutBooks(db, { 'user_id' => user['id'] }) + expect(user_checkout_log.count).to eq 1 + user_checkout_log.each do |entry| + expect(entry['status']).to eq('checked_out') + end + + end + + it "history of checked-out books" do + book1 = Library::BookRepo.save(db, { 'title' => "Alices Adventures in Wonderland", 'author' => "Lewis Carrol" }) + book2 = Library::BookRepo.save(db, { 'title' => "The Prophet", 'author' => "Kahlil Gibran" }) + user = Library::UserRepo.save(db, { 'name' => "Alice" }) + + # Checkout Book and Check Book Status + Library::BookRepo.checkout(db, book1['id'], user['id']) + Library::BookRepo.checkout(db, book2['id'], user['id']) + + # Check Checkouts Table Status from user_id + checkout_log = Library::BookRepo.get_history(db, { 'user_id' => user['id'] }) + expect(checkout_history_count(db)).to eq 2 + + checkout_log.each do |entry| + expect(entry['status']).to eq('checked_out') + end + + # Check Books Back In + Library::BookRepo.checkin(db, book1['id']) + Library::BookRepo.checkin(db, book2['id']) + + checkout_log = Library::BookRepo.get_history(db, { 'user_id' => user['id'] }) + expect(checkout_history_count(db)).to eq 2 + checkout_log.each do |entry| + expect(entry['status']).to eq('returned') + end + end +end diff --git a/spec/repos/user_repo_spec.rb b/spec/repos/user_repo_spec.rb index dc810e5d..e46bbadd 100644 --- a/spec/repos/user_repo_spec.rb +++ b/spec/repos/user_repo_spec.rb @@ -1,4 +1,5 @@ require 'spec_helper' +require 'pg' describe Library::UserRepo do @@ -6,10 +7,19 @@ def user_count(db) db.exec("SELECT COUNT(*) FROM users")[0]["count"].to_i end - let(:db) { Library.create_db_connection('library_test') } + # A let(:db) define means you can use db in an it statement below + # Also, the code in {} does not run until it sees a 'db' statement in an 'it' block + # Therefore, the code will run for each 'it' block + let(:db) { + Library.create_db('library_test') + Library.create_db_connection('library_test') + } + # Before each 'it' block we are clearing the data base + # That way when we crete users we know exactly how many should be in the db before(:each) do Library.clear_db(db) + Library.create_tables(db) end it "gets all users" do @@ -38,13 +48,13 @@ 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, { 'id' => user1['id'], 'name' => "Alicia" }) expect(user2['id']).to eq(user1['id']) @@ -55,11 +65,12 @@ def user_count(db) 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 Library::UserRepo.destroy(db, user['id']) expect(user_count(db)).to eq 0 end + end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 962938ee..6a4c4d17 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,4 +1,4 @@ -require 'library_plus' +require 'library_plus.rb' RSpec.configure do |config| config.treat_symbols_as_metadata_keys_with_true_values = true diff --git a/views/books/checkout/index.erb b/views/books/checkout/index.erb new file mode 100644 index 00000000..534fdeb2 --- /dev/null +++ b/views/books/checkout/index.erb @@ -0,0 +1,17 @@ + + + + Checkout Index + + +

All Users

+ + + \ No newline at end of file diff --git a/views/books/index.erb b/views/books/index.erb new file mode 100644 index 00000000..8312fe20 --- /dev/null +++ b/views/books/index.erb @@ -0,0 +1,31 @@ + + + + Book Index + + +

All Books

+
+

Register New Book

+ + + + + + +
+ + + \ No newline at end of file diff --git a/views/books/summary.erb b/views/books/summary.erb new file mode 100644 index 00000000..00973ad5 --- /dev/null +++ b/views/books/summary.erb @@ -0,0 +1,15 @@ + + + + User Index + + +

History for Book

+ + + \ No newline at end of file diff --git a/views/index.erb b/views/index.erb index aba3235d..b7d34fb8 100644 --- a/views/index.erb +++ b/views/index.erb @@ -1,3 +1,6 @@

The Library Plus System

Welcome to your freedom!

+ +
  • Manage Users
  • +
  • Manage Books
  • \ No newline at end of file diff --git a/views/users/checkout/index.erb b/views/users/checkout/index.erb new file mode 100644 index 00000000..534fdeb2 --- /dev/null +++ b/views/users/checkout/index.erb @@ -0,0 +1,17 @@ + + + + Checkout Index + + +

    All Users

    + + + \ No newline at end of file diff --git a/views/users/index.erb b/views/users/index.erb new file mode 100644 index 00000000..671fb52e --- /dev/null +++ b/views/users/index.erb @@ -0,0 +1,22 @@ + + + + User Index + + +

    All Users

    +
    +

    Register New User

    + + + + +
    + + + \ No newline at end of file diff --git a/views/users/summary.erb b/views/users/summary.erb new file mode 100644 index 00000000..35e29f7a --- /dev/null +++ b/views/users/summary.erb @@ -0,0 +1,21 @@ + + + + User Index + + +

    Summary of Checked- Books For User

    + + + \ No newline at end of file