GoooQo:基于QQM的Golang CRUD框架


GoooQo 是一个基于 OQM 技术的 Golang CRUD 框架。

OQM(Object-Query Mapping)技术是一种通过对象构造数据库查询语句的数据库访问技术。

OQM提出了一种新方法来解决n个查询条件的动态组合问题,通过将具有n个字段的对象实例的2^n个赋值组合映射到n个查询条件的2^n个组合。

这种方式使得开发人员只需要定义和构造对象来构建动态查询语句,从而将 OQM 与 ORM 区分开来。这样的对象称为查询对象,也就是 GoooQo 中的 Qo。

GoooQo 名称中的前三个 O 代表 OQM 技术中的三个主要对象概念:

  • Entity Object用于映射CRUD语句中的静态部分,如表​​名、列名等;
  • Query Object用于映射CRUD语句中的动态部分,例如过滤条件,分页和排序子句;
  • View Object用于映射复杂查询语句中的静态部分,如表​​名、列名、group-by子句和连接。


查看此文章了解更多详细信息。
查看此演示以进行快速浏览。
产品文档:https://goooqo.docs.doyto.win/

快速入门
1、初始化项目
用于go mod init初始化项目并添加GoooQo依赖:

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

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

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)
    
//...
}

3、创建数据访问接口
假设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

我们为该表定义了一个实体对象和一个查询对象:

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

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

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

    ScoreLtAvg *UserQuery <code>subquery:
"select avg(score) from t_user"</code>
    ScoreLtAny *UserQuery <code>subquery:
"SELECT score FROM t_user"</code>
    ScoreLtAll *UserQuery <code>subquery:
"select score from UserEntity"</code>
    ScoreGtAvg *UserQuery <code>select:
"avg(score)" from:"UserEntity"</code>
}

然后,我们创建一个 userDataAccess 接口来执行 CRUD 操作:

userDataAccess := rdb.NewTxDataAccessUserEntity

查询示例:

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{PageSize: P(20), Sort: P(
"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]"

更多CRUD示例请参考:https: //goooqo.docs.doyto.win/v/zh/api/crud


事务案例
TransactionManager#StartTransaction用于启动事务,然后手动提交或回滚事务:

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

或者TransactionManager#SubmitTransaction通过回调函数提交事务:

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