mirror of
https://github.com/Dvorinka/MyClubServer.git
synced 2026-06-04 02:32:57 +00:00
dev day #65
This commit is contained in:
@@ -0,0 +1,237 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// QueryHelper provides query parameter parsing and filtering utilities
|
||||
type QueryHelper struct{}
|
||||
|
||||
// SortParams represents sorting parameters
|
||||
type SortParams struct {
|
||||
Field string
|
||||
Order string // "asc" or "desc"
|
||||
}
|
||||
|
||||
// FilterParams represents generic filter parameters
|
||||
type FilterParams map[string]interface{}
|
||||
|
||||
// NewQueryHelper creates a new QueryHelper instance
|
||||
func NewQueryHelper() *QueryHelper {
|
||||
return &QueryHelper{}
|
||||
}
|
||||
|
||||
// GetSortParams extracts sort parameters from the request
|
||||
// Expects: ?sort=field:order (e.g., ?sort=created_at:desc)
|
||||
func (qh *QueryHelper) GetSortParams(c *gin.Context, defaultField, defaultOrder string) SortParams {
|
||||
sortQuery := c.Query("sort")
|
||||
if sortQuery == "" {
|
||||
return SortParams{
|
||||
Field: defaultField,
|
||||
Order: defaultOrder,
|
||||
}
|
||||
}
|
||||
|
||||
parts := strings.Split(sortQuery, ":")
|
||||
field := parts[0]
|
||||
order := defaultOrder
|
||||
|
||||
if len(parts) > 1 {
|
||||
order = strings.ToLower(parts[1])
|
||||
if order != "asc" && order != "desc" {
|
||||
order = defaultOrder
|
||||
}
|
||||
}
|
||||
|
||||
return SortParams{
|
||||
Field: field,
|
||||
Order: order,
|
||||
}
|
||||
}
|
||||
|
||||
// ApplySort applies sorting to a GORM query
|
||||
func (qh *QueryHelper) ApplySort(db *gorm.DB, params SortParams) *gorm.DB {
|
||||
if params.Field != "" {
|
||||
return db.Order(params.Field + " " + params.Order)
|
||||
}
|
||||
return db
|
||||
}
|
||||
|
||||
// ApplySortFromContext extracts sort params from context and applies them
|
||||
func (qh *QueryHelper) ApplySortFromContext(c *gin.Context, db *gorm.DB, defaultField, defaultOrder string) *gorm.DB {
|
||||
params := qh.GetSortParams(c, defaultField, defaultOrder)
|
||||
return qh.ApplySort(db, params)
|
||||
}
|
||||
|
||||
// GetSearchQuery extracts search query from request
|
||||
// Expects: ?search=term or ?q=term
|
||||
func (qh *QueryHelper) GetSearchQuery(c *gin.Context) string {
|
||||
search := c.Query("search")
|
||||
if search == "" {
|
||||
search = c.Query("q")
|
||||
}
|
||||
return strings.TrimSpace(search)
|
||||
}
|
||||
|
||||
// ApplySearch applies search to specified fields using LIKE
|
||||
func (qh *QueryHelper) ApplySearch(db *gorm.DB, searchTerm string, fields ...string) *gorm.DB {
|
||||
if searchTerm == "" || len(fields) == 0 {
|
||||
return db
|
||||
}
|
||||
|
||||
searchPattern := "%" + searchTerm + "%"
|
||||
query := db
|
||||
|
||||
// Build OR conditions for each field
|
||||
for i, field := range fields {
|
||||
if i == 0 {
|
||||
query = query.Where(field+" LIKE ?", searchPattern)
|
||||
} else {
|
||||
query = query.Or(field+" LIKE ?", searchPattern)
|
||||
}
|
||||
}
|
||||
|
||||
return query
|
||||
}
|
||||
|
||||
// ApplySearchFromContext extracts search query and applies it
|
||||
func (qh *QueryHelper) ApplySearchFromContext(c *gin.Context, db *gorm.DB, fields ...string) *gorm.DB {
|
||||
searchTerm := qh.GetSearchQuery(c)
|
||||
return qh.ApplySearch(db, searchTerm, fields...)
|
||||
}
|
||||
|
||||
// GetBoolQuery extracts a boolean query parameter
|
||||
func (qh *QueryHelper) GetBoolQuery(c *gin.Context, key string) *bool {
|
||||
value := c.Query(key)
|
||||
if value == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
boolValue := strings.ToLower(value) == "true" || value == "1"
|
||||
return &boolValue
|
||||
}
|
||||
|
||||
// ApplyBoolFilter applies a boolean filter if the parameter exists
|
||||
func (qh *QueryHelper) ApplyBoolFilter(db *gorm.DB, c *gin.Context, paramKey, dbField string) *gorm.DB {
|
||||
value := qh.GetBoolQuery(c, paramKey)
|
||||
if value != nil {
|
||||
return db.Where(dbField+" = ?", *value)
|
||||
}
|
||||
return db
|
||||
}
|
||||
|
||||
// GetIDsFromQuery extracts comma-separated IDs from query parameter
|
||||
// Expects: ?ids=1,2,3,4
|
||||
func (qh *QueryHelper) GetIDsFromQuery(c *gin.Context, key string) []uint {
|
||||
idsStr := c.Query(key)
|
||||
if idsStr == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
parts := strings.Split(idsStr, ",")
|
||||
ids := make([]uint, 0, len(parts))
|
||||
|
||||
for _, part := range parts {
|
||||
part = strings.TrimSpace(part)
|
||||
if part == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Parse as uint
|
||||
var id uint
|
||||
if _, err := fmt.Sscanf(part, "%d", &id); err == nil {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
}
|
||||
|
||||
return ids
|
||||
}
|
||||
|
||||
// ApplyIDsFilter applies IN filter for IDs
|
||||
func (qh *QueryHelper) ApplyIDsFilter(db *gorm.DB, c *gin.Context, paramKey, dbField string) *gorm.DB {
|
||||
ids := qh.GetIDsFromQuery(c, paramKey)
|
||||
if len(ids) > 0 {
|
||||
return db.Where(dbField+" IN ?", ids)
|
||||
}
|
||||
return db
|
||||
}
|
||||
|
||||
// GetDateRange extracts date range from query parameters
|
||||
// Expects: ?from=2024-01-01&to=2024-12-31
|
||||
func (qh *QueryHelper) GetDateRange(c *gin.Context) (from, to string) {
|
||||
from = c.Query("from")
|
||||
to = c.Query("to")
|
||||
return
|
||||
}
|
||||
|
||||
// ApplyDateRangeFilter applies date range filter
|
||||
func (qh *QueryHelper) ApplyDateRangeFilter(db *gorm.DB, c *gin.Context, dbField string) *gorm.DB {
|
||||
from, to := qh.GetDateRange(c)
|
||||
|
||||
if from != "" {
|
||||
db = db.Where(dbField+" >= ?", from)
|
||||
}
|
||||
if to != "" {
|
||||
db = db.Where(dbField+" <= ?", to)
|
||||
}
|
||||
|
||||
return db
|
||||
}
|
||||
|
||||
// BuildQueryChain combines multiple query operations
|
||||
func (qh *QueryHelper) BuildQueryChain(c *gin.Context, db *gorm.DB) *QueryChainBuilder {
|
||||
return &QueryChainBuilder{
|
||||
ctx: c,
|
||||
query: db,
|
||||
qh: qh,
|
||||
}
|
||||
}
|
||||
|
||||
// QueryChainBuilder provides a fluent interface for building queries
|
||||
type QueryChainBuilder struct {
|
||||
ctx *gin.Context
|
||||
query *gorm.DB
|
||||
qh *QueryHelper
|
||||
}
|
||||
|
||||
// WithSort adds sorting
|
||||
func (qcb *QueryChainBuilder) WithSort(defaultField, defaultOrder string) *QueryChainBuilder {
|
||||
qcb.query = qcb.qh.ApplySortFromContext(qcb.ctx, qcb.query, defaultField, defaultOrder)
|
||||
return qcb
|
||||
}
|
||||
|
||||
// WithSearch adds search across fields
|
||||
func (qcb *QueryChainBuilder) WithSearch(fields ...string) *QueryChainBuilder {
|
||||
qcb.query = qcb.qh.ApplySearchFromContext(qcb.ctx, qcb.query, fields...)
|
||||
return qcb
|
||||
}
|
||||
|
||||
// WithBoolFilter adds a boolean filter
|
||||
func (qcb *QueryChainBuilder) WithBoolFilter(paramKey, dbField string) *QueryChainBuilder {
|
||||
qcb.query = qcb.qh.ApplyBoolFilter(qcb.query, qcb.ctx, paramKey, dbField)
|
||||
return qcb
|
||||
}
|
||||
|
||||
// WithIDsFilter adds an IDs filter
|
||||
func (qcb *QueryChainBuilder) WithIDsFilter(paramKey, dbField string) *QueryChainBuilder {
|
||||
qcb.query = qcb.qh.ApplyIDsFilter(qcb.query, qcb.ctx, paramKey, dbField)
|
||||
return qcb
|
||||
}
|
||||
|
||||
// WithDateRange adds date range filter
|
||||
func (qcb *QueryChainBuilder) WithDateRange(dbField string) *QueryChainBuilder {
|
||||
qcb.query = qcb.qh.ApplyDateRangeFilter(qcb.query, qcb.ctx, dbField)
|
||||
return qcb
|
||||
}
|
||||
|
||||
// Build returns the final query
|
||||
func (qcb *QueryChainBuilder) Build() *gorm.DB {
|
||||
return qcb.query
|
||||
}
|
||||
|
||||
// Global QueryHelper instance for convenience
|
||||
var QueryParser = NewQueryHelper()
|
||||
Reference in New Issue
Block a user