Skip to content

Commit

Permalink
Filter flights
Browse files Browse the repository at this point in the history
  • Loading branch information
boozec committed Mar 29, 2024
1 parent 3482a80 commit cd8010b
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 11 deletions.
10 changes: 5 additions & 5 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,11 @@ func main() {

flights := v1.Group("/flights")
{
flights.Use(middleware.Auth())
flights.GET("/", handlers.FlightHandlerGet)
flights.POST("/", handlers.FlightHandlerPost)
flights.GET("/:id/", handlers.FlightHandlerGetId)
flights.PUT("/:id/", handlers.FlightHandlerPut)
flights.GET("/", middleware.Auth(), handlers.FlightHandlerGet)
flights.POST("/", middleware.Auth(), handlers.FlightHandlerPost)
flights.GET("/:id/", middleware.Auth(), handlers.FlightHandlerGetId)
flights.PUT("/:id/", middleware.Auth(), handlers.FlightHandlerPut)
flights.POST("/filter/", handlers.FlightHandlerFilter)
}
}

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.22.0

require (
github.com/gin-gonic/gin v1.9.1
github.com/golang-jwt/jwt/v4 v4.5.0
github.com/knadh/koanf/providers/env v0.1.0
github.com/knadh/koanf/v2 v2.1.0
gorm.io/driver/postgres v1.5.7
Expand All @@ -20,7 +21,6 @@ require (
github.com/go-playground/validator/v10 v10.14.0 // indirect
github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect
Expand Down
29 changes: 29 additions & 0 deletions internal/handlers/flight.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,32 @@ func FlightHandlerPut(c *gin.Context) {

c.JSON(http.StatusOK, flight)
}

// Filter flights by departaure (airport and time) and arrival (airport and
// time). This handler can be called by everyone.
func FlightHandlerFilter(c *gin.Context) {
db, _ := db.GetDb()

var input models.FlightFilterInput
if err := c.ShouldBindJSON(&input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"message": err.Error()})
return
}

if err := models.ValidateFlight(db, input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"message": err.Error()})
return
}

var flights []models.Flight
if err := db.Where("departaure_airport_id = ? AND arrival_airport_id = ? AND departaure_time::date = to_date(?, 'YYYY-MM-DD') AND arrival_time::date = to_date(?, 'YYYY-MM-DD')",
input.DepartaureAirportId, input.ArrivalAirportId, input.DepartaureTime.Format("2006-01-02"), input.ArrivalTime.Format("2006-01-02")).Preload("DepartaureAirport").Preload("ArrivalAirport").Find(&flights).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"message": err.Error()})
return
}

c.JSON(http.StatusOK, gin.H{
"count": len(flights),
"data": &flights,
})
}
42 changes: 37 additions & 5 deletions internal/models/flight.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ type Flight struct {
Cost float32 `gorm:"column:cost" json:"cost"`
}

// This interface is used so to have only one `ValidateFlight`
type FlightValidationInput interface {
Departaure() (time.Time, int)
Arrival() (time.Time, int)
}

// Struct used to get new data for a flight
type FlightInput struct {
DepartaureTime time.Time `json:"departaure_time" binding:"required"`
Expand All @@ -29,23 +35,49 @@ type FlightInput struct {
Cost float32 `json:"cost" binding:"required"`
}

func (in FlightInput) Departaure() (time.Time, int) {
return in.DepartaureTime, in.DepartaureAirportId
}

func (in FlightInput) Arrival() (time.Time, int) {
return in.ArrivalTime, in.ArrivalAirportId
}

// Struct used to get info on filter
type FlightFilterInput struct {
DepartaureTime time.Time `json:"departaure_time" binding:"required"`
ArrivalTime time.Time `json:"arrival_time" binding:"required"`
DepartaureAirportId int `json:"departaure_airport_id" binding:"required"`
ArrivalAirportId int `json:"arrival_airport_id" binding:"required"`
}

func (in FlightFilterInput) Departaure() (time.Time, int) {
return in.DepartaureTime, in.DepartaureAirportId
}

func (in FlightFilterInput) Arrival() (time.Time, int) {
return in.ArrivalTime, in.ArrivalAirportId
}

// It validates data from `in` and returns a possible error or not
func ValidateFlight(db *gorm.DB, in FlightInput) error {
func ValidateFlight(db *gorm.DB, in FlightValidationInput) error {
var departaure_airport Airport
if err := db.Where("id = ?", in.DepartaureAirportId).First(&departaure_airport).Error; err != nil {
departaure_time, departaure_airport_id := in.Departaure()
arrival_time, arrival_airport_id := in.Arrival()
if err := db.Where("id = ?", departaure_airport_id).First(&departaure_airport).Error; err != nil {
return errors.New("`departaure_airport_id` does not exist.")
}

var arrival_airport Airport
if err := db.Where("id = ?", in.ArrivalAirportId).First(&arrival_airport).Error; err != nil {
if err := db.Where("id = ?", arrival_airport_id).First(&arrival_airport).Error; err != nil {
return errors.New("`arrival_airport_id` does not exist.")
}

if in.DepartaureAirportId == in.ArrivalAirportId {
if departaure_airport_id == arrival_airport_id {
return errors.New("`departaure_airport_id` can't be equals to `arrival_airport_id`")
}

if in.DepartaureTime.Equal(in.ArrivalTime) || in.DepartaureTime.After(in.ArrivalTime) {
if departaure_time.Equal(arrival_time) || departaure_time.After(arrival_time) {
return errors.New("`departaure_time` can't be after or the same `arrival_time`")
}

Expand Down

0 comments on commit cd8010b

Please sign in to comment.