{"id":19284941,"url":"https://github.com/orca-zhang/borm","last_synced_at":"2025-04-22T03:32:33.475Z","repository":{"id":47242985,"uuid":"173978778","full_name":"orca-zhang/borm","owner":"orca-zhang","description":"【🔥今日热门】🏎️ 更好的ORM库 (Better ORM library that is simple, fast and self-mockable for Go)","archived":false,"fork":false,"pushed_at":"2022-09-21T12:27:42.000Z","size":182,"stargazers_count":121,"open_issues_count":5,"forks_count":19,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-04-10T10:40:58.866Z","etag":null,"topics":["as-is","borm","crud","fast","golang","gorm","orm","reflect2","self-mockable","simple","sql-like","wygiwys","xorm"],"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/orca-zhang.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}},"created_at":"2019-03-05T16:09:33.000Z","updated_at":"2025-02-18T19:03:32.000Z","dependencies_parsed_at":"2022-08-26T11:10:57.016Z","dependency_job_id":null,"html_url":"https://github.com/orca-zhang/borm","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/orca-zhang%2Fborm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/orca-zhang%2Fborm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/orca-zhang%2Fborm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/orca-zhang%2Fborm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/orca-zhang","download_url":"https://codeload.github.com/orca-zhang/borm/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248943426,"owners_count":21186960,"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":["as-is","borm","crud","fast","golang","gorm","orm","reflect2","self-mockable","simple","sql-like","wygiwys","xorm"],"created_at":"2024-11-09T21:40:59.742Z","updated_at":"2025-04-22T03:32:33.166Z","avatar_url":"https://github.com/orca-zhang.png","language":"Go","readme":"\n# borm\n\n[![license](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat)](https://github.com/orca-zhang/borm/blob/master/LICENSE)\n[![Go Report Card](https://goreportcard.com/badge/github.com/orca-zhang/borm)](https://goreportcard.com/report/github.com/orca-zhang/borm)\n[![Build Status](https://orca-zhang.semaphoreci.com/badges/borm.svg?style=shields)](https://orca-zhang.semaphoreci.com/projects/borm)\n[![codecov](https://codecov.io/gh/orca-zhang/borm/branch/master/graph/badge.svg)](https://codecov.io/gh/orca-zhang/borm)\n[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Forca-zhang%2Fborm.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Forca-zhang%2Fborm?ref=badge_shield)\n\n🏎️ 更好的ORM库 (Better ORM library that is simple, fast and self-mockable for Go)\n\n# 目标\n- 易用：SQL-Like（一把梭：One-Line-CRUD）\n- KISS：保持小而美（不做大而全）\n- 通用：支持struct，pb，map和基本类型\n- 可测：支持自mock（因为参数作返回值，大部分mock框架不支持）\n    - 非测试向的library不是好library\n- As-Is：尽可能不作隐藏设定，防止误用\n- 解决核心痛点：\n   - 手撸SQL难免有错，组装数据太花时间\n   - time.Time无法直接读写的问题\n   - SQL函数结果无法直接Scan\n   - db操作无法方便的Mock\n   - QueryRow的sql.ErrNoRows问题\n   - **直接替换系统自带Scanner，完整接管数据读取的类型转换**\n- 核心原则：\n   - 别像使用其他orm那样把一个表映射到一个model\n   - （在borm里可以用Fields过滤器做到）\n   - 尽量保持简单把一个操作映射一个model吧！\n- 其他优点：\n  - 更自然的where条件（仅在需要加括号时添加，对比gorm）\n  - In操作接受各种类型slice，并且单元素时转成Equal操作\n  - 从其他orm库迁移无需修改历史代码，无侵入性修改\n\n# 特性矩阵\n\n#### 下面是和一些主流orm库的对比（请不吝开issue勘误）\n\n\u003ctable style=\"text-align: center\"\u003e\n   \u003ctr\u003e\n      \u003ctd colspan=\"2\"\u003e库\u003c/td\u003e\n      \u003ctd\u003e\u003ca href=\"https://github.com/orca-zhang/borm\"\u003eborm \u003cstrong\u003e(me)\u003c/strong\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003ctd\u003e\u003ca href=\"https://github.com/jinzhu/gorm\"\u003egorm\u003c/a\u003e\u003c/td\u003e\n      \u003ctd\u003e\u003ca href=\"https://github.com/go-xorm/xorm\"\u003exorm\u003c/a\u003e\u003c/td\u003e\n      \u003ctd\u003e备注\u003c/td\u003e\n   \u003c/tr\u003e\n   \u003ctr\u003e\n      \u003ctd rowspan=\"7\"\u003e易用性\u003c/td\u003e\n      \u003ctd\u003e无需指定类型\u003c/td\u003e\n      \u003ctd\u003e:white_check_mark:\u003c/td\u003e\n      \u003ctd\u003e:x:\u003c/td\u003e\n      \u003ctd\u003e:x:\u003c/td\u003e\n      \u003ctd\u003eborm在tag中无需低频的DDL\u003c/td\u003e\n   \u003c/tr\u003e\n   \u003ctr\u003e\n      \u003ctd\u003e无需指定model\u003c/td\u003e\n      \u003ctd\u003e:white_check_mark:\u003c/td\u003e\n      \u003ctd\u003e:x:\u003c/td\u003e\n      \u003ctd\u003e:x:\u003c/td\u003e\n      \u003ctd\u003egorm/xorm改操作需提供“模版”\u003c/td\u003e\n   \u003c/tr\u003e\n   \u003ctr\u003e\n      \u003ctd\u003e无需指定主键\u003c/td\u003e\n      \u003ctd\u003e:white_check_mark:\u003c/td\u003e\n      \u003ctd\u003e:x:\u003c/td\u003e\n      \u003ctd\u003e:x:\u003c/td\u003e\n      \u003ctd\u003egorm/xorm易误操作，如删/改全表\u003c/td\u003e\n   \u003c/tr\u003e\n   \u003ctr\u003e\n      \u003ctd\u003e学习成本低\u003c/td\u003e\n      \u003ctd\u003e:white_check_mark:\u003c/td\u003e\n      \u003ctd\u003e:x:\u003c/td\u003e\n      \u003ctd\u003e:x:\u003c/td\u003e\n      \u003ctd\u003e会SQL就会用borm\u003c/td\u003e\n   \u003c/tr\u003e\n   \u003ctr\u003e\n      \u003ctd\u003e可复用原生连接\u003c/td\u003e\n      \u003ctd\u003e:white_check_mark:\u003c/td\u003e\n      \u003ctd\u003e:x:\u003c/td\u003e\n      \u003ctd\u003e:x:\u003c/td\u003e\n      \u003ctd\u003eborm重构成本极小\u003c/td\u003e\n   \u003c/tr\u003e\n   \u003ctr\u003e\n      \u003ctd\u003e全类型转换\u003c/td\u003e\n      \u003ctd\u003e:white_check_mark:\u003c/td\u003e\n      \u003ctd\u003emaybe\u003c/td\u003e\n      \u003ctd\u003e:x:\u003c/td\u003e\n      \u003ctd\u003e杜绝类型转换的抛错\u003c/td\u003e\n   \u003c/tr\u003e\n   \u003ctr\u003e\n      \u003ctd\u003e复用查询命令\u003c/td\u003e\n      \u003ctd\u003e:white_check_mark:\u003c/td\u003e\n      \u003ctd\u003e:x:\u003c/td\u003e\n      \u003ctd\u003e:x:\u003c/td\u003e\n      \u003ctd\u003eborm批量和单条使用同一个函数\u003c/td\u003e\n   \u003c/tr\u003e\n   \u003ctr\u003e\n      \u003ctd\u003e可测试性\u003c/td\u003e\n      \u003ctd\u003e自mock\u003c/td\u003e\n      \u003ctd\u003e:white_check_mark:\u003c/td\u003e\n      \u003ctd\u003e:x:\u003c/td\u003e\n      \u003ctd\u003e:x:\u003c/td\u003e\n      \u003ctd\u003eborm非常便于单元测试\u003c/td\u003e\n   \u003c/tr\u003e\n   \u003ctr\u003e\n      \u003ctd rowspan=\"2\"\u003e性能\u003c/td\u003e\n      \u003ctd\u003e较原生耗时\u003c/td\u003e\n      \u003ctd\u003e\u003c=1x\u003c/td\u003e\n      \u003ctd\u003e2~3x\u003c/td\u003e\n      \u003ctd\u003e2~3x\u003c/td\u003e\n      \u003ctd\u003exorm使用prepare模式会再慢2～3x\u003c/td\u003e\n   \u003c/tr\u003e\n   \u003ctr\u003e\n      \u003ctd\u003e反射\u003c/td\u003e\n      \u003ctd\u003e\u003ca href=\"https://github.com/modern-go/reflect2\"\u003ereflect2\u003c/a\u003e\u003c/td\u003e\n      \u003ctd\u003ereflect\u003c/td\u003e\n      \u003ctd\u003ereflect\u003c/td\u003e\n      \u003ctd\u003eborm零使用ValueOf\u003c/td\u003e\n   \u003c/tr\u003e\n\u003c/table\u003e\n\n# 快速入门\n\n1. 引入包\n   ``` golang\n   import b \"github.com/orca-zhang/borm\"\n   ```\n\n2. 定义Table对象\n   ``` golang\n   t := b.Table(d.DB, \"t_usr\")\n\n   t1 := b.Table(d.DB, \"t_usr\", ctx)\n   ```\n\n- `d.DB`是支持Exec/Query/QueryRow的数据库连接对象\n- `t_usr`可以是表名，或者是嵌套查询语句\n- `ctx`是需要传递的Context对象，默认不传为context.Background()\n\n3. （可选）定义model对象\n   ``` golang\n   // Info 默认未设置borm tag的字段不会取\n   type Info struct {\n      ID   int64  `borm:\"id\"`\n      Name string `borm:\"name\"`\n      Tag  string `borm:\"tag\"`\n   }\n\n   // 调用t.UseNameWhenTagEmpty()，可以用未设置borm tag的字段名本身作为待获取的db字段\n   ```\n\n4. 执行操作\n\n- **CRUD接口返回值为 (影响的条数，错误)**\n\n- **类型`V`为`map[string]interface{}`的缩写形式，参考`gin.H`**\n\n- 插入\n   ``` golang\n   // o可以是对象/slice/ptr slice\n   n, err = t.Insert(\u0026o)\n   n, err = t.InsertIgnore(\u0026o)\n   n, err = t.ReplaceInto(\u0026o)\n\n   // 只插入部分字段（其他使用缺省）\n   n, err = t.Insert(\u0026o, b.Fields(\"name\", \"tag\"))\n\n   // 解决主键冲突\n   n, err = t.Insert(\u0026o, b.Fields(\"name\", \"tag\"),\n      b.OnDuplicateKeyUpdate(b.V{\n         \"name\": \"new_name\",\n         \"age\":  b.U(\"age+1\"), // 使用b.U来处理非变量更新\n      }))\n   ```\n\n- 查询\n   ``` golang\n   // o可以是对象/slice/ptr slice\n   n, err := t.Select(\u0026o, \n      b.Where(\"name = ?\", name), \n      b.GroupBy(\"id\"), \n      b.Having(b.Gt(\"id\", 0)), \n      b.OrderBy(\"id\", \"name\"), \n      b.Limit(1))\n\n   // 使用基本类型+Fields获取条目数（n的值为1，因为结果只有1条）\n   var cnt int64\n   n, err = t.Select(\u0026cnt, b.Fields(\"count(1)\"), b.Where(\"name = ?\", name))\n\n   // 还可以支持数组\n   var ids []int64\n   n, err = t.Select(\u0026ids, b.Fields(\"id\"), b.Where(\"name = ?\", name))\n\n   // 可以强制索引\n   n, err = t.Select(\u0026ids, b.Fields(\"id\"), b.ForceIndex(\"idx_xxx\"), b.Where(\"name = ?\", name))\n   ```\n\n- 更新\n   ``` golang\n   // o可以是对象/slice/ptr slice\n   n, err = t.Update(\u0026o, b.Where(b.Eq(\"id\", id)))\n\n   // 使用map更新\n   n, err = t.Update(b.V{\n         \"name\": \"new_name\",\n         \"tag\":  \"tag1,tag2,tag3\",\n         \"age\":  b.U(\"age+1\"), // 使用b.U来处理非变量更新\n      }, b.Where(b.Eq(\"id\", id)), b.Limit(1))\n\n   // 使用map更新部分字段\n   n, err = t.Update(b.V{\n         \"name\": \"new_name\",\n         \"tag\":  \"tag1,tag2,tag3\",\n      }, b.Fields(\"name\"), b.Where(b.Eq(\"id\", id)), b.Limit(1))\n\n   n, err = t.Update(\u0026o, b.Fields(\"name\"), b.Where(b.Eq(\"id\", id)), b.Limit(1))\n   ```\n\n- 删除\n   ``` golang\n   // 根据条件删除\n   n, err = t.Delete(b.Where(\"name = ?\", name))\n\n   // 根据条件删除部分条数\n   n, err = t.Delete(b.Where(b.Eq(\"id\", id)), b.Limit(1))\n   ```\n\n- **可变条件**\n   ``` golang\n   conds := []interface{}{b.Cond(\"1=1\")} // 防止空where条件\n   if name != \"\" {\n      conds = append(conds, b.Eq(\"name\", name))\n   }\n   if id \u003e 0 {\n      conds = append(conds, b.Eq(\"id\", id))\n   }\n   // 执行查询操作\n   n, err := t.Select(\u0026o, b.Where(conds...))\n   ```\n\n- **联表查询**\n   ``` golang\n   type Info struct {\n      ID   int64  `borm:\"t_usr.id\"` // 字段定义加表名\n      Name string `borm:\"t_usr.name\"`\n      Tag  string `borm:\"t_tag.tag\"`\n   }\n   \n   // 方法一\n   t := b.Table(d.DB, \"t_usr join t_tag on t_usr.id=t_tag.id\") // 表名用join语句\n   var o Info\n   n, err := t.Select(\u0026o, b.Where(b.Eq(\"t_usr.id\", id))) // 条件加上表名\n\n   // 方法二\n   t = b.Table(d.DB, \"t_usr\") // 正常表名\n   n, err = t.Select(\u0026o, b.Join(\"join t_tag on t_usr.id=t_tag.id\"), b.Where(b.Eq(\"t_usr.id\", id))) // 条件需要加上表名\n   ```\n\n-  获取插入的自增id\n   ``` golang\n   // 首先需要数据库有一个自增ID的字段\n   type Info struct {\n      BormLastId int64 // 添加一个名为BormLastId的整型字段\n      Name       string `borm:\"name\"`\n      Age        string `borm:\"age\"`\n   }\n\n   o := Info{\n      Name: \"OrcaZ\",\n      Age:  30,\n   }\n   n, err = t.Insert(\u0026o)\n\n   id := o.BormLastId // 获取到插入的id\n   ```\n   \n- 正在使用其他orm框架（新的接口先切过来吧）\n   ``` golang\n   // [gorm] db是一个*gorm.DB\n   t := b.Table(db.DB(), \"tbl\")\n\n   // [xorm] db是一个*xorm.EngineGroup\n   t := b.Table(db.Master().DB().DB, \"tbl\")\n   // or\n   t := b.Table(db.Slave().DB().DB, \"tbl\")\n   ```\n\n# 其他细节\n\n### Table的选项\n\n|选项|说明|\n|-|-|\n|Debug|打印sql语句|\n|Reuse|根据调用位置复用sql和存储方式|\n|UseNameWhenTagEmpty|用未设置borm tag的字段名本身作为待获取的db字段|\n|ToTimestamp|调用Insert时，使用时间戳，而非格式化字符串|\n\n选项使用示例：\n   ``` golang\n   n, err = t.Debug().Insert(\u0026o)\n\n   n, err = t.ToTimestamp().Insert(\u0026o)\n   ```\n\n### Where\n\n|示例|说明|\n|-|-|\n|Where(\"id=? and name=?\", id, name)|常规格式化版本|\n|Where(Eq(\"id\", id), Eq(\"name\", name)...)|默认为and连接|\n|Where(And(Eq(\"x\", x), Eq(\"y\", y), Or(Eq(\"x\", x), Eq(\"y\", y)...)...)|And \u0026 Or|\n\n### 预置Where条件\n\n|名称|示例|说明|\n|-|-|-|\n|逻辑与|And(...)|任意个参数，只接受下方的关系运算子|\n|逻辑或|Or(...)|任意个参数，只接受下方的关系运算子|\n|普通条件|Cond(\"id=?\", id)|参数1为格式化字符串，后面跟占位参数|\n|相等|Eq(\"id\", id)|两个参数，id=?|\n|不相等|Neq(\"id\", id)|两个参数，id\u003c\u003e?|\n|大于|Gt(\"id\", id)|两个参数，id\u003e?|\n|大于等于|Gte(\"id\", id)|两个参数，id\u003e=?|\n|小于|Lt(\"id\", id)|两个参数，id\u003c?|\n|小于等于|Lte(\"id\", id)|两个参数，id\u003c=?|\n|在...之间|Between(\"id\", start, end)|三个参数，在start和end之间|\n|近似|Like(\"name\", \"x%\")|两个参数，name like \"x%\"|\n|多值选择|In(\"id\", ids)|两个参数，ids是基础类型的slice，slice只有1个元素会转化成Eq|\n\n### GroupBy\n\n|示例|说明|\n|-|-|\n|GroupBy(\"id\", \"name\"...)|-|\n\n### Having\n\n|示例|说明|\n|-|-|\n|Having(\"id=? and name=?\", id, name)|常规格式化版本|\n|Having(Eq(\"id\", id), Eq(\"name\", name)...)|默认为and连接|\n|Having(And(Eq(\"x\", x), Eq(\"y\", y), Or(Eq(\"x\", x), Eq(\"y\", y)...)...)|And \u0026 Or|\n\n### OrderBy\n\n|示例|说明|\n|-|-|\n|OrderBy(\"id desc\", \"name asc\"...)|-|\n\n### Limit\n\n|示例|说明|\n|-|-|\n|Limit(1)|分页大小为1|\n|Limit(0, 100)|偏移位置为0，分页大小为100|\n\n### OnDuplicateKeyUpdate\n\n|示例|说明|\n|-|-|\n|OnDuplicateKeyUpdate(V{\"name\": \"new\"})|解决主键冲突的更新|\n\n### ForceIndex\n\n|示例|说明|\n|-|-|\n|ForceIndex(\"idx_biz_id\")|解决索引选择性差的问题|\n\n# 如何mock\n\n### mock步骤：\n- 调用`BormMock`指定需要mock的操作\n- 使用`BormMockFinish`检查是否命中mock\n\n### 说明：\n\n- 前五个参数分别为`tbl`, `fun`, `caller`, `file`, `pkg`\n   - 设置为空默认为匹配\n   - 支持通配符'?'和'*'，分别代表匹配一个字符和多个字符\n   - 不区分大小写\n\n      |参数|名称|说明|\n      |-|-|-|\n      |tbl|表名|数据库的表名|\n      |fun|方法名|Select/Insert/Update/Delete|\n      |caller|调用方方法名|需要带包名|\n      |file|文件名|使用处所在文件路径|\n      |pkg|包名|使用处所在的包名|\n\n- 后三个参数分别为`返回的数据`，`返回的影响条数`和`错误`\n- 只能在测试文件中使用\n\n\n### 使用示例：\n\n待测函数：\n\n```golang\n   package x\n\n   func test(db *sql.DB) (X, int, error) {\n      var o X\n      tbl := b.Table(db, \"tbl\")\n      n, err := tbl.Select(\u0026o, b.Where(\"`id` \u003e= ?\", 1), b.Limit(100))\n      return o, n, err\n   }\n```\n\n在`x.test`方法中查询`tbl`的数据，我们需要mock数据库的操作\n\n``` golang\n   // 必须在_test.go里面设置mock\n   // 注意调用方方法名需要带包名\n   b.BormMock(\"tbl\", \"Select\", \"*.test\", \"\", \"\", \u0026o, 1, nil)\n\n   // 调用被测试函数\n   o1, n1, err := test(db)\n\n   So(err, ShouldBeNil)\n   So(n1, ShouldEqual, 1)\n   So(o1, ShouldResemble, o)\n\n   // 检查是否全部命中\n   err = b.BormMockFinish()\n   So(err, ShouldBeNil)\n```\n\n# 待完成\n\n- Select存储到map\n- Insert从map读\n- Insert/Update支持非指针类型\n- Benchmark报告\n- 事务相关支持\n- 联合查询\n- 匿名组合问题\n- 连接池\n- 读写分离\n\n## 赞助\n\n通过成为赞助商来支持这个项目。 您的logo将显示在此处，并带有指向您网站的链接。 [[成为赞助商](https://opencollective.com/borm#sponsor)]\n\n\u003ca href=\"https://opencollective.com/borm/sponsor/0/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/borm/sponsor/0/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/borm/sponsor/1/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/borm/sponsor/1/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/borm/sponsor/2/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/borm/sponsor/2/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/borm/sponsor/3/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/borm/sponsor/3/avatar.svg\"\u003e\u003c/a\u003e\n\n## 贡献者\n\n这个项目的存在要感谢所有做出贡献的人。\n\n请给我们一个💖star💖来支持我们，谢谢。\n\n并感谢我们所有的支持者！ 🙏\n\n\u003ca href=\"https://opencollective.com/borm/backer/0/website?requireActive=false\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/borm/backer/0/avatar.svg?requireActive=false\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/borm/backer/1/website?requireActive=false\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/borm/backer/1/avatar.svg?requireActive=false\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/borm/backer/2/website?requireActive=false\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/borm/backer/2/avatar.svg?requireActive=false\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/borm/backer/3/website?requireActive=false\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/borm/backer/3/avatar.svg?requireActive=false\"\u003e\u003c/a\u003e\n","funding_links":["https://opencollective.com/borm","https://opencollective.com/borm/backer/0/website?requireActive=false","https://opencollective.com/borm/backer/1/website?requireActive=false","https://opencollective.com/borm/backer/2/website?requireActive=false","https://opencollective.com/borm/backer/3/website?requireActive=false"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Forca-zhang%2Fborm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Forca-zhang%2Fborm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Forca-zhang%2Fborm/lists"}