{"id":15642874,"url":"https://github.com/ido50/sqlz","last_synced_at":"2025-05-16T06:04:27.310Z","repository":{"id":22165408,"uuid":"95475741","full_name":"ido50/sqlz","owner":"ido50","description":"SQL Query Builder for Go","archived":false,"fork":false,"pushed_at":"2025-02-28T10:53:50.000Z","size":117,"stargazers_count":62,"open_issues_count":1,"forks_count":29,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-05-16T06:03:53.795Z","etag":null,"topics":["database","go","golang","query-builder","sql","sqlx"],"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/ido50.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"github":["ido50"]}},"created_at":"2017-06-26T18:15:01.000Z","updated_at":"2025-02-28T10:53:54.000Z","dependencies_parsed_at":"2023-12-13T12:28:08.336Z","dependency_job_id":"4b6da9c1-7c45-4f64-a14d-4ed10b31dfc8","html_url":"https://github.com/ido50/sqlz","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ido50%2Fsqlz","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ido50%2Fsqlz/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ido50%2Fsqlz/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ido50%2Fsqlz/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ido50","download_url":"https://codeload.github.com/ido50/sqlz/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254478186,"owners_count":22077675,"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":["database","go","golang","query-builder","sql","sqlx"],"created_at":"2024-10-03T11:57:56.425Z","updated_at":"2025-05-16T06:04:27.287Z","avatar_url":"https://github.com/ido50.png","language":"Go","readme":"\u003ch2 align=\"center\"\u003esqlz\u003c/h2\u003e\n\u003cp align=\"center\"\u003eFlexible SQL query builder for Go\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n\t\u003ca href=\"https://godoc.org/github.com/ido50/sqlz\"\u003e\u003cimg src=\"https://img.shields.io/badge/godoc-reference-blue.svg\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://opensource.org/licenses/Apache-2.0\"\u003e\u003cimg src=\"https://img.shields.io/badge/License-Apache%202.0-blue.svg\"\u003e\u003c/a\u003e\n\t\u003ca href=\"https://goreportcard.com/report/ido50/sqlz\"\u003e\u003cimg src=\"https://goreportcard.com/badge/github.com/ido50/sqlz\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/ido50/sqlz/actions\"\u003e\u003cimg src=\"https://github.com/ido50/sqlz/workflows/build/badge.svg\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n**sqlz** (pronounced \"sequelize\") is an un-opinionated, un-obtrusive SQL query builder for Go projects, based on [sqlx](https://github.com/jmoiron/sqlx/).\n\nAs opposed to other query builders, sqlz does not mean to bridge the gap between different SQL servers and implementations by\nproviding a unified interface. Instead, it aims to support an extended SQL syntax that may be implementation-specific. For\nexample, if you wish to use PostgreSQL-specific features such as JSON operators and upsert statements, sqlz means to support\nthese without caring if the underlying database backend really is PostgreSQL. In other words, sqlz builds whatever queries\nyou want it to build.\n\n**sqlz** is easy to integrate into existing code, as it does not require you to create your database connections through the\n**sqlz** API; in fact, it doesn't supply one. You can either use your existing `*sql.DB` connection or an `*sqlx.DB` connection,\nso you can start writing new queries with sqlz without having to modify any existing code.\n\n**sqlz** leverages **sqlx** for easy loading of query results. Please make sure you are familiar with [how sqlx works](https://jmoiron.github.io/sqlx/)\nin order to understand how row scanning is performed. You may need to add `db` struct tags to your Go structures.\n\n**sqlz** provides a comfortable API for running queries in a transaction, and will automatically commit or rollback the\ntransaction as necessary.\n\n## Install\n\n```go\ngo get -u github.com/ido50/sqlz\n```\n\n## Usage\n\nOnce installed, you can import sqlz into your Go packages. To build and execute queries with\nsqlz, you need to pass the underlying `*sql.DB` or `*sqlx.DB` objects. If using `database/sql`,\nyou'll need to tell sqlz the name of the driver (so that it knows which placeholders to use\nwhen building queries); if using `github.com/jmoiron/sqlx`, this is not necessary.\n\n```go\npackage main\n\nimport (\n    \"fmt\"\n    \"database/sql\"\n    \"github.com/ido50/sqlz\"\n    _ \"sql driver of choice\"\n)\n\nfunc main() {\n    driver := \"postgres\"\n\n    db, err := sql.Open(driver, \"dsn\")\n    if err != nil {\n        panic(err)\n    }\n\n    // find one row in the database and load it\n    // into a struct variable\n    var row someStruct\n    err = sqlz.New(db, driver).  // if using sqlx: sqlz.Newx(dbx)\n        Select(\"*\").\n        From(\"some-table\").\n        Where(sqlz.Eq(\"id\", 1)).\n        GetRow(\u0026row)\n    if err != nil {\n        panic(err)\n    }\n\n    fmt.Printf(\"%+v\\n\", row)\n}\n```\n\n## Examples\n\n### Load one row from a table\n\n```go\nvar row someStruct\nerr = sqlz.New(db, driver).\n    Select(\"*\").\n    From(\"some-table\").\n    Where(Sqlz.Eq(\"id\", 1)).\n    GetRow(\u0026row)\n```\n\nGenerated SQL (disregarding placeholders):\n\n```sql\n   SELECT *\n     FROM some-table\n    WHERE id = 1\n```\n\n### Complex load of many rows with pagination\n\n```go\nvar rows []struct{\n    maxVal int64\n    sumCount uint64\n}\n\nerr = sqlz.New(db, driver).\n     Select(\"MAX(t.col1) maxVal\", \"SUM(t.col2) sumCount\").\n     From(\"some-table t\").\n     LeftJoin(\"other-table o\", sqlz.Eq(\"o.id\", sqlz.Indirect(\"t.id\"))). // there's also RightJoin, InnerJoin, FullJoin\n     GroupBy(\"t.col3\", \"t.col4\").\n     Having(sqlz.Gte(\"maxVal\", 3)).\n     OrderBy(sqlz.Desc(\"maxVal\"), sqlz.Asc(\"sumCount\")).\n     Limit(5).\n     Offset(10).\n     Where(sqlz.Or(sqlz.Eq(\"t.col3\", 5), sqlz.IsNotNull(\"t.col4\"))).\n     GetAll(\u0026rows)\n```\n\nGenerated SQL (disregarding placeholders):\n\n```sql\n        SELECT MAX(t.col1) maxVal, SUM(t.col2) sumCount\n        FROM some-table t\n   LEFT JOIN other-table o ON o.id = t.id\n       WHERE t.col3 = 5 OR t.col4 IS NOT NULL\n    GROUP BY t.col3, t.col4\n      HAVING maxVal \u003e 3\n    ORDER BY maxVal DESC, sumCount ASC\n       LIMIT 5\n      OFFSET 10, 20\n```\n\nWhen paginating results, sqlz provides a nice feature to also calculate the\ntotal number of results matching the query, regardless of limiting and offsets:\n\n```go\nvar rows []struct{\n    maxVal int64\n    sumCount uint64\n}\n\nquery := sqlz.New(db, driver).\n     Select(\"MAX(t.col1) maxVal\", \"SUM(t.col2) sumCount\").\n     // rest of the query as before\ncount, err := query.GetCount() // returns total number of results available, regardless of limits and offsets\nerr = query.GetAll(\u0026rows)      // returns actual results according to limits and offsets\n```\n\n### Simple inserts\n\n```go\nres, err := sqlz.New(db, driver).\n    InsertInto(\"table\").\n    Columns(\"id\", \"name\").\n    Values(1, \"My Name\").\n    Exec()\n\n// res is sql.Result\n```\n\nGenerated SQL:\n\n```sql\nINSERT INTO table (id, name) VALUES (?, ?)\n```\n\n### Inserts with a value map\n\n```go\nres, err := sqlz.New(db, driver).\n    InsertInto(\"table\").\n    ValueMap(map[string]interface{}{\n        \"id\": 1,\n        \"name\": \"My Name\",\n    }).\n    Exec()\n```\n\nGenerates the same SQL as for [simple inserts](#simple-inserts).\n\n### Inserts returning values\n\n```go\nvar id int64\nerr := sqlz.New(db, driver).\n    InsertInto(\"table\").\n    Columns(\"name\").\n    Values(\"My Name\").\n    Returning(\"id\").\n    GetRow(\u0026id)\n```\n\n### Update rows\n\n```go\nres, err := sqlz.New(db, driver).\n    Update(\"table\").\n    Set(\"col1\", \"some-string\").\n    SetMap(map[string]interface{}{\n        \"col2\": true,\n        \"col3\": 5,\n    }).\n    Where(sqlz.Eq(\"id\", 3)).\n    Exec()\n\n```\n\nGenerated SQL:\n\n```sql\n   UPDATE table\n      SET col1 = ?, col2 = ?, col3 = ?\n    WHERE id = ?\n```\n\nUpdates support the RETURNING clause just like inserts.\n\n### Delete rows\n\n```go\nres, err := sqlz.New(db, driver).\n    DeleteFrom(\"table\").\n    Where(sqlz.Eq(\"id\", 3)).\n    Exec()\n```\n\nGenerated SQL:\n\n```sql\n   DELETE FROM table\n         WHERE id = ?\n```\n\n### Easy transactions\n\nsqlz makes it easy to run multiple queries in a transaction, and will automatically rollback or commit as necessary:\n\n```go\nsqlz.\n    New(db, driver).\n    Transactional(func(tx *sqlz.Tx) error {\n        var id int64\n        err := tx.\n            InsertInto(\"table\").\n            Columns(\"name\").\n            Values(\"some guy\").\n            Returning(\"id\").\n            GetRow(\u0026id)\n        if err != nil {\n            return fmt.Errorf(\"failed inserting row: %w\", err)\n        }\n\n        _, err = tx.\n            Update(\"other-table\").\n            Set(\"some-col\", 4).\n            Exec()\n        if err != nil {\n            return fmt.Errorf(\"failed updating row: %w\", err)\n        }\n\n        return nil\n    })\n```\n\nIf the function provided to the `Transactional` method returns an error, the\ntransaction will be rolled back. Otherwise, it will be committed.\n\n### Using strings as-is in queries\n\nIf you need to compare columns, call database functions, modify columns based on their\n(or other's) existing values, and any place you need strings to be used as-is and not\nreplaced with placeholders, use the Indirect function:\n\n - To compare two columns in a WHERE clause, use `sqlz.Eq(\"column-one\", sqlz.Indirect(\"column-two\"))`\n - To increase a column in a SET clause, use `sqlz.Set(\"int-column\", sqlz.Indirect(\"int-column + 1\"))`\n - To set a columm using a database function (e.g. `LOCALTIMESTAMP`), use `sqlz.Set(\"datetime\", sqlz.Indirect(\"LOCALTIMESTAMP\"))`\n\n## Dependencies\n\nThe only non-standard library package used is [jmoiron/sqlx](https://github.com/jmoiron/sqlx).\nThe test suite, however, uses [DATA-DOG/sqlmock](https://github.com/DATA-DOG/sqlmock).\n\n## Acknowledgments\n\nsqlz was inspired by [gocraft/dbr](https://github.com/gocraft/dbr).\n","funding_links":["https://github.com/sponsors/ido50"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fido50%2Fsqlz","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fido50%2Fsqlz","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fido50%2Fsqlz/lists"}