{"id":13543460,"url":"https://github.com/gohouse/gorose","last_synced_at":"2025-05-14T01:08:39.979Z","repository":{"id":45229091,"uuid":"116397470","full_name":"gohouse/gorose","owner":"gohouse","description":"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.","archived":false,"fork":false,"pushed_at":"2024-12-04T09:58:09.000Z","size":14920,"stargazers_count":1150,"open_issues_count":2,"forks_count":124,"subscribers_count":47,"default_branch":"master","last_synced_at":"2025-04-03T06:55:20.973Z","etag":null,"topics":["clickhouse","database","databases","db","eloquent","go","golang","gorose","gorose-orm","laravel","mssql","orm","php","sql"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gohouse.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-01-05T15:12:29.000Z","updated_at":"2025-03-31T15:55:29.000Z","dependencies_parsed_at":"2024-01-13T22:55:20.045Z","dependency_job_id":"d69f49ce-1fd2-44fc-a407-355a4a41084f","html_url":"https://github.com/gohouse/gorose","commit_stats":{"total_commits":624,"total_committers":22,"mean_commits":"28.363636363636363","dds":"0.16506410256410253","last_synced_commit":"b81a47483c948ba55b8bc61c936a00179062b086"},"previous_names":[],"tags_count":48,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gohouse%2Fgorose","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gohouse%2Fgorose/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gohouse%2Fgorose/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gohouse%2Fgorose/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gohouse","download_url":"https://codeload.github.com/gohouse/gorose/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248208748,"owners_count":21065219,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clickhouse","database","databases","db","eloquent","go","golang","gorose","gorose-orm","laravel","mssql","orm","php","sql"],"created_at":"2024-08-01T11:00:31.929Z","updated_at":"2025-04-10T11:37:19.433Z","avatar_url":"https://github.com/gohouse.png","language":"Go","readme":"# GoRose ORM V3\nPHP Laravel ORM 的 go 实现, 与 laravel 官方文档保持一致 https://laravel.com/docs/10.x/queries .  \n分为 go 风格 (struct 结构绑定用法) 和 php 风格 (map 结构用法).  \nphp 风格用法, 完全可以使用 laravel query builder 的文档做参考, 尽量做到 1:1 还原.   \n\n## GoRose V3 架构图\n![](./assets/gorose.svg)\n\n## 安装\n目前还处于beta阶段, 请谨慎使用. 由于没有打 tag, 只能使用 go mod 的方式引入\n```shell\n# go.mod\nrequire github.com/gohouse/gorose/v3 master\n```\n\n## 概览\ngo风格用法\n```go\npackage main\n\nimport (\n    gorose \"github.com/gohouse/gorose/v3\"\n    // 引入mysql驱动\n    _ \"github.com/go-sql-driver/mysql\"\n)\n\ntype User struct {\n\tId    int64  `db:\"id,pk\"`   // 这里的 pk 是指主键\n\tName  string `db:\"name\"`\n\tEmail string `db:\"email\"`\n    \n    // 定义表名字,等同于 func (User) TableName() string {return \"users\"}, 二选一即可\n\t// TableName string `db:\"users\" json:\"-\"` \n}\nfunc (User) TableName() string {\n    return \"users\"\n}\n\nvar rose = gorose.Open(\"mysql\", \"root:123456@tcp(localhost:3306)/test?charset=utf8mb4\u0026parseTime=true\")\n\nfunc db() *gorose.Database {\n\treturn rose.NewDatabase()\n}\nfunc main() {\n    // select id,name,email from users limit 1;\n    var user User\n    db().To(\u0026user)\n\n    // insert into users (name,email) values (\"test\",\"test@test.com\");\n    var user = User{Name: \"test\", Email: \"test@test.com\"}}\n    db().Insert(\u0026user)\n\n    // update users set name=\"test2\" where id=1;\n    var user = User{Id: 1, Name: \"test2\"}\n    db().Update(\u0026user)\n\n    // delete from users where id=1;\n    var user = User{Id: 1}\n    db().Delete(\u0026user) \n}\n```\nphp风格用法 和 go风格用法查询如下sql对比:   \n```sql\nselect id,name,email from users where id=1 and name=\"test\"\n```  \n```go\n// php 风格写法\nuser,err := db().Table(\"users\").\n    Select(\"id\",\"name\",\"email\").\n    Where(\"id\", \"=\", 1).Where(\"name\", \"test\").\n    First()\n// go 风格写法\nvar user = User{Id: 1, Name: \"test\"}\nerr := db().To(\u0026user)\n```\n上边的两种用法结果相同,由此可以看出,除了对 表 模型的绑定区别, 其他方法通用\n\n## 配置\n单数据库连接, 可以直接同官方接口一样用法\n```go\nvar rose = gorose.Open(\"mysql\", \"root:123456@tcp(localhost:3306)/test?charset=utf8mb4\u0026parseTime=true\")\n```\n也可以用\n```go\nvar conf1 = gorose.Config{\n    Driver:          \"mysql\",\n    DSN:             \"root:123456@tcp(localhost:3306)/test?charset=utf8mb4\u0026parseTime=true\",\n    Prefix:          \"tb_\",\n    Weight:          0,\n    MaxIdleConns:    0,\n    MaxOpenConns:    0,\n    ConnMaxLifetime: 0,\n    ConnMaxIdleTime: 0,\n}\nvar rose = gorose.Open(conf)\n```\n或者使用读写分离集群,事务内,自动强制从写库读数据\n```go\nvar rose = gorose.Open(\n    gorose.ConfigCluster{\n        WriteConf: []gorose.Config{\n            conf1,\n            conf2,\n        },\n        ReadConf: []gorose.Config{\n            conf3,\n            conf4,\n        }\n    },\n)\n```\n\n## 驱动支持\n- mysql : https://github.com/go-sql-driver/mysql  \n- sqlite3 : https://github.com/mattn/go-sqlite3  \n- postgres : https://github.com/lib/pq  \n- oracle : https://github.com/mattn/go-oci8  \n- mssql : https://github.com/denisenkom/go-mssqldb  \n\n目前实现了以上5中数据库的支持, 通用数据库,只需要添加更多的 `gorose/driver/dialect.IDialect` 接口即可  \n非通用数据库,只要实现了 gorose/driver.IDriver 接口,理论上可以支持任意数据库,包括 redis,mongo 等都可以通过这个接口来实现  \n所有的 orm 链式操作都在 `gorose/builder.Context` 中, 直接可以拿到最原始的数据  \n\n## 事务\n```go\n// 全自动事务, 有错误会自动回滚, 无错误会自动提交\n// Transaction 方法可以接收多个操作, 同用一个 tx, 方便在不同方法内处理同一个事务\ndb().Transaction(func(tx gorose.TxHandler) error {\n    tx().Insert(\u0026user)\n    tx().Update(\u0026user)\n    tx().To(\u0026user)\n})\n\n// 手动事务\ntx = db().Begin()\ntx().Insert(\u0026user)\ntx().Update(\u0026user)\ntx().To(\u0026user)\ntx().Rollback()\ntx().Commit()\n\n// 全自动嵌套事务\ndb().Transaction(func(tx gorose.TxHandler) error {\n    tx().Insert(\u0026user)\n    ...\n    // 自动子事务\n    tx().Transaction(func(tx2 gorose.TxHandler) error {\n        tx2().Update(\u0026user)\n        ...\n    }\n}\n\n// 手动嵌套事务\nvar tx = db().Begin()\n// 自动子事务\ntx().Begin() // 自动 savepoint 子事务\n...\ntx().Rollback()   // 自动回滚到上一个 savepoint\n...\n// 手动子事务\ntx().SavePoint(\"savepoint1\")    // 手动 savepoint 到 savepoint1(自定义名字)\n...\ntx().RollbackTo(\"savepoint1\") // 手动回滚到自定义的 savepoint\ntx().Commit()\n```\n\n## update\n在插入和更新数据时,如果使用 struct 模型作为数据对象的时候, 默认忽略类型零值,如果想强制写入,则可以从第二个参数开始传入需要强制写入的字段即可,如:\n```go\nvar user = User{Id: 1, Name: \"test\"}\n// 这里不会对 sex 做任何操作, \n//update user set name=\"test\" where id=1\ndb().Update(\u0026user)\n// 这里会强制将sex更改为0\n//update user set name=\"test\", sex=0 where id=1\ndb().Update(\u0026user, \"sex\")\n// 等同于\ndb().Table(\u0026user).Where(\"id\", 1).Update(map[string]any{\"name\": \"test\", \"sex\": 0}))\n```\n如果没有where条件,则会自动添加tag中指定了pk的字段作为条件,如: `db:\"id,pk\"`, 因为指定了 pk,如果 id 的值不为0值, 则 id 会作为主键条件更新\n\n## insert\n参考 update\n\n## delete\n```go\nvar user = User{Id: 1}\ndb().Delete(\u0026user)\n// 等同于\ndb().Table(\u0026user).Where(\"id\", 1).Delete()\n// 要加上字段0值条件,只需要传入第二个字段,如:\n// delete from users where id=1 and sex=0 and name=\"\"\ndb().Delete(\u0026user, \"sex\", \"name\")\n```\n\n## table\n- 参数  \n  table 参数, 可以是字符串, 也可以是 User 结构体\n```go\ndb().Table(User{})\ndb().Table(\"users\")\n```\n- 取别名\n```go\ndb().Table(User{}, \"u\")\ndb().Table(\"users\", \"u\")\n```\n- 结果集查询\n```go\nsub := db().Table(\"users\").Select(\"id\", \"name\")\ndb().Table(sub).Where(\"id\", \"\u003e\", 1).Get()\n```\n\n## join\n```go\ntype UserInfo struct {\n    UserId      int64   `db:\"user_id\"`\n    TableName   string  `db:\"user_info\"`\n}\n```\n\n- 简单用法\n```go\ndb().Table(\"users\").Join(UserInfo{}, \"user.id\", \"=\", \"user_info.user_id\").Get()\n```\n\n- 取别名\n```go\n// select * from users a inner join user_info b on a.id=b.user_id\ndb().Table(\"users\", \"u\").Join(gorose.As(UserInfo{}, \"b\"), \"u.id\", \"=\", \"b.user_id\").Get()\n// 等同于\ndb().Table(User{}, \"u\").Join(gorose.As(\"user_info\", \"b\"), \"u.id\", \"=\", \"b.user_id\").Get()\n```\n`gorose.As(UserInfo{}, \"b\")` 中, `user_info` 取别名 `b`\n\n- 复杂用法\n```go\ndb().Table(\"users\").Join(UserInfo{}, func(wh builder.IJoinOn) {\n    wh.On(\"a.id\", \"b.user_id\").OrOn(\"a.sex\", \"b.sex\")\n}).Get()\n// 等同于\ndb().Table(\"users\").JoinOn(UserInfo{}, func(wh builder.IJoinOn) {\n    wh.On(\"a.id\", \"b.user_id\").OrOn(\"a.sex\", \"b.sex\")\n}).Get()\n```\n当`Join`的第二个参数为`builder.IJoinOn`时,等同于`JoinOn`用法(第二个参数有强类型提醒,方便ide快捷提示)\n\n## where sub\n```go\n// where id in (select user_id from user_info)\nsub := db().Table(\"user_info\").Select(\"user_id\")\ndb().Table(User{}).Where(\"id\", \"in\", sub).Get()\n```\n- where sub query\n```go\n// where id in (select user_id from user_info)\ndb().Table(User{}).WhereSub(\"id\", \"in\", func(tx *builder.Context) {\n    tx.Table(\"user_info\").Select(\"user_id\")\n}).Get()\n```\n- where sub builder\n```go\n// where id in (select user_id from user_info)\nsub := db().Table(\"user_info\").Select(\"user_id\")\ndb().Table(User{}).WhereBuilder(\"id\", \"in\", sub).Get()\n```\n以上3种用法等同\n\n## where nested\n```go\n// where id\u003e1 and (sex=1 or sex=2)\ndb().Table(User{}).Where(\"id\",\"\u003e\", 1).Where(func(wh builder.IWhere) {\n    wh.Where(\"sex\", 1).OrWhere(\"sex\", 2)\n})\n```\n这里的 Where 等同于 WhereNested\n```go\n// where id\u003e1 and (sex=1 or sex=2)\ndb().Table(User{}).Where(\"id\",\"\u003e\", 1).WhereNested(func(wh builder.IWhere) {\n    wh.Where(\"sex\", 1).OrWhere(\"sex\", 2)\n})\n```\n以上两种用法等同\n\n## 子查询\nTable,Where,Join内都可以用子查询\n```go\nsub := db().Table(\"user\").Where().OrWhere()\nsub2 := db().Table(\"address\").Select(\"user_id\").Where().OrWhere()\nsub3 := db().Table(\"user_info\").Select(\"user_id\").Where().OrWhere()\n```\n用在 Table,Where,Join 内\n```go\ndb().\n    Table(sub, \"a\").\n    Join(gorose.As(sub2, \"b\"), \"a.id\", \"=\", \"b.user_id\")).\n    WhereIn(\"a.id\", sub3).\n    Get()\n```\n用在 Union,UnionAll 内\n```go\ndb().\n    Table(\"users\").\n    Union(sub).\n    Get()\n```\n```go\nvar sub2222 = db().Table(\"user\").Where().OrWhere()\nvar to []User\ndb().\n    Table(\"users\").\n    UnionAll(sub, sub2222).\n    To(\u0026to)\n```\n\n## Pluck\n返回两列数据到一个map中,第一列为value,第二列为key\n```go\n// select id,name from users\ndb().Table(\"users\").Pluck(\"name\", \"id\")\n// 返回 map[\u003cid\u003e]\u003cname\u003e, 实际得到 map[int64]string{1: \"张三\", 2: \"李四\"}\n```\n\n## List\n返回一列数据到一个数组中\n```go\n// select id,name from users\ndb().Table(\"users\").List(\"id\")\n// 返回 []\u003cid\u003e, 实际得到 []int64{1,2,3}\n```\n\n## To 查询结果绑定到对象\n使用结构体字段作为 select 字段  \n使用结构体字段值作为 where 条件  \n查询结果绑定到结构体,支持一条或多条\n```go\n// 查询一条数据\nvar user User\ndb().To(\u0026user)\n\n// 查询条件,一条数据\n// select id,name,email from users where id=1\nvar user = User{Id: 1}\ndb().To(\u0026user)\n\n// 查询多条数据\nvar users []User\ndb().To(\u0026users)\n\n// 查询条件,多条数据\nvar users []User\ndb().Where(\"id\", \"\u003e\", 1).To(\u0026users)\n```\n\n## Bind 查询结果绑定到对象\n仅仅用作查询结果的绑定   \n结构体字段,不作为查询字段和条件  \n常用作join或者手动指定字段查询绑定\n```go\ntype Result struct {\n    Id    int64  `db:\"id\"`\n    Aname string `db:\"aname\"`\n    Bname string `db:\"bname\"`\n}\nvar res Result\n// select a.id, a.name aname, b.name bname from a inner join b on a.id=b.aid where a.id\u003e1\ndb().Table(\"a\").Join(\"b\", \"a.id\",\"b.aid\").Select(\"a.id\", \"a.name aname\",\"b.name bname\").Where(\"a.id\", \"\u003e\", 1).Bind(\u0026res)\n```\n查询字段的显示名字一定要跟 结构体的字段 tag(db) 名字相同, 否则不会被赋值  \n字段数量可以不一样\n\n## ListTo,PluckTo,ValueTo\n```go\nvar list []int\ndb().Table(\"users\").ListTo(\"age\", \u0026list)\nvar pluck map[int64]string\ndb().Table(\"users\").PluckTo(\"name\",\"id\", \u0026pluck)\nvar value int\ndb().Table(\"users\").ValueTo(\"age\", \u0026value)\n```\n## SumTo,MaxTo,MinTo\n```go\nvar sum int\ndb().Table(\"users\").SumTo(\"age\", \u0026sum)\nvar max int\ndb().Table(\"users\").MaxTo(\"age\", \u0026max)\nvar min int\ndb().Table(\"users\").MinTo(\"age\", \u0026min)\n```\n\n## 日志\n默认采用 官方库的 slog debug level, 如果不想显示sql日志, 只需要设置slog的level到debug以上即可, 如: Info, Warn, Error\n\n## 数据库字段为null的处理\n```go\ntype User struct {\n    Id  int64  `db:\"id,pk\"`\n    Sex *int8  `db:\"sex\"` // 使用指针可以绑定 null 值\n    Age sql.NullInt64 `db:\"age\"` // 使用sql.NullInt64 可以绑定 null 值\n}\n```\n指针赋值\n```go\nvar sex = int8(1)\nvar user = User{Id: 1, Sex: \u0026sex}\n// 或者,快捷用法\nvar user = User{Id: 1, Sex: gorose.Ptr(int8(1))}\n```\nsql.Null* 赋值\n```go\nvar age = sql.NullInt64{Int64: 18, Valid: true}\n```\nsql.Null* 使用\n```go\nif age.Valid {\n    fmt.Println(age.Int64)\n}\n```\n由此可见,null处理起来还是有点麻烦,所以,建议在设计表的时候,不要允许null即可,给定默认值,而大部分默认值刚好可以与go的类型零值对应\n\n## 已经支持的 laravel query builder 方法\n- [x] Table  \n- [x] Select  \n- [x] SelectRaw  \n- [x] AddSelect  \n- [x] Join  \n- [x] GroupBy  \n- [x] Having  \n- [x] HavingRaw  \n- [x] OrHaving  \n- [x] OrHavingRaw  \n- [x] OrderBy  \n- [x] Limit  \n- [x] Offset\n\n- [x] Where\n- [x] WhereRaw\n- [x] OrWhere\n- [x] OrWhereRaw\n- [x] WhereBetween\n- [x] OrWhereBetween\n- [x] WhereNotBetween\n- [x] OrWhereNotBetween\n- [x] WhereIn\n- [x] OrWhereIn\n- [x] WhereNotIn\n- [x] OrWhereNotIn\n- [x] WhereNull\n- [x] OrWhereNull\n- [x] WhereNotNull\n- [x] OrWhereNotNull\n- [x] WhereLike\n- [x] OrWhereLike\n- [x] WhereNotLike\n- [x] OrWhereNotLike\n- [x] WhereExists\n- [x] WhereNotExists\n- [x] WhereNot\n\n- [x] Get  \n- [x] First  \n- [x] Find  \n- [x] Insert  \n- [x] Update  \n- [x] Delete  \n- [x] Max  \n- [x] Min  \n- [x] Sum  \n- [x] Avg  \n- [x] Count  \n\n- [x] InsertGetId  \n- [x] Upsert  \n- [x] InsertOrIgnore  \n- [x] Exists\n- [x] DoesntExist\n\n- [x] Pluck  \n- [x] List  \n- [x] Value\n- [x] Paginate\n\n- [x] Increment  \n- [x] Decrement  \n- [x] IncrementEach  \n- [x] DecrementEach  \n- [x] Truncate  \n- [x] Union  \n- [x] UnionAll  \n- [x] SharedLock  \n- [x] LockForUpdate  \n\n## 额外增加的 api\n- [x] Replace\n- [x] Page  \n- [x] LastSql  \n\n- [x] WhereBuilder  \n- [x] OrWhereBuilder  \n- [x] WhereSub  \n- [x] OrWhereSub  \n- [x] WhereNested  \n- [x] OrWhereNested  \n\n- [x] To  \n- [x] Bind  \n- [x] ListTo  \n- [x] PluckTo  \n- [x] ValueTo  \n- [x] SumTo  \n- [x] MaxTo  \n- [x] UnionTo  \n- [x] UnionAllTo  \n\n","funding_links":[],"categories":["开源类库","Go","Repositories","Open source library"],"sub_categories":["数据库","Database"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgohouse%2Fgorose","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgohouse%2Fgorose","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgohouse%2Fgorose/lists"}