Skip to content

Latest commit

 

History

History
192 lines (140 loc) · 6.23 KB

File metadata and controls

192 lines (140 loc) · 6.23 KB

Sonar Stats Code Lines Coverage Status

GoooQo

项目介绍

GoooQo是一个采用Go语言实现的基于OQM技术的的数据库访问框架,完全依赖对象构建各种数据库查询语句, 消除各种使用传统ORM框架带来的样板代码,帮助开发人员实现自动化的数据库访问操作。

GoooQo中用于动态构建查询子句的对象被称为查询对象 (Query Object),即GoooQo中Qo。 而GoooQo名称中的前三个O代表了OQM技术中的三大对象概念:

  • Entity Object用于映射增删查改语句中的静态部分,例如表名和列名;
  • Query Object用于映射增删查改语句中的动态部分,例如过滤条件、分页和排序;
  • View Object用于映射复杂查询语句中的静态部分,例如表名、列名、分组子句、嵌套视图和各类连接。

查看这篇文章,了解更多详情。

参考demo,快速上手。

产品文档: https://goooqo.docs.doyto.win/v/zh

快速开始

初始化项目

使用go mod init初始化项目并添加GoooQo依赖:

go get -u github.com/doytowin/goooqo/rdb

初始化数据库连接和事务管理器:

package main

import (
	"database/sql"
	"github.com/doytowin/goooqo/rdb"
	_ "github.com/mattn/go-sqlite3"
)

func main() {
	db, _ := sql.Open("sqlite3", "./test.db")
	tm := rdb.NewTransactionManager(db)

	//...
}

创建数据访问接口

假设我们在test.db中有以下用户表:

id name score memo deleted
1 Alley 80 Good false
2 Dave 75 Well false
3 Bob 60 false
4 Tim 92 Great true
5 Emy 100 Great false

我们为该表定义一个实体对象和一个查询对象,以及一个用于执行数据库访问操作的UserDataAccess接口:

package main

import . "github.com/doytowin/goooqo/core"

type UserEntity struct {
	Int64Id
	Name    *string `json:"name"`
	Score   *int    `json:"score"`
	Memo    *string `json:"memo"`
	Deleted *bool   `json:"deleted"`
}

type UserQuery struct {
	PageQuery
	IdGt     *int64
	IdIn     *[]int64
	ScoreLt  *int
	MemoNull *bool
	MemoLike *string
	Deleted  *bool
	UserOr   *[]UserQuery

	ScoreLtAvg *UserQuery `subquery:"select avg(score) from t_user"`
	ScoreLtAny *UserQuery `subquery:"SELECT score FROM t_user"`
	ScoreLtAll *UserQuery `subquery:"SELECT score FROM t_user"`
	ScoreGtAvg *UserQuery `select:"avg(score)" from:"t_user"`

	Role *RoleQuery `entitypath:"user,role"`
	Perm *PermQuery `entitypath:"user,role,perm"`
}

var UserDataAccess TxDataAccess[UserEntity]

在建立数据库连接并创建事务管理器tm后,初始化UserDataAccess接口:

UserDataAccess := rdb.NewTxDataAccess[UserEntity](tm)

代码生成

GoooQo提供的代码生成工具gooogen支持为查询对象自动生成动态查询语句的构建方法。

安装 gooogen

通过以下命令安装代码生成工具gooogen

go install github.com/doytowin/goooqo/gooogen@latest

添加生成指令

在查询对象的定义上添加注释go:generate gooogen。例如:

//go:generate gooogen -type sql -o user_query_builder.go
type UserQuery struct {
//...
}
  • -type:(可选)指定生成的查询语句类型,如 sql
  • -f:(可选)定义包含查询对象的文件的名称,如 user.go
  • -o:(可选)定义生成文件的名称,如 user_query_builder.go

生成代码

执行go generate命令即可在指定的文件中生成相应的查询语句构建方法。

查询示例

userQuery := UserQuery{ScoreLt: P(80)}
users, err := UserDataAccess.Query(ctx, userQuery)
// SQL="SELECT id, name, score, memo, deleted FROM t_user WHERE score < ?" args="[80]"

userQuery := UserQuery{PageQuery: PageQuery{Size: 20, Sort: "id,desc;score"}, MemoLike: P("Great")}
users, err := UserDataAccess.Query(ctx, userQuery)
// SQL="SELECT id, name, score, memo, deleted FROM t_user WHERE memo LIKE ? ORDER BY id DESC, score LIMIT 20 OFFSET 0" args="[Great]"

userQuery := UserQuery{IdIn: &[]int64{1, 4, 12}, Deleted: P(true)}
users, err := UserDataAccess.Query(ctx, userQuery)
// SQL="SELECT id, name, score, memo, deleted FROM t_user WHERE id IN (?, ?, ?) AND deleted = ?" args="[1 4 12 true]"

userQuery := UserQuery{UserOr: &[]UserQuery{{IdGt: P(int64(10)), MemoNull: P(true)}, {ScoreLt: P(80), MemoLike: P("Good")}}}
users, err := UserDataAccess.Query(ctx, userQuery)
// SQL="SELECT id, name, score, memo, deleted FROM t_user WHERE (id > ? AND memo IS NULL OR score < ? AND memo LIKE ?)" args="[10 80 Good]"

userQuery := UserQuery{ScoreGtAvg: &UserQuery{Deleted: P(true)}, ScoreLtAny: &UserQuery{}}
users, err := UserDataAccess.Query(ctx, userQuery)
// SQL="SELECT id, name, score, memo, deleted FROM t_user WHERE score > (SELECT avg(score) FROM t_user WHERE deleted = ?) AND score < ANY(SELECT score FROM t_user)" args="[true]"

更多接口调用示例请参考:https://goooqo.docs.doyto.win/v/zh/api/crud

事务示例

使用TransactionManager#StartTransaction开启事务,手动提交或者回滚事务:

tc, err := UserDataAccess.StartTransaction(ctx)
userQuery := UserQuery{ScoreLt: P(80)}
cnt, err := UserDataAccess.DeleteByQuery(tc, userQuery)
if err != nil {
	err = tc.Rollback()
	return 0
}
err = tc.Commit()
return cnt

或者使用TransactionManager#SubmitTransaction通过回调的方式提交事务:

err := tm.SubmitTransaction(ctx, func(tc TransactionContext) (err error) {
	// transaction body
	return
})

许可证

本项目遵循BSD 3-Clause Clear License