Files
maxwarden/database/filters.go
2025-03-06 23:54:11 -05:00

226 lines
4.7 KiB
Go

package database
import (
"fmt"
"net/http"
"strconv"
"strings"
. "github.com/go-jet/jet/v2/sqlite"
. "maxwarden/basic"
)
const (
BETWEEN_LEFT_URL_KEY_PREFIX = "betweenLeft_"
BETWEEN_RIGHT_URL_KEY_PREFIX = "betweenRight_"
ORDER_BY_URL_KEY = "orderBy"
ORDER_DESC_URL_KEY = "desc"
PAGE_NUM_URL_KEY = "pageNum"
ITEMS_PER_PAGE_URL_KEY = "itemsPerPage"
SEARCH_URL_KEY_PREFIX = "search_"
FILTER_DEFAULT_MAX_ITEMS = 10
)
const (
COL_POS_LEFT = iota
COL_POS_RIGHT = iota
)
type ColInfo struct {
DisplayName string
DbName string
Sortable bool
DisplayPosition int
}
type Filter struct {
Search map[string]string
Pagination Pagination
OrderBy string
OrderDescending bool
}
type Pagination struct {
Enabled bool
CurrentPage int
NextPage int
PreviousPage int
TotalPages int
TotalItems int
MaxItemsPerPage int
ItemsThisPage int
ViewRangeLower int
ViewRangeUpper int
}
func NewFilterFromSearch(s map[string]string) Filter {
f := Filter {
Search: s,
}
if f.Pagination.CurrentPage <= 0 {
f.Pagination.CurrentPage = 1
}
return f
}
func ParseFilterFromRequest(r *http.Request) Filter {
filter := Filter{}
filter.Search = make(map[string]string)
for k, v := range r.URL.Query() {
if strings.HasPrefix(k, SEARCH_URL_KEY_PREFIX) {
qValue := strings.Join(v, "")
if qValue != "" {
filter.Search[strings.TrimPrefix(k, SEARCH_URL_KEY_PREFIX)] = qValue
}
}
}
filter.OrderBy = r.URL.Query().Get(ORDER_BY_URL_KEY)
filter.OrderDescending, _ = strconv.ParseBool(r.URL.Query().Get(ORDER_DESC_URL_KEY))
filter.Pagination.CurrentPage, _ = strconv.Atoi(r.URL.Query().Get(PAGE_NUM_URL_KEY))
filter.Pagination.MaxItemsPerPage, _ = strconv.Atoi(r.URL.Query().Get(ITEMS_PER_PAGE_URL_KEY))
if filter.Pagination.MaxItemsPerPage == 0 {
filter.Pagination.MaxItemsPerPage = FILTER_DEFAULT_MAX_ITEMS
}
if filter.Pagination.CurrentPage <= 0 {
filter.Pagination.CurrentPage = 1
}
return filter
}
func QueryParamsFromPagenum(pageNum int, f Filter) string {
f.Pagination.CurrentPage = pageNum
return QueryParamsFromFilter(f)
}
func QueryParamsFromOrderBy(orderBy string, direction bool, f Filter) string {
f.OrderBy = orderBy
f.OrderDescending = direction
f.Pagination.CurrentPage = 1
return QueryParamsFromFilter(f)
}
func QueryParamsFromFilter(f Filter) string {
output := fmt.Sprintf(
"?"+ORDER_BY_URL_KEY+"=%s&"+ORDER_DESC_URL_KEY+"=%t&"+PAGE_NUM_URL_KEY+"=%d&"+ITEMS_PER_PAGE_URL_KEY+"=%d",
f.OrderBy,
f.OrderDescending,
f.Pagination.CurrentPage,
f.Pagination.MaxItemsPerPage,
)
for k, v := range f.Search {
output += "&" + SEARCH_URL_KEY_PREFIX + k + "=" + v
}
return output
}
func GetColumnFromStringName(column string, cl ColumnList) (Column, bool) {
for _, col := range cl {
if col.Name() == column {
return col, true
}
}
return nil, false
}
func GetColInfoFromJet(cl ColumnList) []ColInfo {
list := []ColInfo{}
for _, col := range cl {
newCol := ColInfo{
DisplayName: SnakeCaseToTitleCase(col.Name()),
DbName: col.Name(),
}
list = append(list, newCol)
}
return list
}
func (p *Pagination) GeneratePagination(totalItemsInSet int, itemsDisplayedThisPage int) {
p.TotalItems = totalItemsInSet
p.ItemsThisPage = itemsDisplayedThisPage
if p.MaxItemsPerPage == 0 {
p.MaxItemsPerPage = FILTER_DEFAULT_MAX_ITEMS
}
if p.MaxItemsPerPage == 0 {
p.TotalPages = 1
} else {
p.TotalPages = p.TotalItems / p.MaxItemsPerPage
if p.TotalItems%p.MaxItemsPerPage != 0 {
p.TotalPages++
}
}
if p.TotalPages == 0 {
p.TotalPages = 1
}
if p.CurrentPage < 1 {
p.CurrentPage = 1
p.PreviousPage = 1
} else {
p.PreviousPage = p.CurrentPage - 1
}
if p.TotalItems != 0 {
p.ViewRangeLower = p.MaxItemsPerPage*p.CurrentPage - p.MaxItemsPerPage + 1
} else {
p.ViewRangeLower = 0
}
p.ViewRangeUpper = p.MaxItemsPerPage*p.CurrentPage - p.MaxItemsPerPage + p.ItemsThisPage
if p.CurrentPage >= p.TotalPages {
p.CurrentPage = p.TotalPages
p.NextPage = p.TotalPages
} else {
p.NextPage = p.CurrentPage + 1
}
}
///////////////////////////
// IN-MEMORY OPERATIONS
///////////////////////////
// If you are doing filtering against in-memory structures, you can use the following helpers:
func PaginateSlice[T any](arr []T, f Filter) []T {
if f.Pagination.Enabled {
if f.Pagination.CurrentPage <= 0 {
f.Pagination.CurrentPage = 1
}
if f.Pagination.MaxItemsPerPage > 0 {
offset := (f.Pagination.CurrentPage - 1) * f.Pagination.MaxItemsPerPage
limit := f.Pagination.MaxItemsPerPage
// bounds check
if offset > len(arr) {
arr = []T{}
} else if offset+limit > len(arr) {
arr = arr[offset:]
} else {
arr = arr[offset : offset+limit]
}
}
}
return arr
}