Heidou
数据库优先的代码生成工具,CRUD终结者
- 易用跨平台
- 灵活可扩展
- 丰富的模板 无限提升生产力
Heidou 是一个数据库优先的代码生成工具,用于高效生成各种业务代码,主要使用场景是生成工程框架和CRUD类代码,大大缩短业务从设计到上线的时间。在框架层面保证高度的灵活和可扩展性,不限制业务场景。
背景
开发一个生产级的产品,往往需要多端开发,比如要前端、要后端、要APP、要管理系统,通讯协议可能有 Restful 、Rpc、Graphql。甚至于微服务架构下即使一个简单的 Todo Mvc 应用,必不可少系统也会多达十几种。这些系统中很大一部分是高度可模板化的俗称的 CRUD 类代码。每个系统拥有相同的模型定义、协议解析,系统内还有不少的数据模型需要互相转化。这些模板化代码往往令人厌烦却又真实存在、必有可少。如果需要开发的不止一个 TodoMvc应用,相同的过程又要重新来一遍,让人心力憔悴。
如果能有一款工具能根据数据字典即可自动化这个过程,模板代码自动生成, 却又具有高度的灵活性、可扩展性。不限制框架、开发语言、使用方式,程序员可将更多的时间用于业务逻辑开发,这个世界该是多么美好啊。
特性
- 解析数据库表结构,生成丰富的表述信息
- 支持自定义模板,结合不同模板快速生成不同业务场景的项目
- 支持 BelongTo 、HasOne 、HasMany 、ManyToMany 关联配置
- 支持配置校验信息
- 支持业务的灵活扩展
- 表结构更改可重复生成代码
- 使用简单,通过资源内嵌,实现一个二进制文件即可跨平台启动
体验
体验一下如何用几分钟的时间构建一个基于 Golang
的 Todo
后端服务,提供标准的 Graphql API
以供前端应用调用,支持查询过滤、排序、分页、指定返回字段、批量查询、批量更新、批量删除、自动生成 Graphql 文档。
前提条件
数据字典
设计应用的数据字典 todo.sql
如下:
-- Create a database
CREATE DATABASE `todo` DEFAULT CHARACTER SET = `utf8mb4`;
USE `todo`;
DROP TABLE IF EXISTS `todos`;
CREATE TABLE `todos` (
`id` char(36) NOT NULL,
`title` varchar(32) NOT NULL DEFAULT '' COMMENT '标题',
`completed` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否完成',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT = 'Todo';
导入 Mysql
mysql -h <host> -u <user> < mysql.sql
创建项目
运行下列命令创建一个新的项目:
heidou init todo
cd todo
mv heidou-example.yml heidou.yml
此命令将在当前目录生成名为 todo
的项目,并生成配置文件模板。
修改 heidou.yml
内容如下:
# 项目名称
projectName: "todo"
# 是否自动覆盖已有文件
overwrite: false
# 数据库类型
loader: "mysql"
# Extra 为用户自定义变量,以 map 结构读取,golang 中 map的key 不区分大小写,所以引用时全部以小写形式引用,例如 : .Extra.pkgpath
extra:
pkgPath: "github.com/ychengcloud/todo"
# Golang 的默认变量标识符与模板中的变量标识符相同时,需要修改成不同的
#delim:
# left: "@@"
# right: "@@"
# 数据库配置
db:
dialect: "mysql"
user: "<user>"
password: "<password>"
host: "127.0.0.1"
port: 3306
name: "todo"
charset: "utf8mb4"
# NameFormat 目标路径
# Path 模板路径名,以 templates为相对路径
templates:
- nameFormat: "internal/generated/models/%s.go"
path: "models/model.go.tmpl"
- nameFormat: "internal/resolvers/%s.go"
path: "resolvers/resolver.go.tmpl"
- nameFormat: "internal/generated/schemas/%s.gql"
path: "schemas/schema.gql.tmpl"
- nameFormat: "internal/generated/services/%s.go"
path: "services/service.go.tmpl"
# 数据表配置
tables:
- name: "todos"
fields:
- name: "id"
isRequired: true
isFilterable: true
operations: ["Eq", "In"]
- name: "title"
isRequired: true
isFilterable: true
operations: ["Eq", "In"]
生成代码
- 下载
graphql-server
模板
mkdir -p $HOME/.heidou/graphql-server-template
git clone https://github.com/ychengcloud/graphql-server-template $HOME/.heidou/graphql-server-template
- 基于模板和配置文件生成代码
heidou generate -t $HOME/.heidou/graphql-server-template/ -c ./heidou.yml
构建
# 执行 gqlgen
make gql_gen
# go modules
go mod tidy
# 依赖注入
make wire
# 构建
make build
运行前配置
mv configs/server-example.yml server.yml
修改配置模板内容如下:
app:
name: "todo"
http:
mode: "debug"
# mode: release
host: 0.0.0.0
port: 7779
graphqlPath: "graphql"
playgroundPath: "playground"
isPlaygroundEnabled: true
allowOrigins:
- "*"
allowMethods:
- "PUT"
- "GET"
- "POST"
- "HEAD"
- "PATCH"
- "OPTIONS"
- "DELETE"
allowHeaders:
- "*"
db:
dialect: "mysql"
debug: true
autoMigrate: false
mysql:
user: "<user>"
password: "<password>"
host: "127.0.0.1"
port: 3306
name: "todo"
charset: "utf8mb4"
auth:
skip: true
log:
filename: "/tmp/todo.log"
maxSize: 500
maxBackups: 3
maxAge: 3
level: "debug"
stdout: false
jaeger:
serviceName: "admin"
reporter:
localAgentHostPort: "jaeger-agent:6831"
sampler:
type: "const"
param: 1
jwt:
signingKey: "YOUCHENG"
issuer: "ycheng.pro"
claimKey: "claim"
signingMethod: "HS512"
# seconds
expired: 1000000
运行
make run
体验
浏览器打开 Graphql Playground
创建 Todo
# Create
mutation ($input: TodoInput!) {
todoCreate (input: $input) {
todo {
id
title
completed
}
}
}
# Variables
{
"input": {
"title": "My Todo 1",
"completed": 0
}
}
查询 Todo
# Query
query {
todosOffsetBased {
edges {
node {
id
title
completed
}
}
totalCount
pageInfo {
hasNextPage
hasPreviousPage
}
}
}
更新 Todo
# Update
mutation($ids: [ID]!, $input: TodoInput!) {
todoUpdate(ids: $ids, input: $input) {
count
}
}
# Variables
{
"ids": ["595cc895-ca31-4c6f-9897-d376b1ec8bb2"],
"input": {
"title": "My Todo 1",
"completed": 1
}
}
删除 Todo
# Delete
mutation {
todoDelete(ids: ["595cc895-ca31-4c6f-9897-d376b1ec8bb2"]) {
count
}
}