package booking import ( "context" "fmt" "net/http" "strconv" "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 { company *auth.Company HolderName *form.Input BookingStatus *form.Select FromDate *form.Input ToDate *form.Input Cursor *form.Cursor } func newFilterForm(ctx context.Context, conn *database.Conn, company *auth.Company, locale *locale.Locale) *filterForm { return &filterForm{ company: company, 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.Cursor{ Name: "cursor", PerPage: 25, }, } } 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) 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.Paginated() { params := f.Cursor.Params() 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 { return form.BuildCursor(f.Cursor, bookings, func(entry *bookingEntry) []string { return []string{entry.ArrivalDate.Format(database.ISODateFormat), strconv.Itoa(entry.ID)} }) } func (f *filterForm) HasValue() bool { return f.HolderName.Val != "" || (len(f.BookingStatus.Selected) > 0 && f.BookingStatus.Selected[0] != "") || f.FromDate.Val != "" || f.ToDate.Val != "" } func (f *filterForm) PerPage() int { return f.Cursor.PerPage } func (f *filterForm) Paginated() bool { return f.Cursor.Pagination }