package db_utils import ( "fmt" "gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/date_utils" "gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/errors" "gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/number_utils" "gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/struct_utils" "regexp" "strings" "time" ) // Special query cases const ( LastXHours string = "^last \\d+ hour(s)?$" LastDay string = "^last day$" LastXDays string = "^last \\d+ day(s)?$" LastMonth string = "^last month$" Yesterday string = "^yesterday$" ) func checkAbsoluteRegex(regex string, value string) bool { matchesRegex, err := regexp.Match(regex, []byte(value)) if matchesRegex && err == nil { return true } return false } func pullAbsoluteValue(value string) int64 { reg, err := regexp.Compile("[a-zA-Z]+") if err != nil { return 0 } value = reg.ReplaceAllString(value, "") value = strings.TrimSpace(value) val, _ := number_utils.StringToInt64(value) return val } func AbsoluteDateStringQuery(absolute string) string { var value int64 timeNow := date_utils.CurrentDate() if checkAbsoluteRegex(LastXHours, absolute) { value = pullAbsoluteValue(absolute) since := timeNow.Add(time.Duration(-value) * time.Hour) return fmt.Sprintf(" >= '%v'", date_utils.DateDBFormattedString(since)) } if checkAbsoluteRegex(LastDay, absolute) { startDay := time.Date(timeNow.Year(), timeNow.Month(), timeNow.Day(), 0, 0, 0, 0, date_utils.CurrentLocation()) endDay := time.Date(timeNow.Year(), timeNow.Month(), timeNow.Day(), 23, 59, 59, 999999999, date_utils.CurrentLocation()) return fmt.Sprintf(" BETWEEN '%v' AND '%v'", date_utils.DateDBFormattedString(startDay), date_utils.DateDBFormattedString(endDay)) } if checkAbsoluteRegex(LastXDays, absolute) { value = pullAbsoluteValue(absolute) since := timeNow.AddDate(0, 0, -int(value)) return fmt.Sprintf(" >= '%v'", date_utils.DateDBFormattedString(since)) } if checkAbsoluteRegex(LastMonth, absolute) { firstOfMonth := time.Date(timeNow.Year(), timeNow.Month(), 1, 0, 0, 0, 0, date_utils.CurrentLocation()) lastDay := firstOfMonth.AddDate(0, 1, -1) lastOfMonth := time.Date(lastDay.Year(), lastDay.Month(), lastDay.Day(), 23, 59, 59, 999999999, date_utils.CurrentLocation()) return fmt.Sprintf(" BETWEEN '%v' AND '%v'", date_utils.DateDBFormattedString(firstOfMonth), date_utils.DateDBFormattedString(lastOfMonth)) } if checkAbsoluteRegex(Yesterday, absolute) { yesterday := timeNow.AddDate(0, 0, -1) startDay := time.Date(yesterday.Year(), yesterday.Month(), yesterday.Day(), 0, 0, 0, 0, date_utils.CurrentLocation()) endDay := time.Date(yesterday.Year(), yesterday.Month(), yesterday.Day(), 23, 59, 59, 999999999, date_utils.CurrentLocation()) return fmt.Sprintf(" BETWEEN '%v' AND '%v'", date_utils.DateDBFormattedString(startDay), date_utils.DateDBFormattedString(endDay)) } // Not matched, so try to match it literally (It'll probably break and return nothing, but that's good) return fmt.Sprintf(" = '%v'", absolute) } type PageAndOrderParams struct { PageParams OrderBy string `json:"order_by,omitempty"` Order string `json:"order,omitempty"` } type PageParams struct { Limit int64 `json:"limit,omitempty"` // Limit number of items returned in list (default: 0 (no limit)) Offset int64 `json:"offset,omitempty"` // Offset in list (default: 0 (no offset)) } func (params *PageParams) Validate() error { if params.Limit < 0 { return errors.Errorf("limit=%d must be positive", params.Limit) } if params.Offset < 0 { return errors.Errorf("offset=%d must be >=0", params.Offset) } return nil } func (params *PageParams) EnforceLimit() { if params.Limit <= 0 { params.Limit = 20 } } func ValidateDateFilters(params any, dateFiltersToValidate ...string) error { queryParams := struct_utils.MapParams(params) for _, filter := range dateFiltersToValidate { date, present := queryParams[filter] if present { _, err := date_utils.ParseTimeString(date) if err != nil { return errors.Errorf("invalid %s: %s", filter, date) } } } return nil }