194 lines
4.7 KiB
Go
194 lines
4.7 KiB
Go
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}}
|
|
}
|