initial commit for bookish-server and local environment

This commit is contained in:
David Thompson
2020-05-26 00:30:20 -04:00
parent d634e9d00f
commit 2bc790c87b
48 changed files with 15860 additions and 1 deletions
+10
View File
@@ -0,0 +1,10 @@
package mysql
import (
"errors"
)
var (
ErrNotFound = errors.New("no renter found")
ErrAlreadyExists = errors.New("the provided value already exists")
)
+111
View File
@@ -0,0 +1,111 @@
package mysql
import (
"database/sql"
"errors"
"time"
)
// IsBookAvailable queries the database for available books.
func (s *store) IsBookAvailable(title string) (available bool, err error) {
q := `
SELECT
*
FROM
rentals
WHERE
book_title = ?
AND return_date IS NULL;
`
var rr []struct {
ID int `db:"id"`
RenterID int `db:"renter_id"`
RentalDate time.Time `db:"rental_date"`
ReturnDate sql.NullTime `db:"return_date"`
BookTitle string `db:"book_title"`
}
err = s.Select(&rr, q, title)
if err != nil {
// If no records are returned then the book is available for rent.
if errors.Is(sql.ErrNoRows, err) {
return true, nil
}
return false, err
}
// If 5 books are rented out this book is not available.
if len(rr) > 4 {
return false, nil
}
return true, nil
}
// RenterAlreadyCheckedOut queries the database for the given renterId and title. If a record is returned checkedOut will be true.
func (s *store) RenterAlreadyCheckedOut(renterId int, title string) (checkedOut bool, err error) {
q := `
SELECT
*
FROM
rentals
WHERE
renter_id = ?
AND book_title = ?
AND return_date IS NULL;
`
var rr []struct {
ID int `db:"id"`
RenterID int `db:"renter_id"`
RentalDate time.Time `db:"rental_date"`
ReturnDate sql.NullTime `db:"return_date"`
BookTitle string `db:"book_title"`
}
err = s.Select(&rr, q, renterId, title)
if err != nil {
if errors.Is(sql.ErrNoRows, err) {
return false, nil
}
return false, err
}
if len(rr) == 0 {
return false, nil
}
return true, nil
}
// CheckoutBook inserts a record indicating the book is checked out to the renter.
func (s *store) CheckoutBook(renterId int, title string) error {
q := `
INSERT INTO
rentals (renter_id, rental_date, book_title)
VALUES
(?, ?, ?);
`
_, err := s.Exec(q, renterId, time.Now(), title)
return err
}
// ReturnBook sets the return_date field to now indicating the book has been returned.
func (s *store) ReturnBook(renterId int, title string) error {
q := `
UPDATE
rentals
SET
return_date = ?
WHERE
renter_id = ?
AND book_title = ?;
`
_, err := s.Exec(q, time.Now(), renterId, title)
return err
}
+20
View File
@@ -0,0 +1,20 @@
package mysql
import (
"github.com/jmoiron/sqlx"
)
// store holds a connection to the application database.
type store struct {
*sqlx.DB
}
// NewStore creates a new connection to the database and returns a store containing the connection.
func NewStore(dsn string) (s *store, err error) {
db, err := sqlx.Open("mysql", dsn)
if err != nil {
return s, err
}
return &store{db}, nil
}
+66
View File
@@ -0,0 +1,66 @@
package mysql
import (
"database/sql"
"errors"
bookish "github.com/davidlick/bookish/bookish-server"
"github.com/go-sql-driver/mysql"
)
// ListAll returns all renter records.
func (s *store) ListAll() (rr []bookish.Renter, err error) {
q := `
SELECT
*
FROM
renters
`
err = s.Select(&rr, q)
if err != nil && errors.Is(sql.ErrNoRows, err) {
return nil, ErrNotFound
}
return
}
// FetchDetails queries the database for a specific renter.
func (s *store) FetchDetails(id int) (r bookish.Renter, err error) {
q := `
SELECT
*
FROM
renters
WHERE
id = ?
`
err = s.Get(&r, q, id)
if err != nil && errors.Is(sql.ErrNoRows, err) {
return bookish.Renter{}, ErrNotFound
}
return
}
// New inserts a record for a new renter. If that renter already exists it returns an ErrAlreadyExists.
func (s *store) New(name string, address string, email string, phoneNumber string) (id int, err error) {
q := `
INSERT INTO
renters (name, address, email, phone_number)
VALUES
(?, ?, ?, ?)
`
result, err := s.Exec(q, name, address, email, phoneNumber)
if err != nil {
if _, ok := err.(*mysql.MySQLError); ok {
return 0, ErrAlreadyExists
}
}
lastId, err := result.LastInsertId()
if err != nil {
return id, err
}
return int(lastId), nil
}