前言

在看sonic的源码时,发现了一个有趣的东西,就是GORM生成数据库源码(真是我等CURD Boy的福音),想了解一下这个东西是怎么实现的,于是萌生了写这篇文章的想法

需要放入model和generate

核心设计

分层设计

gorm采用三层架构,元数据层,逻辑层,渲染层(Metadata Layer,Transformations Layer,Templates Layer)

关键数据结构

QueryStructMeta

1
2
3
4
5
6
type QueryStructMeta struct {
    TableName      string
    ModelStructName string  
    Fields         []Field
    Source         string // 来源:数据库表或已有结构体
}

genInfo

1
2
3
4
type genInfo struct {
    *QueryStructMeta
    Interfaces []InterfaceMethod // 生成的接口方法集合
}

核心工作原理

  1. 通过数据库表名获取表结构,解析出字段名,字段类型,字段注释等信息
1
2
3
4
func GetQueryStructMeta(db *gorm.DB, conf *model.Config) (*QueryStructMeta, error) {
	if _, ok := db.Config.Dialector.(tests.DummyDialector); ok {
		return nil, fmt.Errorf("UseDB() is necessary to generate model struct [%s] from database table [%s]", conf.ModelName, conf.TableName)
	}
  1. 类型映射

数据库类型 -> Go类型映射表

自定义类型覆盖机制

  1. 结构体生成

应用命名策略(驼峰式转换)

智能处理字段标签

A[数据库元数据] –>|原始表名/列名| B(命名策略处理器) B –> C{应用转换规则} C –>|模型名| D[UserOrder] C –>|字段名| E[CreatedAt] C –>|查询结构体| F[UserQuery] D –> G[生成Go结构体] E –> G F –> H[生成CRUD方法]

总结

实际上,要实现驼峰转换,gorm是通过model.Config中的NamingStrategy来实现的,gorm提供了SnakeCaseGonic两种命名策略,分别对应了SnakeCaseGonic两种命名规则

在代码中需要定义才能使用,而且还要在数据库中定义好结构才能用,我还以为能直接用,这么看来也没特别高明的地方

而且还需要在某些地方重新自定义下规则