mirror of
https://github.com/zhufuyi/sponge.git
synced 2025-10-07 01:33:14 +08:00
219 lines
4.5 KiB
Go
219 lines
4.5 KiB
Go
package query
|
||
|
||
import (
|
||
"fmt"
|
||
"strings"
|
||
)
|
||
|
||
const (
|
||
// Eq equal
|
||
Eq = "eq"
|
||
// Neq not equal
|
||
Neq = "neq"
|
||
// Gt greater than
|
||
Gt = "gt"
|
||
// Gte greater than or equal
|
||
Gte = "gte"
|
||
// Lt less than
|
||
Lt = "lt"
|
||
// Lte less than or equal
|
||
Lte = "lte"
|
||
// Like like
|
||
Like = "like"
|
||
|
||
// AND logic and
|
||
AND string = "and"
|
||
// OR logic or
|
||
OR string = "or"
|
||
)
|
||
|
||
var expMap = map[string]string{
|
||
Eq: " = ",
|
||
Neq: " <> ",
|
||
Gt: " > ",
|
||
Gte: " >= ",
|
||
Lt: " < ",
|
||
Lte: " <= ",
|
||
Like: " LIKE ",
|
||
|
||
"=": " = ",
|
||
"!=": " <> ",
|
||
">": " > ",
|
||
">=": " >= ",
|
||
"<": " < ",
|
||
"<=": " <= ",
|
||
}
|
||
|
||
var logicMap = map[string]string{
|
||
AND: " AND ",
|
||
OR: " OR ",
|
||
|
||
"&": " AND ",
|
||
"&&": " AND ",
|
||
"|": " OR ",
|
||
"||": " OR ",
|
||
}
|
||
|
||
// Params 查询原始参数
|
||
type Params struct {
|
||
Page int `form:"page" binding:"gte=0" json:"page"`
|
||
Size int `form:"size" binding:"gt=0" json:"size"`
|
||
Sort string `form:"sort" binding:"" json:"sort,omitempty"`
|
||
|
||
Columns []Column `json:"columns,omitempty"` // 非必须
|
||
}
|
||
|
||
// Column 表的列查询信息
|
||
type Column struct {
|
||
Name string `json:"name"` // 列名
|
||
Exp string `json:"exp"` // 表达式,值为空时默认为=,有=、!=、>、>=、<、<=、like七种类型
|
||
Value interface{} `json:"value"` // 列值
|
||
Logic string `json:"logic"` // 逻辑类型,值为空时默认为and,有&(and)、||(or)两种类型
|
||
}
|
||
|
||
func (c *Column) checkValid() error {
|
||
if c.Name == "" {
|
||
return fmt.Errorf("field 'name' cannot be empty")
|
||
}
|
||
if c.Value == nil {
|
||
return fmt.Errorf("field 'value' cannot be nil")
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// 把ExpType转换为sql表达式,把LogicType转换为sql使用字符
|
||
func (c *Column) convert() error {
|
||
if c.Exp == "" {
|
||
c.Exp = Eq
|
||
}
|
||
if v, ok := expMap[strings.ToLower(c.Exp)]; ok {
|
||
c.Exp = v
|
||
if c.Exp == " LIKE " {
|
||
c.Value = fmt.Sprintf("%%%v%%", c.Value)
|
||
}
|
||
} else {
|
||
return fmt.Errorf("unknown c expression type '%s'", c.Exp)
|
||
}
|
||
|
||
if c.Logic == "" {
|
||
c.Logic = AND
|
||
}
|
||
if v, ok := logicMap[strings.ToLower(c.Logic)]; ok {
|
||
c.Logic = v
|
||
} else {
|
||
return fmt.Errorf("unknown logic type '%s'", c.Logic)
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// ConvertToPage 根据参数page size sort转换成符合gorm规则参数
|
||
func (p *Params) ConvertToPage() (order string, limit int, offset int) {
|
||
page := NewPage(p.Page, p.Size, p.Sort)
|
||
order = page.sort
|
||
limit = page.size
|
||
offset = page.page * page.size
|
||
return
|
||
}
|
||
|
||
// ConvertToGormConditions 根据参数Columns转换成符合gorm规则参数
|
||
// 无论是一列还是多列查询,忽略最后一列的逻辑类型
|
||
func (p *Params) ConvertToGormConditions() (string, []interface{}, error) {
|
||
str := ""
|
||
args := []interface{}{}
|
||
l := len(p.Columns)
|
||
if l == 0 {
|
||
return "", nil, nil
|
||
}
|
||
|
||
isUseIN := true
|
||
if l == 1 {
|
||
isUseIN = false
|
||
}
|
||
field := p.Columns[0].Name
|
||
|
||
for i, column := range p.Columns {
|
||
if err := column.checkValid(); err != nil {
|
||
return "", nil, err
|
||
}
|
||
|
||
err := column.convert()
|
||
if err != nil {
|
||
return "", nil, err
|
||
}
|
||
|
||
if i == l-1 { // 忽略最后一列的逻辑类型
|
||
str += column.Name + column.Exp + "?"
|
||
} else {
|
||
str += column.Name + column.Exp + "?" + column.Logic
|
||
}
|
||
args = append(args, column.Value)
|
||
|
||
if isUseIN {
|
||
if field != column.Name {
|
||
isUseIN = false
|
||
continue
|
||
}
|
||
if column.Exp != expMap[Eq] {
|
||
isUseIN = false
|
||
}
|
||
}
|
||
}
|
||
|
||
if isUseIN {
|
||
str = field + " IN (?)"
|
||
args = []interface{}{args}
|
||
}
|
||
|
||
return str, args, nil
|
||
}
|
||
|
||
func getExpsAndLogics(keyLen int, paramSrc string) ([]string, []string) { //nolint
|
||
exps, logics := []string{}, []string{}
|
||
param := strings.Replace(paramSrc, " ", "", -1)
|
||
sps := strings.SplitN(param, "?", 2)
|
||
if len(sps) == 2 {
|
||
param = sps[1]
|
||
}
|
||
|
||
num := keyLen
|
||
if num == 0 {
|
||
return exps, logics
|
||
}
|
||
|
||
fields := []string{}
|
||
kvs := strings.Split(param, "&")
|
||
for _, kv := range kvs {
|
||
if strings.Contains(kv, "page=") || strings.Contains(kv, "size=") || strings.Contains(kv, "sort=") {
|
||
continue
|
||
}
|
||
fields = append(fields, kv)
|
||
}
|
||
|
||
// 根据不重复的key分为num组,在每组中判断exp和logic是否存在
|
||
group := map[string]string{}
|
||
for _, field := range fields {
|
||
split := strings.SplitN(field, "=", 2)
|
||
if len(split) != 2 {
|
||
continue
|
||
}
|
||
|
||
if _, ok := group[split[0]]; ok {
|
||
// 在一组中,如果exp不存在则填充默认值空,logic不存在则填充充默认值空
|
||
exps = append(exps, group["exp"])
|
||
logics = append(logics, group["logic"])
|
||
|
||
group = map[string]string{}
|
||
continue
|
||
} else {
|
||
group[split[0]] = split[1]
|
||
}
|
||
}
|
||
|
||
// 处理最后一组
|
||
exps = append(exps, group["exp"])
|
||
logics = append(logics, group["logic"])
|
||
|
||
return exps, logics
|
||
}
|