ORM的Find方法实现
最近复习了一下 Go 的反射,反射在很多 Go 语言的框架都有用到,有些场景下使用起来会十分的便利,最近看了一下就学着一些文档小搓了一个 ORM 的 Find
方法,主要需要做的事情就是将 ?
替换成需要写入的结构体内的元素,以及拼凑出对应的 sql
语句。
代码如下:
package main
import (
"errors"
"fmt"
"reflect"
"strconv"
"strings"
)
type Student struct {
Name string `rg-orm:"name"`
Age int `rg-orm:"age"`
}
type UserInfo struct {
Id int `rg-orm:"id"`
Name string `rg-orm:"name"`
Age int `rg-orm:"age"`
}
func Find(obj any, query ...any) (sql string, err error) {
// 鉴定入参类型,看是不是表映射的结构体
objType := reflect.TypeOf(obj)
if objType.Kind() != reflect.Struct {
err = errors.New("非结构体,入参类型错误")
return "", err
}
var where string
// 判断是否有查询条件元素
if len(query) > 0 {
// 有的话则先切割出where语句
q := query[0]
// 鉴定where语句中有多少个需要映射进去的参数
if strings.Count(q.(string), "?")+1 > len(query) {
if err != nil {
err = errors.New("参数不足")
return "", err
}
}
fmt.Println(q.(string), 0)
// 检测映射的入参元素类型,将其转换成对应类型,方便后续sql语句拼接
for _, value := range query[1:] {
valueType := reflect.TypeOf(value)
switch valueType.Kind() {
case reflect.String:
q = strings.Replace(q.(string), "?", value.(string), 1)
fmt.Println(q, 1)
case reflect.Int:
q = strings.Replace(q.(string), "?", strconv.Itoa(value.(int)), 1)
fmt.Println(q, 2)
}
}
where = "where " + q.(string)
fmt.Println(where, 3)
}
// 获取表内所有Tag标记出来的字段
var columns []string
for i := 0; i < objType.NumField(); i++ {
// 获取表映射结构体的字段
field := objType.Field(i)
fmt.Println(field, 4)
// 获取标签的值,也就是对应sql表所需要查询的字段,一般orm都是通过tag来映射结构体中一个元素对应表的字段名
f := field.Tag.Get("rg-orm")
fmt.Println(f, 5)
columns = append(columns, f)
}
// 获取表名,一般表名为对应结构体的小写+复数的形式,反正gorm是这样的
sqlTable := strings.ToLower(objType.Name()) + "s"
// 拼接sql语句
sql = fmt.Sprintf("SELECT %s FROM %s %s", strings.Join(columns, ","), sqlTable, where)
return sql, err
}
func main() {
sql, err := Find(Student{}, "name = ? and age = ?", "rolingg", 23)
fmt.Println(sql, err, 6) // select name,age from students where name = 'rolingg' and age = 23
sql, err = Find(UserInfo{}, "id = ?", 1)
fmt.Println(sql, err, 7) // select id,name,age from userinfos where id = 1
}
输出为:
name = ? and age = ? 0
name = rolingg and age = ? 1
name = rolingg and age = 23 2
where name = rolingg and age = 23 3
{Name string rg-orm:"name" 0 [0] false} 4
name 5
{Age int rg-orm:"age" 16 [1] false} 4
age 5
SELECT name,age FROM students where name = rolingg and age = 23 <nil> 6
id = ? 0
id = 1 2
where id = 1 3
{Id int rg-orm:"id" 0 [0] false} 4
id 5
{Name string rg-orm:"name" 8 [1] false} 4
name 5
{Age int rg-orm:"age" 24 [2] false} 4
age 5
SELECT id,name,age FROM userinfos where id = 1 <nil> 7
关于表名那里,有时候用的是驼峰或者用 _
进行分割的写法,不同项目写法都有可能不同,改变一下就可以了。
突然想要实现以下这种写法也是因为,Gorm 框架有时候可能会不使用一些数据库的语法,不同数据库的一些语法会有差别,像之前我在实习的时候,Gorm 就不适配海量数据库,需要开发人员去进行驱动的魔改和修正语句使用,还有一些适配的语句可能适用于mysql
、pgsql
,但换到一些小众数据库为了作区分而改变了部分语法的,就会出一定的问题,可能就需要魔改一些 ORM 语句的逻辑判断和写法。
以上,就这样,随便写写。
评论(0)