从此版本开始,所有 where 参数的方法都支持使用泛型来同时接受 map[any]any 和 *Where 两种类型。
定义了一个泛型类型约束 WhereCondition:
type WhereCondition interface {
map[any]any | *Where
}这个约束限制了泛型参数只能是 map[any]any 或 *Where 两种类型之一。
提供了 ToWhere 函数来统一处理两种类型:
func ToWhere[T WhereCondition](condition T) *Where该函数会:
- 如果输入是
*Where,直接返回 - 如果输入是
map[any]any,转换为*Where对象
原来的方法:
func FindOne[T any](where map[any]any) (*T, error)更新后的方法:
func FindOne[T any, W WhereCondition](where W) (*T, error)user, err := gormx.FindOne[User](map[any]any{
"name": "Alice",
"age": 25,
})where := gormx.NewWhere()
where.Set("name", "Bob")
where.Set("age", 30)
user, err := gormx.FindOne[User](where)where := gormx.NewWhere()
where.Set("name", "Charlie", &gormx.SetWhereOptions{IsFuzzy: true})
where.Set("age", 35, &gormx.SetWhereOptions{IsNotEqual: true})
user, err := gormx.FindOne[User](where)where := gormx.NewWhere()
where.Set("age", []int{20, 25, 30}, &gormx.SetWhereOptions{IsIn: true})
user, err := gormx.FindOne[User](where)where := gormx.NewWhere()
// 年龄范围 18-65(默认是闭区间 [A, B])
where.Set("age", []int{18, 65}, &gormx.SetWhereOptions{IsRange: true})
// 生成: age BETWEEN 18 AND 65
// 指定范围模式
where.Set("age", []int{18, 65}, &gormx.SetWhereOptions{
IsRange: true,
RangeMode: gormx.RangeModeClosed, // [A, B] 闭区间(默认)
})
// 日期范围(字符串)
where.Set("created_at", []string{"2023-01-01", "2023-12-31"}, &gormx.SetWhereOptions{IsRange: true})
// 日期范围(time.Time)
start := time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC)
end := time.Date(2023, 12, 31, 23, 59, 59, 0, time.UTC)
where.Set("created_at", []interface{}{start, end}, &gormx.SetWhereOptions{IsRange: true})
users, total, err := gormx.Find[User](1, 10, where, nil)IsRange 支持四种范围模式:
// 1. RangeModeClosed - [A, B] 闭区间(默认)
// 包含两端:A <= field <= B
where.Set("age", []int{18, 65}, &gormx.SetWhereOptions{
IsRange: true,
RangeMode: gormx.RangeModeClosed,
})
// 生成: age BETWEEN 18 AND 65
// 2. RangeModeOpen - (A, B) 开区间
// 不包含两端:A < field < B
where.Set("age", []int{18, 65}, &gormx.SetWhereOptions{
IsRange: true,
RangeMode: gormx.RangeModeOpen,
})
// 生成: (age > 18 AND age < 65)
// 3. RangeModeLeftClosed - [A, B) 左闭右开
// 包含左端,不包含右端:A <= field < B
where.Set("age", []int{18, 65}, &gormx.SetWhereOptions{
IsRange: true,
RangeMode: gormx.RangeModeLeftClosed,
})
// 生成: (age >= 18 AND age < 65)
// 4. RangeModeRightClosed - (A, B] 左开右闭
// 不包含左端,包含右端:A < field <= B
where.Set("age", []int{18, 65}, &gormx.SetWhereOptions{
IsRange: true,
RangeMode: gormx.RangeModeRightClosed,
})
// 生成: (age > 18 AND age <= 65)使用场景:
- RangeModeClosed
[A, B]:通用范围查询,如年龄段 18-65 岁 - RangeModeOpen
(A, B):需要排除边界值的场景 - RangeModeLeftClosed
[A, B):时间范围查询,如某一天的所有数据 - RangeModeRightClosed
(A, B]:分页偏移等场景
where := gormx.NewWhere()
// 大于 (>)
where.Set("age", 18, &gormx.SetWhereOptions{IsGreaterThan: true})
// 小于 (<)
where.Set("age", 65, &gormx.SetWhereOptions{IsLessThan: true})
// 大于等于 (>=)
where.Set("score", 60, &gormx.SetWhereOptions{IsGreaterOrEqualThan: true})
// 小于等于 (<=)
where.Set("price", 100, &gormx.SetWhereOptions{IsLessOrEqualThan: true})
// 组合使用:age >= 18 AND age <= 65
where := gormx.NewWhere()
where.Add("age", 18, &gormx.SetWhereOptions{IsGreaterOrEqualThan: true})
where.Add("age", 65, &gormx.SetWhereOptions{IsLessOrEqualThan: true})
users, total, err := gormx.Find[User](1, 10, where, nil)- 类型安全:编译时就能检查类型错误
- 向后兼容:现有使用
map[any]any的代码无需修改 - 灵活性:可以根据场景选择合适的类型
- 统一接口:所有方法都使用同样的模式
以下方法都可以应用这个模式:
FindOne[T, W]FindOneAndDelete[T, W]FindOneAndUpdate[T, W]FindOneOrCreate[T, W]GetOrCreate[T, W]
Delete[T, W]
Exists[T, W]
Find[T, W]- 需要额外处理 nil 的情况FindAll[T, W]- 需要额外处理 nil 的情况List[T, W]- 需要额外处理 nil 的情况ListALL[T, W]- 需要额外处理 nil 的情况
对于原本接受 *Where 的方法(如 FindAll),如果需要支持 nil 值,有两种方案:
方案A:使用指针约束
type WhereConditionPtr interface {
map[any]any | *Where | nil
}方案B:保持可选参数
func FindAll[T any](where *Where, orderBy *OrderBy) (data []*T, err error)- 使用
map[any]any时,如果是简单的等值查询,内部会直接使用 GORM 的原生 map 支持,性能最优 - 使用
*Where时,会构建完整的 SQL WHERE 子句,支持复杂查询 - 两种方式都经过优化,运行时开销很小
现有代码无需修改,因为泛型参数会自动推断:
// 这行代码依然有效
user, err := gormx.FindOne[User](map[any]any{"name": "Alice"})建议根据场景选择:
- 简单查询:使用
map[any]any - 复杂查询:使用
*Where
- IsEqual: 等值查询
field = ? - IsNotEqual: 不等查询
field != ? - IsFuzzy: 模糊查询
field ILike ? - IsIn: IN 查询
field in (?) - IsNotIn: NOT IN 查询
field not in (?) - IsRange: 范围查询
field BETWEEN ? AND ? - IsGreaterThan: 大于查询
field > ? - IsLessThan: 小于查询
field < ? - IsGreaterOrEqualThan: 大于等于查询
field >= ? - IsLessOrEqualThan: 小于等于查询
field <= ? - IsPlain: 原生 SQL 条件
在 HTTP 请求中,可以通过以下语法使用查询条件:
# 等值查询
?name=Alice
# 模糊查询
?name=Alice:*
# 不等查询
?status=inactive:!
# IN 查询
?age=20,25,30:in
# NOT IN 查询
?age=20,25,30:!in
# 范围查询
?age=18,65:range # 默认闭区间 [A, B]
?age=18,65:range[] # 闭区间 [A, B]
?age=18,65:range() # 开区间 (A, B)
?age=18,65:range[) # 左闭右开 [A, B)
?age=18,65:range(] # 左开右闭 (A, B]
?created_at=2023-01-01,2023-12-31:range[) # 日期范围 [A, B)
# 比较操作符
?age=18:> # age > 18
?age=65:< # age < 65
?score=60:>= # score >= 60
?price=100:<= # price <= 100
示例:
// 在 HTTP Handler 中
params := gormx.NewParams(ctx)
where := params.Where()
// URL: /users?age=18,65:range&status=active
// 会自动转换为:
// WHERE age BETWEEN 18 AND 65 AND status = 'active'
// URL: /users?age=18,65:range()&status=active
// 会自动转换为:
// WHERE (age > 18 AND age < 65) AND status = 'active'
// URL: /orders?created_at=2023-01-01,2023-12-31:range[)
// 会自动转换为:
// WHERE (created_at >= '2023-01-01' AND created_at < '2023-12-31')
// URL: /users?age=18:>&score=60:>=&status=active
// 会自动转换为:
// WHERE age > 18 AND score >= 60 AND status = 'active'
// URL: /products?price=100:<=&quantity=10:>
// 会自动转换为:
// WHERE price <= 100 AND quantity > 10参见 examples/where_generic/main.go
参见 examples/where_range/main.go
参见 examples/where_range_modes/main.go
参见 examples/where_comparison/main.go