package repository import ( "github.com/pkg/errors" "gorm.io/gorm" ) type QueryBuilder[T any] struct { db *gorm.DB model T } func NewQueryBuilder[T any](db *gorm.DB) *QueryBuilder[T] { var model T return &QueryBuilder[T]{ db: db, model: model, } } type Filter struct { Field string Operator string // "=", "!=", ">", "<", ">=", "<=", "LIKE", "IN", "NOT IN", "IS NULL", "IS NOT NULL" Value interface{} } type QueryOptions struct { Filters []Filter Limit int Offset int OrderBy []string Preloads []string GroupBy []string Having []Filter Distinct []string CountOnly bool } func (qb *QueryBuilder[T]) BuildQuery(options QueryOptions) *gorm.DB { query := qb.db.Model(&qb.model) for _, filter := range options.Filters { query = qb.applyFilter(query, filter) } if len(options.Distinct) > 0 { for _, distinct := range options.Distinct { query = query.Distinct(distinct) } } if len(options.GroupBy) > 0 { for _, groupBy := range options.GroupBy { query = query.Group(groupBy) } } for _, having := range options.Having { query = qb.applyFilter(query, having) } return query } func (qb *QueryBuilder[T]) applyFilter(query *gorm.DB, filter Filter) *gorm.DB { switch filter.Operator { case "=", "": return query.Where(filter.Field+" = ?", filter.Value) case "!=": return query.Where(filter.Field+" != ?", filter.Value) case ">": return query.Where(filter.Field+" > ?", filter.Value) case "<": return query.Where(filter.Field+" < ?", filter.Value) case ">=": return query.Where(filter.Field+" >= ?", filter.Value) case "<=": return query.Where(filter.Field+" <= ?", filter.Value) case "LIKE": return query.Where(filter.Field+" LIKE ?", filter.Value) case "IN": return query.Where(filter.Field+" IN ?", filter.Value) case "NOT IN": return query.Where(filter.Field+" NOT IN ?", filter.Value) case "IS NULL": return query.Where(filter.Field + " IS NULL") case "IS NOT NULL": return query.Where(filter.Field + " IS NOT NULL") case "BETWEEN": if values, ok := filter.Value.([]interface{}); ok && len(values) == 2 { return query.Where(filter.Field+" BETWEEN ? AND ?", values[0], values[1]) } return query default: return query.Where(filter.Field+" = ?", filter.Value) } } func (qb *QueryBuilder[T]) ExecuteQuery(baseQuery *gorm.DB, options QueryOptions) *gorm.DB { query := baseQuery.Session(&gorm.Session{}) if len(options.OrderBy) > 0 { for _, orderBy := range options.OrderBy { query = query.Order(orderBy) } } for _, preload := range options.Preloads { query = query.Preload(preload) } if options.Limit > 0 { query = query.Limit(options.Limit) } if options.Offset > 0 { query = query.Offset(options.Offset) } return query } func (qb *QueryBuilder[T]) Count(baseQuery *gorm.DB) (int64, error) { var count int64 if err := baseQuery.Count(&count).Error; err != nil { return 0, errors.Wrap(err, "failed to count records") } return count, nil } func (qb *QueryBuilder[T]) Find(query *gorm.DB) ([]T, error) { var results []T if err := query.Find(&results).Error; err != nil { return nil, errors.Wrap(err, "failed to find records") } return results, nil } func (qb *QueryBuilder[T]) First(query *gorm.DB) (*T, error) { var result T if err := query.First(&result).Error; err != nil { return nil, errors.Wrap(err, "failed to find record") } return &result, nil } func Equal(field string, value interface{}) Filter { return Filter{Field: field, Operator: "=", Value: value} } func NotEqual(field string, value interface{}) Filter { return Filter{Field: field, Operator: "!=", Value: value} } func GreaterThan(field string, value interface{}) Filter { return Filter{Field: field, Operator: ">", Value: value} } func LessThan(field string, value interface{}) Filter { return Filter{Field: field, Operator: "<", Value: value} } func GreaterEqual(field string, value interface{}) Filter { return Filter{Field: field, Operator: ">=", Value: value} } func LessEqual(field string, value interface{}) Filter { return Filter{Field: field, Operator: "<=", Value: value} } func Like(field string, value string) Filter { return Filter{Field: field, Operator: "LIKE", Value: value} } func In(field string, values interface{}) Filter { return Filter{Field: field, Operator: "IN", Value: values} } func NotIn(field string, values interface{}) Filter { return Filter{Field: field, Operator: "NOT IN", Value: values} } func IsNull(field string) Filter { return Filter{Field: field, Operator: "IS NULL"} } func IsNotNull(field string) Filter { return Filter{Field: field, Operator: "IS NOT NULL"} } func Between(field string, start, end interface{}) Filter { return Filter{Field: field, Operator: "BETWEEN", Value: []interface{}{start, end}} }