{"id":16092294,"url":"https://github.com/alecthomas/sequel","last_synced_at":"2025-03-17T17:30:57.272Z","repository":{"id":57489126,"uuid":"147757941","full_name":"alecthomas/sequel","owner":"alecthomas","description":"Sequel - A Go \u003c-\u003e SQL mapping package","archived":false,"fork":false,"pushed_at":"2023-12-02T17:38:40.000Z","size":55,"stargazers_count":25,"open_issues_count":1,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-16T13:11:48.097Z","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":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alecthomas.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2018-09-07T02:11:24.000Z","updated_at":"2025-02-28T03:02:05.000Z","dependencies_parsed_at":"2024-06-20T08:23:53.758Z","dependency_job_id":null,"html_url":"https://github.com/alecthomas/sequel","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alecthomas%2Fsequel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alecthomas%2Fsequel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alecthomas%2Fsequel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alecthomas%2Fsequel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alecthomas","download_url":"https://codeload.github.com/alecthomas/sequel/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244077963,"owners_count":20394382,"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":"2024-10-09T16:06:48.541Z","updated_at":"2025-03-17T17:30:56.961Z","avatar_url":"https://github.com/alecthomas.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Sequel - A Go \u003c-\u003e SQL mapping package (Status: ALPHA)  [![](https://godoc.org/github.com/alecthomas/sequel?status.svg)](http://godoc.org/github.com/alecthomas/sequel) [![CircleCI](https://img.shields.io/circleci/project/github/alecthomas/sequel.svg)](https://circleci.com/gh/alecthomas/sequel)\n\nSequel is similar to SQLx, but with the goal of automating even more of the common\noperations around Go \u003c-\u003e SQL interaction.\n\n## Why?\n\nI wanted a very thin mapping between SQL and Go that provides:\n\n1. `SELECT` into arbitrary `struct`s.\n2. Query parameters populated from arbitrary Go types - structs, slices, etc.\n3. Normalised sequential placeholders across SQL dialects (`?`) (support for positional placeholders will hopefully come later).\n4. Try to be as type safe as possible.\n\nI did not want:\n\n1. A query DSL - I already know SQL.\n2. Migration support - there are much better external tools for this.\n\n## Tutorial / example\n\nOpen a DB connection:\n\n```go\ndb, err := sequel.Open(\"mysql\", \"root@/database\")\n```\n\nInsert some users:\n\n```go\ntype dbUser struct {\n\tID int            `db:\",managed\"`\n    Created time.Time `db:\",managed\"`\n\tName string\n\tEmail string\n}\n\nusers := []dbUser{\n    {Name: \"Moe\", Email: \"moe@stooges.com\"},\n    {Name: \"Larry\", Email: \"larry@stooges.com\"},\n    {Name: \"Curly\", Email: \"curly@stooges.com\"},\n}\n_, err = db.Insert(\"users\", users)\n```\n\nSelecting uses a similar approach:\n\n```go\nusers := []dbUser{}\nerr = db.Select(\u0026users, `\n    SELECT ** FROM users WHERE id IN (\n        SELECT user_id FROM group_members WHERE group_id = ?\n    )\n`, groupID)\n```\n\n## Placeholders\n\nEach placeholder symbol `?` in a query string maps 1:1 to a corresponding argument in the `Select()` or `Exec()` call.\n\nThe placeholder `**` will expand to the set of *unmanaged* fields in your data model. Managed fields are those\nmanaged by the database, such as auto-increment keys, fields with auto-update values, etc. See section \nbelow on \"Dealing with schema changes\" for why this placeholder is useful.\n\nArguments are expanded recursively. Structs map to a parentheses-enclosed, comma-separated list. Slices map to a comma-separated list.\n\nValue                                           | Placeholder | Corresponding expansion\n------------------------------------------------|-------------|-------------------------\n`struct{A, B, C string}{\"A\", \"B\", \"C\"}`         | `?`         | `(?, ?, ?)`\n`[]string{\"A\", \"B\"}`                            | `?`         | `?, ?`\n`[]struct{A, B string}{{\"A\", \"B\"}, {\"C\", \"D\"}}` | `?`         | `(?, ?), (?, ?)`\n`struct{A, B, C string}{\"A\", \"B\", \"C\"}`         | `**`        | `a, b, c`\n\n## Struct tag format\n\nStruct fields may be tagged with `db:\"...\"` to control how Sequel maps fields. The tag has the following\nsyntax:\n\n    db:\"[\u003cname\u003e][,\u003coption\u003e,...]\"\n    \nTo omit a field from mapping use:\n\n    db:\"-\"\n    \nIf a field name is not explicitly provided the lower-snake-case mapping of the Go field name will be used.\neg. `MyIDField` -\u003e `my_id_field`.\n    \nTag option    | Meaning\n--------------|----------------------------------------\n`managed`     | Field is managed by the database. This informs `Insert()` which fields should not be propagated.\n`pk`          | Field is the primary key. `pk` fields will be set after `Insert()`. Auto-increment `pk` fields should also be tagged as `managed`.\n\n## Insert\n\nIt accepts a list of rows (`Insert(table, rows)`), or a vararg \nsequence (`Insert(table, row0, row1, row2)`). Column names are reflected from the first row.\n\n## Upsert\n\n`Upsert()` varargs have the same syntax as `Insert()`, however in addition it requires a list of \ncolumns to use as the unique constraint check.\n\n## Dealing with schema changes\n\nFor minimum disruption, best practice for schema changes (in general, not specifically with Sequel) is\nto write DDL that does not require corresponding DML changes. This means having sane default values for \nnew columns, and the schema change should be applied prior to code deployment. For column removal, \ncode should be modified and deployed prior to schema changes.\n \nSome queries are problematic in the face of column additions, in particular the use of `SELECT *`. \nIf an additional column exists in the schema but does not exist in your model, the result rows will \nfail to deserialise.\n\nThere are two options here. \n\n1. Explicitly list columns in your query.\n2. Use `**`. This automates the approach of explicitly listing column names.\n\n## Examples\n\n### A simple select with parameters populated from a struct\n\n```go\nselector := struct{Name, Email string}{\"Moe\", \"moe@stooges.com\"}\nerr := db.Select(\u0026users, `SELECT * FROM users WHERE (name, email) = ?`, selector)\n```\n\n### A complex multi-row select\n\nFor example, given a query like this:\n\n```sql\nSELECT * FROM users WHERE (name, email) IN\n    (\"Moe\", \"moe@stooges.com\"),\n    (\"Larry\", \"larry@stooges.com\"),\n    (\"Curly\", \"curly@stooges.com\")\n```\n\nSequel allows the equivalent query with dynamic inputs to be expressed like so. First, with the input data:\n\n```go\n// For the purposes of this example this is a static list, but in \"real\" code this would typically be the result\n// of another query, or user-provided.\nmatches := []struct{Name, Email string}{\n    {\"Moe\", \"moe@stooges.com\"},\n    {\"Larry\", \"larry@stooges.com\"},\n    {\"Curly\", \"curly@stooges.com\"},\n}\n```\n\nThe Sequel query to match all rows with those columns is this:\n\n```go\nerr := db.Select(\u0026users, `SELECT * FROM users WHERE (name, email) IN ?`, matches)\n```\n\nWhich is equivalent to the following SQLx code:\n\n```go\nplaceholders := []string{}\nargs := []interface{}\nfor _, match := range matches {\n    placeholders = append(placeholders, \"?\", \"?\")\n    args = append(args, match.Name, match.Email)\n}\nerr := db.Select(\u0026users,\n    ` SELECT * FROM users WHERE email IN (` + strings.Join(placeholders, \",\") + `)`,\n    args...,\n)\n```\n\nOr manually expanded:\n\n```go\nerr := db.Select(\u0026users, `SELECT * FROM users WHERE (name, email) IN (?, ?), (?, ?), (?, ?)`,\n    matches[0].Name, matches[0].Email,\n    matches[1].Name, matches[1].Email,\n    matches[2].Name, matches[2].Email,\n)\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falecthomas%2Fsequel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falecthomas%2Fsequel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falecthomas%2Fsequel/lists"}