{"id":35672520,"url":"https://github.com/borud/dbx","last_synced_at":"2026-01-05T19:04:50.363Z","repository":{"id":323175494,"uuid":"1092381495","full_name":"borud/dbx","owner":"borud","description":"opinionated database utilities","archived":false,"fork":false,"pushed_at":"2025-11-08T16:16:04.000Z","size":26,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-11-08T16:19:25.849Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/borud.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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-11-08T14:23:24.000Z","updated_at":"2025-11-08T16:16:08.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/borud/dbx","commit_stats":null,"previous_names":["borud/dbx"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/borud/dbx","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/borud%2Fdbx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/borud%2Fdbx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/borud%2Fdbx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/borud%2Fdbx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/borud","download_url":"https://codeload.github.com/borud/dbx/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/borud%2Fdbx/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28218057,"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","status":"online","status_checked_at":"2026-01-05T02:00:06.358Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":[],"created_at":"2026-01-05T19:03:00.194Z","updated_at":"2026-01-05T19:04:50.358Z","avatar_url":"https://github.com/borud.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# DBX - A set of opinionated database utilities\n\nThis library is a somewhat opinionated set of database tools that are useful to me, and perhaps to you.  Its primary job is to make my life a bit easier when using databases the way I prefer to use them.\n\nI mostly use [Jason Moiron's](https://github.com/jmoiron) [sqlx](https://github.com/jmoiron/sqlx) excellent library since it provides me with a good balance between convenience and flexibility.  I'm not fond of ORMs, but I am also not very fond of complicating database operations more than they need to be. The `sqlx` library provides a very good balance I think.\n\n## Open\n\nThe primary tool provided here is for opening databases and applying migrations.  Note that we do not bother with *down* migrations.  We only support *up* migrations.\n\nYou can use this to open databases like so:\n\n```go\nimport (\n    \"github.com/borud/dbx\"\n)\n\ndb, err := dbx.Open(\n    dbx.WithDSN(\":memory:\"),\n    dbx.WithDriver(\"sqlite\"),\n    dbx.WithMigrations(migrationsFS, \"testmigrations\"),\n    dbx.WithMigrationDriver(\"sqlite\", \"sqlite3\",\n        func(db *sql.DB) (database.Driver, error) {\n            return sqlite3.WithInstance(db, \u0026sqlite3.Config{})\n        }),\n )\n```\n\nIn the above example we use an embedded filesystem `migrationsFS` for migrations.  If you want to do migrations from the filesystem you can replace\n\n```go\ndbx.WithMigrations(migrationsFS, \"testmigrations\"),\n```\n\nwith\n\n```go\ndbx.WithMigrations(os.DirFS(\"testmigrations\"), \".\"),\n```\n\nWhich will do the same thing.\n\n### Schema\n\nRather than a fixed single schema file we use migrations.  Typically you would want to put the migration files in a subdir and include them using an embedded filesystem.\n\nIf you look in the tests you have this line:\n\n```go\n//go:embed testmigrations/*.sql\nvar migrationsFS embed.FS\n```\n\nThen in the `testmigrations` subdirectory you have your migration SQL files.  Like `testmigrations/0001_init.up.sql`.\n\n### Pragmas\n\nAdding pragmas can be done using the `WithPragmas` option:\n\n```go\ndbx.WithPragmas([]string{\n    \"PRAGMA foreign_keys = ON\",\n    \"PRAGMA synchronous = NORMAL\",\n    \"PRAGMA secure_delete = OFF\",\n    \"PRAGMA synchronous = NORMAL\",\n    \"PRAGMA temp_store = MEMORY\",\n  }),\n```\n\n### Migration database drivers\n\nThe migration library I use ([github.com/golang-migrate/migrate](github.com/golang-migrate/migrate)) has support for a bunch of databases.  In order to avoid dependency on a particular version of the database libraries involved I have opted to add a `WithMigrationDriver` config option that provides the driver mapping for migrations.  If you are using other databases you have to add the appropriate `WithMigrationDriver` config option for your database(s).\n\nThe import statements you will need for various drivers are some subset of the drivers found under \u003chttps://github.com/golang-migrate/migrate/tree/master/database\u003e:\n\n```go\nimport (\n  mysql \"github.com/golang-migrate/migrate/v4/database/mysql\"\n  pg \"github.com/golang-migrate/migrate/v4/database/postgres\"\n  sqlserver \"github.com/golang-migrate/migrate/v4/database/sqlserver\"\n  sqlite3 \"github.com/golang-migrate/migrate/v4/database/sqlite3\"\n)\n```\n\nHere are some options for various databases.  You can probably figure out how this works for any database the library supports that isn't in an example below:\n\n```go\ndbx.WithMigrationDriver(\"sqlite\", \"sqlite3\",\n   func(db *sql.DB) (database.Driver, error) {\n      return sqlite3.WithInstance(db, \u0026sqlite3.Config{})\n   }),\n\ndbx.WithMigrationDriver(\"sqlite3\", \"sqlite3\",\n   func(db *sql.DB) (database.Driver, error) {\n      return sqlite3.WithInstance(db, \u0026sqlite3.Config{})\n   }),\n\ndbx.WithMigrationDriver(\"postgres\", \"postgres\",\n   func(db *sql.DB) (database.Driver, error) {\n      return pg.WithInstance(db, \u0026pg.Config{})\n   }),\n\ndbx.WithMigrationDriver(\"pgx\", \"postgres\",\n   func(db *sql.DB) (database.Driver, error) {\n      return pg.WithInstance(db, \u0026pg.Config{})\n   }),\n\ndbx.WithMigrationDriver(\"mysql\", \"mysql\",\n   func(db *sql.DB) (database.Driver, error) {\n      return mysql.WithInstance(db, \u0026mysql.Config{})\n   }),\n\ndbx.WithMigrationDriver(\"sqlserver\", \"sqlserver\",\n   func(db *sql.DB) (database.Driver, error) {\n      return sqlserver.WithInstance(db, \u0026sqlserver.Config{})\n   }),\n```\n\n## RowIter\n\nThe `RowsIter` type implements an iterator that we can `range` over.  This is particularly useful when streaming a large result set to a client since we do not need to slurp the entire result set into memory before returning it.\n\nTo stop iteration you just cancel the context.\n\nRowsIter ranges over rows and StructScan's into T, which must be a struct that has the appropriate struct tags for the fields.\n\n```go\n// let's say we have a table that matches this record\ntype record struct {\n    ID   int64  `db:\"id\"`\n    Name string `db:\"name\"`\n}\n\n// then we query the table\nrows, err := db.QueryxContext(ctx, \"SELECT * FROM person\")\nif err != nil {\n    return err\n}\n\n// and then iterate over the rows.  If we get an error we break out of the loop\n// and the `rec` will have the zero value for that type.\nfor rec, err := range dbx.RowsIter[record](ctx, rows) {\n    if err != nil {\n      break // or handle error\n    }\n    doSomethingWith(rec)\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fborud%2Fdbx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fborud%2Fdbx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fborud%2Fdbx/lists"}