gorm/params.json
2014-01-28 02:46:54 -08:00

1 line
32 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{"name":"Gorm","tagline":"The fantastic ORM library for Golang, aims to be developer friendly.","body":"# GORM\r\n\r\nThe fantastic ORM library for Golang, aims to be developer friendly.\r\n\r\n## Install\r\n\r\n```\r\ngo get github.com/jinzhu/gorm\r\n```\r\n\r\n## Overview\r\n\r\n* Chainable API\r\n* Relations\r\n* Callbacks (before/after create/save/update/delete/find)\r\n* Soft Deletes\r\n* Auto Migrations\r\n* Transactions\r\n* Logger Support\r\n* Bind struct with tag\r\n* Iteration Support via [Rows](#row--rows)\r\n* Scopes\r\n* sql.Scanner support\r\n* Every feature comes with tests\r\n* Convention Over Configuration\r\n* Developer Friendly\r\n\r\n## Conventions\r\n\r\n* Table name is the plural of struct name's snake case.\r\n Disable pluralization with `db.SingularTable(true)`, or [specify your table name](#specify-table-name)\r\n* Column name is the snake case of field's name.\r\n* Use `Id int64` field as primary key.\r\n* Use tag `sql` to change field's property, change the tag name with `db.SetTagIdentifier(new_name)`.\r\n* Use `CreatedAt` to store record's created time if field exists.\r\n* Use `UpdatedAt` to store record's updated time if field exists.\r\n* Use `DeletedAt` to store record's deleted time if field exists. [Soft Delete](#soft-delete)\r\n* Gorm uses reflection to know which tables to work with:\r\n\r\n```go\r\n// E.g Finding an existing User\r\nvar user User\r\n// Gorm will now know to use table \"users\" (\"user\" if pluralisation has been disabled) for all operations.\r\ndb.First(&user)\r\n\r\n// E.g creating a new User\r\nDB.Save(&User{Name: \"xxx\"}) // table \"users\"\r\n```\r\n\r\n# Getting Started\r\n\r\n```go\r\nimport (\r\n \"database/sql\"\r\n \"time\"\r\n)\r\n\r\ntype User struct {\r\n Id int64\r\n Birthday time.Time\r\n Age int64\r\n Name string `sql:\"size:255\"`\r\n CreatedAt time.Time\r\n UpdatedAt time.Time\r\n DeletedAt time.Time\r\n\r\n Emails []Email // Embedded structs\r\n BillingAddress Address // Embedded struct\r\n BillingAddressId sql.NullInt64 // BillingAddress's foreign key\r\n ShippingAddress Address // Another Embedded struct with same type\r\n ShippingAddressId int64 // ShippingAddress's foreign key\r\n IgnoreMe int64 `sql:\"-\"` // Ignore this field\r\n}\r\n\r\ntype Email struct {\r\n Id int64\r\n UserId int64 // Foreign key for User\r\n Email string `sql:\"type:varchar(100);\"` // Set this field's type\r\n Subscribed bool\r\n}\r\n\r\ntype Address struct {\r\n Id int64\r\n Address1 string `sql:\"not null;unique\"` // Set this field as not nullable and unique in database\r\n Address2 string `sql:\"type:varchar(100);unique\"`\r\n Post sql.NullString `sql:not null`\r\n // FYI, \"NOT NULL\" will only work well with NullXXX Scanner, because golang will initalize a default value for most type...\r\n}\r\n```\r\n\r\n## Opening a Database\r\n\r\n```go\r\n\r\nimport \"github.com/jinzhu/gorm\"\r\nimport _ \"github.com/lib/pq\"\r\n// import _ \"github.com/go-sql-driver/mysql\"\r\n// import _ \"github.com/mattn/go-sqlite3\"\r\n\r\ndb, err := Open(\"postgres\", \"user=gorm dbname=gorm sslmode=disable\")\r\n// db, err = Open(\"mysql\", \"gorm:gorm@/gorm?charset=utf8&parseTime=True\")\r\n// db, err = Open(\"sqlite3\", \"/tmp/gorm.db\")\r\n\r\n// Get database connection handle [*sql.DB](http://golang.org/pkg/database/sql/#DB)\r\nd := db.DB()\r\n\r\n// With it you could use package `database/sql`'s builtin methods\r\ndb.DB().SetMaxIdleConns(10)\r\ndb.DB().SetMaxOpenConns(100)\r\ndb.DB().Ping()\r\n\r\n// By default, table name is plural of struct type, you can use struct type as table name with:\r\ndb.SingularTable(true)\r\n```\r\n\r\nGorm is goroutines friendly, so you can create a global variable to keep the connection and use it everywhere in your project.\r\n```go\r\n// db.go\r\npackage db\r\n\r\nimport (\r\n \"fmt\"\r\n \"github.com/jinzhu/gorm\"\r\n _ \"github.com/lib/pq\"\r\n)\r\n\r\nvar DB gorm.DB\r\nfunc init() {\r\n var err error\r\n DB, err = gorm.Open(\"postgres\", \"user=gorm dbname=gorm sslmode=disable\")\r\n\r\n // Connection string parameters for Postgres - http://godoc.org/github.com/lib/pq, if you are using another\r\n // database refer to the relevant driver's documentation.\r\n\r\n // * dbname - The name of the database to connect to\r\n // * user - The user to sign in as\r\n // * password - The user's password\r\n // * host - The host to connect to. Values that start with / are for unix domain sockets.\r\n // (default is localhost)\r\n // * port - The port to bind to. (default is 5432)\r\n // * sslmode - Whether or not to use SSL (default is require, this is not the default for libpq)\r\n // Valid SSL modes:\r\n // * disable - No SSL\r\n // * require - Always SSL (skip verification)\r\n // * verify-full - Always SSL (require verification)\r\n\r\n if err != nil {\r\n panic(fmt.Sprintf(\"Got error when connect database, the error is '%v'\", err))\r\n }\r\n}\r\n\r\n// user.go\r\npackage user\r\nimport . \"db\"\r\n...\r\nDB.Save(&User{Name: \"xxx\"})\r\n...\r\n```\r\n\r\n## Struct & Database Mapping\r\n\r\n```go\r\n// Create table from struct\r\ndb.CreateTable(User{})\r\n\r\n// Drop table\r\ndb.DropTable(User{})\r\n```\r\n\r\n### Automating Migrations\r\n\r\nFeel free to update your struct, AutoMigrate will keep your database update to date.\r\n\r\nFYI, AutoMigrate will only add new columns, it won't change the current columns' types or delete unused columns, to make sure your data is safe.\r\n\r\nIf the table doesn't exist when AutoMigrate, gorm will run create the table automatically.\r\n(the database first needs to be created manually though...).\r\n\r\n(only postgres and mysql supported)\r\n\r\n```go\r\ndb.AutoMigrate(User{})\r\n```\r\n\r\n# Gorm API\r\n\r\n## Create\r\n\r\n```go\r\nuser := User{Name: \"jinzhu\", Age: 18, Birthday: time.Now()}\r\ndb.Save(&user)\r\n```\r\n\r\n### NewRecord\r\n\r\nReturns true if object hasnt been saved yet (`Id` is blank)\r\n\r\n```go\r\nuser := User{Name: \"jinzhu\", Age: 18, Birthday: time.Now()}\r\ndb.NewRecord(user) // => true\r\n\r\ndb.Save(&user)\r\ndb.NewRecord(user) // => false\r\n```\r\n\r\n### Create With SubStruct\r\n\r\nRefer to [Query With Related](#query-with-related) for how to find associations\r\n\r\n```go\r\nuser := User{\r\n Name: \"jinzhu\",\r\n BillingAddress: Address{Address1: \"Billing Address - Address 1\"},\r\n ShippingAddress: Address{Address1: \"Shipping Address - Address 1\"},\r\n Emails: []Email{{Email: \"jinzhu@example.com\"}, {Email: \"jinzhu-2@example@example.com\"}},\r\n}\r\n\r\ndb.Save(&user)\r\n//// BEGIN TRANSACTION;\r\n//// INSERT INTO \"addresses\" (address1) VALUES (\"Billing Address - Address 1\");\r\n//// INSERT INTO \"addresses\" (address1) VALUES (\"Shipping Address - Address 1\");\r\n//// INSERT INTO \"users\" (name,billing_address_id,shipping_address_id) VALUES (\"jinzhu\", 1, 2);\r\n//// INSERT INTO \"emails\" (user_id,email) VALUES (111, \"jinzhu@example.com\");\r\n//// INSERT INTO \"emails\" (user_id,email) VALUES (111, \"jinzhu-2@example.com\");\r\n//// COMMIT;\r\n```\r\n\r\n## Query\r\n\r\n```go\r\n// Get the first record\r\ndb.First(&user)\r\n//// SELECT * FROM users ORDER BY id LIMIT 1;\r\n// Search table `users` is guessed from struct's type\r\n\r\n// Get the last record\r\ndb.Last(&user)\r\n//// SELECT * FROM users ORDER BY id DESC LIMIT 1;\r\n\r\n// Get All records\r\ndb.Find(&users)\r\n//// SELECT * FROM users;\r\n\r\n// Get record with primary key\r\ndb.First(&user, 10)\r\n//// SELECT * FROM users WHERE id = 10;\r\n```\r\n\r\n### Query With Where (SQL)\r\n\r\n```go\r\n// Get the first matched record\r\ndb.Where(\"name = ?\", \"jinzhu\").First(&user)\r\n//// SELECT * FROM users WHERE name = 'jinzhu' limit 1;\r\n\r\n// Get all matched records\r\ndb.Where(\"name = ?\", \"jinzhu\").Find(&users)\r\n//// SELECT * FROM users WHERE name = 'jinzhu';\r\n\r\ndb.Where(\"name <> ?\", \"jinzhu\").Find(&users)\r\n//// SELECT * FROM users WHERE name <> 'jinzhu';\r\n\r\n// IN\r\ndb.Where(\"name in (?)\", []string{\"jinzhu\", \"jinzhu 2\"}).Find(&users)\r\n//// SELECT * FROM users WHERE name IN ('jinzhu', 'jinzhu 2');\r\n\r\n// LIKE\r\ndb.Where(\"name LIKE ?\", \"%jin%\").Find(&users)\r\n//// SELECT * FROM users WHERE name LIKE \"%jin%\";\r\n\r\n// Multiple Conditions\r\ndb.Where(\"name = ? and age >= ?\", \"jinzhu\", \"22\").Find(&users)\r\n//// SELECT * FROM users WHERE name = 'jinzhu' AND age >= 22;\r\n```\r\n\r\n### Query With Where (Struct & Map)\r\n\r\n```go\r\n// Search with struct\r\ndb.Where(&User{Name: \"jinzhu\", Age: 20}).First(&user)\r\n//// SELECT * FROM users WHERE name = \"jinzhu\" AND age = 20 LIMIT 1;\r\n\r\n// Search with map\r\ndb.Where(map[string]interface{}{\"name\": \"jinzhu\", \"age\": 20}).Find(&users)\r\n//// SELECT * FROM users WHERE name = \"jinzhu\" AND age = 20;\r\n\r\n// IN for primary Keys\r\ndb.Where([]int64{20, 21, 22}).Find(&users)\r\n//// SELECT * FROM users WHERE id IN (20, 21, 22);\r\n```\r\n\r\n### Query With Not\r\n\r\n```go\r\n// Attribute Not Equal\r\ndb.Not(\"name\", \"jinzhu\").First(&user)\r\n//// SELECT * FROM users WHERE name <> \"jinzhu\" LIMIT 1;\r\n\r\n// Not In\r\ndb.Not(\"name\", []string{\"jinzhu\", \"jinzhu 2\"}).Find(&users)\r\n//// SELECT * FROM users WHERE name NOT IN (\"jinzhu\", \"jinzhu 2\");\r\n\r\n// Not In for primary keys\r\ndb.Not([]int64{1,2,3}).First(&user)\r\n//// SELECT * FROM users WHERE id NOT IN (1,2,3);\r\n\r\ndb.Not([]int64{}).First(&user)\r\n//// SELECT * FROM users;\r\n\r\n// SQL string\r\ndb.Not(\"name = ?\", \"jinzhu\").First(&user)\r\n//// SELECT * FROM users WHERE NOT(name = \"jinzhu\");\r\n\r\n// Not with struct\r\ndb.Not(User{Name: \"jinzhu\"}).First(&user)\r\n//// SELECT * FROM users WHERE name <> \"jinzhu\";\r\n```\r\n\r\n### Query With Inline Condition\r\n\r\n```go\r\n// Find with primary key\r\ndb.First(&user, 23)\r\n//// SELECT * FROM users WHERE id = 23 LIMIT 1;\r\n\r\n// SQL string\r\ndb.Find(&user, \"name = ?\", \"jinzhu\")\r\n//// SELECT * FROM users WHERE name = \"jinzhu\";\r\n\r\n// Multiple Conditions\r\ndb.Find(&users, \"name <> ? and age > ?\", \"jinzhu\", 20)\r\n//// SELECT * FROM users WHERE name <> \"jinzhu\" AND age > 20;\r\n\r\n// Inline search with struct\r\ndb.Find(&users, User{Age: 20})\r\n//// SELECT * FROM users WHERE age = 20;\r\n\r\n// Inline search with map\r\ndb.Find(&users, map[string]interface{}{\"age\": 20})\r\n//// SELECT * FROM users WHERE age = 20;\r\n```\r\n\r\n### Query With Or\r\n\r\n```go\r\ndb.Where(\"role = ?\", \"admin\").Or(\"role = ?\", \"super_admin\").Find(&users)\r\n//// SELECT * FROM users WHERE role = 'admin' OR role = 'super_admin';\r\n\r\n// Or With Struct\r\ndb.Where(\"name = 'jinzhu'\").Or(User{Name: \"jinzhu 2\"}).Find(&users)\r\n//// SELECT * FROM users WHERE name = 'jinzhu' OR name = 'jinzhu 2';\r\n\r\n// Or With Map\r\ndb.Where(\"name = 'jinzhu'\").Or(map[string]interface{}{\"name\": \"jinzhu 2\"}).Find(&users)\r\n```\r\n\r\n### Query With Related\r\n\r\n```go\r\n// Find user's emails with guessed foreign key\r\ndb.Model(&user).Related(&emails)\r\n//// SELECT * FROM emails WHERE user_id = 111;\r\n\r\n// Find user's billing address with specified foreign key 'BillingAddressId'\r\ndb.Model(&user).Related(&address1, \"BillingAddressId\")\r\n//// SELECT * FROM addresses WHERE id = 123; // 123 is user's BillingAddressId\r\n\r\n// Find user with guessed primary key value from email\r\ndb.Model(&email).Related(&user)\r\n//// SELECT * FROM users WHERE id = 111; // 111 is email's UserId\r\n```\r\n\r\n### Query Chains\r\n\r\nGorm has a chainable API, so you could query like this\r\n\r\n```go\r\ndb.Where(\"name <> ?\",\"jinzhu\").Where(\"age >= ? and role <> ?\",20,\"admin\").Find(&users)\r\n//// SELECT * FROM users WHERE name <> 'jinzhu' AND age >= 20 AND role <> 'admin';\r\n\r\ndb.Where(\"role = ?\", \"admin\").Or(\"role = ?\", \"super_admin\").Not(\"name = ?\", \"jinzhu\").Find(&users)\r\n```\r\n\r\n## Update\r\n\r\n### Update an existing struct\r\n\r\n```go\r\nuser.Name = \"jinzhu 2\"\r\nuser.Age = 100\r\ndb.Save(&user)\r\n//// UPDATE users SET name='jinzhu 2', age=100, updated_at = '2013-11-17 21:34:10' WHERE id=111;\r\n```\r\n\r\n### Update one attribute with `Update`\r\n\r\n```go\r\n// Update existing user's name if it is changed\r\ndb.Model(&user).Update(\"name\", \"hello\")\r\n//// UPDATE users SET name='hello', updated_at = '2013-11-17 21:34:10' WHERE id=111;\r\n\r\n// Find out a user, and update the name if it is changed\r\ndb.First(&user, 111).Update(\"name\", \"hello\")\r\n//// SELECT * FROM users LIMIT 1;\r\n//// UPDATE users SET name='hello', updated_at = '2013-11-17 21:34:10' WHERE id=111;\r\n\r\n// Update name with search condiation and specified table name\r\ndb.Table(\"users\").Where(10).Update(\"name\", \"hello\")\r\n//// UPDATE users SET name='hello' WHERE id = 10;\r\n```\r\n\r\n### Update multiple attributes with `Updates`\r\n\r\n```go\r\n// Update user's name and age if they are changed\r\ndb.Model(&user).Updates(User{Name: \"hello\", Age: 18})\r\n//// UPDATE users SET name='hello', age=18, updated_at = '2013-11-17 21:34:10' WHERE id = 111;\r\n\r\n// Updates with Map\r\ndb.Table(\"users\").Where(10).Updates(map[string]interface{}{\"name\": \"hello\", \"age\": 18})\r\n//// UPDATE users SET name='hello', age=18 WHERE id = 10;\r\n\r\n// Updates with Struct\r\ndb.Model(User{}).Updates(User{Name: \"hello\", Age: 18})\r\n//// UPDATE users SET name='hello', age=18;\r\n```\r\n\r\n### Update attributes without callbacks\r\n\r\n```go\r\ndb.Model(&user).UpdateColumn(\"name\", \"hello\")\r\n//// UPDATE users SET name='hello' WHERE id = 111;\r\n\r\ndb.Model(&user).UpdateColumns(User{Name: \"hello\", Age: 18})\r\n//// UPDATE users SET name='hello', age=18 WHERE id = 111;\r\n```\r\n\r\n## Delete\r\n\r\n### Delete an existing struct\r\n\r\n```go\r\ndb.Delete(&email)\r\n// DELETE from emails where id=10;\r\n```\r\n\r\n### Batch Delete with search\r\n\r\n```go\r\ndb.Where(\"email LIKE ?\", \"%jinzhu%\").Delete(Email{})\r\n// DELETE from emails where email LIKE \"%jinhu%\";\r\n```\r\n\r\n### Soft Delete\r\n\r\nIf a struct has a DeletedAt field, it will get soft delete ability automatically!\r\n\r\nStructs that don't have a DeletedAt field will be deleted from the database permanently\r\n\r\n```go\r\ndb.Delete(&user)\r\n//// UPDATE users SET deleted_at=\"2013-10-29 10:23\" WHERE id = 111;\r\n\r\n// Delete with search condition\r\ndb.Where(\"age = ?\", 20).Delete(&User{})\r\n//// UPDATE users SET deleted_at=\"2013-10-29 10:23\" WHERE age = 20;\r\n\r\n// Soft deleted records will be ignored when searched\r\ndb.Where(\"age = 20\").Find(&user)\r\n//// SELECT * FROM users WHERE age = 100 AND (deleted_at IS NULL AND deleted_at <= '0001-01-02');\r\n\r\n// Find soft deleted records with Unscoped\r\ndb.Unscoped().Where(\"age = 20\").Find(&users)\r\n//// SELECT * FROM users WHERE age = 20;\r\n\r\n// Delete record permanently with Unscoped\r\ndb.Unscoped().Delete(&order)\r\n// DELETE FROM orders WHERE id=10;\r\n```\r\n\r\n## FirstOrInit\r\n\r\nTry to get the first record, if failed, will initialize the struct with search conditions.\r\n\r\n(only supports search conditions map and struct)\r\n\r\n```go\r\ndb.FirstOrInit(&user, User{Name: \"non_existing\"})\r\n//// User{Name: \"non_existing\"}\r\n\r\ndb.Where(User{Name: \"Jinzhu\"}).FirstOrInit(&user)\r\n//// User{Id: 111, Name: \"Jinzhu\", Age: 20}\r\n\r\ndb.FirstOrInit(&user, map[string]interface{}{\"name\": \"jinzhu\"})\r\n//// User{Id: 111, Name: \"Jinzhu\", Age: 20}\r\n```\r\n\r\n### FirstOrInit With Attrs\r\n\r\nIgnore Attrs's arguments when searching, but use them to initialize the struct if no record is found.\r\n\r\n```go\r\ndb.Where(User{Name: \"non_existing\"}).Attrs(User{Age: 20}).FirstOrInit(&user)\r\n//// SELECT * FROM USERS WHERE name = 'non_existing';\r\n//// User{Name: \"non_existing\", Age: 20}\r\n\r\n// Or write it like this if has only one attribute\r\ndb.Where(User{Name: \"noexisting_user\"}).Attrs(\"age\", 20).FirstOrInit(&user)\r\n\r\n// If a record found, Attrs would be ignored\r\ndb.Where(User{Name: \"Jinzhu\"}).Attrs(User{Age: 30}).FirstOrInit(&user)\r\n//// SELECT * FROM USERS WHERE name = jinzhu';\r\n//// User{Id: 111, Name: \"Jinzhu\", Age: 20}\r\n```\r\n\r\n### FirstOrInit With Assign\r\n\r\nIgnore Assign's arguments when searching, but use them to fill the struct regardless, whether the record is found or not.\r\n\r\n```go\r\ndb.Where(User{Name: \"non_existing\"}).Assign(User{Age: 20}).FirstOrInit(&user)\r\n//// User{Name: \"non_existing\", Age: 20}\r\n\r\ndb.Where(User{Name: \"Jinzhu\"}).Assign(User{Age: 30}).FirstOrInit(&user)\r\n//// User{Id: 111, Name: \"Jinzhu\", Age: 30}\r\n```\r\n\r\n## FirstOrCreate\r\n\r\nTry to get the first record, if failed, will initialize the struct with the search conditions and insert it in the database.\r\n\r\n```go\r\ndb.FirstOrCreate(&user, User{Name: \"non_existing\"})\r\n//// User{Id: 112, Name: \"non_existing\"}\r\n\r\ndb.Where(User{Name: \"Jinzhu\"}).FirstOrCreate(&user)\r\n//// User{Id: 111, Name: \"Jinzhu\"}\r\n\r\ndb.FirstOrCreate(&user, map[string]interface{}{\"name\": \"jinzhu\", \"age\": 30})\r\n//// user -> User{Id: 111, Name: \"jinzhu\", Age: 20}\r\n```\r\n\r\n### FirstOrCreate With Attrs\r\n\r\nIgnore Attrs's arguments when searching, but use them to initialize the struct if no record is found.\r\n\r\n```go\r\ndb.Where(User{Name: \"non_existing\"}).Attrs(User{Age: 20}).FirstOrCreate(&user)\r\n//// SELECT * FROM users WHERE name = 'non_existing';\r\n//// User{Id: 112, Name: \"non_existing\", Age: 20}\r\n\r\ndb.Where(User{Name: \"jinzhu\"}).Attrs(User{Age: 30}).FirstOrCreate(&user)\r\n//// User{Id: 111, Name: \"jinzhu\", Age: 20}\r\n```\r\n\r\n### FirstOrCreate With Assign\r\n\r\nIgnore Assign's arguments when searching, but use them to fill the struct regardless, whether the record is found or not, then save it back to the database.\r\n\r\n```go\r\ndb.Where(User{Name: \"non_existing\"}).Assign(User{Age: 20}).FirstOrCreate(&user)\r\n//// user -> User{Id: 112, Name: \"non_existing\", Age: 20}\r\n\r\ndb.Where(User{Name: \"jinzhu\"}).Assign(User{Age: 30}).FirstOrCreate(&user)\r\n//// SELECT * FROM users WHERE name = 'jinzhu';\r\n//// UPDATE users SET age=30 WHERE id = 111;\r\n//// User{Id: 111, Name: \"jinzhu\", Age: 30}\r\n```\r\n\r\n## Select\r\n\r\n```go\r\ndb.Select(\"name, age\").Find(&users)\r\n//// SELECT name, age FROM users;\r\n```\r\n\r\n## Order\r\n\r\n```go\r\ndb.Order(\"age desc, name\").Find(&users)\r\n//// SELECT * FROM users ORDER BY age desc, name;\r\n\r\n// Multiple orders\r\ndb.Order(\"age desc\").Order(\"name\").Find(&users)\r\n//// SELECT * FROM users ORDER BY age desc, name;\r\n\r\n// ReOrder\r\ndb.Order(\"age desc\").Find(&users1).Order(\"age\", true).Find(&users2)\r\n//// SELECT * FROM users ORDER BY age desc; (users1)\r\n//// SELECT * FROM users ORDER BY age; (users2)\r\n```\r\n\r\n## Limit\r\n\r\n```go\r\ndb.Limit(3).Find(&users)\r\n//// SELECT * FROM users LIMIT 3;\r\n\r\n// Remove limit with -1\r\ndb.Limit(10).Find(&users1).Limit(-1).Find(&users2)\r\n//// SELECT * FROM users LIMIT 10; (users1)\r\n//// SELECT * FROM users; (users2)\r\n```\r\n\r\n## Offset\r\n\r\n```go\r\ndb.Offset(3).Find(&users)\r\n//// SELECT * FROM users OFFSET 3;\r\n\r\n// Remove offset with -1\r\ndb.Offset(10).Find(&users1).Offset(-1).Find(&users2)\r\n//// SELECT * FROM users OFFSET 10; (users1)\r\n//// SELECT * FROM users; (users2)\r\n```\r\n\r\n## Count\r\n\r\n```go\r\ndb.Where(\"name = ?\", \"jinzhu\").Or(\"name = ?\", \"jinzhu 2\").Find(&users).Count(&count)\r\n//// SELECT * from USERS WHERE name = 'jinzhu' OR name = 'jinzhu 2'; (users)\r\n//// SELECT count(*) FROM users WHERE name = 'jinzhu' OR name = 'jinzhu 2'; (count)\r\n\r\n// Set table name with Model\r\ndb.Model(User{}).Where(\"name = ?\", \"jinzhu\").Count(&count)\r\n//// SELECT count(*) FROM users WHERE name = 'jinzhu' OR name = 'jinzhu 2'; (count)\r\n\r\n// Set table name with Table\r\ndb.Table(\"deleted_users\").Count(&count)\r\n//// SELECT count(*) FROM deleted_users;\r\n```\r\n\r\n## Pluck\r\n\r\nGet struct's selected attributes as a map\r\n\r\n```go\r\nvar ages []int64\r\ndb.Find(&users).Pluck(\"age\", &ages)\r\n\r\n// Set Table With Model\r\nvar names []string\r\ndb.Model(&User{}).Pluck(\"name\", &names)\r\n//// SELECT name FROM users;\r\n\r\n// Set Table With Table\r\ndb.Table(\"deleted_users\").Pluck(\"name\", &names)\r\n//// SELECT name FROM deleted_users;\r\n\r\n// Plucking more than one column? Do it like this:\r\ndb.Select(\"name, age\").Find(&users)\r\n```\r\n\r\n## Transactions\r\nAll individual save and delete operations are run in a transaction by default.\r\n\r\n```go\r\ntx := db.Begin()\r\n\r\nuser := User{Name: \"transcation\"}\r\n\r\ntx.Save(&u)\r\ntx.Update(\"age\": 90)\r\n// do whatever\r\n\r\n// rollback\r\ntx.Rollback()\r\n\r\n// commit\r\ntx.Commit()\r\n```\r\n\r\n## Callbacks\r\n\r\nCallbacks are methods defined on the struct's pointer.\r\nIf any callback returns an error, gorm will stop future operations and rollback all changes.\r\n\r\nHere is a list of all available callbacks,\r\nlisted in the same order in which they will get called during the respective operations.\r\n\r\n### Creating an Object\r\n\r\n```go\r\nBeforeSave\r\nBeforeCreate\r\n// save before associations\r\n// save self\r\n// save after associations\r\nAfterCreate\r\nAfterSave\r\n```\r\n### Updating an Object\r\n\r\n```go\r\nBeforeSave\r\nBeforeUpdate\r\n// save before associations\r\n// save self\r\n// save after associations\r\nAfterUpdate\r\nAfterSave\r\n```\r\n\r\n### Destroying an Object\r\n\r\n```go\r\nBeforeDelete\r\n// delete self\r\nAfterDelete\r\n```\r\n\r\n### After Find\r\n\r\n```go\r\n// load record/records from database\r\nAfterFind\r\n```\r\n\r\nHere is an example:\r\n\r\n```go\r\nfunc (u *User) BeforeUpdate() (err error) {\r\n if u.readonly() {\r\n err = errors.New(\"Read Only User!\")\r\n }\r\n return\r\n}\r\n\r\n// Rollback the insertion if there are more than 1000 users (hypothetical example)\r\nfunc (u *User) AfterCreate() (err error) {\r\n if (u.Id > 1000) { // Just as an example, don't use Id to count users!\r\n err = errors.New(\"Only 1000 users allowed!\")\r\n }\r\n return\r\n}\r\n```\r\n\r\n```go\r\n// As you know, the save/delete operations are running in a transaction\r\n// This is means that all your changes will be rolled back if there are any errors\r\n// If you want your changes in callbacks be run in the same transaction\r\n// you have to pass the transaction as argument to the function\r\nfunc (u *User) AfterCreate(tx *gorm.DB) (err error) {\r\n tx.Model(u).Update(\"role\", \"admin\")\r\n return\r\n}\r\n```\r\n\r\n## Specifying the Table Name\r\n\r\n```go\r\n// Create `deleted_users` table with User's fields\r\ndb.Table(\"deleted_users\").CreateTable(&User{})\r\n\r\n// Search from table `deleted_users`\r\nvar deleted_users []User\r\ndb.Table(\"deleted_users\").Find(&deleted_users)\r\n//// SELECT * FROM deleted_users;\r\n\r\n// Delete results from table `deleted_users` with search conditions\r\ndb.Table(\"deleted_users\").Where(\"name = ?\", \"jinzhu\").Delete()\r\n//// DELETE FROM deleted_users WHERE name = 'jinzhu';\r\n```\r\n\r\n### Specifying the Table Name for Struct permanently with TableName\r\n\r\n```go\r\ntype Cart struct {\r\n}\r\n\r\nfunc (c Cart) TableName() string {\r\n return \"shopping_cart\"\r\n}\r\n\r\nfunc (u User) TableName() string {\r\n if u.Role == \"admin\" {\r\n return \"admin_users\"\r\n } else {\r\n return \"users\"\r\n }\r\n}\r\n```\r\n\r\n## Scopes\r\n\r\n```go\r\nfunc AmountGreaterThan1000(d *gorm.DB) *gorm.DB {\r\n d.Where(\"amount > ?\", 1000)\r\n}\r\n\r\nfunc PaidWithCreditCard(d *gorm.DB) *gorm.DB {\r\n d.Where(\"pay_mode_sign = ?\", \"C\")\r\n}\r\n\r\nfunc PaidWithCod(d *gorm.DB) *gorm.DB {\r\n d.Where(\"pay_mode_sign = ?\", \"C\")\r\n}\r\n\r\nfunc OrderStatus(status []string) func (d *gorm.DB) *gorm.DB {\r\n return func (d *gorm.DB) *gorm.DB {\r\n return d.Scopes(AmountGreaterThan1000).Where(\"status in (?)\", status)\r\n }\r\n}\r\n\r\ndb.Scopes(AmountGreaterThan1000, PaidWithCreditCard).Find(&orders)\r\n// Find all credit card orders and amount greater than 1000\r\n\r\ndb.Scopes(AmountGreaterThan1000, PaidWithCod).Find(&orders)\r\n// Find all COD orders and amount greater than 1000\r\n\r\ndb.Scopes(OrderStatus([]string{\"paid\", \"shipped\"})).Find(&orders)\r\n// Find all paid, shipped orders and amount greater than 1000\r\n```\r\n\r\n## Logger\r\n\r\nGorm has built-in logger support, enable it with:\r\n\r\n```go\r\ndb.LogMode(true)\r\n```\r\n\r\n![logger](https://raw.github.com/jinzhu/gorm/master/images/logger.png)\r\n\r\n```go\r\n// Use your own logger\r\n// Refer to gorm's default logger for how to format messages: https://github.com/jinzhu/gorm/blob/master/logger.go#files\r\ndb.SetLogger(log.New(os.Stdout, \"\\r\\n\", 0))\r\n\r\n// If you want to use gorm's default log format, then you could just do it like this\r\ndb.SetLogger(gorm.Logger{revel.TRACE})\r\n\r\n// Disable logging\r\ndb.LogMode(false)\r\n\r\n// Enable logging for a single operation, to make debugging easy\r\ndb.Debug().Where(\"name = ?\", \"jinzhu\").First(&User{})\r\n```\r\n\r\n## Row & Rows\r\n\r\nRow & Rows is not chainable, it works just like `QueryRow` and `Query`\r\n\r\n```go\r\nrow := db.Table(\"users\").Where(\"name = ?\", \"jinzhu\").select(\"name, age\").Row() // (*sql.Row)\r\nrow.Scan(&name, &age)\r\n\r\nrows, err := db.Model(User{}).Where(\"name = ?\", \"jinzhu\").select(\"name, age, email\").Rows() // (*sql.Rows, error)\r\ndefer rows.Close()\r\nfor rows.Next() {\r\n ...\r\n rows.Scan(&name, &age, &email)\r\n ...\r\n}\r\n\r\n// Rows() with raw sql\r\nrows, err := db.Raw(\"select name, age, email from users where name = ?\", \"jinzhu\").Rows() // (*sql.Rows, error)\r\ndefer rows.Close()\r\nfor rows.Next() {\r\n ...\r\n rows.Scan(&name, &age, &email)\r\n ...\r\n}\r\n```\r\n\r\n## Scan\r\n\r\nScan sql results into strcut\r\n\r\n```go\r\ntype Result struct {\r\n\tName string\r\n\tAge int\r\n}\r\n\r\nvar result Result\r\ndb.Table(\"users\").Select(\"name, age\").Where(\"name = ?\", 3).Scan(&result)\r\n\r\n// Scan raw sql\r\ndb.Raw(\"SELECT name, age FROM users WHERE name = ?\", 3).Scan(&result)\r\n```\r\n\r\n## Group & Having\r\n\r\n```go\r\nrows, err := db.Table(\"orders\").Select(\"date(created_at) as date, sum(amount) as total\").Group(\"date(created_at)\").Rows()\r\nfor rows.Next() {\r\n ...\r\n}\r\n\r\nrows, err := db.Table(\"orders\").Select(\"date(created_at) as date, sum(amount) as total\").Group(\"date(created_at)\").Having(\"sum(amount) > ?\", 100).Rows()\r\nfor rows.Next() {\r\n ...\r\n}\r\n\r\ntype Result struct {\r\n\tDate time.Time\r\n\tTotal int64\r\n}\r\ndb.Table(\"orders\").Select(\"date(created_at) as date, sum(amount) as total\").Group(\"date(created_at)\").Having(\"sum(amount) > ?\", 100).Scan(&results)\r\n```\r\n\r\n## Joins\r\n\r\n```go\r\nrows, err := db.Table(\"users\").Select(\"users.name, emails.email\").Joins(\"left join emails on emails.user_id = users.id\").Rows()\r\nfor rows.Next() {\r\n ...\r\n}\r\n\r\ndb.Table(\"users\").Select(\"users.name, emails.email\").Joins(\"left join emails on emails.user_id = users.id\").Scan(&results)\r\n```\r\n\r\n## Run Raw SQL\r\n\r\n```go\r\n// Raw SQL\r\ndb.Exec(\"DROP TABLE users;\")\r\n\r\n// Raw SQL with arguments\r\ndb.Exec(\"UPDATE orders SET shipped_at=? WHERE id IN (?)\", time.Now, []int64{11,22,33})\r\n```\r\n\r\n## Error Handling\r\n\r\n```go\r\nquery := db.Where(\"name = ?\", \"jinzhu\").First(&user)\r\nquery := db.First(&user).Limit(10).Find(&users)\r\n//// query.Error returns the last error\r\n//// query.Errors returns all errors that have taken place\r\n//// If an error has taken place, gorm will stop all following operations\r\n\r\n// I often use some code like below to do error handling when writing applications\r\nif err := db.Where(\"name = ?\", \"jinzhu\").First(&user).Error; err != nil {\r\n // ...\r\n}\r\n\r\n// If no record is found, gorm will return RecordNotFound error, you could check it with\r\ndb.Where(\"name = ?\", \"hello world\").First(&User{}).Error == gorm.RecordNotFound\r\n\r\n// Or use shortcut method\r\nif db.Where(\"name = ?\", \"hello world\").First(&user).RecordNotFound() {\r\n panic(\"no record found\")\r\n} else {\r\n user.Blalala()\r\n}\r\n\r\nif db.Model(&user).Related(&credit_card).RecordNotFound() {\r\n panic(\"no credit card found\")\r\n}\r\n```\r\n\r\n## Advanced Usage With Query Chaining\r\n\r\nAlready excited with what gorm has to offer? Let's see some magic!\r\n\r\n```go\r\ndb.First(&first_article).Count(&total_count).Limit(10).Find(&first_page_articles).Offset(10).Find(&second_page_articles)\r\n//// SELECT * FROM articles LIMIT 1; (first_article)\r\n//// SELECT count(*) FROM articles; (total_count)\r\n//// SELECT * FROM articles LIMIT 10; (first_page_articles)\r\n//// SELECT * FROM articles LIMIT 10 OFFSET 10; (second_page_articles)\r\n\r\n\r\n// Mix where conditions with inline conditions\r\ndb.Where(\"created_at > ?\", \"2013-10-10\").Find(&cancelled_orders, \"state = ?\", \"cancelled\").Find(&shipped_orders, \"state = ?\", \"shipped\")\r\n//// SELECT * FROM orders WHERE created_at > '2013/10/10' AND state = 'cancelled'; (cancelled_orders)\r\n//// SELECT * FROM orders WHERE created_at > '2013/10/10' AND state = 'shipped'; (shipped_orders)\r\n\r\n\r\n// Use variables to keep query chain\r\ntodays_orders := db.Where(\"created_at > ?\", \"2013-10-29\")\r\ncancelled_orders := todays_orders.Where(\"state = ?\", \"cancelled\")\r\nshipped_orders := todays_orders.Where(\"state = ?\", \"shipped\")\r\n\r\n\r\n// Search with shared conditions from different tables\r\ndb.Where(\"product_name = ?\", \"fancy_product\").Find(&orders).Find(&shopping_carts)\r\n//// SELECT * FROM orders WHERE product_name = 'fancy_product'; (orders)\r\n//// SELECT * FROM carts WHERE product_name = 'fancy_product'; (shopping_carts)\r\n\r\n\r\n// Search with shared conditions from different tables with specified table\r\ndb.Where(\"mail_type = ?\", \"TEXT\").Find(&users1).Table(\"deleted_users\").Find(&users2)\r\n//// SELECT * FROM users WHERE mail_type = 'TEXT'; (users1)\r\n//// SELECT * FROM deleted_users WHERE mail_type = 'TEXT'; (users2)\r\n\r\n\r\n// An example on how to use FirstOrCreate\r\ndb.Where(\"email = ?\", \"x@example.org\").Attrs(User{RegisteredIp: \"111.111.111.111\"}).FirstOrCreate(&user)\r\n//// SELECT * FROM users WHERE email = 'x@example.org';\r\n//// INSERT INTO \"users\" (email,registered_ip) VALUES (\"x@example.org\", \"111.111.111.111\") // if no record found\r\n```\r\n\r\n## TODO\r\n* Support plugin\r\n BeforeQuery\r\n BeforeSave\r\n BeforeCreate\r\n BeforeUpdate\r\n BeforeDelete\r\n AfterQuery\r\n AfterSave\r\n AfterCreate\r\n AfterUpdate\r\n SoftDelete\r\n BeforeQuery\r\n BeforeSave\r\n BeforeDelete\r\n\r\n db.RegisterPlugin(\"xxx\")\r\n db.RegisterCallback(\"BeforeQuery\", func() {})\r\n db.RegisterCallback(\"BeforeSave\", func() {})\r\n db.RegisterFuncation(\"Search\", func() {})\r\n db.Model(&[]User{}).Limit(10).Do(\"Search\", \"vip\", \"china\")\r\n db.Mode(&User{}).Do(\"EditForm\").Get(\"edit_form_html\")\r\n\r\n DefaultValue, DefaultTimeZone, R/W Splitting, Validation\r\n* Getter/Setter\r\n share or not? transaction?\r\n* Github Pages\r\n* Includes\r\n* AlertColumn, DropColumn, AddIndex, RemoveIndex\r\n\r\n# Author\r\n\r\n**jinzhu**\r\n\r\n* <http://github.com/jinzhu>\r\n* <wosmvp@gmail.com>\r\n* <http://twitter.com/zhangjinzhu>\r\n\r\n## License\r\n\r\nReleased under the [MIT License](http://www.opensource.org/licenses/MIT).\r\n\r\n[![GoDoc](https://godoc.org/github.com/jinzhu/gorm?status.png)](http://godoc.org/github.com/jinzhu/gorm)\r\n","google":"UA-23459165-4","note":"Don't delete this file! It's used internally to help with page regeneration."}