安然写字的地方

Gorm gen支持自定义查询语句

背景

在使用GORM Gen 作为ORM来写业务逻辑时,会有一些不那么如意的地方。

MySQL在5.7版本后就支持了json类型的存储,这为某个字段提供了一种结构化的能力。在部分后台场景会有针对json数据查询的场景,调研了下,可以使用json内置了部分函数JSON_EXTRACT, JSON_OVERLAPS, JSON_CONTAINS来支持。

Gorm针对这类场景有一个datatypes项目,来支持这种结构化的查询条件。但接口设计和定义上还是比较鸡肋的,对json支持的也不够完整。

一旦涉及到稍复杂的SQL还继续使用Gen就比较吃力了,但本人还不想放弃,于是就去翻了底层源码。还是找到了一个增强的方法

详细设计

在Gorm接口设计上,可以看到Where()条件接收的是一个Condition接口

type (
    // Condition query condition
    // field.Expr and subquery are expect value
    Condition interface {
        BeCond() interface{}
        CondError() error
    }
)

就很自然的想到了使用自定义Condition实现,代码也非常精简,如下:

package cdatatypes

import (
    "gorm.io/gen/field"
    "gorm.io/gorm/clause"
)

type ExprCond struct {
    clause.Expr
    field.String
}

func Cond(expr clause.Expr) *ExprCond {
    return &ExprCond{
        Expr:   expr,
        String: field.String{},
    }
}

func (c *ExprCond) BeCond() interface{} { return c.Expr }

func (c *ExprCond) CondError() error { return nil }

在实际使用时,就可以通过以下的方式生成Where需要的条件。

cdatatypes.Cond(gorm.Expr("JSON_OVERLAPS(JSON_EXTRACT(`query`, '$.query_list'), ?)", querys))

// JSON_OVERLAPS(JSON_EXTRACT(`query`, '$.query_list'), '["自定义查询"]')

这样既不会打破gorm gen提供的语义化模型,还很灵活的支持了各种自定义SQL。这样又可以开心的Coding了。