{"id":29215421,"url":"https://github.com/aackerman/rel","last_synced_at":"2025-07-03T00:09:45.088Z","repository":{"id":10493058,"uuid":"12674688","full_name":"aackerman/rel","owner":"aackerman","description":"A SQL AST manager for Go","archived":false,"fork":false,"pushed_at":"2014-05-13T23:32:14.000Z","size":2531,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-06-20T00:32:55.793Z","etag":null,"topics":[],"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/aackerman.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-09-08T02:03:44.000Z","updated_at":"2019-06-05T07:24:03.000Z","dependencies_parsed_at":"2022-09-04T14:01:05.429Z","dependency_job_id":null,"html_url":"https://github.com/aackerman/rel","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/aackerman/rel","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aackerman%2Frel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aackerman%2Frel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aackerman%2Frel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aackerman%2Frel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aackerman","download_url":"https://codeload.github.com/aackerman/rel/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aackerman%2Frel/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263234966,"owners_count":23434922,"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":[],"created_at":"2025-07-03T00:09:44.117Z","updated_at":"2025-07-03T00:09:44.946Z","avatar_url":"https://github.com/aackerman.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Rel [![Build Status](https://travis-ci.org/aackerman/rel.png?branch=master)](https://travis-ci.org/aackerman/rel)\n\nA SQL AST manager for Go.\n\n## Usage\n\n```go\npackage main\n\nimport (\n  \"fmt\"\n  \"rel\"\n)\n\nfunc main() {\n  sql := rel.Select(rel.Star()).From(\"users\").ToSql()\n  fmt.Println(sql) // SELECT * FROM \"users\"\n}\n```\n\n## Where\n\n```go\nusers := rel.NewTable(\"users\")\nusers.Where(users.Attr(\"name\").Eq(rel.Sql(\"amy\")))\n// SELECT * FROM \"users\" WHERE \"users\".\"name\" = \"amy\"\n```\n\n## Joins\n\n```go\nusers := rel.NewTable(\"users\")\npreferences := rel.NewTable(\"preferences\")\nmanager := rel.Select(rel.Star()).From(users).Join(preferences).On(preferences.Attr(\"user_id\").Eq(users.Attr(\"user_id\")))\nfmt.Println(manager.ToSql()) // SELECT * FROM \"users\" INNER JOIN \"preferences\" ON \"preferences\".\"user_id\" = \"users\".\"user_id\"\n```\n\n## Updates\n\n```go\nusers := rel.NewTable(\"users\")\nupdate := rel.NewUpdateManager(rel.RelEngine)\nupdate.Table(users).Set(users.Attr(\"name\"), rel.Sql(\"amy\"))\nfmt.Println(update.ToSql()) // UPDATE \"users\" SET \"name\" = amy\n```\n\n## Deletes\n\n```go\nusers := rel.NewTable(\"users\")\ndelete := rel.NewDeleteManager(rel.RelEngine)\ndelete.From(users).Where(users.Attr(\"id\").Eq(rel.Sql(1)))\nfmt.Println(delete.ToSql()) // DELETE FROM \"users\" WHERE \"id\" = 1\n```\n\n## Inserts\n\n```go\nusers := rel.NewTable(\"users\")\ninsert := rel.Insert().Into(users).Values(users.Attr(\"email\"), Sql(\"a@b.com\"))\nfmt.Println(insert.ToSql()) // INSERT INTO \"users\" (\"email\") VALUES ('a@b.com')\n```\n\n## Orders\n\n```go\nusers := rel.NewTable(\"users\")\nmanager := users.Select(rel.Star()).Order(users.Attr(\"first_name\"))\nfmt.Println(manager.ToSql()) // SELECT * FROM \"users\" ORDER BY \"users\".\"first_name\"\n```\n\n### With Direction\n\n```go\nusers := rel.NewTable(\"users\")\nmanager := users.Select(rel.Star()).Order(users.Attr(\"first_name\").Desc())\nfmt.Println(manager.ToSql()) // SELECT * FROM \"users\" ORDER BY \"users\".\"first_name\" DESC\n```\n\n## Group By\n\n```go\nusers := rel.NewTable(\"users\")\nmanager := users.Select(rel.Star()).GroupBy(users.Attr(\"first_name\"))\nfmt.Println(manager.ToSql()) // SELECT * FROM \"users\" GROUP BY \"users\".\"first_name\"\n```\n\n## Counts\n\n```go\nusers := rel.NewTable(\"users\")\nmanager := users.Select(rel.Count())\nfmt.Println(manager.ToSql()) // SELECT COUNT(1) FROM \"users\"\n```\n\n```go\nusers := rel.NewTable(\"users\")\nmanager := users.Select(users.Attr(\"id\").Count())\nfmt.Println(manager.ToSql()) // SELECT COUNT(\"users\".\"id\") FROM \"users\"\n```\n\n## Database Specific SQL\n\nNearly every RDBMS has it's own quirks and non-standard features. For the most general cases we use the `ToSqlVisitor` to handle compiling the AST to a SQL statement. It's likely that consumers will want to be more specific, for example using PostgreSQL, MySQL, or SQLite.\n\n```go\npackage main\n\nimport (\n  \"fmt\"\n  \"rel\"\n)\n\nfunc main() {\n  rel.RegisterDatabase(\"postgresql\")\n  fmt.Println(rel.Select(rel.Sql(\"*\")).From(\"users\").ToSql()) // SELECT * FROM \"users\"\n}\n```\n\n`rel.RegisterDatabase` is a shorthand to allow easy use of built in functionality for PostgreSQL, MySQL, or SQLite.\n\n## Method Interfaces\n\nSeveral methods in Rel only allow values that satisfy the `Visitable` interface. Rel methods will generally return `Visitable` values. In some cases methods will allow primitive types as method inputs when the type of input is predictable.\n\n```go\nusers := rel.NewTable(\"users\")\nusers.Having(users.Attr(\"id\").Eq(rel.Sql(10)))\n// SELECT FROM \"users\" HAVING \"users\".\"id\" = 10\n```\n\nBreaking down the code here, `users` is a `Table` type. `Table#Having` allows a variadic number of values that satisfy the `Visitable` interface. `users.Attr(\"id\")` returns a pointer to an `AttributeNode` and only accepts a `string`. SQL table fields/attributes can be expressed in terms of strings so an input satifying the `Visitable` interface isn't required because it's only ever necessary to use a string. `AttributeNode#Eq` allows a single `Visitable` type as an input. We use the `Sql` method to wrap an `int` value in a `SqlLiteralNode` to satisfy the `Visitable` interface requirement of `AttributeNode#Eq`.\n\nThe type of input for `AttributeNode#Eq` is somewhat predictable ahead of time. In some cases a user may want to use an `int`, `string`, or another `AttributeNode`. That means using an interface. When an input type is unpredictable, Rel uses the `Visitable` type for input as opposed to an empty interface, and offers the `Sql` method as a way to convert primitive types to a value that will satisfy the `Visitable` interface.\n\n## Author\n\n| [![twitter/_aaronackerman_](http://gravatar.com/avatar/c73ff9c7e654647b2b339d9e08b52143?s=70)](http://twitter.com/_aaronackerman_ \"Follow @_aaronackerman_ on Twitter\") |\n|---|\n| [Aaron Ackerman](https://twitter.com/_aaronackerman_) |\n\n## License\n\n[MIT](https://github.com/aackerman/rel/blob/master/LICENSE.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faackerman%2Frel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faackerman%2Frel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faackerman%2Frel/lists"}