udemy-go-web-1/internal/repository/dbrepo/postgres.go

345 lines
8.5 KiB
Go
Raw Normal View History

package dbrepo
import (
"context"
"errors"
"go-udemy-web-1/internal/models"
"time"
"golang.org/x/crypto/bcrypt"
)
func (m *postgresDBRepo) AllUsers() bool {
return true
}
// InsertReservation inserts a reservation into the database
2024-07-09 20:57:07 +00:00
func (m *postgresDBRepo) InsertReservation(res models.Reservation) (int, error) {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
2024-07-09 20:57:07 +00:00
var newId int
// statement
stmt := `insert into reservations (first_name, last_name, email, phone,
start_date, end_date, room_id, created_at, updated_at)
2024-07-09 20:57:07 +00:00
values ($1, $2, $3, $4, $5, $6, $7, $8, $9) returning id`
row := m.DB.QueryRowContext(ctx, stmt,
res.FirstName,
res.LastName,
res.Email,
res.Phone,
res.StartDate,
res.EndDate,
res.RoomID,
time.Now(),
time.Now())
err := row.Scan(&newId)
if err != nil {
return 0, err
}
return newId, nil
}
// InsertRoomRestriction inserts a room restriction into the database
func (m *postgresDBRepo) InsertRoomRestriction(r models.RoomRestriction) error {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
stmt := `insert into room_restrictions (
start_date, end_date, room_id, reservation_id, restriction_id,
created_at, updated_at)
values ($1, $2, $3, $4, $5, $6, $7)`
2024-07-09 20:57:07 +00:00
_, err := m.DB.ExecContext(ctx, stmt,
r.StartDate,
r.EndDate,
r.RoomID,
r.ReservationID,
r.RestrictionID,
time.Now(),
time.Now())
if err != nil {
return err
}
return nil
}
2024-07-09 21:08:31 +00:00
// SearchAvailabilityByDatesByRoomID returns true if availability exists for roomID, and false if no availability
func (m *postgresDBRepo) SearchAvailabilityByDatesByRoomID(start, end time.Time, roomID int) (bool, error) {
2024-07-09 21:08:31 +00:00
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
var numRows int
stmt := `select count(id) from room_restrictions
where room_id = $1 and
$2 < end_date and $3> start_date`
row := m.DB.QueryRowContext(ctx, stmt, roomID, start, end)
err := row.Scan(&numRows)
if err != nil {
return false, err
}
if numRows == 0 {
return true, nil
}
return false, nil
}
// SearchAvailabilityForAllRooms returns a slice of rooms, if any, for given date range
func (m *postgresDBRepo) SearchAvailabilityForAllRooms(start, end time.Time) ([]models.Room, error) {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
var rooms []models.Room
stmt := `select
r.id, r.room_name
from
rooms r
where r.id not in
(select
room_id
from
room_restrictions rr
where
$1 < rr.end_date and $2> rr.start_date)`
rows, err := m.DB.QueryContext(ctx, stmt, start, end)
if err != nil {
return nil, err
}
2024-07-22 20:14:48 +00:00
defer rows.Close()
for rows.Next() {
var room models.Room
err := rows.Scan(&room.ID, &room.RoomName)
if err != nil {
return rooms, err
}
rooms = append(rooms, room)
}
if err = rows.Err(); err != nil {
return rooms, err
}
return rooms, nil
}
// GetRoomById gets a room by id
func (m *postgresDBRepo) GetRoomById(id int) (models.Room, error) {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
var room models.Room
stmt := `select
id, room_name, created_at, updated_at
from
rooms
where id = $1`
row := m.DB.QueryRowContext(ctx, stmt, id)
err := row.Scan(&room.ID, &room.RoomName, &room.CreatedAt, &room.UpdatedAt)
if err != nil {
return room, err
}
return room, nil
}
// GetUserByID gets a user by id
func (m *postgresDBRepo) GetUserByID(id int) (models.User, error) {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
query := `select id, first_name, last_name, email, password, access_level, created_at, updated_at
from users where id = $1`
row := m.DB.QueryRowContext(ctx, query, id)
var u models.User
err := row.Scan(
&u.ID,
&u.FirstName,
&u.LastName,
&u.Email,
&u.Password,
&u.AccessLevel,
&u.CreatedAt,
&u.UpdatedAt,
)
if err != nil {
return models.User{}, err
}
return u, nil
}
// UpdateUser updates a user in the database
func (m *postgresDBRepo) UpdateUser(u models.User) error {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
query := `update users set first_name = $1, last_name = $2, email = $3, access_level = $4, updated_at = $5`
_, err := m.DB.ExecContext(ctx, query, u.FirstName, u.LastName, u.Email, u.AccessLevel, time.Now())
if err != nil {
return err
}
return nil
}
// Authenticate authenticates a user
func (m *postgresDBRepo) Authenticate(email, testPassword string) (int, string, error) {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
var id int
var hashedPassword string
row := m.DB.QueryRowContext(ctx, "select id, password from users where email = $1", email)
err := row.Scan(&id, &hashedPassword)
if err != nil {
return id, "", err
}
err = bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(testPassword))
if err == bcrypt.ErrMismatchedHashAndPassword {
return 0, "", errors.New("incorrect password")
} else if err != nil {
return 0, "", err
}
return id, hashedPassword, nil
}
2024-07-22 20:14:48 +00:00
// AllReservations returns a slice of all reservations
func (m *postgresDBRepo) AllReservations() ([]models.Reservation, error) {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
var reservations []models.Reservation
query := `select r.id, r.first_name, r.last_name, r.email, r.phone,
r.start_date, r.end_date, r.room_id, r.created_at,
2024-07-24 12:20:30 +00:00
r.updated_at, r.processed, rm.id, rm.room_name
2024-07-22 20:14:48 +00:00
from reservations r
left join rooms rm on (r.room_id = rm.id)
order by r.start_date asc`
rows, err := m.DB.QueryContext(ctx, query)
if err != nil {
return reservations, err
}
defer rows.Close() // To avoid memory leak
for rows.Next() {
var i models.Reservation
err := rows.Scan(
&i.ID,
&i.FirstName,
&i.LastName,
&i.Email,
&i.Phone,
&i.StartDate,
&i.EndDate,
&i.RoomID,
&i.CreatedAt,
&i.UpdatedAt,
2024-07-24 12:20:30 +00:00
&i.Processed,
&i.Room.ID,
&i.Room.RoomName,
)
if err != nil {
return reservations, err
}
reservations = append(reservations, i)
}
return reservations, nil
}
// AllNewReservations returns a slice of all new reservations
func (m *postgresDBRepo) AllNewReservations() ([]models.Reservation, error) {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
var reservations []models.Reservation
query := `select r.id, r.first_name, r.last_name, r.email, r.phone,
r.start_date, r.end_date, r.room_id, r.created_at,
r.updated_at, r.processed, rm.id, rm.room_name
from reservations r
left join rooms rm on (r.room_id = rm.id)
where r.processed = 0
order by r.start_date asc`
rows, err := m.DB.QueryContext(ctx, query)
if err != nil {
return reservations, err
}
defer rows.Close() // To avoid memory leak
for rows.Next() {
var i models.Reservation
err := rows.Scan(
&i.ID,
&i.FirstName,
&i.LastName,
&i.Email,
&i.Phone,
&i.StartDate,
&i.EndDate,
&i.RoomID,
&i.CreatedAt,
&i.UpdatedAt,
&i.Processed,
2024-07-22 20:14:48 +00:00
&i.Room.ID,
&i.Room.RoomName,
)
if err != nil {
return reservations, err
}
reservations = append(reservations, i)
}
return reservations, nil
}
2024-07-24 20:23:31 +00:00
// GetReservationByID returns one reservation by ID
func (m *postgresDBRepo) GetReservationByID(id int) (models.Reservation, error) {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
var res models.Reservation
query := `select r.id, r.first_name, r.last_name, r.email, r.phone,
r.start_date, r.end_date, r.room_id, r.created_at,
r.updated_at, r.processed, rm.id, rm.room_name
from reservations r
left join rooms rm on (r.room_id = rm.id)
where r.id = $1`
row := m.DB.QueryRowContext(ctx, query, id)
err := row.Scan(
&res.ID,
&res.FirstName,
&res.LastName,
&res.Email,
&res.Phone,
&res.StartDate,
&res.EndDate,
&res.RoomID,
&res.CreatedAt,
&res.UpdatedAt,
&res.Processed,
&res.Room.ID,
&res.Room.RoomName,
)
if err != nil {
return res, err
}
return res, nil
}