Initial commit

This commit is contained in:
user
2026-07-12 13:47:34 +04:00
commit 51e2e789d0
37 changed files with 2005 additions and 0 deletions
+110
View File
@@ -0,0 +1,110 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Table Booking</title>
<link rel="stylesheet" href="styles.css">
<script src="script.js" defer></script>
</head>
<body>
<header>
<h1>Table and Booking Management</h1>
</header>
<main>
<!-- Section to display and manage tables -->
<section id="manage-tables">
<h2>Manage Tables</h2>
<table id="tables">
<thead>
<tr>
<th>ID</th>
<th>Name (Number)</th>
<th>Max People</th>
<th>Room</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<!-- Data will be populated here -->
</tbody>
</table>
<h3>Create/Update Table</h3>
<form id="table-form">
<label for="table-id">Table ID (leave blank to create new):</label>
<input type="number" id="table-id" name="id">
<label for="table-name">Name (Number):</label>
<input type="number" id="table-name" name="name" required>
<label for="table-max-people">Max People:</label>
<input type="number" id="table-max-people" name="max_people" required>
<label for="table-room">Room:</label>
<input type="text" id="table-room" name="room" required>
<button type="submit">Save Table</button>
</form>
<h3>Find Table by ID</h3>
<form id="find-table-form">
<label for="find-table-id">Enter Table ID:</label>
<input type="number" id="find-table-id" name="id" required>
<button type="submit">Find Table</button>
</form>
</section>
<!-- Section to display and manage bookings -->
<section id="manage-bookings">
<h2>Manage Bookings</h2>
<table id="bookings">
<thead>
<tr>
<th>ID</th>
<th>Table ID</th>
<th>Reservation DateTime</th>
<th>Time Reserve</th>
<th>Who Booked</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<!-- Data will be populated here -->
</tbody>
</table>
<h3>Create/Update Booking</h3>
<form id="booking-form">
<label for="booking-id">Booking ID (leave blank to create new):</label>
<input type="number" id="booking-id" name="id">
<label for="booking-table-id">Table ID:</label>
<input type="number" id="booking-table-id" name="id_tables" required>
<label for="reservation-datetime">Reservation Date & Time:</label>
<input type="datetime-local" id="reservation-datetime" name="reservation" required>
<label for="time-reserve">Time Reserve:</label>
<input type="text" id="time-reserve" name="time_reserve" placeholder="e.g., 2 hours" required>
<label for="who-booked">Who Booked:</label>
<input type="text" id="who-booked" name="who_booked" required>
<button type="submit">Save Booking</button>
</form>
<!-- Section to find a booking by ID -->
<h3>Find Booking by ID</h3>
<form id="find-booking-form">
<label for="find-booking-id">Enter Booking ID:</label>
<input type="number" id="find-booking-id" name="id" required>
<button type="submit">Find Booking</button>
</form>
</section>
</main>
</body>
</html>
+249
View File
@@ -0,0 +1,249 @@
document.addEventListener("DOMContentLoaded", () => {
const apiUrl = "http://localhost:8080"; // Replace with your actual backend URL
// Fetch and populate table data
function loadTables() {
fetch(`${apiUrl}/tables`)
.then((response) => response.json())
.then((tables) => {
const tableBody = document.querySelector("#tables tbody");
tableBody.innerHTML = ""; // Clear existing rows
tables.forEach((table) => {
const row = document.createElement("tr");
row.innerHTML = `
<td>${table.id}</td>
<td>${table.name}</td>
<td>${table.max_people}</td>
<td>${table.room}</td>
<td>
<button data-id="${table.id}" class="edit">Edit</button>
<button data-id="${table.id}" class="delete">Delete</button>
</td>
`;
tableBody.appendChild(row);
});
})
.catch((error) => console.error("Error loading tables:", error));
}
// Handle form submission to create or update a table
document.querySelector("#table-form").addEventListener("submit", (e) => {
e.preventDefault();
const id = parseInt(document.querySelector("#table-id").value, 10) || undefined;
const name = parseInt(document.querySelector("#table-name").value, 10); // Adjusted for name as integer
const maxPeople = parseInt(document.querySelector("#table-max-people").value, 10);
const room = document.querySelector("#table-room").value;
const method = id ? "PUT" : "POST";
const endpoint = id ? `/table` : `/table`;
fetch(`${apiUrl}${endpoint}`, {
method,
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ id, name, max_people: maxPeople, room }),
})
.then((response) => {
if (!response.ok) {
return response.text().then((text) => {
if (text.trim() === "") {
throw new Error("Empty response from server");
}
try {
const errorJson = JSON.parse(text);
throw new Error(errorJson.message || "Failed to save table");
} catch {
throw new Error("Unexpected server response: " + text);
}
});
}
return response.text().then((text) => {
if (text.trim() === "") {
return {}; // Handle empty body for successful responses
}
return JSON.parse(text);
});
})
.then(() => {
document.querySelector("#table-form").reset();
loadTables();
alert(`Table ${id ? 'updated' : 'created'} successfully.`);
})
.catch((error) => {
console.error("Error saving table:", error);
alert(`Failed to save table: ${error.message}`);
});
});
// Handle table row actions (edit/delete)
document.querySelector("#tables").addEventListener("click", (e) => {
const button = e.target;
const id = button.dataset.id;
if (button.classList.contains("edit")) {
fetch(`${apiUrl}/table/${id}`)
.then((response) => response.json())
.then((table) => {
document.querySelector("#table-id").value = table.id;
document.querySelector("#table-name").value = table.name;
document.querySelector("#table-max-people").value = table.max_people;
document.querySelector("#table-room").value = table.room;
})
.catch((error) => console.error("Error fetching table:", error));
} else if (button.classList.contains("delete")) {
fetch(`${apiUrl}/table/${id}`, { method: "DELETE" })
.then(() => loadTables())
.catch((error) => console.error("Error deleting table:", error));
}
});
// Handle find table by ID
document.querySelector("#find-table-form").addEventListener("submit", (e) => {
e.preventDefault();
const id = parseInt(document.querySelector("#find-table-id").value, 10);
fetch(`${apiUrl}/table/${id}`)
.then((response) => {
if (!response.ok) {
throw new Error(`Table with ID ${id} not found`);
}
return response.json();
})
.then((table) => {
alert(`Table ID: ${table.id}\nName (Number): ${table.name}\nMax People: ${table.max_people}\nRoom: ${table.room}`);
})
.catch((error) => {
alert(`Error: ${error.message}`);
console.error("Error finding table:", error);
});
});
// Initial load
loadTables();
// Fetch and populate booking data
function loadBookings() {
fetch(`${apiUrl}/bookings`)
.then((response) => response.json())
.then((bookings) => {
const bookingBody = document.querySelector("#bookings tbody");
bookingBody.innerHTML = ""; // Clear existing rows
bookings.forEach((booking) => {
const row = document.createElement("tr");
row.innerHTML = `
<td>${booking.id}</td>
<td>${booking.id_tables}</td>
<td>${booking.reservation}</td>
<td>${booking.time_reserve}</td>
<td>${booking.who_booked}</td>
<td>
<button data-id="${booking.id}" class="edit">Edit</button>
<button data-id="${booking.id}" class="delete">Delete</button>
</td>
`;
bookingBody.appendChild(row);
});
})
.catch((error) => console.error("Error loading bookings:", error));
}
// Handle form submission to create or update a booking
document.querySelector("#booking-form").addEventListener("submit", (e) => {
e.preventDefault();
const id = parseInt(document.querySelector("#booking-id").value, 10) || undefined;
const tableId = parseInt(document.querySelector("#booking-table-id").value, 10);
const reservationDatetime = String(document.querySelector("#reservation-datetime").value);
const timeReserve = document.querySelector("#time-reserve").value;
const whoBooked = document.querySelector("#who-booked").value;
const method = id ? "PUT" : "POST";
const endpoint = id ? `/booking` : `/booking`;
fetch(`${apiUrl}${endpoint}`, {
method,
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ id, id_tables: tableId, reservation: reservationDatetime, time_reserve: timeReserve, who_booked: whoBooked }),
})
.then((response) => {
if (!response.ok) {
return response.text().then((text) => {
if (text.trim() === "") {
throw new Error("Empty response from server");
}
try {
const errorJson = JSON.parse(text);
throw new Error(errorJson.message || "Failed to save table");
} catch {
throw new Error("Unexpected server response: " + text);
}
});
}
return response.text().then((text) => {
if (text.trim() === "") {
return {}; // Handle empty body for successful responses
}
return JSON.parse(text);
});
})
.then(() => {
document.querySelector("#booking-form").reset();
loadBookings();
alert(`Booking ${id ? 'updated' : 'created'} successfully.`);
})
.catch((error) => {
console.error("Error saving booking:", error);
alert(`Failed to save booking: ${error.message}`);
});
});
// Handle booking row actions (edit/delete)
document.querySelector("#bookings").addEventListener("click", (e) => {
const button = e.target;
const id = button.dataset.id;
if (button.classList.contains("edit")) {
fetch(`${apiUrl}/booking/${id}`)
.then((response) => response.json())
.then((booking) => {
document.querySelector("#booking-id").value = booking.id;
document.querySelector("#booking-table-id").value = booking.id_tables;
document.querySelector("#reservation-datetime").value = booking.reservation;
document.querySelector("#time-reserve").value = booking.time_reserve;
document.querySelector("#who-booked").value = booking.who_booked;
})
.catch((error) => console.error("Error fetching booking:", error));
} else if (button.classList.contains("delete")) {
fetch(`${apiUrl}/booking/${id}`, { method: "DELETE" })
.then(() => loadBookings())
.catch((error) => console.error("Error deleting booking:", error));
}
});
// Handle find booking by ID
document.querySelector("#find-booking-form").addEventListener("submit", (e) => {
e.preventDefault();
const id = document.querySelector("#find-booking-id").value;
fetch(`${apiUrl}/booking/${id}`)
.then((response) => {
if (!response.ok) throw new Error("Booking not found");
return response.json();
})
.then((booking) => {
alert(`Booking ID: ${booking.id}\nTable ID: ${booking.id_tables}\nReservation: ${booking.reservation}\nTime Reserve: ${booking.time_reserve}\nWho Booked: ${booking.who_booked}`);
})
.catch((error) => {
alert(`Error: ${error.message}`);
console.error("Error finding booking:", error);
});
});
// Initial load
loadBookings();
});
+40
View File
@@ -0,0 +1,40 @@
body {
font-family: Arial, sans-serif;
margin: 20px;
}
table {
width: 100%;
border-collapse: collapse;
margin-bottom: 20px;
}
table, th, td {
border: 1px solid black;
}
th, td {
padding: 10px;
text-align: left;
}
form {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 5px;
}
input, select {
padding: 5px;
margin-bottom: 10px;
width: 100%;
box-sizing: border-box;
}
button {
padding: 10px 15px;
background-color: #007BFF;
color: white;
border: none;
cursor: pointer;
}
button:hover {
background-color: #0056b3;
}
+86
View File
@@ -0,0 +1,86 @@
package configuration
import (
"flag"
"time"
)
var databaseLocationFlag *string
var forceCreateSchemaFlag *bool
var createSchemaFlag *bool
var serverHostFlag *string
var serverPortFlag *int
var recordsLimitFlag *int
var recordsOffsetFlag *int
// Write timeout in seconds
var writeTimeoutFlag *int
// Read timeout in seconds
var readTimeoutFlag *int
func Init() {
databaseLocationFlag = flag.String("file", "SQLiteDatabase.db", "The file contains the sql lite database")
forceCreateSchemaFlag = flag.Bool("force-new-schema", false, "Force create a new database by erasing the data. Overrides the new flag")
createSchemaFlag = flag.Bool("new-schema", false, "Create a new database")
serverHostFlag = flag.String("host", "localhost", "The host for the server")
serverPortFlag = flag.Int("port", 8080, "The port for the server")
recordsLimitFlag = flag.Int("limit", 10, "The number of records to return")
recordsOffsetFlag = flag.Int("offset", 0, "The number of records to skip")
writeTimeoutFlag = flag.Int("write-timeout", 10, "The write timeout in seconds")
readTimeoutFlag = flag.Int("read-timeout", 10, "The read timeout in seconds")
flag.Parse()
}
func GetForceCreateSchema() bool {
return *forceCreateSchemaFlag
}
func GetCreateSchema() bool {
return *createSchemaFlag
}
func GetWriteTimeout() time.Duration {
result := time.Duration(*writeTimeoutFlag) * time.Second
return result
}
func GetReadTimeout() time.Duration {
result := time.Duration(*readTimeoutFlag) * time.Second
return result
}
func GetServerHost() string {
return *serverHostFlag
}
func GetRecordsOffset() int {
return *recordsOffsetFlag
}
func GetRecordsLimit() int {
return *recordsLimitFlag
}
func GetServerPort() int {
return *serverPortFlag
}
func GetDatabaseLocation() string {
return *databaseLocationFlag
}
+33
View File
@@ -0,0 +1,33 @@
package connection
import (
"github.com/jmoiron/sqlx"
_ "github.com/mattn/go-sqlite3"
"go_project/internal/configuration"
"go_project/pkg/behaivor"
)
func OpenDefault() (db *sqlx.DB, err error) {
connectionParameters := configuration.GetDatabaseLocation()
return Open(connectionParameters)
}
func Open(connectionParameters string) (db *sqlx.DB, err error) {
db, err = sqlx.Open("sqlite3", connectionParameters)
if err != nil {
return nil, err
}
err = db.Ping()
if err != nil {
return nil, err
}
return db, err
}
// Closing the database with error checking
func MustClose(db *sqlx.DB) {
err := db.Close()
behaivor.Anxiety("Database closing error", err)
}
+143
View File
@@ -0,0 +1,143 @@
package controllers
import (
"database/sql"
"errors"
"github.com/jmoiron/sqlx"
"go_project/internal/models"
"log"
)
type (
ListBookingParams struct {
Limit int `db:"limit" json:"limit"`
Offset int `db:"offset" json:"offset"`
}
CreateBookingParams struct {
IdTables int `db:"id_tables" json:"id_tables"`
Reservation string `db:"reservation" json:"reservation"`
TimeReserve string `db:"time_reserve" json:"time_reserve"`
WhoBooked string `db:"who_booked" json:"who_booked"`
}
UpdateBookingParams struct {
Id int `db:"id" json:"id"`
IdTables int `db:"id_tables" json:"id_tables"`
Reservation string `db:"reservation" json:"reservation"`
TimeReserve string `db:"time_reserve" json:"time_reserve"`
WhoBooked string `db:"who_booked" json:"who_booked"`
}
)
func BookingById(db *sqlx.DB, id int) (*models.Booking, error) {
rows, err := db.Query("SELECT * FROM Bookings WHERE id = ?", id)
if err != nil {
return nil, err
}
defer rows.Close()
if isEmpty := !rows.Next(); isEmpty {
return nil, nil
}
result := new(models.Booking)
err = rows.Scan(&result.Id, &result.IdTables, &result.ReservationDatetime, &result.TimeReserve, &result.WhoBooked)
return result, err
}
func AllBookings(db *sqlx.DB, params ListBookingParams) ([]models.Booking, error) {
query := `SELECT * FROM Bookings ORDER BY id LIMIT $1 OFFSET $2`
rows, err := db.Query(query, params.Limit, params.Offset)
if err == sql.ErrNoRows {
return nil, nil
}
if err != nil {
return nil, err
}
defer rows.Close()
var result []models.Booking
for rows.Next() {
var currentBooking models.Booking
err = rows.Scan(&currentBooking.Id, &currentBooking.IdTables, &currentBooking.ReservationDatetime, &currentBooking.TimeReserve, &currentBooking.WhoBooked)
if err != nil {
return nil, err
}
result = append(result, currentBooking)
}
return result, err
}
func CreateBooking(db *sqlx.DB, params CreateBookingParams) (*models.Booking, error) {
query := `
INSERT INTO Bookings (id_tables, reservation, time_reserve, who_booked)
VALUES ($1, $2, $3, $4)
RETURNING id, id_tables, reservation, time_reserve, who_booked
`
var result models.Booking
err := db.QueryRow(query,
params.IdTables,
params.Reservation,
params.TimeReserve,
params.WhoBooked,
).Scan(
&result.Id,
&result.IdTables,
&result.ReservationDatetime,
&result.TimeReserve,
&result.WhoBooked,
)
if err != nil {
log.Printf("CreateBooking: Insertion operation of the Bookings object is failed: %v\n", err)
return nil, err
}
log.Println("CreateBooking: Insertion operation of the Bookings object is successful")
return &result, nil
}
func DeleteBookingById(db *sqlx.DB, id int) (sql.Result, error) {
sqlResult, err := db.Exec("DELETE FROM Bookings WHERE id = ?", id)
if err == nil {
log.Println("DeleteBookingById: Deletion operation of the Bookings object is successful")
}
return sqlResult, err
}
func UpdateBooking(db *sqlx.DB, params UpdateBookingParams) (*models.Booking, error) {
query := `
UPDATE Bookings
SET id_tables = $1, reservation = $2, time_reserve = $3
WHERE id = $4
RETURNING id, id_tables, reservation, time_reserve, who_booked
`
result := &models.Booking{}
err := db.QueryRow(query, params.IdTables, params.Reservation, params.TimeReserve, params.Id).
Scan(&result.Id, &result.IdTables, &result.ReservationDatetime, &result.TimeReserve, &result.WhoBooked)
if err != nil {
switch {
case err == sql.ErrNoRows:
log.Printf("UpdateBooking: No rows affected for Booking ID %d", params.Id)
return nil, errors.New("update failed: no rows affected")
default:
log.Printf("UpdateBooking: Error executing query for Booking ID %d: %v", params.Id, err)
return nil, err
}
}
log.Printf("UpdateBooking: Successfully updated Booking ID %d", result.Id)
return result, nil
}
+135
View File
@@ -0,0 +1,135 @@
package controllers
import (
"database/sql"
"errors"
"github.com/jmoiron/sqlx"
"go_project/internal/models"
"log"
)
type (
ListTableParams struct {
Limit int `db:"limit" json:"limit"`
Offset int `db:"offset" json:"offset"`
}
CreateTableParams struct {
Name int `db:"name" json:"name"`
MaxPeople int `db:"max_people" json:"max_people"`
Room string `db:"room" json:"room"`
}
UpdateTableParams struct {
Id int `db:"id" json:"id"`
Name int `db:"name" json:"name"`
MaxPeople int `db:"max_people" json:"max_people"`
Room string `db:"room" json:"room"`
}
)
func TableById(db *sqlx.DB, id int) (*models.Table, error) {
rows, err := db.Query("SELECT * FROM Tables WHERE id = ?", id)
if err != nil {
return nil, err
}
defer rows.Close()
if isEmpty := !rows.Next(); isEmpty {
return nil, nil
}
result := new(models.Table)
err = rows.Scan(&result.Id, &result.Name, &result.MaxPeople, &result.Room)
return result, err
}
func AllTables(db *sqlx.DB, params ListTableParams) ([]models.Table, error) {
query := `SELECT * FROM Tables ORDER BY id LIMIT $1 OFFSET $2`
rows, err := db.Query(query, params.Limit, params.Offset)
if err == sql.ErrNoRows {
return nil, nil
}
if err != nil {
return nil, err
}
defer rows.Close()
var result []models.Table
for rows.Next() {
var currentTable models.Table
err = rows.Scan(&currentTable.Id, &currentTable.Name, &currentTable.MaxPeople, &currentTable.Room)
if err != nil {
return nil, err
}
result = append(result, currentTable)
}
return result, err
}
func CreateTable(db *sqlx.DB, params CreateTableParams) (*models.Table, error) {
query := `
INSERT INTO Tables (name, max_people, room)
VALUES (?, ?, ?)
RETURNING id, name, max_people, room
`
var table models.Table
err := db.QueryRow(query, params.Name, params.MaxPeople, params.Room).Scan(
&table.Id,
&table.Name,
&table.MaxPeople,
&table.Room,
)
if err != nil {
log.Printf("CreateTable: Insertion operation of the Tables object is failed: %v\n", err)
return nil, err
}
log.Println("CreateTable: Insertion operation of the Tables object is successful")
return &table, nil
}
func DeleteTableById(db *sqlx.DB, id int) (sql.Result, error) {
sqlResult, err := db.Exec("DELETE FROM Tables WHERE id = ?", id)
if err == nil {
log.Println("DeleteTableById: Deletion operation of the Tables object is successful")
}
return sqlResult, err
}
func UpdateTable(db *sqlx.DB, params UpdateTableParams) (*models.Table, error) {
query := `
UPDATE Tables
SET name = $1, max_people = $2, room = $3
WHERE id = $4
RETURNING id, name, max_people, room
`
result := &models.Table{}
err := db.QueryRow(query, params.Name, params.MaxPeople, params.Room, params.Id).
Scan(&result.Id, &result.Name, &result.MaxPeople, &result.Room)
if err != nil {
switch {
case errors.Is(err, sql.ErrNoRows):
log.Printf("No rows affected for Table ID %d", params.Id)
return nil, errors.New("no rows affected: update failed")
default:
log.Printf("Query execution error for Table ID %d: %v", params.Id, err)
return nil, err
}
}
log.Printf("Table ID %d updated successfully", result.Id)
return result, nil
}
+213
View File
@@ -0,0 +1,213 @@
package handlers
import (
"encoding/json"
"github.com/gorilla/mux"
"go_project/internal/configuration"
"go_project/internal/connection"
"go_project/internal/controllers"
"log"
"net/http"
"strconv"
)
func GetBookingById(response http.ResponseWriter, request *http.Request) {
log.Println("GetBookingById Serving:", request.URL.Path, "from", request.Host)
sqlHandler, err := connection.OpenDefault()
if err != nil {
log.Println("Error opening database connection:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
defer connection.MustClose(sqlHandler)
requestVars := mux.Vars(request)
bookingIdStringValue := requestVars["id"]
id, err := strconv.Atoi(bookingIdStringValue)
if err != nil {
log.Println("Current id string value of the booking record to get: \"" + bookingIdStringValue + "\"")
log.Println("Error parse id string value to int:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
booking, err := controllers.BookingById(sqlHandler, id)
if err != nil {
log.Println("Error getting booking by id from database:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
bookingMarshaled, err := json.Marshal(booking)
if err != nil {
log.Println("Error marshaling booking to json string format:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
response.Header().Set("Content-Type", "application/json")
_, err = response.Write(bookingMarshaled)
if err != nil {
log.Println("Error writing booking to response:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
response.WriteHeader(http.StatusOK)
}
func GetAllBookings(response http.ResponseWriter, request *http.Request) {
log.Println("GetAllBookings Serving:", request.URL.Path, "from", request.Host)
sqlHandler, err := connection.OpenDefault()
if err != nil {
log.Println("Error opening database connection:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
defer connection.MustClose(sqlHandler)
limit, offset := configuration.GetRecordsLimit(), configuration.GetRecordsOffset()
listBookingParams := controllers.ListBookingParams{Limit: limit, Offset: offset}
allBookings, err := controllers.AllBookings(sqlHandler, listBookingParams)
if err != nil {
log.Println("Error getting all bookings from database:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
allBookingsMarshaled, err := json.Marshal(allBookings)
if err != nil {
log.Println("Error marshaling all bookings:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
response.Header().Set("Content-Type", "application/json")
_, err = response.Write(allBookingsMarshaled)
if err != nil {
log.Println("Error writing all bookings to response:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
response.WriteHeader(http.StatusOK)
}
func CreateBooking(response http.ResponseWriter, request *http.Request) {
log.Println("CreateBooking Serving:", request.URL.Path, "from", request.Host)
sqlHandler, err := connection.OpenDefault()
if err != nil {
log.Println("Error opening database connection:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
defer connection.MustClose(sqlHandler)
var createBookingParams controllers.CreateBookingParams
err = json.NewDecoder(request.Body).Decode(&createBookingParams)
if err != nil {
log.Println("CreateBooking: Values of createBookingParams:", createBookingParams)
log.Println("Error unmarshaling booking from json string format:", err)
response.WriteHeader(http.StatusBadRequest)
return
}
newBooking, err := controllers.CreateBooking(sqlHandler, createBookingParams)
if err != nil {
log.Println("Error creating booking:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
newBookingMarshaled, err := json.Marshal(newBooking)
if err != nil {
log.Println("Error marshaling booking to json string format:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
response.Header().Set("Content-Type", "application/json")
_, err = response.Write(newBookingMarshaled)
if err != nil {
log.Println("Error writing booking to response:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
response.WriteHeader(http.StatusOK)
}
func UpdateBooking(response http.ResponseWriter, request *http.Request) {
log.Println("UpdateBookingById Serving:", request.URL.Path, "from", request.Host)
sqlHandler, err := connection.OpenDefault()
if err != nil {
log.Println("Error opening database connection:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
defer connection.MustClose(sqlHandler)
var updateBookingParams controllers.UpdateBookingParams
err = json.NewDecoder(request.Body).Decode(&updateBookingParams)
if err != nil {
log.Println("UpdateBooking: Values of updateBookingParams:", updateBookingParams)
log.Println("Error unmarshaling booking from json string format:", err)
response.WriteHeader(http.StatusBadRequest)
return
}
newBooking, err := controllers.UpdateBooking(sqlHandler, updateBookingParams)
if err != nil {
log.Println("Error updating booking by id from database:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
log.Println("SQL result: Updated booking record is:", newBooking)
response.WriteHeader(http.StatusOK)
}
func DeleteBookingById(response http.ResponseWriter, request *http.Request) {
log.Println("DeleteBookingById Serving:", request.URL.Path, "from", request.Host)
sqlHandler, err := connection.OpenDefault()
if err != err {
log.Println("Error opening database connection:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
defer connection.MustClose(sqlHandler)
requestVars := mux.Vars(request)
bookingIdStringValue := requestVars["id"]
id, err := strconv.Atoi(bookingIdStringValue)
if err != nil {
log.Println("Current id string value of the booking record to delete: \"" + bookingIdStringValue + "\"")
log.Println("Error parse id string value to int:", err)
response.WriteHeader(http.StatusBadRequest)
return
}
sqlResult, err := controllers.DeleteBookingById(sqlHandler, id)
if err != nil {
log.Println("Error deleting booking by id from database:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
rowsAffected, err := sqlResult.RowsAffected()
if err != nil {
log.Println("Error getting number of rows affected by an delete:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
log.Println("SQL result: Number of rows affected by an delete:", rowsAffected)
response.WriteHeader(http.StatusOK)
}
+213
View File
@@ -0,0 +1,213 @@
package handlers
import (
"encoding/json"
"github.com/gorilla/mux"
"go_project/internal/configuration"
"go_project/internal/connection"
"go_project/internal/controllers"
"log"
"net/http"
"strconv"
)
func GetAllTables(response http.ResponseWriter, request *http.Request) {
log.Println("GetAllTables Serving:", request.URL.Path, "from", request.Host)
sqlHandler, err := connection.OpenDefault()
if err != nil {
log.Println("Error opening database connection:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
defer connection.MustClose(sqlHandler)
limit, offset := configuration.GetRecordsLimit(), configuration.GetRecordsOffset()
listTableParams := controllers.ListTableParams{Limit: limit, Offset: offset}
allTables, err := controllers.AllTables(sqlHandler, listTableParams)
if err != nil {
log.Println("Error getting all tables from database:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
allTablesMarshaled, err := json.Marshal(allTables)
if err != nil {
log.Println("Error marshaling all tables:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
response.Header().Set("Content-Type", "application/json")
_, err = response.Write(allTablesMarshaled)
if err != nil {
log.Println("Error writing all tables to response:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
response.WriteHeader(http.StatusOK)
}
func GetTableById(response http.ResponseWriter, request *http.Request) {
log.Println("GetTableById Serving:", request.URL.Path, "from", request.Host)
sqlHandler, err := connection.OpenDefault()
if err != nil {
log.Println("Error opening database connection:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
defer connection.MustClose(sqlHandler)
requestVars := mux.Vars(request)
tableIdStringValue := requestVars["id"]
id, err := strconv.Atoi(tableIdStringValue)
if err != nil {
log.Println("Current id string value of the table record to get: \"" + tableIdStringValue + "\"")
log.Println("Error parse id string value to int:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
table, err := controllers.TableById(sqlHandler, id)
if err != nil {
log.Println("Error getting table by id from database:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
tableMarshaled, err := json.Marshal(table)
if err != nil {
log.Println("Error marshaling table to json string format:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
response.Header().Set("Content-Type", "application/json")
_, err = response.Write(tableMarshaled)
if err != nil {
log.Println("Error writing table to response:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
response.WriteHeader(http.StatusOK)
}
func CreateTable(response http.ResponseWriter, request *http.Request) {
log.Println("CreateTable Serving:", request.URL.Path, "from", request.Host)
sqlHandler, err := connection.OpenDefault()
if err != nil {
log.Println("Error opening database connection:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
defer connection.MustClose(sqlHandler)
var createTableParams controllers.CreateTableParams
err = json.NewDecoder(request.Body).Decode(&createTableParams)
if err != nil {
log.Println("CreateTable: Values of createTableParams:", createTableParams)
log.Println("Error unmarshaling table from json string format:", err)
response.WriteHeader(http.StatusBadRequest)
return
}
newTable, err := controllers.CreateTable(sqlHandler, createTableParams)
if err != nil {
log.Println("Error creating table:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
newTableMarshaled, err := json.Marshal(newTable)
if err != nil {
log.Println("Error marshaling table to json string format:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
response.Header().Set("Content-Type", "application/json")
_, err = response.Write(newTableMarshaled)
if err != nil {
log.Println("Error writing table to response:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
response.WriteHeader(http.StatusOK)
}
func DeleteTableById(response http.ResponseWriter, request *http.Request) {
log.Println("DeleteTableById Serving:", request.URL.Path, "from", request.Host)
sqlHandler, err := connection.OpenDefault()
if err != nil {
log.Println("Error opening database connection:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
defer connection.MustClose(sqlHandler)
requestVars := mux.Vars(request)
tableIdStringValue := requestVars["id"]
id, err := strconv.Atoi(tableIdStringValue)
if err != nil {
log.Println("Current id string value of the table record to delete: \"" + tableIdStringValue + "\"")
log.Println("Error parse id string value to int:", err)
response.WriteHeader(http.StatusBadRequest)
return
}
sqlResult, err := controllers.DeleteTableById(sqlHandler, id)
if err != nil {
log.Println("Error deleting table by id from database:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
rowsAffected, err := sqlResult.RowsAffected()
if err != nil {
log.Println("Error getting number of rows affected by an delete:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
log.Println("SQL result: Number of rows affected by an delete:", rowsAffected)
response.WriteHeader(http.StatusOK)
}
func UpdateTable(response http.ResponseWriter, request *http.Request) {
log.Println("UpdateTableById Serving:", request.URL.Path, "from", request.Host)
sqlHandler, err := connection.OpenDefault()
if err != nil {
log.Println("Error opening database connection:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
defer connection.MustClose(sqlHandler)
var updateTableParams controllers.UpdateTableParams
err = json.NewDecoder(request.Body).Decode(&updateTableParams)
if err != nil {
log.Println("UpdateTable: Values of updateTableParams:", updateTableParams)
log.Println("Error unmarshaling table from json string format:", err)
response.WriteHeader(http.StatusBadRequest)
return
}
newTable, err := controllers.UpdateTable(sqlHandler, updateTableParams)
if err != nil {
log.Println("Error updating table by id from database:", err)
response.WriteHeader(http.StatusInternalServerError)
return
}
log.Println("SQL result: Updated table record is:", newTable)
response.WriteHeader(http.StatusOK)
}
+18
View File
@@ -0,0 +1,18 @@
package models
type (
Table struct {
Id int64 `db:"id" json:"id"`
Name int64 `db:"name" json:"name"`
MaxPeople int64 `db:"max_people" json:"max_people"`
Room string `db:"room" json:"room"`
}
Booking struct {
Id int64 `db:"id" json:"id"`
IdTables int64 `db:"id_tables" json:"id_tables"`
ReservationDatetime string `db:"reservation" json:"reservation"`
TimeReserve string `db:"time_reserve" json:"time_reserve"`
WhoBooked string `db:"who_booked" json:"who_booked"`
}
)
+35
View File
@@ -0,0 +1,35 @@
package routes
import (
"github.com/gorilla/mux"
"go_project/internal/handlers"
"go_project/pkg/behaivor"
"go_project/pkg/information"
"net/http"
)
func DefaultRouter() *mux.Router {
router := mux.NewRouter()
declareRoutes(router)
http.Handle("/", router)
err := router.Walk(information.AboutRoute)
behaivor.Anxiety("Error walking routes", err)
return router
}
var declareRoutes = func(router *mux.Router) {
// End points for Table record
router.HandleFunc("/tables", handlers.GetAllTables).Methods("GET")
router.HandleFunc("/table/{id:[0-9]+}", handlers.GetTableById).Methods("GET")
router.HandleFunc("/table", handlers.CreateTable).Methods("POST")
router.HandleFunc("/table", handlers.UpdateTable).Methods("PUT")
router.HandleFunc("/table/{id:[0-9]+}", handlers.DeleteTableById).Methods("DELETE")
// End points for Booking record
router.HandleFunc("/bookings", handlers.GetAllBookings).Methods("GET")
router.HandleFunc("/booking/{id:[0-9]+}", handlers.GetBookingById).Methods("GET")
router.HandleFunc("/booking", handlers.CreateBooking).Methods("POST")
router.HandleFunc("/booking", handlers.UpdateBooking).Methods("PUT")
router.HandleFunc("/booking/{id:[0-9]+}", handlers.DeleteBookingById).Methods("DELETE")
}
+66
View File
@@ -0,0 +1,66 @@
package schema
import (
"github.com/jmoiron/sqlx"
)
type schema struct {
create string
drop string
}
func MustCreate(db *sqlx.DB) {
db.MustExec(defaultSchema.create)
}
func MustDrop(db *sqlx.DB) {
db.MustExec(defaultSchema.drop)
}
// Type time_reserve stores the reserve time reserve by time
// Type TIME(0) has minimal accuracy, counts down by seconds
// Type SMALLDATETIME has format'YYYYMMDD hh:mm', for example '20090212 12:30', counts down by minuts
var defaultSchema = schema{
create: `
CREATE TABLE IF NOT EXISTS Tables (
id INTEGER
CONSTRAINT PK_Tables PRIMARY KEY AUTOINCREMENT,
name INTEGER NOT NULL UNIQUE,
max_people INTEGER NOT NULL,
room TEXT NOT NULL,
CONSTRAINT CHK_max_people CHECK (
max_people > 0
AND max_people < 11
)
);
CREATE TABLE IF NOT EXISTS Bookings (
id INTEGER
CONSTRAINT PK_Bookings PRIMARY KEY AUTOINCREMENT,
id_tables INTEGER,
reservation TEXT NOT NULL,
time_reserve TEXT NOT NULL,
who_booked TEXT NOT NULL,
CONSTRAINT FK_Bookings_Tables FOREIGN KEY (id_tables) REFERENCES Tables (id),
CONSTRAINT CHK_min_max_time_reserve CHECK (time_reserve BETWEEN "00:30" AND "12:00")
);
CREATE TRIGGER IF NOT EXISTS CHK_Bookings_Insert
BEFORE INSERT ON Bookings
BEGIN
SELECT RAISE(
FAIL,
"Reservation of table is not possible due to the existing reservation"
)
FROM (
SELECT
datetime(NEW.reservation) AS new_res_dt,
datetime(reservation) AS res_dt,
datetime(reservation, time_reserve) AS reserved_until,
id_tables
FROM Bookings
)
WHERE
(new_res_dt >= res_dt AND new_res_dt < reserved_until)
AND id_tables = NEW.id_tables;
END;
`,
}