Initial commit
This commit is contained in:
Executable
+17
@@ -0,0 +1,17 @@
|
|||||||
|
clear
|
||||||
|
|
||||||
|
# Get dependencies
|
||||||
|
# go mod tidy
|
||||||
|
|
||||||
|
# Build server
|
||||||
|
go build .
|
||||||
|
|
||||||
|
# Delete previous database
|
||||||
|
sudo rm ./SQLiteDatabase.db
|
||||||
|
|
||||||
|
# Create new database
|
||||||
|
./cmd --new-schema
|
||||||
|
|
||||||
|
# Run server
|
||||||
|
./cmd --host=127.0.0.1 --port=8080 --limit=10 --offset=0 --write-timeout=10 --read-timeout=10
|
||||||
|
|
||||||
Executable
+11
@@ -0,0 +1,11 @@
|
|||||||
|
clear
|
||||||
|
|
||||||
|
# A 1 tables in Room 1
|
||||||
|
curl -X POST -H 'Content-Type: application/json' -d '{"name":11,"max_people":1,"room":"Room 1"}' localhost:8080/table --silent
|
||||||
|
# A 2 tables in Room 2
|
||||||
|
curl -X POST -H 'Content-Type: application/json' -d '{"name":21,"max_people":2,"room":"Room 2"}' localhost:8080/table --silent
|
||||||
|
curl -X POST -H 'Content-Type: application/json' -d '{"name":22,"max_people":4,"room":"Room 2"}' localhost:8080/table --silent
|
||||||
|
# A 3 tables in Room 3
|
||||||
|
curl -X POST -H 'Content-Type: application/json' -d '{"name":31,"max_people":3,"room":"Room 3"}' localhost:8080/table --silent
|
||||||
|
curl -X POST -H 'Content-Type: application/json' -d '{"name":32,"max_people":5,"room":"Room 3"}' localhost:8080/table --silent
|
||||||
|
curl -X POST -H 'Content-Type: application/json' -d '{"name":33,"max_people":6,"room":"Room 3"}' localhost:8080/table --silent
|
||||||
Executable
+7
@@ -0,0 +1,7 @@
|
|||||||
|
clear
|
||||||
|
|
||||||
|
# We move the table with id 6 from room 3 to room 1, rename it to 12
|
||||||
|
curl -X PUT -H 'Content-Type: application/json' -d '{"id":6,"name":12,"max_people":6,"room":"Room 1"}' localhost:8080/table --silent
|
||||||
|
|
||||||
|
# Now there are an equal number of tables in each room
|
||||||
|
|
||||||
Executable
+7
@@ -0,0 +1,7 @@
|
|||||||
|
clear
|
||||||
|
|
||||||
|
# Get all record of Tables
|
||||||
|
# curl -X GET -H 'Content-Type: application/json' localhost:8080/tables
|
||||||
|
|
||||||
|
# Get only one record of Table by id 6
|
||||||
|
curl -X GET -H 'Content-Type: application/json' localhost:8080/table/6
|
||||||
Executable
+4
@@ -0,0 +1,4 @@
|
|||||||
|
clear
|
||||||
|
|
||||||
|
# They decided to remove one table from the establishment. It was a table with id 6
|
||||||
|
curl -X DELETE localhost:8080/table/6 --silent
|
||||||
Executable
+4
@@ -0,0 +1,4 @@
|
|||||||
|
clear
|
||||||
|
|
||||||
|
# We will create the first booking for the very first table with a reservation for 1 hour
|
||||||
|
curl -X POST -H 'Content-Type: application/json' -d '{"id_tables":1,"reservation":"2000-01-01T12:00:00Z","time_reserve":"01:00","who_booked":"Ivan 1"}' localhost:8080/booking --silent
|
||||||
Executable
+4
@@ -0,0 +1,4 @@
|
|||||||
|
clear
|
||||||
|
|
||||||
|
# Ivan warned that he did not have time and asked to postpone the reservation of the table an hour later, he also informed that the duration of the reservation should be increased in time
|
||||||
|
curl -X PUT -H 'Content-Type: application/json' -d '{"id_tables":1,"reservation":"2000-01-01T13:00:00Z","time_reserve":"02:00","who_booked":"Ivan 1"}' localhost:8080/booking --silent
|
||||||
Executable
+7
@@ -0,0 +1,7 @@
|
|||||||
|
clear
|
||||||
|
|
||||||
|
# Get all record of Booking
|
||||||
|
# curl -X GET -H 'Content-Type: application/json' localhost:8080/booking
|
||||||
|
|
||||||
|
# Get only one record of Booking by id 1
|
||||||
|
curl -X GET -H 'Content-Type: application/json' localhost:8080/booking/1
|
||||||
Executable
+4
@@ -0,0 +1,4 @@
|
|||||||
|
clear
|
||||||
|
|
||||||
|
# Delete one record of Booking by id 1
|
||||||
|
curl -X DELETE localhost:8080/booking/1 --silent
|
||||||
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
+125
@@ -0,0 +1,125 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/gorilla/handlers"
|
||||||
|
"go_project/internal/configuration"
|
||||||
|
"go_project/internal/connection"
|
||||||
|
"go_project/internal/controllers"
|
||||||
|
"go_project/internal/routes"
|
||||||
|
"go_project/internal/schema"
|
||||||
|
"go_project/pkg/behaivor"
|
||||||
|
"go_project/pkg/file"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
configuration.Init()
|
||||||
|
|
||||||
|
// Create database
|
||||||
|
if configuration.GetForceCreateSchema() {
|
||||||
|
sqlDBFileName := configuration.GetDatabaseLocation()
|
||||||
|
file.MustCreate(sqlDBFileName)
|
||||||
|
sqlHandler, err := connection.Open(sqlDBFileName)
|
||||||
|
|
||||||
|
behaivor.Anxiety("Database connection error", err)
|
||||||
|
|
||||||
|
schema.MustCreate(sqlHandler)
|
||||||
|
|
||||||
|
log.Println("Database created")
|
||||||
|
|
||||||
|
return
|
||||||
|
} else if configuration.GetCreateSchema() {
|
||||||
|
sqlDBFileName := configuration.GetDatabaseLocation()
|
||||||
|
|
||||||
|
if file.MustIsNotExist(sqlDBFileName) {
|
||||||
|
file.MustCreate(sqlDBFileName)
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlHandler, err := connection.Open(sqlDBFileName)
|
||||||
|
|
||||||
|
behaivor.Anxiety("Database connection error", err)
|
||||||
|
|
||||||
|
schema.MustCreate(sqlHandler)
|
||||||
|
|
||||||
|
log.Println("Database created")
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Create database end
|
||||||
|
|
||||||
|
// NOTE: Temp data for testing
|
||||||
|
MustFillDatabase()
|
||||||
|
|
||||||
|
serverRouter := routes.DefaultRouter()
|
||||||
|
|
||||||
|
// Adding CORS policy
|
||||||
|
corsHandler := handlers.CORS(
|
||||||
|
handlers.AllowedOrigins([]string{"*"}), // Allow all origins
|
||||||
|
handlers.AllowedMethods([]string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}), // Allow common HTTP methods
|
||||||
|
handlers.AllowedHeaders([]string{"Content-Type"}), // Allow specific headers
|
||||||
|
)
|
||||||
|
|
||||||
|
serverHost := configuration.GetServerHost()
|
||||||
|
serverPort := strconv.FormatInt(int64(configuration.GetServerPort()), 10)
|
||||||
|
serverAddr := serverHost + ":" + serverPort
|
||||||
|
serverWriteTimeout := configuration.GetWriteTimeout()
|
||||||
|
serverReadTimeout := configuration.GetReadTimeout()
|
||||||
|
|
||||||
|
server := &http.Server{
|
||||||
|
Handler: corsHandler(serverRouter),
|
||||||
|
Addr: serverAddr,
|
||||||
|
WriteTimeout: serverWriteTimeout,
|
||||||
|
ReadTimeout: serverReadTimeout,
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("Preparations for listen and serve are complete. Starting server at " + serverAddr)
|
||||||
|
|
||||||
|
log.Fatal(server.ListenAndServe())
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Temp data for testing
|
||||||
|
func MustFillDatabase() {
|
||||||
|
sqlHandler, err := connection.OpenDefault()
|
||||||
|
|
||||||
|
behaivor.Anxiety("Database connection error", err)
|
||||||
|
|
||||||
|
log.Println("Database filling operations are started")
|
||||||
|
defer connection.MustClose(sqlHandler)
|
||||||
|
|
||||||
|
// Fill database with Tables data
|
||||||
|
for i := 1; i <= 5; i++ {
|
||||||
|
createTableParams := controllers.CreateTableParams{
|
||||||
|
Name: i,
|
||||||
|
MaxPeople: 2,
|
||||||
|
Room: "Room 1",
|
||||||
|
}
|
||||||
|
log.Printf("Current CreateTableParams: %v\n", createTableParams)
|
||||||
|
_, err := controllers.CreateTable(sqlHandler, createTableParams)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Fill database with Bookings data
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
reservationTime := fmt.Sprintf("2025-01-01T%02d:00:00", 10+i)
|
||||||
|
createBookingParams := controllers.CreateBookingParams{
|
||||||
|
IdTables: i%5 + 1,
|
||||||
|
Reservation: reservationTime,
|
||||||
|
TimeReserve: "01:00",
|
||||||
|
WhoBooked: "John Doe",
|
||||||
|
}
|
||||||
|
log.Printf("Current CreateBookingParams: %v\n", createBookingParams)
|
||||||
|
_, err := controllers.CreateBooking(sqlHandler, createBookingParams)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("Database filling operations are completed")
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
module go_project
|
||||||
|
|
||||||
|
go 1.22.2
|
||||||
|
|
||||||
|
require github.com/mattn/go-sqlite3 v1.14.24
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/gin-gonic/gin v1.10.0
|
||||||
|
github.com/gorilla/mux v1.8.1
|
||||||
|
github.com/jmoiron/sqlx v1.4.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/bytedance/sonic v1.11.6 // indirect
|
||||||
|
github.com/bytedance/sonic/loader v0.1.1 // indirect
|
||||||
|
github.com/cloudwego/base64x v0.1.4 // indirect
|
||||||
|
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||||
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||||
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
|
github.com/go-playground/validator/v10 v10.20.0 // indirect
|
||||||
|
github.com/goccy/go-json v0.10.2 // indirect
|
||||||
|
github.com/gorilla/handlers v1.5.2 // indirect
|
||||||
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||||
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
|
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||||
|
golang.org/x/arch v0.8.0 // indirect
|
||||||
|
golang.org/x/crypto v0.23.0 // indirect
|
||||||
|
golang.org/x/net v0.25.0 // indirect
|
||||||
|
golang.org/x/sys v0.20.0 // indirect
|
||||||
|
golang.org/x/text v0.15.0 // indirect
|
||||||
|
google.golang.org/protobuf v1.34.1 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
)
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||||
|
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||||
|
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
|
||||||
|
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
|
||||||
|
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
|
||||||
|
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||||
|
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
|
||||||
|
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||||
|
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
||||||
|
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||||
|
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
||||||
|
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||||
|
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||||
|
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
|
||||||
|
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
||||||
|
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||||
|
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||||
|
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||||
|
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||||
|
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||||
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
|
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
|
||||||
|
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||||
|
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
||||||
|
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
||||||
|
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||||
|
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||||
|
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||||
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE=
|
||||||
|
github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w=
|
||||||
|
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||||
|
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||||
|
github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
|
||||||
|
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
|
||||||
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||||
|
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||||
|
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||||
|
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||||
|
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||||
|
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
|
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||||
|
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
||||||
|
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||||
|
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||||
|
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
|
||||||
|
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||||
|
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||||
|
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||||
|
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||||
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||||
|
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
||||||
|
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
|
||||||
|
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||||
|
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||||
Executable
+110
@@ -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>
|
||||||
|
|
||||||
Executable
+249
@@ -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();
|
||||||
|
});
|
||||||
|
|
||||||
Executable
+40
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
Executable
+86
@@ -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
|
||||||
|
}
|
||||||
Executable
+33
@@ -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)
|
||||||
|
}
|
||||||
Executable
+143
@@ -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(¤tBooking.Id, ¤tBooking.IdTables, ¤tBooking.ReservationDatetime, ¤tBooking.TimeReserve, ¤tBooking.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
|
||||||
|
}
|
||||||
Executable
+135
@@ -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(¤tTable.Id, ¤tTable.Name, ¤tTable.MaxPeople, ¤tTable.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
|
||||||
|
}
|
||||||
Executable
+213
@@ -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)
|
||||||
|
}
|
||||||
Executable
+213
@@ -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)
|
||||||
|
}
|
||||||
Executable
+18
@@ -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"`
|
||||||
|
}
|
||||||
|
)
|
||||||
Executable
+35
@@ -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")
|
||||||
|
}
|
||||||
Executable
+66
@@ -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;
|
||||||
|
`,
|
||||||
|
}
|
||||||
Executable
+5
@@ -0,0 +1,5 @@
|
|||||||
|
DROP TABLE IF EXISTS Tables;
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS Bookings;
|
||||||
|
|
||||||
|
DROP TRIGGER IF EXISTS CHK_Bookings_Insert;
|
||||||
Executable
+33
@@ -0,0 +1,33 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS Tables (
|
||||||
|
-- column-def:
|
||||||
|
id INTEGER -- column-constraint:
|
||||||
|
CONSTRAINT PK_Tables PRIMARY KEY AUTOINCREMENT,
|
||||||
|
--
|
||||||
|
name INTEGER NOT NULL UNIQUE,
|
||||||
|
--
|
||||||
|
max_people INTEGER NOT NULL,
|
||||||
|
--
|
||||||
|
room TEXT NOT NULL,
|
||||||
|
-- table-constraint:
|
||||||
|
CONSTRAINT CHK_max_people CHECK (
|
||||||
|
max_people > 0
|
||||||
|
AND max_people < 11
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS Bookings (
|
||||||
|
-- column-def:
|
||||||
|
id INTEGER -- column-constraint:
|
||||||
|
CONSTRAINT PK_Bookings PRIMARY KEY AUTOINCREMENT,
|
||||||
|
--
|
||||||
|
id_tables INTEGER,
|
||||||
|
--
|
||||||
|
reservation TEXT NOT NULL,
|
||||||
|
--
|
||||||
|
time_reserve TEXT NOT NULL,
|
||||||
|
--
|
||||||
|
who_booked TEXT NOT NULL,
|
||||||
|
-- table-constraint:
|
||||||
|
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")
|
||||||
|
);
|
||||||
Executable
+21
@@ -0,0 +1,21 @@
|
|||||||
|
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
|
||||||
|
FROM
|
||||||
|
Bookings
|
||||||
|
)
|
||||||
|
WHERE
|
||||||
|
new_res_dt >= res_dt
|
||||||
|
OR new_res_dt < reserved_until;
|
||||||
|
|
||||||
|
--
|
||||||
|
END;
|
||||||
Executable
+7
@@ -0,0 +1,7 @@
|
|||||||
|
INSERT INTO
|
||||||
|
Tables (name, max_people, room)
|
||||||
|
VALUES
|
||||||
|
(1, 5, "Red room"),
|
||||||
|
(4, 4, "Red room"),
|
||||||
|
(2, 7, "Green room"),
|
||||||
|
(3, 10, "Game hall");
|
||||||
Executable
+144
@@ -0,0 +1,144 @@
|
|||||||
|
-- reservation format "YYYY-MM-DDTHH:MM"
|
||||||
|
-- time_reserve "HH:MM"
|
||||||
|
-- fail check time_reserve
|
||||||
|
INSERT INTO
|
||||||
|
Bookings (
|
||||||
|
id_tables,
|
||||||
|
reservation,
|
||||||
|
time_reserve,
|
||||||
|
who_booked
|
||||||
|
)
|
||||||
|
VALUES
|
||||||
|
(1, "2000-01-01T00:00", "00:00", "");
|
||||||
|
|
||||||
|
-- fail check time_reserve
|
||||||
|
INSERT INTO
|
||||||
|
Bookings (
|
||||||
|
id_tables,
|
||||||
|
reservation,
|
||||||
|
time_reserve,
|
||||||
|
who_booked
|
||||||
|
)
|
||||||
|
VALUES
|
||||||
|
(1, "2000-01-01T00:00", "00:29", "");
|
||||||
|
|
||||||
|
-- fail check time_reserve
|
||||||
|
INSERT INTO
|
||||||
|
Bookings (
|
||||||
|
id_tables,
|
||||||
|
reservation,
|
||||||
|
time_reserve,
|
||||||
|
who_booked
|
||||||
|
)
|
||||||
|
VALUES
|
||||||
|
(1, "2000-01-01T00:00", "12:01", "");
|
||||||
|
|
||||||
|
-- success check time_reserve
|
||||||
|
INSERT INTO
|
||||||
|
Bookings (
|
||||||
|
id_tables,
|
||||||
|
reservation,
|
||||||
|
time_reserve,
|
||||||
|
who_booked
|
||||||
|
)
|
||||||
|
VALUES
|
||||||
|
(1, "2000-01-01T00:00", "00:30", "");
|
||||||
|
|
||||||
|
-- success until 02:30
|
||||||
|
INSERT INTO
|
||||||
|
Bookings (
|
||||||
|
id_tables,
|
||||||
|
reservation,
|
||||||
|
time_reserve,
|
||||||
|
who_booked
|
||||||
|
)
|
||||||
|
VALUES
|
||||||
|
(1, "2000-01-01T01:00", "01:30", "");
|
||||||
|
|
||||||
|
-- fail check begin
|
||||||
|
INSERT INTO
|
||||||
|
Bookings (
|
||||||
|
id_tables,
|
||||||
|
reservation,
|
||||||
|
time_reserve,
|
||||||
|
who_booked
|
||||||
|
)
|
||||||
|
VALUES
|
||||||
|
(1, "2000-01-01T00:30", "01:00", "");
|
||||||
|
|
||||||
|
-- fail check middle
|
||||||
|
INSERT INTO
|
||||||
|
Bookings (
|
||||||
|
id_tables,
|
||||||
|
reservation,
|
||||||
|
time_reserve,
|
||||||
|
who_booked
|
||||||
|
)
|
||||||
|
VALUES
|
||||||
|
(1, "2000-01-01T00:30", "01:30", "");
|
||||||
|
|
||||||
|
-- fail check end
|
||||||
|
INSERT INTO
|
||||||
|
Bookings (
|
||||||
|
id_tables,
|
||||||
|
reservation,
|
||||||
|
time_reserve,
|
||||||
|
who_booked
|
||||||
|
)
|
||||||
|
VALUES
|
||||||
|
(1, "2000-01-01T00:30", "02:00", "");
|
||||||
|
|
||||||
|
-- fail check begin
|
||||||
|
INSERT INTO
|
||||||
|
Bookings (
|
||||||
|
id_tables,
|
||||||
|
reservation,
|
||||||
|
time_reserve,
|
||||||
|
who_booked
|
||||||
|
)
|
||||||
|
VALUES
|
||||||
|
(1, "2000-01-01T01:00", "00:30", "");
|
||||||
|
|
||||||
|
-- fail check middle
|
||||||
|
INSERT INTO
|
||||||
|
Bookings (
|
||||||
|
id_tables,
|
||||||
|
reservation,
|
||||||
|
time_reserve,
|
||||||
|
who_booked
|
||||||
|
)
|
||||||
|
VALUES
|
||||||
|
(1, "2000-01-01T01:30", "00:30", "");
|
||||||
|
|
||||||
|
-- fail check end
|
||||||
|
INSERT INTO
|
||||||
|
Bookings (
|
||||||
|
id_tables,
|
||||||
|
reservation,
|
||||||
|
time_reserve,
|
||||||
|
who_booked
|
||||||
|
)
|
||||||
|
VALUES
|
||||||
|
(1, "2000-01-01T02:00", "00:30", "");
|
||||||
|
|
||||||
|
-- success
|
||||||
|
INSERT INTO
|
||||||
|
Bookings (
|
||||||
|
id_tables,
|
||||||
|
reservation,
|
||||||
|
time_reserve,
|
||||||
|
who_booked
|
||||||
|
)
|
||||||
|
VALUES
|
||||||
|
(1, "2000-01-01T02:30", "00:30", "");
|
||||||
|
|
||||||
|
-- success
|
||||||
|
INSERT INTO
|
||||||
|
Bookings (
|
||||||
|
id_tables,
|
||||||
|
reservation,
|
||||||
|
time_reserve,
|
||||||
|
who_booked
|
||||||
|
)
|
||||||
|
VALUES
|
||||||
|
(1, "2000-01-01T03:00", "00:30", "");
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
SELECT -- Incorrect table reservations
|
||||||
|
Left.reservation,
|
||||||
|
datetime (Left.reservation, Left.time_reserve) AS reserved_until,
|
||||||
|
Right.reservation
|
||||||
|
from
|
||||||
|
Bookings AS Left
|
||||||
|
LEFT JOIN Bookings AS Right ON Left.id != Right.id
|
||||||
|
AND Left.id_tables = Right.id_tables
|
||||||
|
WHERE
|
||||||
|
datetime (Right.reservation) BETWEEN datetime (Left.reservation) AND datetime (Left.reservation, Left.time_reserve)
|
||||||
Executable
+10
@@ -0,0 +1,10 @@
|
|||||||
|
package behaivor
|
||||||
|
|
||||||
|
import "log"
|
||||||
|
|
||||||
|
// Crash the program if an error exists. Anxiety before panic
|
||||||
|
func Anxiety(prefixMessage string, err error) {
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("%v:\n\t%v", prefixMessage, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
Executable
+27
@@ -0,0 +1,27 @@
|
|||||||
|
package file
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go_project/pkg/behaivor"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Verification of the existence of a program with an emergency termination in case of an error
|
||||||
|
func MustIsNotExist(filename string) (result bool) {
|
||||||
|
_, err := os.Stat(filename)
|
||||||
|
if err != nil {
|
||||||
|
result = os.IsNotExist(err)
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if result == false {
|
||||||
|
behaivor.Anxiety("Error checking the existence of the file", err)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a file with truncated data
|
||||||
|
func MustCreate(filename string) {
|
||||||
|
file, err := os.Create(filename)
|
||||||
|
behaivor.Anxiety("File creating error", err)
|
||||||
|
file.Close()
|
||||||
|
}
|
||||||
Executable
+53
@@ -0,0 +1,53 @@
|
|||||||
|
package information
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Following prints all of the registered routes
|
||||||
|
func AboutRoute(route *mux.Route, _ *mux.Router, _ []*mux.Route) error {
|
||||||
|
pathTemplate, err := route.GetPathTemplate()
|
||||||
|
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
buffer.WriteString("\n\t")
|
||||||
|
buffer.WriteString("ROUTE: ")
|
||||||
|
buffer.WriteString(pathTemplate)
|
||||||
|
}
|
||||||
|
pathRegexp, err := route.GetPathRegexp()
|
||||||
|
if err == nil {
|
||||||
|
buffer.WriteString("\n\t")
|
||||||
|
buffer.WriteString("Path regexp: ")
|
||||||
|
buffer.WriteString(pathRegexp)
|
||||||
|
}
|
||||||
|
queriesTemplates, err := route.GetQueriesTemplates()
|
||||||
|
if err == nil {
|
||||||
|
buffer.WriteString("\n\t")
|
||||||
|
buffer.WriteString("Queries templates: ")
|
||||||
|
buffer.WriteString(strings.Join(queriesTemplates, ","))
|
||||||
|
}
|
||||||
|
queriesRegexps, err := route.GetQueriesRegexp()
|
||||||
|
if err == nil {
|
||||||
|
buffer.WriteString("\n\t")
|
||||||
|
buffer.WriteString("Queries regexps: ")
|
||||||
|
buffer.WriteString(strings.Join(queriesRegexps, ","))
|
||||||
|
}
|
||||||
|
methods, err := route.GetMethods()
|
||||||
|
if err == nil {
|
||||||
|
buffer.WriteString("\n\t")
|
||||||
|
buffer.WriteString("Methods: ")
|
||||||
|
buffer.WriteString(strings.Join(methods, ","))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len := buffer.Len(); len != 0 {
|
||||||
|
|
||||||
|
log.Println(buffer.String())
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Executable
+16
@@ -0,0 +1,16 @@
|
|||||||
|
package marshaling
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"go_project/pkg/behaivor"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NOTE: Not used in this project
|
||||||
|
func MustUnmarshalBody(r *http.Request, x interface{}) {
|
||||||
|
body, err := io.ReadAll(r.Body)
|
||||||
|
behaivor.Anxiety("Error reading the request body", err)
|
||||||
|
err = json.Unmarshal([]byte(body), x)
|
||||||
|
behaivor.Anxiety("Error unmarshaling the request body", err)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user