{"id":13413677,"url":"https://github.com/go-gorp/gorp","last_synced_at":"2025-05-12T13:05:13.375Z","repository":{"id":2159218,"uuid":"3104806","full_name":"go-gorp/gorp","owner":"go-gorp","description":"Go Relational Persistence - an ORM-ish library for Go","archived":false,"fork":false,"pushed_at":"2024-11-19T16:27:48.000Z","size":791,"stargazers_count":3746,"open_issues_count":149,"forks_count":378,"subscribers_count":103,"default_branch":"main","last_synced_at":"2025-05-01T13:48:01.157Z","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/go-gorp.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","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}},"created_at":"2012-01-04T19:50:09.000Z","updated_at":"2025-04-27T12:38:44.000Z","dependencies_parsed_at":"2024-06-18T10:52:58.804Z","dependency_job_id":"f03951d0-9b4f-449e-9c72-885f5e5b9c6e","html_url":"https://github.com/go-gorp/gorp","commit_stats":{"total_commits":408,"total_committers":91,"mean_commits":4.483516483516484,"dds":0.7843137254901961,"last_synced_commit":"2db0f5e22596df067c3d4edf9b2f3e0727cc31ca"},"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/go-gorp%2Fgorp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/go-gorp%2Fgorp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/go-gorp%2Fgorp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/go-gorp%2Fgorp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/go-gorp","download_url":"https://codeload.github.com/go-gorp/gorp/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252134060,"owners_count":21699646,"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-07-30T20:01:46.202Z","updated_at":"2025-05-03T02:34:16.813Z","avatar_url":"https://github.com/go-gorp.png","language":"Go","readme":"# Go Relational Persistence\n\n[![build status](https://github.com/go-gorp/gorp/actions/workflows/go.yml/badge.svg)](https://github.com/go-gorp/gorp/actions)\n[![issues](https://img.shields.io/github/issues/go-gorp/gorp.svg)](https://github.com/go-gorp/gorp/issues)\n[![Go Reference](https://pkg.go.dev/badge/github.com/go-gorp/gorp/v3.svg)](https://pkg.go.dev/github.com/go-gorp/gorp/v3)\n\n### Update 2016-11-13: Future versions\n\nAs many of the maintainers have become busy with other projects,\nprogress toward the ever-elusive v2 has slowed to the point that we're\nonly occasionally making progress outside of merging pull requests.\nIn the interest of continuing to release, I'd like to lean toward a\nmore maintainable path forward.\n\nFor the moment, I am releasing a v2 tag with the current feature set\nfrom master, as some of those features have been actively used and\nrelied on by more than one project.  Our next goal is to continue\ncleaning up the code base with non-breaking changes as much as\npossible, but if/when a breaking change is needed, we'll just release\nnew versions.  This allows us to continue development at whatever pace\nwe're capable of, without delaying the release of features or refusing\nPRs.\n\n## Introduction\n\nI hesitate to call gorp an ORM.  Go doesn't really have objects, at\nleast not in the classic Smalltalk/Java sense.  There goes the \"O\".\ngorp doesn't know anything about the relationships between your\nstructs (at least not yet).  So the \"R\" is questionable too (but I use\nit in the name because, well, it seemed more clever).\n\nThe \"M\" is alive and well.  Given some Go structs and a database, gorp\nshould remove a fair amount of boilerplate busy-work from your code.\n\nI hope that gorp saves you time, minimizes the drudgery of getting\ndata in and out of your database, and helps your code focus on\nalgorithms, not infrastructure.\n\n* Bind struct fields to table columns via API or tag\n* Support for embedded structs\n* Support for transactions\n* Forward engineer db schema from structs (great for unit tests)\n* Pre/post insert/update/delete hooks\n* Automatically generate insert/update/delete statements for a struct\n* Automatic binding of auto increment PKs back to struct after insert\n* Delete by primary key(s)\n* Select by primary key(s)\n* Optional trace sql logging\n* Bind arbitrary SQL queries to a struct\n* Bind slice to SELECT query results without type assertions\n* Use positional or named bind parameters in custom SELECT queries\n* Optional optimistic locking using a version column (for\n  update/deletes)\n\n## Installation\n\nUse `go get` or your favorite vendoring tool, using whichever import\npath you'd like.\n\n## Versioning\n\nWe use semantic version tags.  Feel free to import through `gopkg.in`\n(e.g. `gopkg.in/gorp.v2`) to get the latest tag for a major version,\nor check out the tag using your favorite vendoring tool.\n\nDevelopment is not very active right now, but we have plans to\nrestructure `gorp` as we continue to move toward a more extensible\nsystem.  Whenever a breaking change is needed, the major version will\nbe bumped.\n\nThe `master` branch is where all development is done, and breaking\nchanges may happen from time to time.  That said, if you want to live\non the bleeding edge and are comfortable updating your code when we\nmake a breaking change, you may use `github.com/go-gorp/gorp` as your\nimport path.\n\nCheck the version tags to see what's available.  We'll make a good\nfaith effort to add badges for new versions, but we make no\nguarantees.\n\n## Supported Go versions\n\nThis package is guaranteed to be compatible with the latest 2 major\nversions of Go.\n\nAny earlier versions are only supported on a best effort basis and can\nbe dropped any time.  Go has a great compatibility promise. Upgrading\nyour program to a newer version of Go should never really be a\nproblem.\n\n## Migration guide\n\n#### Pre-v2 to v2\nAutomatic mapping of the version column used in optimistic locking has\nbeen removed as it could cause problems if the type was not int. The\nversion column must now explicitly be set with\n`tablemap.SetVersionCol()`.\n\n## Help/Support\n\nUse our [`gitter` channel](https://gitter.im/go-gorp/gorp).  We used\nto use IRC, but with most of us being pulled in many directions, we\noften need the email notifications from `gitter` to yell at us to sign\nin.\n\n## Quickstart\n\n```go\npackage main\n\nimport (\n    \"database/sql\"\n    \"gopkg.in/gorp.v1\"\n    _ \"github.com/mattn/go-sqlite3\"\n    \"log\"\n    \"time\"\n)\n\nfunc main() {\n    // initialize the DbMap\n    dbmap := initDb()\n    defer dbmap.Db.Close()\n\n    // delete any existing rows\n    err := dbmap.TruncateTables()\n    checkErr(err, \"TruncateTables failed\")\n\n    // create two posts\n    p1 := newPost(\"Go 1.1 released!\", \"Lorem ipsum lorem ipsum\")\n    p2 := newPost(\"Go 1.2 released!\", \"Lorem ipsum lorem ipsum\")\n\n    // insert rows - auto increment PKs will be set properly after the insert\n    err = dbmap.Insert(\u0026p1, \u0026p2)\n    checkErr(err, \"Insert failed\")\n\n    // use convenience SelectInt\n    count, err := dbmap.SelectInt(\"select count(*) from posts\")\n    checkErr(err, \"select count(*) failed\")\n    log.Println(\"Rows after inserting:\", count)\n\n    // update a row\n    p2.Title = \"Go 1.2 is better than ever\"\n    count, err = dbmap.Update(\u0026p2)\n    checkErr(err, \"Update failed\")\n    log.Println(\"Rows updated:\", count)\n\n    // fetch one row - note use of \"post_id\" instead of \"Id\" since column is aliased\n    //\n    // Postgres users should use $1 instead of ? placeholders\n    // See 'Known Issues' below\n    //\n    err = dbmap.SelectOne(\u0026p2, \"select * from posts where post_id=?\", p2.Id)\n    checkErr(err, \"SelectOne failed\")\n    log.Println(\"p2 row:\", p2)\n\n    // fetch all rows\n    var posts []Post\n    _, err = dbmap.Select(\u0026posts, \"select * from posts order by post_id\")\n    checkErr(err, \"Select failed\")\n    log.Println(\"All rows:\")\n    for x, p := range posts {\n        log.Printf(\"    %d: %v\\n\", x, p)\n    }\n\n    // delete row by PK\n    count, err = dbmap.Delete(\u0026p1)\n    checkErr(err, \"Delete failed\")\n    log.Println(\"Rows deleted:\", count)\n\n    // delete row manually via Exec\n    _, err = dbmap.Exec(\"delete from posts where post_id=?\", p2.Id)\n    checkErr(err, \"Exec failed\")\n\n    // confirm count is zero\n    count, err = dbmap.SelectInt(\"select count(*) from posts\")\n    checkErr(err, \"select count(*) failed\")\n    log.Println(\"Row count - should be zero:\", count)\n\n    log.Println(\"Done!\")\n}\n\ntype Post struct {\n    // db tag lets you specify the column name if it differs from the struct field\n    Id      int64  `db:\"post_id\"`\n    Created int64\n    Title   string `db:\",size:50\"`               // Column size set to 50\n    Body    string `db:\"article_body,size:1024\"` // Set both column name and size\n}\n\nfunc newPost(title, body string) Post {\n    return Post{\n        Created: time.Now().UnixNano(),\n        Title:   title,\n        Body:    body,\n    }\n}\n\nfunc initDb() *gorp.DbMap {\n    // connect to db using standard Go database/sql API\n    // use whatever database/sql driver you wish\n    db, err := sql.Open(\"sqlite3\", \"/tmp/post_db.bin\")\n    checkErr(err, \"sql.Open failed\")\n\n    // construct a gorp DbMap\n    dbmap := \u0026gorp.DbMap{Db: db, Dialect: gorp.SqliteDialect{}}\n\n    // add a table, setting the table name to 'posts' and\n    // specifying that the Id property is an auto incrementing PK\n    dbmap.AddTableWithName(Post{}, \"posts\").SetKeys(true, \"Id\")\n\n    // create the table. in a production system you'd generally\n    // use a migration tool, or create the tables via scripts\n    err = dbmap.CreateTablesIfNotExists()\n    checkErr(err, \"Create tables failed\")\n\n    return dbmap\n}\n\nfunc checkErr(err error, msg string) {\n    if err != nil {\n        log.Fatalln(msg, err)\n    }\n}\n```\n\n## Examples\n\n### Mapping structs to tables\n\nFirst define some types:\n\n```go\ntype Invoice struct {\n    Id       int64\n    Created  int64\n    Updated  int64\n    Memo     string\n    PersonId int64\n}\n\ntype Person struct {\n    Id      int64\n    Created int64\n    Updated int64\n    FName   string\n    LName   string\n}\n\n// Example of using tags to alias fields to column names\n// The 'db' value is the column name\n//\n// A hyphen will cause gorp to skip this field, similar to the\n// Go json package.\n//\n// This is equivalent to using the ColMap methods:\n//\n//   table := dbmap.AddTableWithName(Product{}, \"product\")\n//   table.ColMap(\"Id\").Rename(\"product_id\")\n//   table.ColMap(\"Price\").Rename(\"unit_price\")\n//   table.ColMap(\"IgnoreMe\").SetTransient(true)\n//\n// You can optionally declare the field to be a primary key and/or autoincrement\n//\ntype Product struct {\n    Id         int64     `db:\"product_id, primarykey, autoincrement\"`\n    Price      int64     `db:\"unit_price\"`\n    IgnoreMe   string    `db:\"-\"`\n}\n```\n\nThen create a mapper, typically you'd do this one time at app startup:\n\n```go\n// connect to db using standard Go database/sql API\n// use whatever database/sql driver you wish\ndb, err := sql.Open(\"mymysql\", \"tcp:localhost:3306*mydb/myuser/mypassword\")\n\n// construct a gorp DbMap\ndbmap := \u0026gorp.DbMap{Db: db, Dialect: gorp.MySQLDialect{\"InnoDB\", \"UTF8\"}}\n\n// register the structs you wish to use with gorp\n// you can also use the shorter dbmap.AddTable() if you\n// don't want to override the table name\n//\n// SetKeys(true) means we have a auto increment primary key, which\n// will get automatically bound to your struct post-insert\n//\nt1 := dbmap.AddTableWithName(Invoice{}, \"invoice_test\").SetKeys(true, \"Id\")\nt2 := dbmap.AddTableWithName(Person{}, \"person_test\").SetKeys(true, \"Id\")\nt3 := dbmap.AddTableWithName(Product{}, \"product_test\").SetKeys(true, \"Id\")\n```\n\n### Struct Embedding\n\ngorp supports embedding structs.  For example:\n\n```go\ntype Names struct {\n    FirstName string\n    LastName  string\n}\n\ntype WithEmbeddedStruct struct {\n    Id int64\n    Names\n}\n\nes := \u0026WithEmbeddedStruct{-1, Names{FirstName: \"Alice\", LastName: \"Smith\"}}\nerr := dbmap.Insert(es)\n```\n\nSee the `TestWithEmbeddedStruct` function in `gorp_test.go` for a full example.\n\n### Create/Drop Tables ###\n\nAutomatically create / drop registered tables.  This is useful for unit tests\nbut is entirely optional.  You can of course use gorp with tables created manually,\nor with a separate migration tool (like [sql-migrate](https://github.com/rubenv/sql-migrate), [goose](https://bitbucket.org/liamstask/goose) or [migrate](https://github.com/mattes/migrate)).\n\n```go\n// create all registered tables\ndbmap.CreateTables()\n\n// same as above, but uses \"if not exists\" clause to skip tables that are\n// already defined\ndbmap.CreateTablesIfNotExists()\n\n// drop\ndbmap.DropTables()\n```\n\n### SQL Logging\n\nOptionally you can pass in a logger to trace all SQL statements.\nI recommend enabling this initially while you're getting the feel for what\ngorp is doing on your behalf.\n\nGorp defines a `GorpLogger` interface that Go's built in `log.Logger` satisfies.\nHowever, you can write your own `GorpLogger` implementation, or use a package such\nas `glog` if you want more control over how statements are logged.\n\n```go\n// Will log all SQL statements + args as they are run\n// The first arg is a string prefix to prepend to all log messages\ndbmap.TraceOn(\"[gorp]\", log.New(os.Stdout, \"myapp:\", log.Lmicroseconds))\n\n// Turn off tracing\ndbmap.TraceOff()\n```\n\n### Insert\n\n```go\n// Must declare as pointers so optional callback hooks\n// can operate on your data, not copies\ninv1 := \u0026Invoice{0, 100, 200, \"first order\", 0}\ninv2 := \u0026Invoice{0, 100, 200, \"second order\", 0}\n\n// Insert your rows\nerr := dbmap.Insert(inv1, inv2)\n\n// Because we called SetKeys(true) on Invoice, the Id field\n// will be populated after the Insert() automatically\nfmt.Printf(\"inv1.Id=%d  inv2.Id=%d\\n\", inv1.Id, inv2.Id)\n```\n\n### Update\n\nContinuing the above example, use the `Update` method to modify an Invoice:\n\n```go\n// count is the # of rows updated, which should be 1 in this example\ncount, err := dbmap.Update(inv1)\n```\n\n### Delete\n\nIf you have primary key(s) defined for a struct, you can use the `Delete`\nmethod to remove rows:\n\n```go\ncount, err := dbmap.Delete(inv1)\n```\n\n### Select by Key\n\nUse the `Get` method to fetch a single row by primary key.  It returns\nnil if no row is found.\n\n```go\n// fetch Invoice with Id=99\nobj, err := dbmap.Get(Invoice{}, 99)\ninv := obj.(*Invoice)\n```\n\n### Ad Hoc SQL\n\n#### SELECT\n\n`Select()` and `SelectOne()` provide a simple way to bind arbitrary queries to a slice\nor a single struct.\n\n```go\n// Select a slice - first return value is not needed when a slice pointer is passed to Select()\nvar posts []Post\n_, err := dbmap.Select(\u0026posts, \"select * from post order by id\")\n\n// You can also use primitive types\nvar ids []string\n_, err := dbmap.Select(\u0026ids, \"select id from post\")\n\n// Select a single row.\n// Returns an error if no row found, or if more than one row is found\nvar post Post\nerr := dbmap.SelectOne(\u0026post, \"select * from post where id=?\", id)\n```\n\nWant to do joins?  Just write the SQL and the struct. gorp will bind them:\n\n```go\n// Define a type for your join\n// It *must* contain all the columns in your SELECT statement\n//\n// The names here should match the aliased column names you specify\n// in your SQL - no additional binding work required.  simple.\n//\ntype InvoicePersonView struct {\n    InvoiceId   int64\n    PersonId    int64\n    Memo        string\n    FName       string\n}\n\n// Create some rows\np1 := \u0026Person{0, 0, 0, \"bob\", \"smith\"}\nerr = dbmap.Insert(p1)\ncheckErr(err, \"Insert failed\")\n\n// notice how we can wire up p1.Id to the invoice easily\ninv1 := \u0026Invoice{0, 0, 0, \"xmas order\", p1.Id}\nerr = dbmap.Insert(inv1)\ncheckErr(err, \"Insert failed\")\n\n// Run your query\nquery := \"select i.Id InvoiceId, p.Id PersonId, i.Memo, p.FName \" +\n\t\"from invoice_test i, person_test p \" +\n\t\"where i.PersonId = p.Id\"\n\n// pass a slice to Select()\nvar list []InvoicePersonView\n_, err := dbmap.Select(\u0026list, query)\n\n// this should test true\nexpected := InvoicePersonView{inv1.Id, p1.Id, inv1.Memo, p1.FName}\nif reflect.DeepEqual(list[0], expected) {\n    fmt.Println(\"Woot! My join worked!\")\n}\n```\n\n#### SELECT string or int64\n\ngorp provides a few convenience methods for selecting a single string or int64.\n\n```go\n// select single int64 from db (use $1 instead of ? for postgresql)\ni64, err := dbmap.SelectInt(\"select count(*) from foo where blah=?\", blahVal)\n\n// select single string from db:\ns, err := dbmap.SelectStr(\"select name from foo where blah=?\", blahVal)\n\n```\n\n#### Named bind parameters\n\nYou may use a map or struct to bind parameters by name.  This is currently\nonly supported in SELECT queries.\n\n```go\n_, err := dbm.Select(\u0026dest, \"select * from Foo where name = :name and age = :age\", map[string]interface{}{\n  \"name\": \"Rob\",\n  \"age\": 31,\n})\n```\n\n#### UPDATE / DELETE\n\nYou can execute raw SQL if you wish.  Particularly good for batch operations.\n\n```go\nres, err := dbmap.Exec(\"delete from invoice_test where PersonId=?\", 10)\n```\n\n### Transactions\n\nYou can batch operations into a transaction:\n\n```go\nfunc InsertInv(dbmap *DbMap, inv *Invoice, per *Person) error {\n    // Start a new transaction\n    trans, err := dbmap.Begin()\n    if err != nil {\n        return err\n    }\n\n    err = trans.Insert(per)\n    checkErr(err, \"Insert failed\")\n\n    inv.PersonId = per.Id\n    err = trans.Insert(inv)\n    checkErr(err, \"Insert failed\")\n\n    // if the commit is successful, a nil error is returned\n    return trans.Commit()\n}\n```\n\n### Hooks\n\nUse hooks to update data before/after saving to the db. Good for timestamps:\n\n```go\n// implement the PreInsert and PreUpdate hooks\nfunc (i *Invoice) PreInsert(s gorp.SqlExecutor) error {\n    i.Created = time.Now().UnixNano()\n    i.Updated = i.Created\n    return nil\n}\n\nfunc (i *Invoice) PreUpdate(s gorp.SqlExecutor) error {\n    i.Updated = time.Now().UnixNano()\n    return nil\n}\n\n// You can use the SqlExecutor to cascade additional SQL\n// Take care to avoid cycles. gorp won't prevent them.\n//\n// Here's an example of a cascading delete\n//\nfunc (p *Person) PreDelete(s gorp.SqlExecutor) error {\n    query := \"delete from invoice_test where PersonId=?\"\n    \n    _, err := s.Exec(query, p.Id)\n    \n    if err != nil {\n        return err\n    }\n    return nil\n}\n```\n\nFull list of hooks that you can implement:\n\n    PostGet\n    PreInsert\n    PostInsert\n    PreUpdate\n    PostUpdate\n    PreDelete\n    PostDelete\n\n    All have the same signature.  for example:\n\n    func (p *MyStruct) PostUpdate(s gorp.SqlExecutor) error\n\n### Optimistic Locking\n\n#### Note that this behaviour has changed in v2. See [Migration Guide](#migration-guide).\n\ngorp provides a simple optimistic locking feature, similar to Java's\nJPA, that will raise an error if you try to update/delete a row whose\n`version` column has a value different than the one in memory.  This\nprovides a safe way to do \"select then update\" style operations\nwithout explicit read and write locks.\n\n```go\n// Version is an auto-incremented number, managed by gorp\n// If this property is present on your struct, update\n// operations will be constrained\n//\n// For example, say we defined Person as:\n\ntype Person struct {\n    Id       int64\n    Created  int64\n    Updated  int64\n    FName    string\n    LName    string\n\n    // automatically used as the Version col\n    // use table.SetVersionCol(\"columnName\") to map a different\n    // struct field as the version field\n    Version  int64\n}\n\np1 := \u0026Person{0, 0, 0, \"Bob\", \"Smith\", 0}\nerr = dbmap.Insert(p1)  // Version is now 1\ncheckErr(err, \"Insert failed\")\n\nobj, err := dbmap.Get(Person{}, p1.Id)\np2 := obj.(*Person)\np2.LName = \"Edwards\"\n_,err = dbmap.Update(p2)  // Version is now 2\ncheckErr(err, \"Update failed\")\n\np1.LName = \"Howard\"\n\n// Raises error because p1.Version == 1, which is out of date\ncount, err := dbmap.Update(p1)\n_, ok := err.(gorp.OptimisticLockError)\nif ok {\n    // should reach this statement\n\n    // in a real app you might reload the row and retry, or\n    // you might propegate this to the user, depending on the desired\n    // semantics\n    fmt.Printf(\"Tried to update row with stale data: %v\\n\", err)\n} else {\n    // some other db error occurred - log or return up the stack\n    fmt.Printf(\"Unknown db err: %v\\n\", err)\n}\n```\n### Adding INDEX(es) on column(s) beyond the primary key ###\n\nIndexes are frequently critical for performance. Here is how to add\nthem to your tables.\n\nNB: SqlServer and Oracle need testing and possible adjustment to the\nCreateIndexSuffix() and DropIndexSuffix() methods to make AddIndex()\nwork for them.\n\nIn the example below we put an index both on the Id field, and on the\nAcctId field.\n\n```\ntype Account struct {\n\tId      int64\n\tAcctId  string // e.g. this might be a long uuid for portability\n}\n\n// indexType (the 2nd param to AddIndex call) is \"Btree\" or \"Hash\" for MySQL.\n// demonstrate adding a second index on AcctId, and constrain that field to have unique values.\ndbm.AddTable(iptab.Account{}).SetKeys(true, \"Id\").AddIndex(\"AcctIdIndex\", \"Btree\", []string{\"AcctId\"}).SetUnique(true)\n\nerr = dbm.CreateTablesIfNotExists()\ncheckErr(err, \"CreateTablesIfNotExists failed\")\n\nerr = dbm.CreateIndex()\ncheckErr(err, \"CreateIndex failed\")\n\n```\nCheck the effect of the CreateIndex() call in mysql:\n```\n$ mysql\n\nMariaDB [test]\u003e show create table Account;\n+---------+--------------------------+\n| Account | CREATE TABLE `Account` (\n  `Id` bigint(20) NOT NULL AUTO_INCREMENT,\n  `AcctId` varchar(255) DEFAULT NULL,\n  PRIMARY KEY (`Id`),\n  UNIQUE KEY `AcctIdIndex` (`AcctId`) USING BTREE   \u003c\u003c\u003c--- yes! index added.\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 \n+---------+--------------------------+\n\n```\n\n\n## Database Drivers\n\ngorp uses the Go 1 `database/sql` package.  A full list of compliant\ndrivers is available here:\n\nhttp://code.google.com/p/go-wiki/wiki/SQLDrivers\n\nSadly, SQL databases differ on various issues. gorp provides a Dialect\ninterface that should be implemented per database vendor.  Dialects\nare provided for:\n\n* MySQL\n* PostgreSQL\n* sqlite3\n\nEach of these three databases pass the test suite.  See `gorp_test.go`\nfor example DSNs for these three databases.\n\nSupport is also provided for:\n\n* Oracle (contributed by @klaidliadon)\n* SQL Server (contributed by @qrawl) - use driver:\n  github.com/denisenkom/go-mssqldb\n\nNote that these databases are not covered by CI and I (@coopernurse)\nhave no good way to test them locally.  So please try them and send\npatches as needed, but expect a bit more unpredicability.\n\n## Sqlite3 Extensions\n\nIn order to use sqlite3 extensions you need to first register a custom driver:\n\n```go\nimport (\n\t\"database/sql\"\n\n\t// use whatever database/sql driver you wish\n\tsqlite \"github.com/mattn/go-sqlite3\"\n)\n\nfunc customDriver() (*sql.DB, error) {\n\n\t// create custom driver with extensions defined\n\tsql.Register(\"sqlite3-custom\", \u0026sqlite.SQLiteDriver{\n\t\tExtensions: []string{\n\t\t\t\"mod_spatialite\",\n\t\t},\n\t})\n\n\t// now you can then connect using the 'sqlite3-custom' driver instead of 'sqlite3'\n\treturn sql.Open(\"sqlite3-custom\", \"/tmp/post_db.bin\")\n}\n```\n\n## Known Issues\n\n### SQL placeholder portability\n\nDifferent databases use different strings to indicate variable\nplaceholders in prepared SQL statements.  Unlike some database\nabstraction layers (such as JDBC), Go's `database/sql` does not\nstandardize this.\n\nSQL generated by gorp in the `Insert`, `Update`, `Delete`, and `Get`\nmethods delegates to a Dialect implementation for each database, and\nwill generate portable SQL.\n\nRaw SQL strings passed to `Exec`, `Select`, `SelectOne`, `SelectInt`,\netc will not be parsed.  Consequently you may have portability issues\nif you write a query like this:\n\n```go \n// works on MySQL and Sqlite3, but not with Postgresql err :=\ndbmap.SelectOne(\u0026val, \"select * from foo where id = ?\", 30)\n```\n\nIn `Select` and `SelectOne` you can use named parameters to work\naround this.  The following is portable:\n\n```go \nerr := dbmap.SelectOne(\u0026val, \"select * from foo where id = :id\",\nmap[string]interface{} { \"id\": 30})\n```\n\nAdditionally, when using Postgres as your database, you should utilize\n`$1` instead of `?` placeholders as utilizing `?` placeholders when\nquerying Postgres will result in `pq: operator does not exist`\nerrors. Alternatively, use `dbMap.Dialect.BindVar(varIdx)` to get the\nproper variable binding for your dialect.\n\n### time.Time and time zones\n\ngorp will pass `time.Time` fields through to the `database/sql`\ndriver, but note that the behavior of this type varies across database\ndrivers.\n\nMySQL users should be especially cautious.  See:\nhttps://github.com/ziutek/mymysql/pull/77\n\nTo avoid any potential issues with timezone/DST, consider:\n\n- Using an integer field for time data and storing UNIX time.\n- Using a custom time type that implements some SQL types:\n  - [`\"database/sql\".Scanner`](https://golang.org/pkg/database/sql/#Scanner)\n  - [`\"database/sql/driver\".Valuer`](https://golang.org/pkg/database/sql/driver/#Valuer)\n\n## Running the tests\n\nThe included tests may be run against MySQL, Postgresql, or sqlite3.\nYou must set two environment variables so the test code knows which\ndriver to use, and how to connect to your database.\n\n```sh\n# MySQL example:\nexport GORP_TEST_DSN=gomysql_test/gomysql_test/abc123\nexport GORP_TEST_DIALECT=mysql\n\n# run the tests\ngo test\n\n# run the tests and benchmarks\ngo test -bench=\"Bench\" -benchtime 10\n```\n\nValid `GORP_TEST_DIALECT` values are: \"mysql\"(for mymysql),\n\"gomysql\"(for go-sql-driver), \"postgres\", \"sqlite\" See the\n`test_all.sh` script for examples of all 3 databases.  This is the\nscript I run locally to test the library.\n\n## Performance\n\ngorp uses reflection to construct SQL queries and bind parameters.\nSee the BenchmarkNativeCrud vs BenchmarkGorpCrud in gorp_test.go for a\nsimple perf test.  On my MacBook Pro gorp is about 2-3% slower than\nhand written SQL.\n\n\n## Contributors\n\n* matthias-margush - column aliasing via tags\n* Rob Figueiredo - @robfig\n* Quinn Slack - @sqs\n","funding_links":[],"categories":["Misc","Go","ORM","网络相关库","\u003cspan id=\"orm\"\u003eORM\u003c/span\u003e","Relational Databases"],"sub_categories":["HTTP Clients","HTTP客户端","Advanced Console UIs","ORM","\u003cspan id=\"高级控制台用户界面-advanced-console-uis\"\u003e高级控制台用户界面 Advanced Console UIs\u003c/span\u003e","OpenGL","交流"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgo-gorp%2Fgorp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgo-gorp%2Fgorp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgo-gorp%2Fgorp/lists"}