{"id":19637850,"url":"https://github.com/n-r-w/squirrel","last_synced_at":"2026-01-16T08:03:00.228Z","repository":{"id":225309427,"uuid":"763164723","full_name":"n-r-w/squirrel","owner":"n-r-w","description":"Fluent SQL generator for Go. Evolution of Masterminds/squirrel","archived":false,"fork":false,"pushed_at":"2026-01-13T22:28:58.000Z","size":389,"stargazers_count":19,"open_issues_count":0,"forks_count":4,"subscribers_count":3,"default_branch":"master","last_synced_at":"2026-01-14T00:47:25.398Z","etag":null,"topics":["builder","go","sql"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/n-r-w.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":"AGENTS.md","dco":null,"cla":null}},"created_at":"2024-02-25T18:11:51.000Z","updated_at":"2026-01-13T22:27:37.000Z","dependencies_parsed_at":"2024-03-12T15:30:26.815Z","dependency_job_id":"d89e300c-045c-4115-ae14-1df36a2567c9","html_url":"https://github.com/n-r-w/squirrel","commit_stats":null,"previous_names":["n-r-w/squirrel"],"tags_count":21,"template":false,"template_full_name":null,"purl":"pkg:github/n-r-w/squirrel","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/n-r-w%2Fsquirrel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/n-r-w%2Fsquirrel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/n-r-w%2Fsquirrel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/n-r-w%2Fsquirrel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/n-r-w","download_url":"https://codeload.github.com/n-r-w/squirrel/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/n-r-w%2Fsquirrel/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28478047,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T06:30:42.265Z","status":"ssl_error","status_checked_at":"2026-01-16T06:30:16.248Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["builder","go","sql"],"created_at":"2024-11-11T12:36:30.651Z","updated_at":"2026-01-16T08:03:00.205Z","avatar_url":"https://github.com/n-r-w.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Go Reference](https://pkg.go.dev/badge/github.com/n-r-w/squirrel.svg)](https://pkg.go.dev/github.com/n-r-w/squirrel)\n[![Go Coverage](https://github.com/n-r-w/squirrel/wiki/coverage.svg)](https://raw.githack.com/wiki/n-r-w/squirrel/coverage.html)\n![CI Status](https://github.com/n-r-w/squirrel/actions/workflows/go.yml/badge.svg)\n[![Stability](http://badges.github.io/stability-badges/dist/stable.svg)](http://github.com/badges/stability-badges)\n[![Go Report](https://goreportcard.com/badge/github.com/n-r-w/squirrel)](https://goreportcard.com/badge/github.com/n-r-w/squirrel)\n\n# Evolution of [github.com/Masterminds/squirrel](https://github.com/Masterminds/squirrel), which unfortunately has not been updated by the author for a long time\n\nContains breaking changes and new features (see below).\n\n# Squirrel - fluent SQL generator for Go\n\n```go\nimport \"github.com/n-r-w/squirrel\"\n```\n\n**Squirrel is not an ORM.**\n\nSquirrel helps you build SQL queries from composable parts:\n\n```go\nimport sq \"github.com/n-r-w/squirrel\"\n\nusers := sq.Select(\"*\").From(\"users\").Join(\"emails USING (email_id)\")\n\nactive := users.Where(sq.Eq{\"deleted_at\": nil})\n\nsql, args, err := active.ToSql()\n\nsql == \"SELECT * FROM users JOIN emails USING (email_id) WHERE deleted_at IS NULL\"\n```\n\n```go\nsql, args, err := sq.\n    Insert(\"users\").Columns(\"name\", \"age\").\n    Values(\"moe\", 13).Values(\"larry\", sq.Expr(\"? + 5\", 12)).\n    ToSql()\n\nsql == \"INSERT INTO users (name,age) VALUES (?,?),(?,? + 5)\"\n```\n\nSquirrel makes conditional query building a breeze:\n\n```go\nif len(q) \u003e 0 {\n    users = users.Where(\"name LIKE ?\", fmt.Sprint(\"%\", q, \"%\"))\n}\n```\n\nSquirrel loves PostgreSQL:\n\n```go\npsql := sq.StatementBuilder.PlaceholderFormat(sq.Dollar)\n\n// You use question marks for placeholders...\nsql, _, _ := psql.Select(\"*\").From(\"elephants\").Where(\"name IN (?,?)\", \"Dumbo\", \"Verna\").ToSql()\n\n/// ...squirrel replaces them using PlaceholderFormat.\nsql == \"SELECT * FROM elephants WHERE name IN ($1,$2)\"\n```\n\nYou can escape question marks by inserting two question marks:\n\n```sql\nSELECT * FROM nodes WHERE meta-\u003e'format' ??| array[?,?]\n```\n\nwill generate with the Dollar Placeholder:\n\n```sql\nSELECT * FROM nodes WHERE meta-\u003e'format' ?| array[$1,$2]\n```\n\n## FAQ\n\n- **How can I build an IN query on composite keys / tuples, e.g. `WHERE (col1, col2) IN ((1,2),(3,4))`?**\n\n    Squirrel does not explicitly support tuples, but you can get the same effect with e.g.:\n\n    ```go\n    sq.Or{\n      sq.Eq{\"col1\": 1, \"col2\": 2},\n      sq.Eq{\"col1\": 3, \"col2\": 4}}\n    ```\n\n    ```sql\n    WHERE (col1 = 1 AND col2 = 2) OR (col1 = 3 AND col2 = 4)\n    ```\n\n    (which should produce the same query plan as the tuple version)\n\n## Breaking changes in comparison to the original [github.com/Masterminds/squirrel](https://github.com/Masterminds/squirrel)\n\n### Removed all database interaction methods. Only query building functions are left\n\nSquirrel is now a pure SQL query builder. For database interaction, use:\n\n- Sqlizer.ToSql() to get the SQL query and arguments.\n- `database/sql`, \u003chttps://github.com/jackc/pgx\u003e, etc. for executing queries.\n- \u003chttps://github.com/georgysavva/scany\u003e for scanning rows into structs.\n\n### Changes in the `Case` method\n\n- To pass an integer value to the `When` and `Else` methods, you need to pass it as an int, not as a string.\n- To pass a string value to the `When` and `Else` methods, you don't need to add quotes.\n\nBefore:\n\n```go\nsq.Case(\"id\").When(1, \"2\").When(2, \"'text'\").Else(\"4\")\n```\n\nAfter:\n\n```go\nsq.Case(\"id\").When(1, 2).When(2, \"text\").Else(4)\n```\n\n## New features\n\n### Subquery support for `WHERE` clause\n\n```go\nSelect(\"id\", \"name\").From(\"users\").Where(Eq{\"id\": Select(\"id\").From(\"other_table\")}).ToSql()\n// SELECT id, name FROM users WHERE id IN (SELECT id1 FROM other_table)\n```\n\n### Support for integer values in `CASE THEN/ELSE` clause\n\n```go\nSelect(\"id\", \"name\").From(\"users\").Where(Case(\"id\").When(1, 2).When(2, 3).Else(4))\n// SELECT id, name FROM users WHERE CASE id WHEN 1 THEN 2 WHEN 2 THEN 3 ELSE 4 END\n```\n\n### Support for aggregate functions `SUM`, `COUNT`, `AVG`, `MIN`, `MAX`\n\n```go\nsq.Sum(subQuery)\n```\n\n### Support for using slice as argument for `Column` function\n\n```go\nColumn(sq.Expr(\"id = ANY(?)\", []int{1,2,3}))\n```\n\n### Support for `IN`, `NOT` and `NOT IN` clause\n\n```go\nIn(\"id\", []int{1, 2, 3}) // id=ANY(ARRAY[1,2,3])\nNotIn(\"id\", subQuery) // id NOT IN (\u003csubQuery\u003e)\n\nNot(Select(\"col\").From(\"table\")) // NOT (SELECT col FROM table)\n// double NOT is removed\nNot(Not(Select(\"col\").From(\"table\"))) // SELECT col FROM table\n```\n\n### Equal, NotEqual, Greater, GreaterOrEqual, Less, LessOrEqual functions\n\n```go\nEqual(Select(\"col\").From(\"table\"), 1) // (SELECT col FROM table) = 1\nNotEqual(Select(\"col\").From(\"table\"), 1) // (SELECT col FROM table) != 1\nGreater(Select(\"col\").From(\"table\"), 1) // (SELECT col FROM table) \u003e 1\nGreaterOrEqual(Select(\"col\").From(\"table\"), 1) // (SELECT col FROM table) \u003e= 1\nLess(Select(\"col\").From(\"table\"), 1) // (SELECT col FROM table) \u003c 1\nLessOrEqual(Select(\"col\").From(\"table\"), 1) // (SELECT col FROM table) \u003c= 1\n```\n\n### Coalesce expression\n\n```go\nCoalesce(\"value\", Select(\"col1\").From(\"table1\"), Select(\"col2\").From(\"table2\"))\n// COALESCE((SELECT col1 FROM table1), (SELECT col2 FROM table2, ?)), args = [\"value\"]\n```\n\n### Range function\n\n```go\nsq.Range(\"id\", 1, 10) // id BETWEEN 1 AND 10\nsq.Range(\"id\", 1, nil) //id \u003e= 1\nsq.Range(\"id\", nil, 10) // id \u003c= 10\n```\n\n### EqNotEmpty function: ignores empty and zero values in Eq map. Useful for filtering\n\n```go\nEqNotEmpty{\"id1\": 1, \"name\": nil, id2: 0, \"desc\": \"\"} // id1 = 1\n```\n\n### OrderByCond function: can be used to avoid hardcoding column names in the code\n\n```go\ncolumns := map[int]string{1: \"id\", 2: \"created\"}\norderConds := []OrderCond{{1, Asc}, {2, Desc}, {1, Desc}} // duplicate should be ignored\n\nSelect(\"id\").From(\"users\").OrderByCond(columns, orderConds)\n// SELECT id FROM users ORDER BY id ASC, created DESC\n```\n\n### Search function\n\nThe search condition is a WHERE clause with LIKE expressions. All columns will be converted to text. Value can be a string or a number.\n\n```go\nSelect(\"id\", \"name\").From(\"users\").Search(\"John\", \"name\", \"email\")\n// SELECT id, name FROM users WHERE (name::text LIKE ? OR email::text LIKE ?)  \n// args = [\"%John%\", \"%John%\"]\n```\n\n### PaginateByID: adds a LIMIT and start from ID condition to the query. WARNING: The columnID must be included in the ORDER BY clause to avoid unexpected results\n\n```go\nSelect(\"id\", \"name\").From(\"users\").PaginateByID(10, 20, \"id\").OrderBy(\"id ASC\")\n// SELECT id, name FROM users WHERE id \u003e ? ORDER BY id ASC LIMIT 10\n// args = [20]\n```\n\n### PaginateByPage: adds a LIMIT and OFFSET to the query. WARNING: The columnID must be included in the ORDER BY clause to avoid unexpected results\n\n```go\nSelect(\"id\", \"name\").From(\"users\").PaginateByPage(10, 3).OrderBy(\"id ASC\")\n// SELECT id, name FROM users ORDER BY id ASC LIMIT 10 OFFSET 20\n```\n\n### Paginate: allows you to use separated Paginator object to paginate the query\n\nIt's useful when you want to use the same Paginator object in different application layers.\nIn following example, SetIDColumn method is used to specify the column name that will be used to paginate the query. If not set, error will be returned. It's required for combination with Paginate and PaginatorByID methods.\n\n```go\nSelect(\"id\", \"name\").From(\"users\").Paginate(PaginatorByID(10, 20)).SetIDColumn(\"id\").OrderBy(\"id ASC\")\n// SELECT id, name FROM users WHERE id \u003e ? ORDER BY id ASC LIMIT 10\n```\n\n```go\nSelect(\"id\", \"name\").From(\"users\").Paginate(PaginatorByPage(10, 3)).OrderBy(\"id ASC\")\n// SELECT id, name FROM users ORDER BY id ASC LIMIT 10 OFFSET 20\n```\n\n### Alias for Select statement: allows to use table alias in the query for multiple columns and add prefix to the column names if needed\n\n```go\nSelect().\nAlias(\"u\").Columns(\"id\", \"name\").\nFrom(\"users u\")\nAlias(\"u\").GroupBy(\"id\", \"name\").\nAlias(\"u\").OrderBy(\"id\").\n// SELECT u.id, u.name FROM users u GROUP BY u.id, u.name ORDER BY u.id\n\nSelect().\nAlias(\"u\", \"pref\").Columns(\"id\", \"name\").\nFrom(\"users u\")\nAlias(\"u\", \"pref\").GroupBy(\"id\", \"name\").\nAlias(\"u\", \"pref\").OrderBy(\"id\").\n// SELECT SELECT u.id AS pref_id, u.name AS pref_name FROM users u GROUP BY u.id AS pref_id, u.name AS pref_name ORDER BY u.id AS pref_id\n```\n\n### CTE support (taken from \u003chttps://github.com/joshring/squirrel\u003e)\n\n```go\nWith(\"alias\").As(\n  Select(\"col1\").From(\"table\"),\n).Select(\n  Select(\"col2\").From(\"alias\"),\n)\n// WITH alias AS (SELECT col1 FROM table) SELECT col2 FROM alias\n\nWithRecursive(\"alias\").As(\n  Select(\"col1\").From(\"table\"),\n).Select(\n  Select(\"col2\").From(\"alias\"),\n)\n// WITH RECURSIVE alias AS (SELECT col1 FROM table) SELECT col2 FROM alias\n```\n\n## Miscellaneous\n\n- Added a linter and fixed all warnings.\n\n## License\n\nSquirrel is released under the\n[MIT License](http://www.opensource.org/licenses/MIT).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fn-r-w%2Fsquirrel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fn-r-w%2Fsquirrel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fn-r-w%2Fsquirrel/lists"}