GoBatis

Introduction

An easy ORM tool for Golang, support MyBatis-Like XML template SQL

待完成的任务

  1. 重构 parser
  2. 对象继承的实现
  3. 延迟加载的实现

已知 bug

< < < < 

和 MyBatis 的区别

GoBatis 就是对 MyBatis 的简单模仿。 但有下列不同

  1. 动态 sql 语句的格式

    我实现一个和 mybatis 类似的 if, chose, foreach, trim, set 和 where 之类的 xml 基本实现,同时也支持 go template 来生成 sql。

  2. 自动生成 sql 语句

    MyBatis 是不会自动生成 sql 语句的, 我觉得能像大部份的 orm 一样能生成 sql 的话,可以省很多工作 请见 SQL 自动生成

基本思路

  1. 用户定义结构和接口
  2. 在接口的方法上定义 sql (可以在 xml 中或方法的注释中)
  3. 用工具生成接口的实现
  4. 创建接口的实例并使用它

Roadmap

  1. 升级 go1.14 后 goparser 特别慢,准备用 goparser2 替换
  2. 将 xml 相关代码移到 xml 子目录
  3. 将 sql 生成工具 builder 相关代码移到 sql 子目录

Usage

注意, gobatis 也支持 xml, 请见 example_xml 目录

gobatisgo get -u -v github.com/runner-mei/GoBatis/cmd/gobatis//go:generate gobatis user.go
//go:generate gobatis user.go
package example

import (
  "time"
)

type AuthUser struct {
  ID        int64      `json:"id"`
  Username  string     `json:"username"`
  Phone     string     `json:"phone"`
  Address   *string    `json:"address"`
  Status    uint8      `json:"status"`
  BirthDay  *time.Time `json:"birth_day"`
  CreatedAt time.Time  `json:"created_at"`
  UpdatedAt time.Time  `json:"updated_at"`
}

type UserDao interface {
  // @postgres insert into auth_users(username, phone, address, status, birth_day, created_at, updated_at)
  // values (#{username},#{phone},#{address},#{status},#{birth_day},CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) returning id
  //
  // @default insert into auth_users(username, phone, address, status, birth_day, created_at, updated_at)
  // values (#{username},#{phone},#{address},#{status},#{birth_day},CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
  Insert(u *AuthUser) (int64, error)
}
go generate ./...
// Please don't edit this file!
package example

import (
  "errors"

  gobatis "github.com/runner-mei/GoBatis"
)

func init() {
  gobatis.Init(func(ctx *gobatis.InitContext) error {
    { //// UserDao.Insert
      if _, exists := ctx.Statements["UserDao.Insert"]; !exists {
        sqlStr := "insert into auth_users(username, phone, address, status, birth_day, created_at, updated_at)\r\n values (#{username},#{phone},#{address},#{status},#{birth_day},CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)"
        switch ctx.Dialect {
        case gobatis.ToDbType("mssql"):
          sqlStr = "insert into auth_users(username, phone, address, status, birth_day, created_at, updated_at)\r\n output inserted.id\r\n values (#{username},#{phone},#{address},#{status},#{birth_day},CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)"
        case gobatis.ToDbType("postgres"):
          sqlStr = "insert into auth_users(username, phone, address, status, birth_day, created_at, updated_at)\r\n values (#{username},#{phone},#{address},#{status},#{birth_day},CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) returning id"
        }
        stmt, err := gobatis.NewMapppedStatement(ctx, "UserDao.Insert",
          gobatis.StatementTypeInsert,
          gobatis.ResultStruct,
          sqlStr)
        if err != nil {
          return err
        }
        ctx.Statements["UserDao.Insert"] = stmt
      }
    }
  })
}

func NewUserDao(session gobatis.SqlSession) UserDao {
  return &UserDaoImpl{session: session}
}

type UserDaoImpl struct {
  session gobatis.SqlSession
}

func (impl *UserDaoImpl) Insert(u *AuthUser) (int64, error) {
  return impl.session.Insert("UserDao.Insert",
    []string{
      "u",
    },
    []interface{}{
      u,
    })
}

...
  1. use UserDao
  factory, err := gobatis.New(&gobatis.Config{DriverName: tests.TestDrv,
    DataSource: tests.TestConnURL,
    // XMLPaths: []string{"example/test.xml"},
    })
    
  userDao := NewUserDao(factory.SessionReference())
  id, err := userDao.Insert(&insertUser)
  if err != nil {
    fmt.Println(err)
    return
  }
  fmt.Println("insert success!")

  u, err := userDao.Get(id)
  if err != nil {
    fmt.Println(err)
    return
  }
  fmt.Println("fetch user from database!")

  _, err = userDao.Delete(id)
  if err != nil {
    fmt.Println(err)
    return
  }
  fmt.Println("delete success!")

注意

GoBatis 是基于 osm 的基础上修改来的,goparser 则是在 light 的基础上修改来的, reflectx 则从 sqlx 拷贝过来的