finish pgc impl

This commit is contained in:
vinchent 2024-07-31 22:15:37 +02:00
parent f20f256313
commit cec183b416
4 changed files with 564 additions and 0 deletions

View File

@ -194,6 +194,17 @@ func (q *Queries) AllRooms(ctx context.Context) ([]Room, error) {
return items, nil return items, nil
} }
const deleteBlockByID = `-- name: DeleteBlockByID :exec
DELETE FROM room_restrictions
WHERE
id = $1
`
func (q *Queries) DeleteBlockByID(ctx context.Context, id int32) error {
_, err := q.db.Exec(ctx, deleteBlockByID, id)
return err
}
const deleteReservation = `-- name: DeleteReservation :exec const deleteReservation = `-- name: DeleteReservation :exec
DELETE FROM reservations DELETE FROM reservations
WHERE WHERE
@ -264,6 +275,64 @@ func (q *Queries) GetReservationByID(ctx context.Context, id int32) (GetReservat
return i, err return i, err
} }
const getRestrictionsForRoomByDate = `-- name: GetRestrictionsForRoomByDate :many
SELECT
id,
coalesce(reservation_id, 0),
restriction_id,
room_id,
start_date,
end_date
FROM
room_restrictions
WHERE
$1 < end_date
AND $2 >= start_date
AND room_id = $3
`
type GetRestrictionsForRoomByDateParams struct {
EndDate pgtype.Date
StartDate pgtype.Date
RoomID int32
}
type GetRestrictionsForRoomByDateRow struct {
ID int32
ReservationID int32
RestrictionID int32
RoomID int32
StartDate pgtype.Date
EndDate pgtype.Date
}
func (q *Queries) GetRestrictionsForRoomByDate(ctx context.Context, arg GetRestrictionsForRoomByDateParams) ([]GetRestrictionsForRoomByDateRow, error) {
rows, err := q.db.Query(ctx, getRestrictionsForRoomByDate, arg.EndDate, arg.StartDate, arg.RoomID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetRestrictionsForRoomByDateRow
for rows.Next() {
var i GetRestrictionsForRoomByDateRow
if err := rows.Scan(
&i.ID,
&i.ReservationID,
&i.RestrictionID,
&i.RoomID,
&i.StartDate,
&i.EndDate,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getRoomById = `-- name: GetRoomById :one const getRoomById = `-- name: GetRoomById :one
SELECT SELECT
id, id,
@ -342,6 +411,41 @@ func (q *Queries) GetUserCred(ctx context.Context, email string) (GetUserCredRow
return i, err return i, err
} }
const insertBlockForRoom = `-- name: InsertBlockForRoom :exec
INSERT INTO
room_restrictions (
start_date,
end_date,
room_id,
restriction_id,
created_at,
updated_at
)
VALUES
($1, $2, $3, $4, $5, $6)
`
type InsertBlockForRoomParams struct {
StartDate pgtype.Date
EndDate pgtype.Date
RoomID int32
RestrictionID int32
CreatedAt pgtype.Timestamp
UpdatedAt pgtype.Timestamp
}
func (q *Queries) InsertBlockForRoom(ctx context.Context, arg InsertBlockForRoomParams) error {
_, err := q.db.Exec(ctx, insertBlockForRoom,
arg.StartDate,
arg.EndDate,
arg.RoomID,
arg.RestrictionID,
arg.CreatedAt,
arg.UpdatedAt,
)
return err
}
const insertReservation = `-- name: InsertReservation :one const insertReservation = `-- name: InsertReservation :one
INSERT INTO INSERT INTO
reservations ( reservations (

View File

@ -4,6 +4,7 @@ import (
"database/sql" "database/sql"
"go-udemy-web-1/internal/config" "go-udemy-web-1/internal/config"
"go-udemy-web-1/internal/repository" "go-udemy-web-1/internal/repository"
"go-udemy-web-1/internal/repository/db"
) )
type postgresDBRepo struct { type postgresDBRepo struct {
@ -11,6 +12,11 @@ type postgresDBRepo struct {
DB *sql.DB DB *sql.DB
} }
type pgcDBRepo struct {
App *config.AppConfig
Q *db.Queries
}
type testDBRepo struct { type testDBRepo struct {
App *config.AppConfig App *config.AppConfig
DB *sql.DB DB *sql.DB
@ -28,3 +34,10 @@ func NewTestingRepo(a *config.AppConfig) repository.DatabaseRepo {
App: a, App: a,
} }
} }
func NewPgcRepo(q *db.Queries, a *config.AppConfig) repository.DatabaseRepo {
return &pgcDBRepo{
App: a,
Q: q,
}
}

View File

@ -0,0 +1,414 @@
package dbrepo
import (
"context"
"errors"
"go-udemy-web-1/internal/models"
"go-udemy-web-1/internal/repository/db"
"time"
"github.com/jackc/pgx/v5/pgtype"
"golang.org/x/crypto/bcrypt"
)
func (m *pgcDBRepo) AllUsers() bool {
return true
}
// InsertReservation inserts a reservation into the database
func (m *pgcDBRepo) InsertReservation(res models.Reservation) (int, error) {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
var newId int32
newId, err := m.Q.InsertReservation(ctx, db.InsertReservationParams{
FirstName: res.FirstName,
LastName: res.LastName,
Email: res.Email,
Phone: res.Phone,
StartDate: pgtype.Date{Time: res.StartDate, Valid: true},
EndDate: pgtype.Date{Time: res.EndDate, Valid: true},
RoomID: int32(res.Room.ID),
CreatedAt: pgtype.Timestamp{Time: res.CreatedAt, Valid: true},
UpdatedAt: pgtype.Timestamp{Time: res.UpdatedAt, Valid: true},
})
if err != nil {
return 0, err
}
return int(newId), nil
}
// InsertRoomRestriction inserts a room restriction into the database
func (m *pgcDBRepo) InsertRoomRestriction(r models.RoomRestriction) error {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
err := m.Q.InsertRoomRestriction(ctx, db.InsertRoomRestrictionParams{
StartDate: pgtype.Date{Time: r.StartDate, Valid: true},
EndDate: pgtype.Date{Time: r.EndDate, Valid: true},
RoomID: int32(r.Room.ID),
ReservationID: pgtype.Int4{Int32: int32(r.ID), Valid: true},
RestrictionID: int32(r.RestrictionID),
CreatedAt: pgtype.Timestamp{Time: r.CreatedAt, Valid: true},
UpdatedAt: pgtype.Timestamp{Time: r.UpdatedAt, Valid: true},
})
if err != nil {
return err
}
return nil
}
// SearchAvailabilityByDatesByRoomID returns true if availability exists for roomID, and false if no availability
func (m *pgcDBRepo) SearchAvailabilityByDatesByRoomID(start, end time.Time, roomID int) (bool, error) {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
numRows, err := m.Q.SearchAvailabilityByDatesByRoomID(ctx, db.SearchAvailabilityByDatesByRoomIDParams{
RoomID: int32(roomID),
EndDate: pgtype.Date{Time: start, Valid: true},
StartDate: pgtype.Date{Time: end, Valid: false},
})
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 *pgcDBRepo) SearchAvailabilityForAllRooms(start, end time.Time) ([]models.Room, error) {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
var rooms []models.Room
rows, err := m.Q.SearchAvailabilityForAllRooms(ctx, db.SearchAvailabilityForAllRoomsParams{
EndDate: pgtype.Date{Time: start, Valid: true},
StartDate: pgtype.Date{Time: start, Valid: true},
})
if err != nil {
return nil, err
}
for _, row := range rows {
room := models.Room{
RoomName: row.RoomName,
ID: int(row.ID),
}
rooms = append(rooms, room)
}
return rooms, nil
}
// GetRoomById gets a room by id
func (m *pgcDBRepo) GetRoomById(id int) (models.Room, error) {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
var room models.Room
row, err := m.Q.GetRoomById(ctx, int32(id))
if err != nil {
return room, err
}
room = models.Room{
ID: int(row.ID),
RoomName: row.RoomName,
}
return room, nil
}
// GetUserByID gets a user by id
func (m *pgcDBRepo) GetUserByID(id int) (models.User, error) {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
var u models.User
row, err := m.Q.GetUserByID(ctx, int32(id))
if err != nil {
return u, err
}
u = models.User{
ID: int(row.ID),
FirstName: row.FirstName,
LastName: row.LastName,
Email: row.Email,
Password: row.Password,
AccessLevel: int(row.AccessLevel),
}
return u, nil
}
// UpdateUser updates a user in the database
func (m *pgcDBRepo) UpdateUser(u models.User) error {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
err := m.Q.UpdateUser(ctx, db.UpdateUserParams{
FirstName: u.FirstName,
LastName: u.LastName,
Email: u.Email,
AccessLevel: int32(u.AccessLevel),
UpdatedAt: pgtype.Timestamp{Time: u.UpdatedAt, Valid: true},
})
if err != nil {
return err
}
return nil
}
// Authenticate authenticates a user
func (m *pgcDBRepo) 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, err := m.Q.GetUserCred(ctx, email)
if err != nil {
return id, "", err
}
id = int(row.ID)
hashedPassword = row.Password
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
}
// AllReservations returns a slice of all reservations
func (m *pgcDBRepo) AllReservations() ([]models.Reservation, error) {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
var reservations []models.Reservation
rows, err := m.Q.AllReservations(ctx)
if err != nil {
return nil, err
}
for _, row := range rows {
r := models.Reservation{
StartDate: row.StartDate.Time,
EndDate: row.EndDate.Time,
FirstName: row.FirstName,
LastName: row.LastName,
Email: row.Email,
Phone: row.Phone,
Room: models.Room{ID: int(row.RoomID), RoomName: row.RoomName.String},
ID: int(row.ID),
RoomID: int(row.RoomID),
Processed: int(row.Processed),
}
reservations = append(reservations, r)
}
return reservations, nil
}
// AllNewReservations returns a slice of all new reservations
func (m *pgcDBRepo) AllNewReservations() ([]models.Reservation, error) {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
var reservations []models.Reservation
rows, err := m.Q.AllNewReservations(ctx)
if err != nil {
return nil, err
}
for _, row := range rows {
r := models.Reservation{
StartDate: row.StartDate.Time,
EndDate: row.EndDate.Time,
FirstName: row.FirstName,
LastName: row.LastName,
Email: row.Email,
Phone: row.Phone,
Room: models.Room{ID: int(row.RoomID), RoomName: row.RoomName.String},
ID: int(row.ID),
RoomID: int(row.RoomID),
Processed: int(row.Processed),
}
reservations = append(reservations, r)
}
return reservations, nil
}
// GetReservationByID returns one reservation by ID
func (m *pgcDBRepo) GetReservationByID(id int) (models.Reservation, error) {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
var res models.Reservation
row, err := m.Q.GetReservationByID(ctx, int32(id))
if err != nil {
return res, err
}
res = models.Reservation{
StartDate: row.StartDate.Time,
EndDate: row.EndDate.Time,
FirstName: row.FirstName,
LastName: row.LastName,
Email: row.Email,
Phone: row.Phone,
Room: models.Room{ID: int(row.RoomID), RoomName: row.RoomName.String},
ID: int(row.ID),
RoomID: int(row.RoomID),
Processed: int(row.Processed),
}
return res, nil
}
// UpdateReservation updates a user in the database
func (m *pgcDBRepo) UpdateReservation(r models.Reservation) error {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
err := m.Q.UpdateReservation(ctx, db.UpdateReservationParams{
ID: int32(r.ID),
FirstName: r.FirstName,
LastName: r.LastName,
Email: r.Email,
Phone: r.Phone,
UpdatedAt: pgtype.Timestamp{Time: r.UpdatedAt, Valid: true},
})
if err != nil {
return err
}
return nil
}
func (m *pgcDBRepo) DeleteReservation(id int) error {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
err := m.Q.DeleteReservation(ctx, int32(id))
if err != nil {
return err
}
return nil
}
// UpdateProcessedForReservation set processed for a reservation
func (m *pgcDBRepo) UpdateProcessedForReservation(id, processed int) error {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
err := m.Q.UpdateProcessedForReservation(ctx, db.UpdateProcessedForReservationParams{
Processed: int32(processed),
ID: int32(id),
})
if err != nil {
return err
}
return nil
}
func (m *pgcDBRepo) AllRooms() ([]models.Room, error) {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
var rooms []models.Room
rows, err := m.Q.AllRooms(ctx)
if err != nil {
return nil, err
}
for _, row := range rows {
room := models.Room{
RoomName: row.RoomName,
ID: int(row.ID),
}
rooms = append(rooms, room)
}
return rooms, nil
}
// GetRestrictionsForRoomByDate returns restrictions for a room by date range
func (m *pgcDBRepo) GetRestrictionsForRoomByDate(roomId int, start, end time.Time) ([]models.RoomRestriction, error) {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
var restrictions []models.RoomRestriction
rows, err := m.Q.GetRestrictionsForRoomByDate(ctx, db.GetRestrictionsForRoomByDateParams{
EndDate: pgtype.Date{Time: end, Valid: true},
StartDate: pgtype.Date{Time: start, Valid: true},
RoomID: int32(roomId),
})
if err != nil {
return restrictions, err
}
for _, row := range rows {
r := models.RoomRestriction{
StartDate: row.StartDate.Time,
EndDate: row.EndDate.Time,
ID: int(row.ID),
RoomID: int(row.RoomID),
ReservationID: int(row.ReservationID),
RestrictionID: int(row.RestrictionID),
}
restrictions = append(restrictions, r)
}
return restrictions, nil
}
// InsertBlockForRoom inserts a room restriction
func (m *pgcDBRepo) InsertBlockForRoom(id int, startDate time.Time) error {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
err := m.Q.InsertBlockForRoom(ctx, db.InsertBlockForRoomParams{
StartDate: pgtype.Date{Time: startDate, Valid: true},
EndDate: pgtype.Date{Time: startDate.AddDate(0, 0, 1)},
RoomID: int32(id),
RestrictionID: 2,
CreatedAt: pgtype.Timestamp{Time: time.Now(), Valid: true},
UpdatedAt: pgtype.Timestamp{Time: time.Now(), Valid: true},
})
if err != nil {
return err
}
return nil
}
// DeleteBlockByID deletes a block by ID
func (m *pgcDBRepo) DeleteBlockByID(id int) error {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
err := m.Q.DeleteBlockByID(ctx, int32(id))
if err != nil {
return err
}
return nil
}

View File

@ -199,3 +199,36 @@ FROM
rooms rooms
ORDER BY ORDER BY
room_name; room_name;
-- name: GetRestrictionsForRoomByDate :many
SELECT
id,
coalesce(reservation_id, 0),
restriction_id,
room_id,
start_date,
end_date
FROM
room_restrictions
WHERE
$1 < end_date
AND $2 >= start_date
AND room_id = $3;
-- name: InsertBlockForRoom :exec
INSERT INTO
room_restrictions (
start_date,
end_date,
room_id,
restriction_id,
created_at,
updated_at
)
VALUES
($1, $2, $3, $4, $5, $6);
-- name: DeleteBlockByID :exec
DELETE FROM room_restrictions
WHERE
id = $1;