Skip to content

Commit

Permalink
feat(wip): custom filter
Browse files Browse the repository at this point in the history
  • Loading branch information
0xJacky committed Dec 17, 2024
1 parent 959a11f commit 20a81ba
Show file tree
Hide file tree
Showing 12 changed files with 413 additions and 325 deletions.
27 changes: 18 additions & 9 deletions api_internal_hook.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cosy

import (
"github.com/elliotchance/orderedmap/v3"
"github.com/uozi-tech/cosy/model"
)

Expand Down Expand Up @@ -28,15 +29,16 @@ func getListHook[T any]() func(core *Ctx[T]) {

return func(core *Ctx[T]) {
var (
in []string
eq []string
fussy []string
orIn []string
orEq []string
orFussy []string
preload []string
search []string
between []string
in []string
eq []string
fussy []string
orIn []string
orEq []string
orFussy []string
preload []string
search []string
between []string
customFilters = orderedmap.NewOrderedMap[string, string]() // key=>filter
)

for _, field := range resolved.OrderedFields {
Expand All @@ -62,6 +64,8 @@ func getListHook[T any]() func(core *Ctx[T]) {
search = append(search, field.JsonTag)
case Between:
between = append(between, field.JsonTag)
default:
customFilters.Set(field.JsonTag, dir)
}
}
}
Expand Down Expand Up @@ -93,5 +97,10 @@ func getListHook[T any]() func(core *Ctx[T]) {
if len(between) > 0 {
core.SetBetween(between...)
}
if customFilters.Len() > 0 {
for key, filterName := range customFilters.AllFromFront() {
core.SetCustomFilter(key, filterName)
}
}
}
}
3 changes: 3 additions & 0 deletions cosy.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cosy

import (
"github.com/elliotchance/orderedmap/v3"
"github.com/gin-gonic/gin"
"github.com/spf13/cast"
"gorm.io/gorm"
Expand Down Expand Up @@ -42,6 +43,7 @@ type Ctx[T any] struct {
search []string
between []string
unique []string
customFilters *orderedmap.OrderedMap[string, string]
}

func Core[T any](c *gin.Context) *Ctx[T] {
Expand All @@ -54,6 +56,7 @@ func Core[T any](c *gin.Context) *Ctx[T] {
skipAssociationsOnCreate: true,
columnWhiteList: make(map[string]bool),
selectedFields: make(map[string]bool),
customFilters: orderedmap.NewOrderedMap[string, string](),
}
}

Expand Down
237 changes: 22 additions & 215 deletions filter.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
package cosy

import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/uozi-tech/cosy/filter"
"github.com/uozi-tech/cosy/logger"
"github.com/uozi-tech/cosy/model"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"strings"
)

func (c *Ctx[T]) SetFussy(keys ...string) *Ctx[T] {
c.fussy = append(c.fussy, keys...)
for _, key := range keys {
c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
return QueryToFussySearch(c.Context, tx, key)
return filter.QueryToFussySearch(c.Context, tx, key)
})
}
return c
Expand All @@ -23,273 +20,83 @@ func (c *Ctx[T]) SetFussy(keys ...string) *Ctx[T] {
func (c *Ctx[T]) SetSearchFussyKeys(keys ...string) *Ctx[T] {
c.search = append(c.search, keys...)
c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
return QueryToFussyKeysSearch(c.Context, tx, keys...)
return filter.QueryToFussyKeysSearch(c.Context, tx, keys...)
})
return c
}

func (c *Ctx[T]) SetEqual(keys ...string) *Ctx[T] {
c.eq = append(c.eq, keys...)
c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
return QueryToEqualSearch(c.Context, tx, keys...)
return filter.QueryToEqualSearch(c.Context, tx, keys...)
})
return c
}

func (c *Ctx[T]) SetIn(keys ...string) *Ctx[T] {
c.in = append(c.in, keys...)
c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
return QueriesToInSearch(c.Context, tx, keys...)
return filter.QueriesToInSearch(c.Context, tx, keys...)
})
return c
}

func (c *Ctx[T]) SetInWithKey(value string, key string) *Ctx[T] {
c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
return QueryToInSearch(c.Context, tx, value, key)
return filter.QueryToInSearch(c.Context, tx, value, key)
})
return c
}

func (c *Ctx[T]) SetOrFussy(keys ...string) *Ctx[T] {
c.orFussy = append(c.orFussy, keys...)
c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
return QueryToOrFussySearch(c.Context, tx, keys...)
return filter.QueryToOrFussySearch(c.Context, tx, keys...)
})
return c
}

func (c *Ctx[T]) SetOrEqual(keys ...string) *Ctx[T] {
c.orEq = append(c.orEq, keys...)
c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
return QueryToOrEqualSearch(c.Context, tx, keys...)
return filter.QueryToOrEqualSearch(c.Context, tx, keys...)
})
return c
}

func (c *Ctx[T]) SetBetween(keys ...string) *Ctx[T] {
c.between = append(c.between, keys...)
c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
return QueriesToBetweenSearch(c.Context, tx, keys...)
return filter.QueriesToBetweenSearch(c.Context, tx, keys...)
})
return c
}

func (c *Ctx[T]) SetBetweenWithKey(value string, key string) *Ctx[T] {
c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
return QueryToBetweenSearch(c.Context, tx, value, key)
return filter.QueryToBetweenSearch(c.Context, tx, value, key)
})
return c
}

func (c *Ctx[T]) SetOrIn(keys ...string) *Ctx[T] {
c.orIn = append(c.orIn, keys...)
c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
return QueryToOrInSearch(c.Context, tx, keys...)
return filter.QueryToOrInSearch(c.Context, tx, keys...)
})
return c
}

func QueriesToInSearch(c *gin.Context, db *gorm.DB, keys ...string) *gorm.DB {
for _, v := range keys {
QueryToInSearch(c, db, v)
func (c *Ctx[T]) SetCustomFilter(key string, filterName string) *Ctx[T] {
customFilter := filter.FilterMap[filterName]
if customFilter == nil {
logger.Errorf("Filter not found: %s", filterName)
return c
}
return db
}

func QueryToInSearch(c *gin.Context, db *gorm.DB, value string, key ...string) *gorm.DB {
queryArray := c.QueryArray(value + "[]")
if len(queryArray) == 0 {
queryArray = c.QueryArray(value)
}
if len(queryArray) == 1 && queryArray[0] == "" {
return db
}

if len(queryArray) >= 1 {
var builder strings.Builder
stmt := db.Statement

column := value
if len(key) != 0 {
column = key[0]
}

stmt.QuoteTo(&builder, clause.Column{Table: stmt.Table, Name: column})
builder.WriteString(" IN ?")

return db.Where(builder.String(), queryArray)
}
return db
}

func QueryToEqualSearch(c *gin.Context, db *gorm.DB, keys ...string) *gorm.DB {
for _, v := range keys {
if c.Query(v) != "" {
var sb strings.Builder
stmt := db.Statement

stmt.QuoteTo(&sb, clause.Column{Table: stmt.Table, Name: v})
sb.WriteString(" = ?")

db = db.Where(sb.String(), c.Query(v))
}
}
return db
}

func QueryToFussySearch(c *gin.Context, db *gorm.DB, key string) *gorm.DB {
if qArr := c.QueryArray(key + "[]"); qArr != nil {
db = applyFuzzyCondition(db, key, qArr)
} else if q := c.Query(key); q != "" {
db = applyFuzzyCondition(db, key, []string{q})
}
return db
}

func applyFuzzyCondition(tx *gorm.DB, column string, values []string) *gorm.DB {
stmt := tx.Statement

// build column name (column LIKE ?)
var colBuilder strings.Builder
stmt.QuoteTo(&colBuilder, clause.Column{Table: stmt.Table, Name: column})
colBuilder.WriteString(" LIKE ?")

db := model.UseDB()
var valueBuilder strings.Builder

for _, value := range values {
// build value for query (%value%)
valueBuilder.Reset()
valueBuilder.WriteString("%")
valueBuilder.WriteString(value)
valueBuilder.WriteString("%")

db = db.Or(colBuilder.String(), valueBuilder.String())
}

return tx.Where(db)
}

func QueryToFussyKeysSearch(c *gin.Context, tx *gorm.DB, keys ...string) *gorm.DB {
value := c.Query("search")
if value == "" {
return tx
}

// build value for query (%value%)
var valueBuilder strings.Builder
valueBuilder.WriteString("%")
valueBuilder.WriteString(value)
valueBuilder.WriteString("%")
likeValue := valueBuilder.String()

db := model.UseDB()
var colBuilder strings.Builder

for _, v := range keys {
// build column name (column LIKE ?)
colBuilder.Reset()
colBuilder.WriteString(v)
colBuilder.WriteString(" LIKE ?")

db = db.Or(colBuilder.String(), likeValue)
}

return tx.Where(db)
}

func QueryToOrInSearch(c *gin.Context, db *gorm.DB, keys ...string) *gorm.DB {
for _, v := range keys {
queryArray := c.QueryArray(v + "[]")
if len(queryArray) == 0 {
queryArray = c.QueryArray(v)
}
if len(queryArray) == 1 && queryArray[0] == "" {
continue
}
if len(queryArray) >= 1 {
var sb strings.Builder
stmt := db.Statement

stmt.QuoteTo(&sb, clause.Column{Table: stmt.Table, Name: v})
sb.WriteString(" IN ?")

db = db.Or(sb.String(), queryArray)
}
}
return db
}

func QueryToOrEqualSearch(c *gin.Context, db *gorm.DB, keys ...string) *gorm.DB {
for _, v := range keys {
if c.Query(v) != "" {
var sb strings.Builder
stmt := db.Statement

stmt.QuoteTo(&sb, clause.Column{Table: stmt.Table, Name: v})
sb.WriteString(" = ?")

db = db.Or(sb.String(), c.Query(v))
}
}
return db
}

func QueryToOrFussySearch(c *gin.Context, db *gorm.DB, keys ...string) *gorm.DB {
for _, v := range keys {
if c.Query(v) != "" {
var sb strings.Builder
stmt := db.Statement

stmt.QuoteTo(&sb, clause.Column{Table: stmt.Table, Name: v})

sb.WriteString(" LIKE ?")

var sbValue strings.Builder

_, err := fmt.Fprintf(&sbValue, "%%%s%%", c.Query(v))

if err != nil {
logger.Error(err)
continue
}

db = db.Or(sb.String(), sbValue.String())
}
}
return db
}

func QueriesToBetweenSearch(c *gin.Context, db *gorm.DB, keys ...string) *gorm.DB {
for _, v := range keys {
db = QueryToBetweenSearch(c, db, v)
}
return db
}

func QueryToBetweenSearch(c *gin.Context, db *gorm.DB, value string, key ...string) *gorm.DB {
queryArray := c.QueryArray(value + "[]")
if len(queryArray) == 0 {
queryArray = c.QueryArray(value)
}
if len(queryArray) <= 1 {
return db
}

if len(queryArray) == 2 && queryArray[0] != "" && queryArray[1] != "" {
var builder strings.Builder
stmt := db.Statement

column := value
if len(key) != 0 {
column = key[0]
}

stmt.QuoteTo(&builder, clause.Column{Table: stmt.Table, Name: column})
builder.WriteString(" BETWEEN ? AND ?")

return db.Where(builder.String(), queryArray[0], queryArray[1])
}
return db
c.customFilters.Set(key, filterName)
c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB {
resolvedModel := model.GetResolvedModel[T]()
return customFilter.Filter(c.Context, tx, key, resolvedModel.Fields[key], resolvedModel)
})
return c
}
Loading

0 comments on commit 20a81ba

Please sign in to comment.