mirror of
https://github.com/gohouse/gorose.git
synced 2025-12-24 12:47:55 +08:00
383 lines
12 KiB
Go
383 lines
12 KiB
Go
package gorose
|
|
|
|
import (
|
|
"errors"
|
|
"reflect"
|
|
"slices"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
type IWhere interface {
|
|
Where(column any, args ...any) IWhere
|
|
OrWhere(column any, args ...any) IWhere
|
|
WhereRaw(raw string, bindingsAndBoolean ...any) IWhere
|
|
OrWhereRaw(sqlSeg string, bindingsAndBoolean ...any) IWhere
|
|
|
|
WhereBetween(column string, values any) IWhere
|
|
OrWhereBetween(column string, values any) IWhere
|
|
WhereNotBetween(column string, values any) IWhere
|
|
OrWhereNotBetween(column string, values any) IWhere
|
|
|
|
WhereIn(column string, values any) IWhere
|
|
OrWhereIn(column string, values any) IWhere
|
|
WhereNotIn(column string, values any) IWhere
|
|
OrWhereNotIn(column string, values any) IWhere
|
|
|
|
WhereNull(column string) IWhere
|
|
OrWhereNull(column string) IWhere
|
|
WhereNotNull(column string) IWhere
|
|
OrWhereNotNull(column string) IWhere
|
|
|
|
WhereLike(column string, value string) IWhere
|
|
OrWhereLike(column string, value string) IWhere
|
|
WhereNotLike(column string, value string) IWhere
|
|
OrWhereNotLike(column string, value string) IWhere
|
|
|
|
WhereExists(clause IDriver) IWhere
|
|
WhereNotExists(clause IDriver) IWhere
|
|
}
|
|
|
|
// WhereClause 存储所有WHERE条件 ///////////////////start
|
|
type WhereClause struct {
|
|
Conditions []any
|
|
Not bool
|
|
Err error
|
|
}
|
|
type TypeWhereRaw struct {
|
|
LogicalOp string
|
|
Column string
|
|
Bindings []any
|
|
}
|
|
type TypeWhereNested struct {
|
|
LogicalOp string
|
|
Column func(where IWhere)
|
|
}
|
|
type TypeWhereSubQuery struct {
|
|
LogicalOp string
|
|
Column string
|
|
Operator string
|
|
SubQuery IDriver
|
|
}
|
|
type TypeWhereStandard struct {
|
|
LogicalOp string
|
|
Column string
|
|
Operator string
|
|
Value any
|
|
}
|
|
type TypeWhereIn struct {
|
|
LogicalOp string
|
|
Column string
|
|
Operator string
|
|
Value any
|
|
}
|
|
type TypeWhereBetween struct {
|
|
LogicalOp string
|
|
Column string
|
|
Operator string
|
|
Value any
|
|
}
|
|
type TypeWhereExists struct {
|
|
IDriver
|
|
Not bool
|
|
}
|
|
|
|
// WhereRaw Add a raw where clause to the query.
|
|
//
|
|
// whereRaw($sql, $bindings = [], $boolean = 'and')
|
|
//
|
|
// Parameters:
|
|
//
|
|
// string $sql
|
|
// mixed $bindings
|
|
// string $boolean
|
|
//
|
|
// Returns:
|
|
//
|
|
// SubQuery
|
|
//
|
|
// Laravel api
|
|
func (w *WhereClause) WhereRaw(raw string, bindingsAndBoolean ...any) IWhere {
|
|
return w.whereRaw("AND", raw, bindingsAndBoolean...)
|
|
}
|
|
|
|
// OrWhereRaw clause
|
|
func (w *WhereClause) OrWhereRaw(sqlSeg string, bindingsAndBoolean ...any) IWhere {
|
|
return w.whereRaw("OR", sqlSeg, bindingsAndBoolean...)
|
|
}
|
|
|
|
func (w *WhereClause) whereRaw(boolean string, sqlSeg string, bindingsAndBoolean ...any) IWhere {
|
|
if sqlSeg == "" {
|
|
return w
|
|
}
|
|
if len(bindingsAndBoolean) == 0 {
|
|
return w.WhereRaw(sqlSeg, []any{}, boolean)
|
|
} else if len(bindingsAndBoolean) == 1 {
|
|
return w.WhereRaw(sqlSeg, bindingsAndBoolean[0], boolean)
|
|
} else if len(bindingsAndBoolean) == 2 {
|
|
rfv := reflect.ValueOf(bindingsAndBoolean[0])
|
|
var bindTmp []any
|
|
if rfv.Kind() == reflect.Slice {
|
|
for i := 0; i < rfv.Len(); i++ {
|
|
bindTmp = append(bindTmp, rfv.Index(i).Interface())
|
|
}
|
|
} else {
|
|
bindTmp = append(bindTmp, rfv.Interface())
|
|
}
|
|
rfv1 := reflect.ValueOf(bindingsAndBoolean[1])
|
|
if rfv1.Kind() == reflect.String {
|
|
w.addTypeWhereRaw(rfv1.String(), sqlSeg, bindTmp)
|
|
}
|
|
}
|
|
return w
|
|
}
|
|
|
|
// Where Add a basic where clause to the query.
|
|
//
|
|
// where($column, $operator = null, $value = null, $boolean = 'and')
|
|
//
|
|
// Parameters:
|
|
//
|
|
// array|Closure|Expression|string $column
|
|
// mixed $operator
|
|
// mixed $value
|
|
// string $boolean
|
|
//
|
|
// Returns:
|
|
//
|
|
// iface.WhereClause
|
|
//
|
|
// Examples:
|
|
//
|
|
// Where("id=1")
|
|
// Where("id=?",1)
|
|
// Where("id",1)
|
|
// Where("id","=",1)
|
|
// Where("id","=",1,"AND")
|
|
// Where("id","=",(select id from table limit 1))
|
|
// Where("id","in",(select id from table), "AND")
|
|
// Where(func(wh iface.WhereClause){wh.Where().OrWhere().WhereRaw()...})
|
|
// Where(["id=1"])
|
|
// Where(["id","=",1])
|
|
// Where(["id",1])
|
|
// Where([ ["id",1],["name","=","John"],["age",">",3] ])
|
|
func (w *WhereClause) Where(column any, args ...any) IWhere {
|
|
return w.where("AND", column, args...)
|
|
}
|
|
|
|
// OrWhere clause
|
|
func (w *WhereClause) OrWhere(column any, args ...any) IWhere {
|
|
return w.where("OR", column, args...)
|
|
}
|
|
|
|
func (w *WhereClause) where(boolean string, column any, args ...any) IWhere {
|
|
if column == nil {
|
|
return w
|
|
}
|
|
switch len(args) {
|
|
case 0:
|
|
rfv := reflect.Indirect(reflect.ValueOf(column))
|
|
switch rfv.Kind() {
|
|
case reflect.Map:
|
|
keys := rfv.MapKeys()
|
|
sort.Slice(keys, func(i, j int) bool {
|
|
return keys[i].String() < keys[j].String()
|
|
})
|
|
for _, k := range keys {
|
|
w.where("AND", k.Interface(), "=", rfv.MapIndex(k).Interface())
|
|
}
|
|
case reflect.Func:
|
|
if fn, ok := column.(func(where IWhere)); ok {
|
|
w.addTypeWhereNested(boolean, fn)
|
|
} else {
|
|
w.Err = errors.New("not supported where params")
|
|
}
|
|
case reflect.String:
|
|
return w.whereRaw(boolean, rfv.String())
|
|
case reflect.Slice:
|
|
if rfv.Len() > 1 {
|
|
rfvItem := rfv.Index(0)
|
|
if rfvItem.Kind() == reflect.Slice {
|
|
return w.where(boolean, rfvItem.Interface())
|
|
} else {
|
|
var tmp []any
|
|
for i := 0; i < rfv.Len(); i++ {
|
|
tmp = append(tmp, rfv.Index(i).Interface())
|
|
}
|
|
return w.where(boolean, tmp[0], tmp[1:]...)
|
|
}
|
|
} else if rfv.Len() > 0 {
|
|
return w.whereRaw(boolean, rfv.Index(0).String())
|
|
}
|
|
w.Err = errors.New("not supported where params")
|
|
default:
|
|
w.Err = errors.New("not supported where params")
|
|
}
|
|
case 1:
|
|
if IsExpression(column) {
|
|
return w.whereRaw(boolean, column.(string), args...)
|
|
}
|
|
return w.where(boolean, column, "=", args[0], boolean)
|
|
case 2:
|
|
return w.where(boolean, column, args[0], args[1], boolean)
|
|
case 3:
|
|
rfv := reflect.Indirect(reflect.ValueOf(args[1]))
|
|
if rfv.Kind() == reflect.Slice { // in/between
|
|
var operators = []string{"in", "not in"}
|
|
if slices.Contains(operators, strings.ToLower(args[0].(string))) {
|
|
val := ToSlice(args[1])
|
|
if len(val) > 0 {
|
|
w.addTypeWhereIn(args[2].(string), column.(string), args[0].(string), ToSlice(args[1]))
|
|
}
|
|
}
|
|
operators = []string{"between", "not between"}
|
|
if slices.Contains(operators, strings.ToLower(args[0].(string))) {
|
|
val := ToSlice(args[1])
|
|
if len(val) > 0 {
|
|
w.addTypeWhereBetween(args[2].(string), column.(string), args[0].(string), ToSlice(args[1]))
|
|
}
|
|
}
|
|
} else if builder, ok := args[1].(IDriver); ok {
|
|
w.addTypeWhereSubQuery(args[2].(string), column.(string), args[0].(string), builder)
|
|
} else {
|
|
w.addTypeWhereStandard(args[2].(string), column.(string), args[0].(string), args[1])
|
|
}
|
|
default:
|
|
w.Err = errors.New("not supported where params")
|
|
}
|
|
return w
|
|
}
|
|
|
|
// WhereBetween 在指定列的值位于给定范围内时添加一个"where"条件。
|
|
//
|
|
// relation: and/or
|
|
// column: 列名。
|
|
// values: 区间范围数组。
|
|
// not: 是否取反,默认为 false。
|
|
func (w *WhereClause) WhereBetween(column string, values any) IWhere {
|
|
return w.whereBetween("AND", column, values, false)
|
|
}
|
|
func (w *WhereClause) OrWhereBetween(column string, values any) IWhere {
|
|
return w.whereBetween("OR", column, values, false)
|
|
}
|
|
func (w *WhereClause) WhereNotBetween(column string, values any) IWhere {
|
|
return w.whereBetween("AND", column, values, true)
|
|
}
|
|
func (w *WhereClause) OrWhereNotBetween(column string, values any) IWhere {
|
|
return w.whereBetween("OR", column, values, true)
|
|
}
|
|
func (w *WhereClause) whereBetween(relation string, column string, values any, not ...bool) IWhere {
|
|
if len(not) > 0 && not[0] {
|
|
return w.addTypeWhereBetween(relation, column, "NOT BETWEEN", values)
|
|
}
|
|
return w.addTypeWhereBetween(relation, column, "BETWEEN", values)
|
|
}
|
|
|
|
// WhereIn 在指定列的值存在于给定的集合内时添加一个"where"条件。
|
|
//
|
|
// relation: and/or
|
|
// column: 要检查的列名。
|
|
// values: 集合值。
|
|
// not: 是否取反,默认为 false。
|
|
func (w *WhereClause) WhereIn(column string, values any) IWhere {
|
|
return w.whereIn("AND", column, values, false)
|
|
}
|
|
func (w *WhereClause) OrWhereIn(column string, values any) IWhere {
|
|
return w.whereIn("Or", column, values, false)
|
|
}
|
|
func (w *WhereClause) WhereNotIn(column string, values any) IWhere {
|
|
return w.whereIn("AND", column, values, true)
|
|
}
|
|
func (w *WhereClause) OrWhereNotIn(column string, values any) IWhere {
|
|
return w.whereIn("Or", column, values, true)
|
|
}
|
|
func (w *WhereClause) whereIn(relation string, column string, values any, not ...bool) IWhere {
|
|
if len(not) > 0 && not[0] {
|
|
return w.addTypeWhereIn(relation, column, "NOT IN", values)
|
|
}
|
|
return w.addTypeWhereIn(relation, column, "IN", values)
|
|
}
|
|
|
|
// WhereNull 指定列的值为 NULL 时添加一个"where"条件。
|
|
//
|
|
// relation: and/or
|
|
// column: 列名。
|
|
func (w *WhereClause) WhereNull(column string) IWhere { return w.whereNull("AND", column, false) }
|
|
func (w *WhereClause) OrWhereNull(column string) IWhere { return w.whereNull("OR", column, false) }
|
|
func (w *WhereClause) WhereNotNull(column string) IWhere { return w.whereNull("AND", column, true) }
|
|
func (w *WhereClause) OrWhereNotNull(column string) IWhere { return w.whereNull("OR", column, true) }
|
|
func (w *WhereClause) whereNull(relation string, column string, not ...bool) IWhere {
|
|
if len(not) > 0 && not[0] {
|
|
return w.addTypeWhereStandard(relation, column, "IS NOT", "NULL")
|
|
}
|
|
return w.addTypeWhereStandard(relation, column, "IS", "NULL")
|
|
}
|
|
|
|
// WhereLike 在指定列进行模糊匹配时添加一个"where"条件。
|
|
//
|
|
// relation: and/or
|
|
// column: 要进行模糊匹配的列名。
|
|
// value: 包含通配符(%)的匹配字符串。
|
|
func (w *WhereClause) WhereLike(column string, value string) IWhere {
|
|
return w.whereLike("NAD", column, value, false)
|
|
}
|
|
func (w *WhereClause) OrWhereLike(column string, value string) IWhere {
|
|
return w.whereLike("OR", column, value, false)
|
|
}
|
|
func (w *WhereClause) WhereNotLike(column string, value string) IWhere {
|
|
return w.whereLike("NAD", column, value, true)
|
|
}
|
|
func (w *WhereClause) OrWhereNotLike(column string, value string) IWhere {
|
|
return w.whereLike("OR", column, value, true)
|
|
}
|
|
func (w *WhereClause) whereLike(relation string, column string, value string, not ...bool) IWhere {
|
|
if len(not) > 0 && not[0] {
|
|
return w.addTypeWhereStandard(relation, column, "NOT LIKE", value)
|
|
}
|
|
return w.addTypeWhereStandard(relation, column, "LIKE", value)
|
|
}
|
|
|
|
// WhereExists 使用WHERE EXISTS子查询条件。
|
|
//
|
|
// clause: Database 语句,或者实现了 IDriver.ToSql() 接口的对象
|
|
func (w *WhereClause) WhereExists(clause IDriver) IWhere { return w.whereExists(clause, false) }
|
|
func (w *WhereClause) WhereNotExists(clause IDriver) IWhere { return w.whereExists(clause, true) }
|
|
func (w *WhereClause) whereExists(clause IDriver, not ...bool) IWhere {
|
|
var b bool
|
|
if len(not) > 0 {
|
|
b = not[0]
|
|
}
|
|
w.Conditions = append(w.Conditions, TypeWhereExists{clause, b})
|
|
return w
|
|
}
|
|
|
|
func (w *WhereClause) WhereNot(column any, args ...any) IWhere {
|
|
w.Not = true
|
|
return w.Where(column, args...)
|
|
}
|
|
|
|
func (w *WhereClause) addTypeWhereRaw(boolean string, value string, bindings []any) *WhereClause {
|
|
w.Conditions = append(w.Conditions, TypeWhereRaw{LogicalOp: boolean, Column: value, Bindings: bindings})
|
|
return w
|
|
}
|
|
func (w *WhereClause) addTypeWhereNested(boolean string, value func(where IWhere)) *WhereClause {
|
|
w.Conditions = append(w.Conditions, TypeWhereNested{LogicalOp: boolean, Column: value})
|
|
return w
|
|
}
|
|
func (w *WhereClause) addTypeWhereSubQuery(boolean string, column string, operator string, value IDriver) *WhereClause {
|
|
w.Conditions = append(w.Conditions, TypeWhereSubQuery{LogicalOp: boolean, Column: column, Operator: operator, SubQuery: value})
|
|
return w
|
|
}
|
|
func (w *WhereClause) addTypeWhereIn(boolean string, column string, operator string, value any) *WhereClause {
|
|
w.Conditions = append(w.Conditions, TypeWhereIn{LogicalOp: boolean, Column: column, Operator: operator, Value: value})
|
|
return w
|
|
}
|
|
func (w *WhereClause) addTypeWhereBetween(boolean string, column string, operator string, value any) *WhereClause {
|
|
w.Conditions = append(w.Conditions, TypeWhereBetween{LogicalOp: boolean, Column: column, Operator: operator, Value: value})
|
|
return w
|
|
}
|
|
func (w *WhereClause) addTypeWhereStandard(boolean string, column string, operator string, value any) *WhereClause {
|
|
w.Conditions = append(w.Conditions, TypeWhereStandard{LogicalOp: boolean, Column: column, Operator: operator, Value: value})
|
|
return w
|
|
}
|