GoRose(go orm), a mini database ORM for golang, which inspired by the famous php framwork laravle's eloquent. It will be friendly for php developer and python or ruby developer. Currently provides six major database drivers: mysql,sqlite3,postgres,oracle,mssql, Clickhouse.

Overview

GoRose ORM

GoDoc Go Report Card GitHub release Gitter GitHub GitHub All Releases gorose-orm

  _______   ______   .______        ______        _______. _______ 
 /  _____| /  __  \  |   _  \      /  __  \      /       ||   ____|
|  |  __  |  |  |  | |  |_)  |    |  |  |  |    |   (----`|  |__   
|  | |_ | |  |  |  | |      /     |  |  |  |     \   \    |   __|  
|  |__| | |  `--'  | |  |\  \----.|  `--'  | .----)   |   |  |____ 
 \______|  \______/  | _| `._____| \______/  |_______/    |_______|

翻译(translation)

English readme | 中文 readme

文档

最新版2.x文档 | 1.x文档 | 0.x文档

简介

gorose是一个golang orm框架, 借鉴自laravel的eloquent. gorose 2.0 采用模块化架构, 通过interface的api通信,严格的上层依赖下层.每一个模块都可以拆卸, 甚至可以自定义为自己喜欢的样子.
模块关系图如下: gorose-2.0-design

安装

  • go.mod
require github.com/gohouse/gorose/v2 v2.1.10

重要的事情说三遍!
重要的事情说三遍!
重要的事情说三遍!
使用的时候必须import "github.com/gohouse/gorose/v2"方可正常使用.
千万不要漏掉末尾的v2,这个是vgo的规定

如果使用最新更新,没有tag的话,可以使用require github.com/gohouse/gorose/v2 master,执行go mod tidy后,会自动获取最新提交的版本hash最为版本号,最终效果如:github.com/gohouse/gorose/v2 v2.1.6-0.20200403045240-167d9094d7bd

  • docker
docker run -it --rm ababy/gorose sh -c "go run main.go"

docker 镜像: ababy/gorose, docker镜像包含了gorose所必须的包和运行环境, 查看Dockerfile

  • go get
go get -u github.com/gohouse/gorose/v2

支持驱动

api预览

db.Table().Fields().Where().GroupBy().Having().OrderBy().Limit().Select()
db.Table().Data().Insert()
db.Table().Data().Where().Update()
db.Table().Where().Delete()

简单用法示例

package main
import (
	"fmt"
	"github.com/gohouse/gorose/v2"
	_ "github.com/mattn/go-sqlite3"
)
var err error
var engin *gorose.Engin
func init() {
    // 全局初始化数据库,并复用
    // 这里的engin需要全局保存,可以用全局变量,也可以用单例
    // 配置&gorose.Config{}是单一数据库配置
    // 如果配置读写分离集群,则使用&gorose.ConfigCluster{}
	engin, err = gorose.Open(&gorose.Config{Driver: "sqlite3", Dsn: "./db.sqlite"})
    // mysql示例, 记得导入mysql驱动 github.com/go-sql-driver/mysql
	// engin, err = gorose.Open(&gorose.Config{Driver: "mysql", Dsn: "root:[email protected](localhost:3306)/test?charset=utf8mb4&parseTime=true"})
}
func DB() gorose.IOrm {
	return engin.NewOrm()
}
func main() {
    // 原生sql, 直接返回结果集
    res,err := DB().Query("select * from users where uid>? limit 2", 1)
    fmt.Println(res)
    affected_rows,err := DB().Execute("delete from users where uid=?", 1)
    fmt.Println(affected_rows, err)

    // orm链式操作,查询单条数据
    res, err = DB().Table("users").First()
    // res 类型为 map[string]interface{}
    fmt.Println(res)
    
    // orm链式操作,查询多条数据
    res2, _ := DB().Table("users").Get()
    // res2 类型为 []map[string]interface{}
    fmt.Println(res2)
}

使用建议

gorose提供数据对象绑定(map, struct), 同时支持字符串表名和map数据返回. 提供了很大的灵活性
建议优先采用数据绑定的方式来完成查询操作, 做到数据源类型可控
gorose提供了默认的 gorose.Mapgorose.Data 类型, 用来方便初始化绑定和data

配置和链接初始化

简单配置

var configSimple = &gorose.Config{
	Driver: "sqlite3", 
	Dsn: "./db.sqlite",
}

更多配置, 可以配置集群,甚至可以同时配置不同数据库在一个集群中, 数据库会随机选择集群的数据库来完成对应的读写操作, 其中master是写库, slave是读库, 需要自己做好主从复制, 这里只负责读写

var config1 = gorose.Config{Dsn: "./db.sqlite"}
var config2 = gorose.Config{Dsn: "./db2.sqlite"}
var config3 = gorose.Config{Dsn: "./db3.sqlite"}
var config4 = gorose.Config{Dsn: "./db4.sqlite"}
var configCluster = &gorose.ConfigCluster{
    Master:  []gorose.Config{config3, config4},
    Slave: []gorose.Config{config1, config2},
    Driver: "sqlite3",
}

初始化使用

var engin *gorose.Engin
engin, err := Open(config)
//engin, err := Open(configCluster)

if err != nil {
    panic(err.Error())
}

原生sql操作(增删改查), session的使用

创建用户表 users

DROP TABLE IF EXISTS "users";
CREATE TABLE "users" (
	 "uid" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
	 "name" TEXT NOT NULL,
	 "age" integer NOT NULL
);

INSERT INTO "users" VALUES (1, 'gorose', 18);
INSERT INTO "users" VALUES (2, 'goroom', 18);
INSERT INTO "users" VALUES (3, 'fizzday', 18);

定义表struct

type Users struct {
	Uid  int    `gorose:"uid"`
	Name string `gorose:"name"`
	Age  int    `gorose:"age"`
}
// 设置表名, 如果没有设置, 默认使用struct的名字
func (u *Users) TableName() string {
	return "users"
}

原生查询操作
除了上边的直接返回结果集外, 还支持绑定结果到给定对象上

// 这里是要绑定的结构体对象
// 如果你没有定义结构体, 则可以直接使用map, map示例
// var u = gorose.Data{}
// var u = gorose.Map{}  这两个都是可以的
var u Users
session := engin.NewSession()
// 这里Bind()是为了存放结果的, 如果你使用的是NewOrm()初始化,则可以直接使用 NewOrm().Table().Query()
_,err := session.Bind(&u).Query("select * from users where uid=? limit 2", 1)
fmt.Println(err)
fmt.Println(u)
fmt.Println(session.LastSql())

struct字段顺序需要跟select *内的表结构字段顺序一致(也可以手动指定要查询的字段), 具体原因参考 https://github.com/gohouse/gorose/issues/136

原生增删改操作

session.Execute("insert into users(name,age) values(?,?)(?,?)", "gorose",18,"fizzday",19)
session.Execute("update users set name=? where uid=?","gorose",1)
session.Execute("delete from users where uid=?", 1)

对象关系映射, orm的使用

    1. 基本链式使用
var u Users
db := engin.NewOrm()
err := db.Table(&u).Fields("name").AddFields("uid","age").Distinct().Where("uid",">",0).OrWhere("age",18).
	Group("age").Having("age>1").OrderBy("uid desc").Limit(10).Offset(1).Select()

也可以使用xxx.Limit().Page(),这个是固定用法,Page()必须在Limit()后边

    1. 如果不想定义struct, 又想绑定指定类型的map结果, 则可以定义map类型, 如
type user gorose.Map
// 或者 以下的type定义, 都是可以正常解析的
type user2 map[string]interface{}
type users3 []user
type users4 []map[string]string
type users5 []gorose.Map
type users6 []gorose.Data
  • 2.1 开始使用map绑定
db.Table(&user).Select()
db.Table(&users4).Limit(5).Select()

注意: 如果使用的不是slice数据结构, 则只能获取到一条数据


这里使用的 gorose.Data , 实际上就是 map[string]interface{} 类型.
gorose.Map, 实际上是 t.MapStringT 类型, 这里出现了一个 t 包, 是一个golang基本数据类型的相互转换包, 请看详细介绍 http://github.com/gohouse/t

    1. laravel的First(),Get(), 用来返回结果集
      也就是说, 你甚至可以不用传入各种绑定的struct和map, 直接传入表名, 返回两个参数, 一个是 []gorose.Map结果集, 第二个是error,堪称简单粗暴
      用法就是把上边的 Select() 方法换成 Get,First 即可, 只不过, Select() 只返回一个参数
    1. orm的增删改查
db.Table(&user2).Limit(10.Select()
db.Table(&user2).Where("uid", 1).Data(gorose.Data{"name","gorose"}).Update()
db.Table(&user2).Data(gorose.Data{"name","gorose33"}).Insert()
db.Table(&user2).Data([]gorose.Data{{"name","gorose33"},"name","gorose44"}).Insert()
db.Table(&user2).Where("uid", 1).Delete()

最终sql构造器, builder构造不同数据库的sql

目前支持 mysql, sqlite3, postgres, oracle, mssql, clickhouse等符合 database/sql 接口支持的数据库驱动
这一部分, 用户基本无感知, 分理出来, 主要是为了开发者可以自由添加和修改相关驱动以达到个性化的需求

binder, 数据绑定对象

这一部分也是用户无感知的, 主要是传入的绑定对象解析和数据绑定, 同样是为了开发者个性化定制而独立出来的

模块化

gorose2.0 完全模块化, 每一个模块都封装了interface接口api, 模块间调用, 都是通过接口, 上层依赖下层

  • 主模块
    • engin
      gorose 初始化配置模块, 可以全局保存并复用
    • session
      真正操作数据库底层模块, 所有的操作, 最终都会走到这里来获取或修改数据
    • orm
      对象关系映射模块, 所有的orm操作, 都在这里完成
    • builder
      构建终极执行的sql模块, 可以构建任何数据库的sql, 但要符合database/sql包的接口
  • 子模块
    • driver
      数据库驱动模块, 被engin和builder依赖, 根据驱动来搞事情
    • binder
      结果集绑定模块, 所有的返回结果集都在这里

以上主模块, 都相对独立, 可以个性化定制和替换, 只要实现相应模块的接口即可.

最佳实践

sql

DROP TABLE IF EXISTS "users";
CREATE TABLE "users" (
	 "uid" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
	 "name" TEXT NOT NULL,
	 "age" integer NOT NULL
);

INSERT INTO "users" VALUES (1, 'gorose', 18);
INSERT INTO "users" VALUES (2, 'goroom', 18);
INSERT INTO "users" VALUES (3, 'fizzday', 18);

实战代码

package main

import (
	"fmt"
	"github.com/gohouse/gorose/v2"
	_ "github.com/mattn/go-sqlite3"
)

type Users struct {
    Uid int64 `gorose:"uid"`
    Name string `gorose:"name"`
    Age int64 `gorose:"age"`
    Xxx interface{} `gorose:"-"` // 这个字段在orm中会忽略
}

func (u *Users) TableName() string {
	return "users"
}

var err error
var engin *gorose.Engin

func init() {
    // 全局初始化数据库,并复用
    // 这里的engin需要全局保存,可以用全局变量,也可以用单例
    // 配置&gorose.Config{}是单一数据库配置
    // 如果配置读写分离集群,则使用&gorose.ConfigCluster{}
	engin, err = gorose.Open(&gorose.Config{Driver: "sqlite3", Dsn: "./db.sqlite"})
}
func DB() gorose.IOrm {
	return engin.NewOrm()
}
func main() {
	// 这里定义一个变量db, 是为了复用db对象, 可以在最后使用 db.LastSql() 获取最后执行的sql
	// 如果不复用 db, 而是直接使用 DB(), 则会新建一个orm对象, 每一次都是全新的对象
	// 所以复用 db, 一定要在当前会话周期内
	db := DB()
	
	// 查询一条
	var u Users
	// 查询数据并绑定到 user{} 上
	err = db.Table(&u).Fields("uid,name,age").Where("age",">",0).OrderBy("uid desc").Select()
	if err!=nil {
		fmt.Println(err)
	}
	fmt.Println(u, u.Name)
	fmt.Println(db.LastSql())
	
	// 查询多条
	// 查询数据并绑定到 []Users 上, 这里复用了 db 及上下文条件参数
	// 如果不想复用,则可以使用DB()就会开启全新会话,或者使用db.Reset()
	// db.Reset()只会清除上下文参数干扰,不会更换链接,DB()则会更换链接
	var u2 []Users
	err = db.Table(&u2).Limit(10).Offset(1).Select()
	fmt.Println(u2)
	
	// 统计数据
	var count int64
	// 这里reset清除上边查询的参数干扰, 可以统计所有数据, 如果不清除, 则条件为上边查询的条件
	// 同时, 可以新调用 DB(), 也不会产生干扰
	count,err = db.Reset().Count()
	// 或
	count, err = DB().Table(&u).Count()
	fmt.Println(count, err)
}

高级用法

  • Chunk 数据分片 大量数据批量处理 (累积处理)

    当需要操作大量数据的时候, 一次性取出再操作, 不太合理, 就可以使用chunk方法 chunk的第一个参数是指定一次操作的数据量, 根据业务量, 取100条或者1000条都可以 chunk的第二个参数是一个回调方法, 用于书写正常的数据处理逻辑 目的是做到, 无感知处理大量数据 实现原理是, 每一次操作, 自动记录当前的操作位置, 下一次重复取数据的时候, 从当前位置开始取

     User := db.Table("users")
     User.Fields("id, name").Where("id",">",2).Chunk(2, func(data []gorose.Data) error {
         // for _,item := range data {
         // 	   fmt.Println(item)
         // }
         fmt.Println(data)
         
         // 这里不要忘记返回错误或nil
         return nil
     })
    
     // 打印结果:  
     // map[id:3 name:gorose]
     // map[id:4 name:fizzday]
     // map[id:5 name:fizz3]
     // map[id:6 name:gohouse]
     [map[id:3 name:gorose] map[name:fizzday id:4]]
     [map[id:5 name:fizz3] map[id:6 name:gohouse]]
  • Loop 数据分片 大量数据批量处理 (从头处理)

    类似 chunk 方法, 实现原理是, 每一次操作, 都是从头开始取数据 原因: 当我们更改数据时, 更改的结果可能作为where条件会影响我们取数据的结果,所以, 可以使用Loop

    User := db.Table("users")
    User.Fields("id, name").Where("id",">",2).Loop(2, func(data []gorose.Data) error {
        // for _,item := range data {
        // 	   fmt.Println(item)
        // }
        // 这里执行update / delete  等操作
        
        // 这里不要忘记返回错误或nil
        return nil
    })
  • 嵌套where

     // SELECT  * FROM users  
     //     WHERE  id > 1 
     //         and ( name = 'fizz' 
     //             or ( name = 'fizz2' 
     //                 and ( name = 'fizz3' or website like 'fizzday%')
     //                 )
     //             ) 
     //     and job = 'it' LIMIT 1
     User := db.Table("users")
     User.Where("id", ">", 1).Where(func() {
             User.Where("name", "fizz").OrWhere(func() {
                 User.Where("name", "fizz2").Where(func() {
                     User.Where("name", "fizz3").OrWhere("website", "like", "fizzday%")
                 })
             })
         }).Where("job", "it").First()
  • 嵌入原生sql示例
    以下几种操作是等效的

db.Table("users").WhereRegexp("name","\w+").BuildSql()
db.Table("users").Where("name","regexp","\w+").BuildSql()
db.Table("users").Where([]interface{}{"name","regexp","\w+"}).BuildSql()
db.Table("users").Where(gorose.Data{"name regexp","\w+"}).BuildSql()

升级日志

  • v2.1.5-master:

    • 增加regexp表达式在where中的使用
  • v2.1.4:

    • logger修正
    • 事物改进
    • 依赖包改为 gohouse/golib(gohouse/t,gohouse/gocar)
  • v2.1.x:

    • join表自动加前缀,不需要再手动加前缀
    • 原生sql的query()方法,增加返回结果集[]map[string]interface{}
  • v2.0.0: 船新版本,船新架构

升级指南

从2.0.x升级到2.1.x

  • xxx.Join("pre_tablename")更改为xxx.Join("tablename"),这里不需要手动指定表前缀
  • err:=DB().Bind().Query(),更改为多返回res,err:=DB().Query(),同时保留了Bind()用法

从1.x升级到2.x, 全新安装


Jetbrains 开源支持

gorose 项目一直以来都是在 JetBrains 公司旗下的 GoLand 集成开发环境中进行开发,基于 free JetBrains Open Source license(s) 正版免费授权,在此表达我的谢意。


赞助渠道

微信 支付宝 paypal: click
  • 捐赠列表
total avator
¥100
Issues
  • 事务隔离性有点不对

    事务隔离性有点不对

    先贴一下代码,其中,

    • wrong()方法是使用gorose的事务来进行操作的.
    • right()使用的底层提供事务,并且分别预设事务级别isolation=0,1,2三种不同事务级别进行同样的操作。
    • 整个操作的流程是:在同一个事务里,分别插入和查询插入的数据,在未提交时,wrong()里的count未能响应到insert的变化,而right()是可以的。
    package main
    
    import (
    	"context"
    	"database/sql"
    	"fmt"
    
    	_ "github.com/go-sql-driver/mysql"
    	"github.com/gohouse/gorose/v2"
    )
    
    var err error
    var engin *gorose.Engin
    
    /*
        CREATE DATABASE test;
        CREATE TABLE t_user(
    		id INT NOT NULL,
    		name VARCHAR(20) NOT NULL
    	)ENGINE=InnoDB DEFAULT CHARSET=utf8;
    */
    
    func init() {
    	engin, err = gorose.Open(&gorose.Config{Driver: "mysql", Dsn: "ft:[email protected](localhost:3306)/test?charset=utf8&parseTime=true&allowNativePasswords=true"})
    	if err != nil {
    		panic(err)
    	}
    }
    func DB() gorose.IOrm {
    	return engin.NewOrm()
    }
    func main() {
    	wrong()
    }
    
    func right() {
    	var id = 6
    	var name = "gorose"
    	db := DB()
    	tx, e := db.GetISession().GetIEngin().GetExecuteDB().BeginTx(context.Background(), &sql.TxOptions{
    		ReadOnly: false,
    
    		// 分别测试0,1,2,三种隔离级别,其他隔离级别该驱动不支持
    		Isolation: 0,
    	})
    	if e != nil {
    		panic(e)
    	}
    
    	_, err := tx.Exec("insert into t_user(id, name) values(?, ?)", id, name)
    	if err != nil {
    		tx.Rollback()
    		panic(err)
    	}
    
    	res, err := tx.Query("select count(*) from t_user where id=?", id)
    	if err != nil {
    		tx.Rollback()
    		panic(err)
    	}
    	var count int
    
    	for res.Next() {
    		if e := res.Scan(&count); e != nil {
    			panic(e)
    		}
    	}
            // 不管isoloation为0还是1还是2,count都可以显示为1
    	fmt.Println(count)
    
    	if e := tx.Commit(); e != nil {
    		panic(e)
    	}
    }
    
    func wrong() {
    	var id = 6
    	var name = "gorose"
    
    	db := DB()
    
    	db.Begin()
    
    	if _, e := db.Execute("insert into t_user(id, name) values(?, ?)", id, name); e != nil {
    		db.Rollback()
    		panic(e)
    		return
    	}
    
    	rs, e := db.Query("select count(*) from t_user where id=?", id)
    	if e != nil {
    		db.Rollback()
    		panic(e)
    		return
    	}
    
    	// 期望输出count为1,实际输出为0
    	// [map[count(*):0]]
    	fmt.Println(rs)
    
    	db.Commit()
    }
    
    

    贴一下结果:

    right() isolation=0:

    1
    

    right() isolation=1:

    1
    

    right() isolation=2:

    1
    

    wrong():

    [map[count(*):0]]
    
    • right()方法,分别对isolation=1,2,0进行操作,所得到的的count都是健康的1,也就是同事务里,count可以响应到插入,哪怕是未commit。

    • wrong()方法,count无法响应到insert的方法。

    基于以上结论,猜测:

    • gorose的事务脏了,期望同事务下的select countinsert可能各自进了不同的事务里,导致了事务隔离造成的count异常。

    • go1.12.7

    • gorose/v2

    • win10 x64

    • mysql, docker image<36fcb346aa55> Ver 8.0.18 for Linux on x86_64

    opened by fwhezfwhez 7
  • 调用事务报错,大神帮忙看下

    调用事务报错,大神帮忙看下

    gin框架测试orm各项功能,增删改查无问题,测试到事务的时候就报错了,只要调用rollback或commit就panic了,环境:Mac 、go 1.13.6、 gin 1.5.0、gorose 2.1.4

    以下是代码: Router.GET("/commit", func(c *gin.Context) { db := models.DB() tableName := "admin" // 开始事务 db.Begin() data := map[string]interface{}{ "mobile": "11111111111", "password": utils.Md5("aaa"), "name": "ggyy", }

    	res, err := db.Table(tableName).Where("id", 6).Data(data).Update()
    	if res == 0 || err != nil {
    		// 回滚事务
    		db.Rollback()
    	}
    	res2, err2 := db.Table(tableName).Data(data).Insert()
    	if res2 == 0 || err2 != nil {
    		// 回滚事务
    		db.Rollback()
    	}
    	// 提交事务
    	db.Commit()
    	c.String(200, "ok")
    })
    

    runtime error: invalid memory address or nil pointer dereference /usr/local/Cellar/go/1.13.6/libexec/src/runtime/panic.go:199 (0x4044e7b) panicmem: panic(memoryError) /usr/local/Cellar/go/1.13.6/libexec/src/runtime/signal_unix.go:394 (0x4044cb8) sigpanic: panicmem() /usr/local/Cellar/go/1.13.6/libexec/src/database/sql/sql.go:2107 (0x4584ffc) (*Tx).rollback: if !atomic.CompareAndSwapInt32(&tx.done, 0, 1) { /usr/local/Cellar/go/1.13.6/libexec/src/database/sql/sql.go:2126 (0x4684133) (*Tx).Rollback: return tx.rollback(false) /Users/cookies/go/pkg/mod/github.com/gohouse/gorose/[email protected]/session.go:106 (0x468411d) (*Session).Rollback: err = s.tx.Rollback() /Users/cookies/WWW/gin-admin/route/router.go:245 (0x46ee0ad) SetupRouter.func11: db.Rollback() /Users/cookies/go/src/github.com/gin-gonic/gin/context.go:147 (0x45563ca) (*Context).Next: c.handlersc.index /Users/cookies/go/pkg/mod/github.com/gin-contrib/[email protected]/sessions.go:52 (0x46a43c6) Sessions.func1: c.Next() /Users/cookies/go/src/github.com/gin-gonic/gin/context.go:147 (0x45563ca) (*Context).Next: c.handlersc.index /Users/cookies/go/src/github.com/gin-gonic/gin/recovery.go:83 (0x456a0b3) RecoveryWithWriter.func1: c.Next() /Users/cookies/go/src/github.com/gin-gonic/gin/context.go:147 (0x45563ca) (*Context).Next: c.handlersc.index /Users/cookies/go/src/github.com/gin-gonic/gin/logger.go:241 (0x45691e0) LoggerWithConfig.func1: c.Next() /Users/cookies/go/src/github.com/gin-gonic/gin/context.go:147 (0x45563ca) (*Context).Next: c.handlersc.index /Users/cookies/go/src/github.com/gin-gonic/gin/gin.go:412 (0x456056c) (*Engine).handleHTTPRequest: c.Next() /Users/cookies/go/src/github.com/gin-gonic/gin/gin.go:370 (0x455fc6d) (*Engine).ServeHTTP: engine.handleHTTPRequest(c) /usr/local/Cellar/go/1.13.6/libexec/src/net/http/server.go:2802 (0x4373973) serverHandler.ServeHTTP: handler.ServeHTTP(rw, req) /usr/local/Cellar/go/1.13.6/libexec/src/net/http/server.go:1890 (0x436f214) (*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req) /usr/local/Cellar/go/1.13.6/libexec/src/runtime/asm_amd64.s:1357 (0x405cee0) goexit: BYTE $0x90 // NOP

    [GIN] 2020/03/13 - 19:13:03 | 500 | 3.572032ms | 127.0.0.1 | GET /commit

    opened by goodqq140 7
  • 嵌套查询好像不好用。

    嵌套查询好像不好用。

    嵌套查询好像不好用。 `

    User := ConnectionMS.NewSession().Table(t.TableName())
    User.Where("name", ">", 1)
    User.Where(func() {
    	User.OrWhere("name", "fizz").OrWhere(func() {
    		User.Where("name", "fizz2").Where(func() {
    			User.Where("name", "fizz53").OrWhere("website", "like", "fizzday%")
    		})
    	})
    })
    
    fmt.Println(User.BuildSql())
    

    `

    居然生成SELECT * FROM T_Room_Order WHERE name > 1 and ()

    是不是有什么bug

    opened by ghostljj 6
  • Execute()执行insert以后无法取到插入的行数量

    Execute()执行insert以后无法取到插入的行数量

    Execute()执行insert以后无法取到插入的行数量,只能返回上一次插入的最后一个ID,在某些情况下不方便使用。我看了database.go,parseExecute()时要不只返回LastInsertId,要不只返回RowsAffected,并且没有保存:

    func (dba *Database) parseExecute(stmt *sql.Stmt, operType string, vals []interface{}) (int64, error) {
    	var res int64
    	var err error
    	result, errs := stmt.Exec(vals...)
    	if errs != nil {
    		return 0, errs
    	}
    
    	switch operType {
    	case "insert":
    		res, err = result.LastInsertId()
    	case "update":
    		res, err = result.RowsAffected()
    	case "delete":
    		res, err = result.RowsAffected()
    	}
    
    	return res, err
    }
    

    能否改进一下?

    opened by masuz 6
  • 升级到go 1.13无法get

    升级到go 1.13无法get

    之前go 1.12可以正常用v1.0.5,现在go升级到1.13 执行: go get -u github.com/gohouse/[email protected] 出错: go get github.com/gohouse/[email protected]: github.com/gohouse/[email protected]: invalid version: module contains a go.mod file, so major version must be compatible: should be v0 or v1, not v2

    opened by ZhiweiWang 5
  • gorose 2.0 版本开发计划讨论

    gorose 2.0 版本开发计划讨论

    2.0版本规划

    开发计划

    按照 laravel 的数据库操作 query builder 的标准开发, 同时可酌情添加 eloquent 的部分设计思想和 api

    产品规划

    采用模块分离的方式, 每个模块以 接口 的方式相互调用, 做到模块相互独立, 后期可以自由方便的拓展.
    比如驱动, 不同驱动的sql构建

    设计目标

    每个模块要做到可以自由横向扩展, 以实现个性化需求.
    比如返回结果: map, struct, 自定义数据类型等.

    模块大致结构图

    gorose_2.0

    opened by fizzday 5
  • dbconfig配置参数不方便存储到外部json/yaml等格式配置文件中,能否改进?

    dbconfig配置参数不方便存储到外部json/yaml等格式配置文件中,能否改进?

    dbconfig配置参数为map[string]interface{}格式,数据库连接配置是map[string]string格式,数据库配置项不固定,很难使用struct进行定义并加载。而且使用json/simplejson等解析工具从外部读取配置文件后,数据库配置项自动变成了map[string]interface{}格式,gorose认为是不正确的配置。能否将配置文件中的数据库配置项改成数组,以方便动态加载并自动适配?如下:

    ``type DBConfig struct {

    Default string `json:"default"`
    
    SetMaxOpenConns int `json:"SetMaxOpenConns"`
    
    SetMaxIdleConns int `json:"SetMaxIdleConns"`
    
    DBList []map[string]string `json:"dblist"`    \\ 适配可变数据库连接配置,方便进行配置文件持久化
    

    }``

    是否可行?

    opened by masuz 5
  • postgresql 生成的sql有语法问题

    postgresql 生成的sql有语法问题

    你好, 在使用 gorose 连接 postgresql 时, where条件中的字段名会加上 反引号`, 导致无法正确执行.

    fmt.Println(db.Table("users").Where(`name`, name).BuildSql("select"))
    

    生成的sql 如下:

    SELECT * FROM users WHERE `name` =  $1 ['xxxx'];
    

    由于 name 字段上 有反引号, 导致无法执行此SQL

    opened by linuxr 4
  • builder_default中的BUG

    builder_default中的BUG

    • 1、BuildExecute未处理类型为string或[]string的data引起Increment,Decrement生成错误的sql如下: update xxx set where xxx = ?,丢失更新字段列表,同样的table.data('click_count=click_count+1').update()一样生成错误sql;建议允许使用如下的更新或插入方法: table.data('click_count=click_count+1,visit_count=visit_count+1, tikcet=tikcet-1').update(), // 多字段计数累加或累减

    • 2、查询条件中如果where传入nil或空数组,将生成错误的sql语句,在应用中不得不如下处理:

    var where [][]interface{}
    if search != "" {
         where = append(where, []interface{}{"name","like", search + "%%"})
    }
    query := db.Table('xxxx')
    if len(where) > 0 {
        query = query.where(**where**)  // 此处如果where为nil或是[]将生成错误的sql
    }
    rows, err := query.Get()
    
    

    是否可能直接如下调用更简洁:

    var where [][]interface{}
    if search != "" {
         where = append(where, []interface{}{"name","like", search + "%%"})
    }
    rows, err := db.Table('xxxx').where(where).Get()
    
    opened by go-xe2 4
  • 同时使用多个连接配置,每次都要重新Open一个新配置?

    同时使用多个连接配置,每次都要重新Open一个新配置?

    一个简单的例子:业务逻辑需要用到多个库(或用户),这可以在ConnectionConfigs里面配置。但是每次到切换配置时,都会用Open去建立一个新的Connection来覆盖之前Connect全局变量,之前的Connection则被“丢弃”。

    PS:一开始我以为gorose.Open()会返回一条新的Connection,所以我使用map将配置对应的Connection关联,这样就不用重复Open相同的配置,结果不行,发现map中的Connection都是同一个(且最后一次Open的那个);接着尝试GetInstance()来返回一个新的DataBase指针,利用Map对应配置,最后发现所有的DataBase指针都会去找那个全局的Connet变量。故,提出问题,望得到正解!

    opened by haowanxing 4
  • 关于实现with方法的建议

    关于实现with方法的建议

    关于关联模型#20 ,用Join实现的并不是我想要的。 thinkphp5中有个with方法,可以实现关联模型,以单独查询一个对象为例。 系统有user、user_info、user_category三个表,其数据结构分别为:

    user: id,name,gender,c_id(对应user_category的id); user_info: id,u_id(对应user的id),id_card user_category: id,name

    在tp中可以通过:UserModel->Where("Id","=",1)->with("user_info","user_category")->find();获取如下格式的数据:

    { id:1, name:"小明", user_info:{u_id:1,id_card:"411423333333333333"}, user_category:{id:11,name:"老师"} }

    这样用起来特别方便,建议gorose实现with方法。 提供一个不成熟的思路:

    1.先忽略with方法,执行解析的sql语句,得到table1的一个记录。 2.定义with("relation","table2_name","table1.key","table2.key"); 3.取1中记录的table1.key的value,和with方法构成第二条sql语句,并执行。 4.将执行的结果挂载到1中的记录上。 5.返回数据

    对于列表的获取,为了避免多次循环查询,可以基于步骤一做些改变,具体如下。

    1.先忽略with方法,执行解析的sql语句,得到table1的记录集合。 2.定义with("relation","table2_name","table1.key","table2.key"); 3.取1中记录集合的table1.key的value构成一个IN (table1.key.v1,table1.key.v2,table1.key.v3....),和with方法构成第二条sql语句,查询出table2的集合。 4.对两个集合进行合成,基于with中的table1.key和table2.key合并集合。 5.返回列表。

    如果表达的不清楚,欢迎追问。

    opened by AnsonCode 4
  • transaction中使用select()会造成执行结果无法写回映射对象

    transaction中使用select()会造成执行结果无法写回映射对象

    例如: db.Transaction(func(db gorose.IOrm) error { var obj Obj db.Table(&obj).Where("id", 1).Select() return nil }) 在这种情况下,obj对象无法被正确赋值,查询源码后发现是在orm.go/304执行了dba.ResetTable()这个方法,我认为Transaction中即使不ResetTable,也不会对参数产生感染,因此Transaction中的Reset()能否去掉ResetTable呢?

    opened by SoapLiu 0
  • 这个没办法手动设置要查询的数据库么?

    这个没办法手动设置要查询的数据库么?

    dsn := fmt.Sprintf("%s:%[email protected](%s:%d)/?charset=utf8&parseTime=true", Common.GAppCfg.SaasCfg.Username, Common.GAppCfg.SaasCfg.Password, Common.GAppCfg.SaasCfg.Host, Common.GAppCfg.SaasCfg.Port) enginSaas, err = gorose.Open(&gorose.Config{Driver: "mysql", Dsn: dsn, SetMaxIdleConns: 3, SetMaxOpenConns: 3})

    代码如上,DSN并没有指定数据库,需要在查询的时候指定,好像这是不支持的是吧!?

    opened by ysp198910 0
Releases(v2.1.8)
Owner
gohouse
a go organization served for go, php, python, javascript or java developer
gohouse
It's a Go console utility for migration from MSSQL to MySQL engine.

A tool for migration the databases to MySQL It's a Go console utility for migration from MSSQL to MySQL engine. The databases should have prepopulated

Eugen Vasilyeu 0 Jan 4, 2022
ClickHouse Operator creates, configures and manages ClickHouse clusters running on Kubernetes

ClickHouse Operator ClickHouse Operator creates, configures and manages ClickHouse clusters running on Kubernetes. Features The ClickHouse Operator fo

RadonDB 19 Jul 9, 2022
Go-clickhouse - ClickHouse client for Go

ClickHouse client for Go 1.18+ This client uses native protocol to communicate w

Uptrace 119 Aug 2, 2022
Go-postgres - go-postgres library provide NoSQL functionality which can execute queries with pool of connections

GO Postgres go-postgres library provide NoSQL functionality which can execute queries with pool of connections. What is this repository for? Establish

Damindu Lakmal 0 Dec 31, 2021
Database - Example project of database realization using drivers and models

database Golang based database realization Description Example project of databa

Denis 1 Feb 10, 2022
Devcloud-go provides a sql-driver for mysql which named devspore driver and a redis client which named devspore client,

Devcloud-go Devcloud-go provides a sql-driver for mysql which named devspore driver and a redis client which named devspore client, you can use them w

HUAWEI CLOUD 11 Jun 9, 2022
Mogo: a lightweight browser-based logs analytics and logs search platform for some datasource(ClickHouse, MySQL, etc.)

mogo Mogo is a lightweight browser-based logs analytics and logs search platform

Shimo HQ 745 Aug 5, 2022
Bifrost ---- 面向生产环境的 MySQL 同步到Redis,MongoDB,ClickHouse,MySQL等服务的异构中间件

Bifrost ---- 面向生产环境的 MySQL 同步到Redis,ClickHouse等服务的异构中间件 English 漫威里的彩虹桥可以将 雷神 送到 阿斯加德 和 地球 而这个 Bifrost 可以将 你 MySQL 里的数据 全量 , 实时的同步到 : Redis MongoDB Cl

brokerCAP 1.3k Aug 1, 2022
Create key value sqlite3 database from tabular data, fast.

Turn tabular data into a lookup table using sqlite3. This is a working PROTOTYPE with limitations, e.g. no customizations, the table definition is fixed, etc.

Martin Czygan 5 Apr 2, 2022
Make a sqlite3 database from tabular data, fast.

MAKTA make a database from tabular data Turn tabular data into a lookup table using sqlite3. This is a working PROTOTYPE with limitations, e.g. no cus

Martin Czygan 5 Apr 2, 2022
A tool I made to quickly store bug bounty program scopes in a local sqlite3 database

GoScope A tool I made to quickly store bug bounty program scopes in a local sqlite3 database. Download or copy a Burpsuite configuration file from the

null 3 Nov 18, 2021
BQB is a lightweight and easy to use query builder that works with sqlite, mysql, mariadb, postgres, and others.

Basic Query Builder Why Simple, lightweight, and fast Supports any and all syntax by the nature of how it works Doesn't require learning special synta

Aaron M 39 Jul 22, 2022
Implementasi database oracle kedalam golang

Go with Oracle database Implementasi database oracle kedalam golang How to using swagger Install generator swagger menggunakan perintah : go get -u gi

Muhammad Rais Adlani 0 Nov 20, 2021
Go sqlite3 http vfs: query sqlite databases over http with range headers

sqlite3vfshttp: a Go sqlite VFS for querying databases over http(s) sqlite3vfshttp is a sqlite3 VFS for querying remote databases over http(s). This a

Peter Sanford 45 Jul 18, 2022
A reverse proxy for postgres which rewrites queries.

pg-rewrite-proxy A reverse proxy for postgres which rewrites queries. Arbitrary rewriting is supported by supplying an LUA script to the proxy applica

Patients Know Best 8 Jun 16, 2022
ClickHouse http proxy and load balancer

chproxy English | 简体中文 Chproxy, is an http proxy and load balancer for ClickHouse database. It provides the following features: May proxy requests to

Vertamedia 945 Aug 3, 2022
Collects many small inserts to ClickHouse and send in big inserts

ClickHouse-Bulk Simple Yandex ClickHouse insert collector. It collect requests and send to ClickHouse servers. Installation Download binary for you pl

Nikolay Pavlovich 373 Jul 27, 2022
Distributed tracing using OpenTelemetry and ClickHouse

Distributed tracing backend using OpenTelemetry and ClickHouse Uptrace is a dist

Uptrace 774 Aug 2, 2022
support clickhouse

Remote storage adapter This is a write adapter that receives samples via Prometheus's remote write protocol and stores them in Graphite, InfluxDB, cli

weetime 29 Jun 29, 2022