自动生成sql语句的插件_go ast的应用: 自动生成xorm的建表语句

ff2fe1836a195982c59d60bb44ac7edb.png

缘起

最近在工作学习的过程中,接触到一些通过自动生成代码的方式来减少重复的工作量,以及自动生成文档或桩代码的方式,包括:

  • 使用Kubernetes CRD,可以通过code-generator工具自动生成客户端代码以及一些其他工具函数
  • 使用goa,可以通过定义的DSL自动生成服务端的框架代码,以及文档等

一般有以下几种方式来自动生成代码:

  • 通过 goast 获取代码的抽象语法树,然后通过抽象语法树来生成对应的代码
  • 通过自定义DSL的方式获取代码信息,然后生成代码
  • 通过反射获取信息来生成代码

正好最近在学习使用golang的ast解析工具,遂通过实现一个简单的工具来加深理解。该工具将自动读取xorm的类型信息,并自动生成对应的建表sql语句。

目标

首先明确该工具的适用目标及范围:

  • 只支持xorm框架
  • 只支持少量的xorm框架特性: 包括created, updated, pk, unique, notnull
  • 只支持少量的sql类型: 包括BIGINT, INT, VARCHAR, DATETIME
  • 支持设定表名: 通过 +genTable spec
  • 只支持mysql

测试数据如下:

package main

import "time"

// User is orm for user
// +genTable: user
type User struct {
    
    Id      int64
    Name    string `xorm:"unique notnull"`
    Salt    string
    Age     int
    Passwd  string    `xorm:"varchar(200)"`
    Created time.Time `xorm:"created"`
    Update  time.Time `xorm:"updated"`
}

/*
+genTable:
*/
// User2 and User3
type (
    // User2
    // +genTable: user2
    User2 struct {
     // user2 line
        Uid int `xorm:"pk 'uid'"`
    }

    // comment group

    // User3
    // +genTable:
    User3 struct {
     // user3 line
    }
)

type I1 interface {
    
}

最终输出的建表语句如下:

CREATE TABLE `user` (
    `Id` BIGINT,
    `Name` VARCHAR(255) NOT NULL,
    `Salt` VARCHAR(255),
    `Age` INT,
    `Passwd` varchar(200),
    `Created` DATETIME DEFAULT CURRENT_TIMESTAMP,
    `Update` DATETIME ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY(`Id`),
    UNIQUE KEY `Name` (`Name`)
);
CREATE TABLE `user2` (
    `uid` INT,
    PRIMARY KEY(`uid`)
);

实现

1. 生成 ast

ast 即抽象语法树, go/parser 包提供了工具来解析生成ast:

fs := token.NewFileSet()
f, err := parser.ParseFile(fs, file, src, parser.ParseComments)

其中:

  • 通过token.NewFileSet来生成一个FileSet对象,这个对象会保存更详细的源码位置信息
  • file是文件名, 当src为nil时会读取该文件的内容;当src是字节数组/字符串时会直接将src的内容作为文件内容解析
  • 需要通过ParseComments参数告知parser解析注释,因为我们的 +genTable 是通过注释实现的

2. 获取所有的table struct

在得到 ast 之后,我们需要筛选出对应的表的struct,首先定义一个结构体保存具体的信息:

type tableStruct struct {
    
        node      *ast.StructType
        tableName string
}

其中表名可能来自以下内容:

  • 在多个类型上的 +genTable spec,这时不能跟表名,表示使用类型名作为表名,当有多个类型都直接使用类型名作为表名时可使用
  • 在单个类型上的 +genTable spec,这时可以指定表
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值