camper/pkg/booking/filter.go

132 lines
3.5 KiB
Go

package booking
import (
"context"
"fmt"
"net/http"
"strings"
"dev.tandem.ws/tandem/camper/pkg/auth"
"dev.tandem.ws/tandem/camper/pkg/database"
"dev.tandem.ws/tandem/camper/pkg/form"
"dev.tandem.ws/tandem/camper/pkg/locale"
)
type filterForm struct {
locale *locale.Locale
company *auth.Company
perPage int
pagination bool
HolderName *form.Input
BookingStatus *form.Select
FromDate *form.Input
ToDate *form.Input
Cursor *form.Input
}
func newFilterForm(ctx context.Context, conn *database.Conn, company *auth.Company, locale *locale.Locale) *filterForm {
return &filterForm{
locale: locale,
company: company,
perPage: 25,
HolderName: &form.Input{
Name: "holder_name",
},
BookingStatus: &form.Select{
Name: "booking_status",
Options: mustGetBookingStatusOptions(ctx, conn, locale),
},
FromDate: &form.Input{
Name: "from_date",
},
ToDate: &form.Input{
Name: "to_date",
},
Cursor: &form.Input{
Name: "cursor",
},
}
}
func mustGetBookingStatusOptions(ctx context.Context, conn *database.Conn, locale *locale.Locale) []*form.Option {
return form.MustGetOptions(ctx, conn, `
select booking_status.booking_status
, isi18n.name
from booking_status
join booking_status_i18n isi18n using(booking_status)
where isi18n.lang_tag = $1
and booking_status <> 'created'
order by booking_status`, locale.Language)
}
func (f *filterForm) Parse(r *http.Request) error {
if err := r.ParseForm(); err != nil {
return err
}
f.HolderName.FillValue(r)
f.BookingStatus.FillValue(r)
f.FromDate.FillValue(r)
f.ToDate.FillValue(r)
f.Cursor.FillValue(r)
f.pagination = f.Cursor.Val != ""
return nil
}
func (f *filterForm) BuildQuery(args []interface{}) (string, []interface{}) {
var where []string
appendWhere := func(expression string, value interface{}) {
args = append(args, value)
where = append(where, fmt.Sprintf(expression, len(args)))
}
maybeAppendWhere := func(expression string, value string, conv func(string) interface{}) {
if value != "" {
if conv == nil {
appendWhere(expression, value)
} else {
appendWhere(expression, conv(value))
}
}
}
appendWhere("booking.company_id = $%d", f.company.ID)
maybeAppendWhere("booking.holder_name ILIKE $%d", f.HolderName.Val, func(v string) interface{} {
return "%" + v + "%"
})
if len(f.BookingStatus.Selected) == 0 {
where = append(where, "booking.booking_status <> 'created'")
} else {
maybeAppendWhere("booking.booking_status = $%d", f.BookingStatus.String(), nil)
}
maybeAppendWhere("lower(stay) >= $%d", f.FromDate.Val, nil)
maybeAppendWhere("lower(stay) <= $%d", f.ToDate.Val, nil)
if f.Cursor.Val != "" {
params := strings.Split(f.Cursor.Val, ";")
if len(params) == 2 {
where = append(where, fmt.Sprintf("(lower(stay), booking_id) < ($%d, $%d)", len(args)+1, len(args)+2))
args = append(args, params[0])
args = append(args, params[1])
}
}
return strings.Join(where, ") AND ("), args
}
func (f *filterForm) buildCursor(bookings []*bookingEntry) []*bookingEntry {
if len(bookings) <= f.perPage {
f.Cursor.Val = ""
return bookings
}
bookings = bookings[:f.perPage]
last := bookings[f.perPage-1]
f.Cursor.Val = fmt.Sprintf("%s;%d", last.ArrivalDate.Format(database.ISODateFormat), last.ID)
return bookings
}
func (f *filterForm) HasValue() bool {
return f.HolderName.Val != "" ||
(len(f.BookingStatus.Selected) > 0 && f.BookingStatus.Selected[0] != "") ||
f.FromDate.Val != "" ||
f.ToDate.Val != ""
}