Skip to content

Commit

Permalink
Add code for airports and filter flights by it
Browse files Browse the repository at this point in the history
  • Loading branch information
boozec committed Apr 27, 2024
1 parent b7974c7 commit 862ea51
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 18 deletions.
10 changes: 8 additions & 2 deletions internal/handlers/flight.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
// Handle GET request for `Flight` model.
// It returns a list of flights.
// GetFlights godoc
//
// @Summary Get all flights
// @Schemes
// @Description Get all flights
Expand All @@ -34,6 +35,7 @@ func FlightHandlerGet(c *gin.Context) {
// Validate JSON input by the request and crate a new flight. Finally returns
// the new created data (after preloading the foreign key objects).
// PostFlights godoc
//
// @Summary Create a new flight
// @Schemes
// @Description Create a new flight
Expand Down Expand Up @@ -65,6 +67,7 @@ func FlightHandlerPost(c *gin.Context) {
// Handle GET request for a selected id.
// Returns the flight or a 404 status
// GetFlightById godoc
//
// @Summary Get a flight
// @Schemes
// @Description Get a flight
Expand All @@ -88,6 +91,7 @@ func FlightHandlerGetId(c *gin.Context) {
// First checks if the selected flight exists or not. Then, validates JSON input by the
// request and edit a selected flight. Finally returns the new created data.
// EditFlightById godoc
//
// @Summary Edit a flight
// @Schemes
// @Description Edit a flight
Expand Down Expand Up @@ -124,6 +128,7 @@ func FlightHandlerPut(c *gin.Context) {
// Filter flights by departaure (airport and time) and arrival (airport and
// time). This handler can be called by everyone.
// FilterFlights godoc
//
// @Summary Filter flights
// @Schemes
// @Description Filter flights
Expand All @@ -141,14 +146,15 @@ func FlightHandlerFilter(c *gin.Context) {
return
}

if err := models.ValidateFlight(db, input); err != nil {
airports, err := models.ValidateFlightFilter(db, input)
if 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 {
airports[0], airports[1], 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
}
Expand Down
3 changes: 3 additions & 0 deletions internal/models/airport.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package models
type Airport struct {
Id uint `gorm:"column:id" json:"id"`
Name string `gorm:"column:name" json:"name"`
Code string `gorm:"column:code" json:"code"`
Location string `gorm:"column:location" json:"location"`
Latitude float32 `gorm:"column:latitude" json:"latitude"`
Longitude float32 `gorm:"column:longitude" json:"longitude"`
Expand All @@ -12,6 +13,7 @@ type Airport struct {
// Struct used to get new data for an airport
type AirportInput struct {
Name string `json:"name" binding:"required"`
Code string `json:"code" binding:"required"`
Location string `json:"location" binding:"required"`
Latitude float32 `json:"latitude" binding:"required"`
Longitude float32 `json:"longitude" binding:"required"`
Expand All @@ -21,6 +23,7 @@ type AirportInput struct {
func NewAirport(in AirportInput) Airport {
return Airport{
Name: in.Name,
Code: in.Code,
Location: in.Location,
Latitude: in.Latitude,
Longitude: in.Longitude,
Expand Down
55 changes: 39 additions & 16 deletions internal/models/flight.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,6 @@ 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 {
Code string `json:"code" binding:"required"`
Expand All @@ -45,24 +39,24 @@ func (in FlightInput) Arrival() (time.Time, int) {
return in.ArrivalTime, in.ArrivalAirportId
}

// Struct used to get info on filter
// Struct used to get info on filter. Filter fliths by airport code
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"`
DepartaureTime time.Time `json:"departaure_time" binding:"required"`
ArrivalTime time.Time `json:"arrival_time" binding:"required"`
DepartaureAirport string `json:"departaure_airport" binding:"required"`
ArrivalAirport string `json:"arrival_airport" binding:"required"`
}

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

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

// It validates data from `in` and returns a possible error or not
func ValidateFlight(db *gorm.DB, in FlightValidationInput) error {
func ValidateFlight(db *gorm.DB, in FlightInput) error {
var departaure_airport Airport
departaure_time, departaure_airport_id := in.Departaure()
arrival_time, arrival_airport_id := in.Arrival()
Expand All @@ -86,6 +80,35 @@ func ValidateFlight(db *gorm.DB, in FlightValidationInput) error {
return nil
}

// It validates data from `in` and returns a possible error or not. If there's
// no error, returns an array of airport ids: first one for departaure airport
// and the latter for the arrival airport.
func ValidateFlightFilter(db *gorm.DB, in FlightFilterInput) (*[2]uint, error) {
var departaure_airport Airport
departaure_time, departaure_airport_code := in.Departaure()
arrival_time, arrival_airport_code := in.Arrival()
if err := db.Where("code = ?", departaure_airport_code).First(&departaure_airport).Error; err != nil {
return nil, errors.New("`departaure_airport_id` does not exist.")
}

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

if departaure_airport.Id == arrival_airport.Id {
return nil, errors.New("`departaure_airport_id` can't be equals to `arrival_airport_id`")
}

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

airports := [2]uint{departaure_airport.Id, arrival_airport.Id}

return &airports, nil
}

// Returns a new Flight with the data from `in`. It should be called after
// `ValidateFlight(..., in)` method
func NewFlight(in FlightInput) Flight {
Expand Down

0 comments on commit 862ea51

Please sign in to comment.