{"id":13677189,"url":"https://github.com/mailru/dbr","last_synced_at":"2025-04-06T16:12:37.660Z","repository":{"id":42878990,"uuid":"77594957","full_name":"mailru/dbr","owner":"mailru","description":"Additions to Go's database/sql for super fast performance and convenience. (fork of gocraft/dbr)","archived":false,"fork":false,"pushed_at":"2024-05-13T10:35:29.000Z","size":281,"stargazers_count":180,"open_issues_count":11,"forks_count":36,"subscribers_count":13,"default_branch":"master","last_synced_at":"2025-03-30T14:11:28.411Z","etag":null,"topics":["go","query-builder","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/mailru.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2016-12-29T08:05:40.000Z","updated_at":"2025-03-25T06:07:10.000Z","dependencies_parsed_at":"2024-01-14T14:57:58.222Z","dependency_job_id":"1792d140-fb84-4a21-9402-147ef690f96d","html_url":"https://github.com/mailru/dbr","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mailru%2Fdbr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mailru%2Fdbr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mailru%2Fdbr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mailru%2Fdbr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mailru","download_url":"https://codeload.github.com/mailru/dbr/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247509235,"owners_count":20950232,"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":["go","query-builder","sql"],"created_at":"2024-08-02T13:00:38.429Z","updated_at":"2025-04-06T16:12:37.638Z","avatar_url":"https://github.com/mailru.png","language":"Go","readme":"dbr (fork of gocraft/dbr) provides additions to Go's database/sql for super fast performance and convenience.\n\n[![Build Status](https://travis-ci.org/mailru/dbr.svg?branch=master)](https://travis-ci.org/mailru/dbr)\n[![Go Report Card](https://goreportcard.com/badge/github.com/mailru/dbr)](https://goreportcard.com/report/github.com/mailru/dbr)\n[![Coverage Status](https://coveralls.io/repos/github/mailru/dbr/badge.svg?branch=develop)](https://coveralls.io/github/mailru/dbr?branch=develop)\n\n## Getting Started\n\n```go\n// create a connection (e.g. \"postgres\", \"mysql\", or \"sqlite3\")\nconn, _ := dbr.Open(\"postgres\", \"...\")\n\n// create a session for each business unit of execution (e.g. a web request or goworkers job)\nsess := conn.NewSession(nil)\n\n// get a record\nvar suggestion Suggestion\nsess.Select(\"id\", \"title\").From(\"suggestions\").Where(\"id = ?\", 1).Load(\u0026suggestion)\n\n// JSON-ready, with dbr.Null* types serialized like you want\njson.Marshal(\u0026suggestion)\n```\n\n## Feature highlights\n\n### Use a Sweet Query Builder or use Plain SQL\n\nmailru/dbr supports both.\n\nSweet Query Builder:\n```go\nstmt := dbr.Select(\"title\", \"body\").\n\tFrom(\"suggestions\").\n\tOrderBy(\"id\").\n\tLimit(10)\n```\n\nPlain SQL:\n\n```go\nbuilder := dbr.SelectBySql(\"SELECT `title`, `body` FROM `suggestions` ORDER BY `id` ASC LIMIT 10\")\n```\n\n### Amazing instrumentation with session\n\nAll queries in mailru/dbr are made in the context of a session. This is because when instrumenting your app, it's important to understand which business action the query took place in.\n\nWriting instrumented code is a first-class concern for mailru/dbr. We instrument each query to emit to a EventReceiver interface.\n\n### Faster performance than using database/sql directly\nEvery time you call database/sql's db.Query(\"SELECT ...\") method, under the hood, the mysql driver will create a prepared statement, execute it, and then throw it away. This has a big performance cost.\n\nmailru/dbr doesn't use prepared statements. We ported mysql's query escape functionality directly into our package, which means we interpolate all of those question marks with their arguments before they get to MySQL. The result of this is that it's way faster, and just as secure.\n\nCheck out these [benchmarks](https://github.com/tyler-smith/golang-sql-benchmark).\n\n### IN queries that aren't horrible\nTraditionally, database/sql uses prepared statements, which means each argument in an IN clause needs its own question mark. mailru/dbr, on the other hand, handles interpolation itself so that you can easily use a single question mark paired with a dynamically sized slice.\n```go\nids := []int64{1, 2, 3, 4, 5}\nbuilder.Where(\"id IN ?\", ids) // `id` IN ?\n```\nmap object can be used for IN queries as well.\nNote: interpolation map is slower than slice and it is preferable to use slice when it is possible.\n```go\nids := map[int64]string{1: \"one\", 2: \"two\"}\nbuilder.Where(\"id IN ?\", ids)  // `id` IN ?\n```\n\n### JSON Friendly\nEvery try to JSON-encode a sql.NullString? You get:\n```json\n{\n\t\"str1\": {\n\t\t\"Valid\": true,\n\t\t\"String\": \"Hi!\"\n\t},\n\t\"str2\": {\n\t\t\"Valid\": false,\n\t\t\"String\": \"\"\n  }\n}\n```\n\nNot quite what you want. mailru/dbr has dbr.NullString (and the rest of the Null* types) that encode correctly, giving you:\n\n```json\n{\n\t\"str1\": \"Hi!\",\n\t\"str2\": null\n}\n```\n\n### Inserting multiple records\n\n```go\nsess.InsertInto(\"suggestions\").Columns(\"title\", \"body\").\n  Record(suggestion1).\n  Record(suggestion2)\n```\n\n### Updating records on conflict\n\n```go\nstmt := sess.InsertInto(\"suggestions\").Columns(\"title\", \"body\").Record(suggestion1)\nstmt.OnConflict(\"suggestions_pkey\").Action(\"body\", dbr.Proposed(\"body\"))\n```\n\n\n### Updating records\n\n```go\nsess.Update(\"suggestions\").\n\tSet(\"title\", \"Gopher\").\n\tSet(\"body\", \"I love go.\").\n\tWhere(\"id = ?\", 1)\n```\n\n### Transactions\n\n```go\ntx, err := sess.Begin()\nif err != nil {\n  return err\n}\ndefer tx.RollbackUnlessCommitted()\n\n// do stuff...\n\nreturn tx.Commit()\n```\n\n### Load database values to variables\n\nQuerying is the heart of mailru/dbr.\n\n* Load(\u0026any): load everything!\n* LoadStruct(\u0026oneStruct): load struct\n* LoadStructs(\u0026manyStructs): load a slice of structs\n* LoadValue(\u0026oneValue): load basic type\n* LoadValues(\u0026manyValues): load a slice of basic types\n\n```go\n// columns are mapped by tag then by field\ntype Suggestion struct {\n\tID int64  // id, will be autoloaded by last insert id\n\tTitle string // title\n\tUrl string `db:\"-\"` // ignored\n\tsecret string // ignored\n\tBody dbr.NullString `db:\"content\"` // content\n\tUser User\n}\n\n// By default dbr converts CamelCase property names to snake_case column_names\n// You can override this with struct tags, just like with JSON tags\n// This is especially helpful while migrating from legacy systems\ntype Suggestion struct {\n\tId        int64\n\tTitle     dbr.NullString `db:\"subject\"` // subjects are called titles now\n\tCreatedAt dbr.NullTime\n}\n\nvar suggestions []Suggestion\nsess.Select(\"*\").From(\"suggestions\").Load(\u0026suggestions)\n```\n\n### Join multiple tables\n\ndbr supports many join types:\n\n```go\nsess.Select(\"*\").From(\"suggestions\").\n  Join(\"subdomains\", \"suggestions.subdomain_id = subdomains.id\")\n\nsess.Select(\"*\").From(\"suggestions\").\n  LeftJoin(\"subdomains\", \"suggestions.subdomain_id = subdomains.id\")\n\nsess.Select(\"*\").From(\"suggestions\").\n  RightJoin(\"subdomains\", \"suggestions.subdomain_id = subdomains.id\")\n\nsess.Select(\"*\").From(\"suggestions\").\n  FullJoin(\"subdomains\", \"suggestions.subdomain_id = subdomains.id\")\n```\n\nYou can join on multiple tables:\n\n```go\nsess.Select(\"*\").From(\"suggestions\").\n  Join(\"subdomains\", \"suggestions.subdomain_id = subdomains.id\").\n  Join(\"accounts\", \"subdomains.accounts_id = accounts.id\")\n```\n\n### Quoting/escaping identifiers (e.g. table and column names)\n\n```go\ndbr.I(\"suggestions.id\") // `suggestions`.`id`\n```\n\n### Subquery\n\n```go\nsess.Select(\"count(id)\").From(\n  dbr.Select(\"*\").From(\"suggestions\").As(\"count\"),\n)\n```\n\n### Union\n\n```go\ndbr.Union(\n  dbr.Select(\"*\"),\n  dbr.Select(\"*\"),\n)\n\ndbr.UnionAll(\n  dbr.Select(\"*\"),\n  dbr.Select(\"*\"),\n)\n```\n\nUnion can be used in subquery.\n\n### Alias/AS\n\n* SelectStmt\n\n```go\ndbr.Select(\"*\").From(\"suggestions\").As(\"count\")\n```\n\n* Identity\n\n```go\ndbr.I(\"suggestions\").As(\"s\")\n```\n\n* Union\n\n```go\ndbr.Union(\n  dbr.Select(\"*\"),\n  dbr.Select(\"*\"),\n).As(\"u1\")\n\ndbr.UnionAll(\n  dbr.Select(\"*\"),\n  dbr.Select(\"*\"),\n).As(\"u2\")\n```\n\n### Building arbitrary condition\n\nOne common reason to use this is to prevent string concatenation in a loop.\n\n* And\n* Or\n* Eq\n* Neq\n* Gt\n* Gte\n* Lt\n* Lte\n\n```go\ndbr.And(\n  dbr.Or(\n    dbr.Gt(\"created_at\", \"2015-09-10\"),\n    dbr.Lte(\"created_at\", \"2015-09-11\"),\n  ),\n  dbr.Eq(\"title\", \"hello world\"),\n)\n```\n\n### Built with extensibility\n\nThe core of dbr is interpolation, which can expand `?` with arbitrary SQL. If you need a feature that is not currently supported,\nyou can build it on your own (or use `dbr.Expr`).\n\nTo do that, the value that you wish to be expaned with `?` needs to implement `dbr.Builder`.\n\n```go\ntype Builder interface {\n\tBuild(Dialect, Buffer) error\n}\n```\n\n## Driver support\n\n* MySQL\n* PostgreSQL\n* SQLite3\n* ClickHouse\n\nThese packages were developed by the [engineering team](https://eng.uservoice.com) at [UserVoice](https://www.uservoice.com) and currently power much of its infrastructure and tech stack.\n\n## Thanks \u0026 Authors\nInspiration from these excellent libraries:\n* [sqlx](https://github.com/jmoiron/sqlx) - various useful tools and utils for interacting with database/sql.\n* [Squirrel](https://github.com/lann/squirrel) - simple fluent query builder.\n\nAuthors:\n* Jonathan Novak -- [https://github.com/cypriss](https://github.com/cypriss)\n* Tyler Smith -- [https://github.com/tyler-smith](https://github.com/tyler-smith)\n* Tai-Lin Chu -- [https://github.com/taylorchu](https://github.com/taylorchu)\n* Sponsored by [UserVoice](https://eng.uservoice.com)\n\nContributors:\n* Paul Bergeron -- [https://github.com/dinedal](https://github.com/dinedal) - SQLite dialect\n* Bulat Gaifullin -- [https://github.com/bgaifullin](https://github.com/bgaifullin) - ClickHouse dialect\n","funding_links":[],"categories":["SQL Builders"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmailru%2Fdbr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmailru%2Fdbr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmailru%2Fdbr/lists"}