Skip to content

tmoeish/tsq

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

27 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

TSQ - 类型安全的 Go SQL 查询代码生成工具

 _____  __    ____
/__   \/ _\  /___ \
  / /\/\ \  //  / /
 / /   _\ \/ \_/ /
 \/    \__/\___,_\

GitHub release (latest by date) Build Status Go Report Card License: MIT

TSQ(Type-Safe Query)是一个强大的 Go 语言代码生成工具,专为构建类型安全的 SQL 查询而设计。通过解析 Go 结构体和注解,TSQ 能够自动生成高效、类型安全的数据库访问代码,大幅提升开发效率和代码质量。

✨ 核心特性

  • 🔒 类型安全:编译时检查字段类型和 SQL 语法,避免运行时错误
  • 🚀 代码生成:自动生成 CRUD 操作、复杂查询和分页功能
  • 📝 注解驱动:通过简单注解定义表结构、索引、唯一约束等
  • 🔍 灵活查询:支持联表查询、子查询、聚合函数等复杂 SQL 操作
  • 📄 分页支持:内置高效的分页查询机制
  • 🗃️ 多数据库:支持 SQLite、MySQL、PostgreSQL 等主流数据库
  • 🛠️ DTO 支持:支持复杂查询结果的数据传输对象
  • ⚡ 高性能:生成的代码经过优化,性能接近手写 SQL
  • 🔍 关键词搜索:内置关键词搜索功能,支持多字段模糊查询
  • 📊 聚合查询:支持 COUNT、SUM、AVG、MIN、MAX 等聚合函数

📦 安装

从源码构建

git clone https://github.com/tmoeish/tsq.git
cd tsq
make build

使用 go install

go install github.com/tmoeish/tsq/cmd/tsq@latest

🚀 快速开始

1. 定义数据结构(最新 DSL 注解示例)

// @TABLE(
//   name="User",
//   ux=[{name="UxName", fields=["Name"]}],
//   kw=["Name","Email"]
// )
type User struct {
    common.ImmutableTable
    OrgID int64  `db:"org_id" json:"org_id"`
    Name  string `db:"name" json:"name"`
    Email string `db:"email" json:"email"`
}

// @TABLE(
//   name="Order",
//   idx=[{name="IdxUserItem", fields=["UserID","ItemID"]}, {name="IdxItem", fields=["ItemID"]}],
//   ct
// )
type Order struct {
    common.MutableTable
    UserID int64 `db:"user_id"`
    ItemID int64 `db:"item_id"`
    Amount int64 `db:"amount"`
    Price  int64 `db:"price"`
    Status OrderStatus `db:"status"`
}

// @TABLE(
//   ux=[{fields=["Name"]}],
//   idx=[{name="IdxCategory", fields=["CategoryID"]}],
//   kw=["Name"]
// )
type Item struct {
    common.ImmutableTable
    CategoryID int64 `db:"category_id"`
    Name       string `db:"name,size:200"`
    Price      int64  `db:"price"`
}

// @TABLE(
//   ux=[{fields=["Name"]}],
//   kw=["Name","Description"]
// )
type Category struct {
    common.ImmutableTable
    CategoryContent
}
type CategoryContent struct {
    Type        CategoryType `db:"type" json:"type"`
    Name        string       `db:"name,size:200" json:"name"`
    Description string       `db:"description,size:4096" json:"description"`
}

// @TABLE(
//   name="Org",
//   ux=[{name="UxName", fields=["Name"]}]
// )
type Org struct {
    common.ImmutableTable
    Name string `db:"name"`
}

2. 生成 TSQ 代码

tsq gen ./examples/database

3. 使用生成的代码(主流程示例)

package main

import (
    "context"
    "database/sql"
    "encoding/json"
    "fmt"
    "os"
    "github.com/juju/errors"
    _ "github.com/mattn/go-sqlite3"
    logrus "log/slog"
    "github.com/tmoeish/tsq"
    "github.com/tmoeish/tsq/examples/database"
    "gopkg.in/gorp.v2"
)

func main() {
    logrus.SetLevel(logrus.TraceLevel)

    // 1. 连接 SQLite 内存数据库
    db, err := sql.Open("sqlite3", ":memory:")
    if err != nil {
        logrus.Fatal(errors.ErrorStack(err))
    }
    defer func() { _ = db.Close() }()

    // 2. 初始化 gorp
    dbmap := &gorp.DbMap{Db: db, Dialect: gorp.SqliteDialect{}}
    err = tsq.Init(dbmap, true, TraceDB)
    if err != nil {
        logrus.Fatal(errors.ErrorStack(err))
    }

    // 初始化数据库,执行 mock.sql 文件
    mockSQL, err := os.ReadFile("examples/database/mock.sql")
    if err != nil {
        logrus.Fatal(errors.ErrorStack(err))
    }
    _, err = db.Exec(string(mockSQL))
    if err != nil {
        logrus.Fatal(errors.ErrorStack(err))
    }

    // 3. 构造分页参数
    pageReq := &tsq.PageReq{
        Page:    1,
        Size:    10,
        Order:   "asc,desc",
        OrderBy: "user_id,order_id",
    }

    // 4. 调用 PageUserOrder,假设 user_id = 1
    ctx := context.Background()
    resp, err := database.PageUserOrder(ctx, dbmap, pageReq, 1, "图书", "视频", "杂志")
    if err != nil {
        logrus.Fatal(errors.ErrorStack(err))
    }

    // 5. 打印结果
    rs, _ := json.MarshalIndent(resp, "", "  ")
    fmt.Println(string(rs))
}

func TraceDB(next tsq.Fn) tsq.Fn {
    return func(ctx context.Context) error {
        err := next(ctx)
        return err
    }
}

4. DTO 复杂查询示例

// @DTO(
//   name="UserOrder"
// )
type UserOrder struct {
    UserID    int64  `json:"user_id"    tsq:"User.ID"`
    UserName  string `json:"user_name"  tsq:"User.Name"`
    UserEmail string `json:"user_email" tsq:"User.Email"`
    OrgName   string `json:"org_name"   tsq:"Org.Name"`
    OrderID     int         `json:"order_id"     tsq:"Order.ID"`
    OrderAmount float64     `json:"order_amount" tsq:"Order.Amount"`
    OrderPrice  float64     `json:"order_price"  tsq:"Order.Price"`
    OrderStatus OrderStatus `json:"order_status" tsq:"Order.Status"`
    OrderTime   string      `json:"order_time"   tsq:"Order.CT"`
    ItemID    int64  `json:"item_id"    tsq:"Item.ID"`
    ItemName  string `json:"item_name"  tsq:"Item.Name"`
    ItemPrice int64  `json:"item_price" tsq:"Item.Price"`
    ItemCategory string `json:"item_category" tsq:"Category.Name"`
}

// 复杂分页查询
resp, err := database.PageUserOrder(ctx, dbmap, pageReq, 1, "图书", "视频", "杂志")

5. 查询与分页用法

// 条件查询
query := tsq.
    Select(database.TableUser.Cols()...).
    Where(database.User_Name.Like("%admin%")).
    OrderBy(database.User_ID.Desc()).
    MustBuild()
users, err := database.ListUserByQuery(ctx, dbmap, query)

// 分页查询
pageReq := &tsq.PageReq{
    Page:    1,
    Size:    10,
    Order:   "asc,desc",
    OrderBy: "user_id,order_id",
}
resp, err := database.PageUserOrder(ctx, dbmap, pageReq, 1, "图书", "视频", "杂志")

6. 批量操作

users := []*database.User{
    {OrgID: 1, Name: "张三", Email: "[email protected]"},
    {OrgID: 1, Name: "李四", Email: "[email protected]"},
}
err := tsq.BatchInsert(ctx, dbmap, users)

7. mock 数据初始化

mockSQL, err := os.ReadFile("examples/database/mock.sql")
if err != nil {
    logrus.Fatal(errors.ErrorStack(err))
}
_, err = db.Exec(string(mockSQL))
if err != nil {
    logrus.Fatal(errors.ErrorStack(err))
}

其它如聚合、子查询、关键词搜索等高级用法,请参考 examples/main.goexamples/database/userorder.go 的最新写法。

🏗️ 构建和开发

开发环境要求

  • Go 1.24.2+
  • Make
  • Git

构建项目

# 克隆项目
git clone https://github.com/tmoeish/tsq.git
cd tsq

# 安装依赖
make mod-tidy

# 运行测试
make test

# 构建项目
make build

# 运行所有检查和构建
make all

Make 命令

make help          # 显示所有可用命令
make build         # 构建应用
make test          # 运行测试
make test-coverage # 运行覆盖率测试
make fmt           # 格式化代码
make vet           # 代码检查
make lint          # 静态分析
make clean         # 清理构建产物
make install       # 安装到 GOPATH/bin
make update-sample # 更新示例代码

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •  

Languages