gorm/README.md

743 lines
20 KiB
Markdown
Raw Normal View History

2013-10-25 12:24:29 +04:00
# GORM
2013-10-26 11:18:44 +04:00
Yet Another ORM library for Go, aims for developer friendly
2013-10-25 12:24:29 +04:00
2013-10-28 06:09:44 +04:00
## Overview
* Chainable API
2013-11-07 08:12:25 +04:00
* Relations
* Callbacks (before/after create/save/update/delete)
* Soft Delete
2013-11-07 08:12:25 +04:00
* Auto Migration
2013-11-11 09:16:08 +04:00
* Transaction
2013-11-11 13:50:27 +04:00
* Logger Support
2013-11-13 20:03:31 +04:00
* Bind struct with tag
2013-11-07 08:12:25 +04:00
* Every feature comes with tests
2013-11-03 06:09:56 +04:00
* Convention Over Configuration
2013-11-07 08:12:25 +04:00
* Developer Friendly
2013-10-28 06:09:44 +04:00
2013-11-02 17:02:54 +04:00
## Conventions
2013-10-27 17:37:31 +04:00
```go
2013-11-03 07:38:53 +04:00
type User struct { // TableName: `users`, gorm will pluralize struct's name as table name
2013-11-03 06:49:09 +04:00
Id int64 // Id: Database Primary key
Birthday time.Time
Age int64
2013-11-13 20:03:31 +04:00
Name string `sql:"size:255"` // set this field's length and as not null with tag
2013-11-03 06:49:09 +04:00
CreatedAt time.Time // Time of record is created, will be insert automatically
UpdatedAt time.Time // Time of record is updated, will be updated automatically
2013-11-03 07:32:25 +04:00
DeletedAt time.Time // Time of record is deleted, refer `Soft Delete` for more
2013-11-03 06:18:16 +04:00
2013-11-14 14:59:11 +04:00
Emails []Email // Embedded structs
2013-11-13 20:03:31 +04:00
BillingAddress Address // Embedded struct
BillingAddressId sql.NullInt64 // Embedded struct BillingAddress's foreign key
ShippingAddress Address // Embedded struct
ShippingAddressId int64 // Embedded struct ShippingAddress's foreign key
IgnoreMe int64 `sql:"-"` // Ignore this field with tag
2013-10-27 17:37:31 +04:00
}
2013-11-02 17:02:54 +04:00
type Email struct { // TableName: `emails`
Id int64
UserId int64 // Foreign key for above embedded structs
2013-11-13 20:03:31 +04:00
Email string `sql:"type:varchar(100);"` // Set column type directly with tag
2013-11-02 17:02:54 +04:00
Subscribed bool
}
2013-10-28 06:09:44 +04:00
2013-11-02 17:02:54 +04:00
type Address struct { // TableName: `addresses`
Id int64
2013-11-13 20:03:31 +04:00
Address1 string `sql:"not null;unique"` // Set column as unique with tag
Address2 string `sql:"type:varchar(100);unique"`
Post sql.NullString `sql:not null`
// Be careful: "NOT NULL" will only works for NullXXX scanner, because golang will initalize a default value for most type...
2013-11-02 17:02:54 +04:00
}
```
2013-11-03 07:32:25 +04:00
## Opening a Database
```go
2013-11-03 07:38:53 +04:00
import "github.com/jinzhu/gorm"
import _ "github.com/lib/pq"
2013-11-04 16:32:46 +04:00
// import _ "github.com/go-sql-driver/mysql"
2013-11-04 16:47:45 +04:00
// import _ "github.com/mattn/go-sqlite3"
2013-11-03 07:38:53 +04:00
db, err := Open("postgres", "user=gorm dbname=gorm sslmode=disable")
2013-11-04 16:32:46 +04:00
// db, err = Open("mysql", "gorm:gorm@/gorm?charset=utf8&parseTime=True")
2013-11-04 16:47:45 +04:00
// db, err = Open("sqlite3", "/tmp/gorm.db")
2013-11-04 16:32:46 +04:00
2013-11-03 07:38:53 +04:00
// Set the maximum idle database connections
db.SetPool(100)
2013-11-06 17:43:41 +04:00
// By default, table name is plural of struct type, if you like singular table name
db.SingularTable(true)
2013-11-03 07:32:25 +04:00
2013-11-03 07:32:25 +04:00
// Gorm is goroutines friendly, so you can create a global variable to keep the connection and use it everywhere like this
var DB gorm.DB
func init() {
DB, err = gorm.Open("postgres", "user=gorm dbname=gorm sslmode=disable")
if err != nil {
panic(fmt.Sprintf("Got error when connect database, the error is '%v'", err))
}
}
```
2013-11-02 17:02:54 +04:00
## Struct & Database Mapping
```go
// Create table from struct
db.CreateTable(User{})
// Drop table
db.DropTable(User{})
```
2013-11-07 07:42:36 +04:00
### Automating Migrations
Feel Free to update your struct, AutoMigrate will keep your database update to date.
FYI, AutoMigrate will only add new columns, won't change column's type or delete unused columns, to make sure gorm won't harm your data.
If table doesn't exist when AutoMigrate, it will run create table automatically.
2013-11-07 08:23:45 +04:00
(only postgres and mysql supported)
2013-11-07 07:42:36 +04:00
```go
db.AutoMigrate(User{})
```
2013-11-02 17:02:54 +04:00
## Create
```go
user := User{Name: "jinzhu", Age: 18, Birthday: time.Now()}
2013-10-27 17:37:31 +04:00
db.Save(&user)
2013-11-02 17:02:54 +04:00
```
2013-10-27 17:37:31 +04:00
2013-11-03 06:31:36 +04:00
### Create With SubStruct
2013-11-05 04:08:42 +04:00
Refer [Query With Related](#query-with-related) to find how to find associations
2013-11-03 06:31:36 +04:00
```go
user := User{
Name: "jinzhu",
BillingAddress: Address{Address1: "Billing Address - Address 1"},
ShippingAddress: Address{Address1: "Shipping Address - Address 1"},
2013-11-14 14:59:11 +04:00
Emails: []Email{{Email: "jinzhu@example.com"}, {Email: "jinzhu-2@example@example.com"}},
2013-11-03 06:31:36 +04:00
}
db.Save(&user)
//// INSERT INTO "addresses" (address1) VALUES ("Billing Address - Address 1");
//// INSERT INTO "addresses" (address1) VALUES ("Shipping Address - Address 1");
//// INSERT INTO "users" (name,billing_address_id,shipping_address_id) VALUES ("jinzhu", 1, 2);
//// INSERT INTO "emails" (user_id,email) VALUES (111, "jinzhu@example.com");
//// INSERT INTO "emails" (user_id,email) VALUES (111, "jinzhu-2@example.com");
```
2013-11-02 17:02:54 +04:00
## Query
```go
// Get the first record
db.First(&user)
//// SELECT * FROM users ORDER BY id LIMIT 1;
2013-11-03 06:49:09 +04:00
// Search table `users` are guessed from the out struct type.
2013-11-03 06:09:56 +04:00
// You are possible to specify the table name with Model() if no out struct for some methods like Pluck()
2013-11-03 06:49:09 +04:00
// Or set table name with Table(), if so, it will ignore the out struct even have it. more details following.
2013-10-27 17:37:31 +04:00
// Get the last record
db.Last(&user)
//// SELECT * FROM users ORDER BY id DESC LIMIT 1;
// Get a record without order by primary key
db.Find(&user)
//// SELECT * FROM users LIMIT 1;
// Get first record as map
db.First(&users)
//// SELECT * FROM users LIMIT 1;
2013-11-02 17:02:54 +04:00
// Get All records
db.Find(&users)
2013-11-03 06:09:56 +04:00
//// SELECT * FROM users;
2013-11-02 17:02:54 +04:00
// Using a Primary Key
db.First(&user, 10)
2013-11-03 06:09:56 +04:00
//// SELECT * FROM users WHERE id = 10;
2013-11-02 17:02:54 +04:00
```
2013-11-03 06:09:56 +04:00
### Query With Where (SQL like condition)
2013-11-02 17:02:54 +04:00
```go
// Get the first matched record
2013-10-27 17:37:31 +04:00
db.Where("name = ?", "jinzhu").First(&user)
2013-11-02 17:02:54 +04:00
//// SELECT * FROM users WHERE name = 'jinzhu' limit 1;
2013-10-27 17:37:31 +04:00
2013-11-02 17:02:54 +04:00
// Get all matched records
2013-10-27 17:37:31 +04:00
db.Where("name = ?", "jinzhu").Find(&users)
2013-11-02 17:02:54 +04:00
//// SELECT * FROM users WHERE name = 'jinzhu';
2013-10-27 17:37:31 +04:00
db.Where("name <> ?", "jinzhu").Find(&users)
2013-11-02 17:02:54 +04:00
//// SELECT * FROM users WHERE name <> 'jinzhu';
// IN
2013-11-03 17:19:38 +04:00
db.Where("name in (?)", []string{"jinzhu", "jinzhu 2"}).Find(&users)
2013-11-02 17:02:54 +04:00
//// SELECT * FROM users WHERE name IN ('jinzhu', 'jinzhu 2');
// LIKE
2013-10-28 05:05:44 +04:00
db.Where("name LIKE ?", "%jin%").Find(&users)
2013-11-02 17:02:54 +04:00
//// SELECT * FROM users WHERE name LIKE "%jin%";
// Multiple Conditions
db.Where("name = ? and age >= ?", "jinzhu", "22").Find(&users)
//// SELECT * FROM users WHERE name = 'jinzhu' AND age >= 22;
```
2013-11-03 06:09:56 +04:00
### Query With Where (Struct & Map)
2013-11-02 17:02:54 +04:00
```go
// Search with struct
2013-10-29 13:37:45 +04:00
db.Where(&User{Name: "jinzhu", Age: 20}).First(&user)
2013-11-02 17:02:54 +04:00
//// SELECT * FROM users WHERE name = "jinzhu" AND age = 20 LIMIT 1;
// Search with map
db.Where(map[string]interface{}{"name": "jinzhu", "age": 20}).Find(&users)
//// SELECT * FROM users WHERE name = "jinzhu" AND age = 20;
2013-11-03 06:09:56 +04:00
// IN For Primary Key
db.Where([]int64{20, 21, 22}).Find(&users)
//// SELECT * FROM users WHERE id IN (20, 21, 22);
2013-11-02 17:02:54 +04:00
```
2013-11-03 06:09:56 +04:00
### Query With Not
2013-11-02 17:02:54 +04:00
```go
2013-11-03 06:09:56 +04:00
// Attribute Not Equal
2013-11-02 17:02:54 +04:00
db.Not("name", "jinzhu").First(&user)
//// SELECT * FROM users WHERE name <> "jinzhu" LIMIT 1;
2013-10-27 17:37:31 +04:00
2013-11-02 17:02:54 +04:00
// Not In
db.Not("name", []string{"jinzhu", "jinzhu 2"}).Find(&users)
//// SELECT * FROM users WHERE name NOT IN ("jinzhu", "jinzhu 2");
// Not In for Primary Key
2013-10-31 14:12:18 +04:00
db.Not([]int64{1,2,3}).First(&user)
2013-11-02 17:02:54 +04:00
//// SELECT * FROM users WHERE id NOT IN (1,2,3);
2013-10-31 14:12:18 +04:00
db.Not([]int64{}).First(&user)
2013-11-02 17:02:54 +04:00
//// SELECT * FROM users;
// Normal SQL
2013-10-31 18:49:48 +04:00
db.Not("name = ?", "jinzhu").First(&user)
2013-11-02 17:02:54 +04:00
//// SELECT * FROM users WHERE NOT(name = "jinzhu");
// Not With Struct
2013-10-31 14:12:18 +04:00
db.Not(User{Name: "jinzhu"}).First(&user)
2013-11-02 17:02:54 +04:00
//// SELECT * FROM users WHERE name <> "jinzhu";
```
2013-11-03 06:49:09 +04:00
### Query With Inline Condition
2013-10-31 14:12:18 +04:00
2013-11-02 17:02:54 +04:00
```go
// Find with primary key
2013-10-27 18:36:43 +04:00
db.First(&user, 23)
2013-11-02 17:02:54 +04:00
//// SELECT * FROM users WHERE id = 23 LIMIT 1;
// Normal SQL
db.Find(&user, "name = ?", "jinzhu")
//// SELECT * FROM users WHERE name = "jinzhu";
// Multiple Conditions
2013-10-27 18:36:43 +04:00
db.Find(&users, "name <> ? and age > ?", "jinzhu", 20)
2013-11-02 17:02:54 +04:00
//// SELECT * FROM users WHERE name <> "jinzhu" AND age > 20;
// Inline Search With Struct
db.Find(&users, User{Age: 20})
//// SELECT * FROM users WHERE age = 20;
// Inline Search With Map
2013-10-29 13:52:37 +04:00
db.Find(&users, map[string]interface{}{"age": 20})
2013-11-02 17:02:54 +04:00
//// SELECT * FROM users WHERE age = 20;
```
2013-11-03 06:09:56 +04:00
### Query With Or
2013-11-03 06:49:09 +04:00
```go
2013-11-03 06:09:56 +04:00
db.Where("role = ?", "admin").Or("role = ?", "super_admin").Find(&users)
//// SELECT * FROM users WHERE role = 'admin' OR role = 'super_admin';
// Or With Struct
db.Where("name = 'jinzhu'").Or(User{Name: "jinzhu 2"}).Find(&users)
//// SELECT * FROM users WHERE name = 'jinzhu' OR name = 'jinzhu 2';
// Or With Map
db.Where("name = 'jinzhu'").Or(map[string]interface{}{"name": "jinzhu 2"}).Find(&users)
```
### Query With Related
```go
2013-11-05 04:08:42 +04:00
// Find emails from user with guessed foreign key
db.Model(&user).Related(&emails)
//// SELECT * FROM emails WHERE user_id = 111;
2013-11-05 04:08:42 +04:00
// Find address from user with specified foreign key 'BillingAddressId'
db.Model(&user).Related(&address1, "BillingAddressId")
//// SELECT * FROM addresses WHERE id = 123; // 123 is the value of user's BillingAddressId
2013-11-05 04:08:42 +04:00
// Find user from email with guessed primary key value from emails
db.Model(&email).Related(&user)
//// SELECT * FROM users WHERE id = 111; // 111 is the value of email's UserId
```
2013-11-03 06:09:56 +04:00
### Query Chains
2013-11-03 06:49:09 +04:00
Gorm has a chainable API, so you could query like this
2013-11-03 06:09:56 +04:00
```go
2013-11-03 06:49:09 +04:00
db.Where("name <> ?","jinzhu").Where("age >= ? and role <> ?",20,"admin").Find(&users)
2013-11-03 06:09:56 +04:00
//// SELECT * FROM users WHERE name <> 'jinzhu' AND age >= 20 AND role <> 'admin';
db.Where("role = ?", "admin").Or("role = ?", "super_admin").Not("name = ?", "jinzhu").Find(&users)
```
## Update
### Update an existing struct
```go
user.Name = "jinzhu 2"
user.Age = 100
db.Save(&user)
//// UPDATE users SET name='jinzhu 2', age=100 WHERE id=111;
```
### Update one attribute with `Update`
2013-11-03 06:49:09 +04:00
```go
2013-11-03 06:09:56 +04:00
// Update an existing struct's name if name is different
db.Model(&user).Update("name", "hello")
//// UPDATE users SET name='hello' WHERE id=111;
// Find out a struct, and update it if name is different
db.First(&user, 111).Update("name", "hello")
//// SELECT * FROM users LIMIT 1;
//// UPDATE users SET name='hello' WHERE id=111;
2013-11-03 06:49:09 +04:00
// Specify table name with where search
2013-11-03 06:09:56 +04:00
db.Table("users").Where(10).Update("name", "hello")
//// UPDATE users SET name='hello' WHERE id = 10;
```
### Update multiple attributes with `Updates`
2013-11-03 06:49:09 +04:00
```go
// Update an existing record if have any changed values
2013-11-03 06:09:56 +04:00
db.Model(&user).Updates(User{Name: "hello", Age: 18})
//// UPDATE users SET name='hello', age=18 WHERE id = 111;
2013-11-03 06:49:09 +04:00
// Updates with Map
2013-11-03 06:09:56 +04:00
db.Table("users").Where(10).Updates(map[string]interface{}{"name": "hello", "age": 18})
//// UPDATE users SET name='hello', age=18 WHERE id = 10;
2013-11-03 06:49:09 +04:00
// Updates with Struct
2013-11-03 06:09:56 +04:00
db.Model(User{}).Updates(User{Name: "hello", Age: 18})
//// UPDATE users SET name='hello', age=18;
```
## Delete
### Delete an existing struct
```go
db.Delete(&email)
// DELETE from emails where id=10;
```
### Batch Delete with search
```go
db.Where("email LIKE ?", "%jinzhu%").Delete(Email{})
// DELETE from emails where email LIKE "%jinhu%";
```
### Soft Delete
2013-11-03 06:49:09 +04:00
If a struct has DeletedAt field, it will get soft delete ability automatically!
2013-11-03 06:09:56 +04:00
For those don't have the filed, will be deleted from database permanently
```go
db.Delete(&user)
//// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE id = 111;
// Batch delete when search
db.Where("age = ?", 20).Delete(&User{})
//// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE age = 20;
// For structs have DeletedAt field, when do query, will ignore deleted records by default
db.Where("age = 20").Find(&user)
//// SELECT * FROM users WHERE age = 100 AND (deleted_at IS NULL AND deleted_at <= '0001-01-02');
// Find out all records including those deleted with Unscoped
db.Unscoped().Where("age = 20").Find(&users)
//// SELECT * FROM users WHERE age = 20;
// Permanently delete a record with Unscoped
db.Unscoped().Delete(&order)
// DELETE FROM orders WHERE id=10;
```
2013-11-02 17:02:54 +04:00
## FirstOrInit
Try to load the first record, if fails, initialize struct with search conditions.
2013-11-03 06:49:09 +04:00
2013-11-02 17:02:54 +04:00
(only support map or struct conditions, SQL like conditions are not supported)
```go
db.FirstOrInit(&user, User{Name: "non_existing"})
//// User{Name: "non_existing"}
2013-10-27 18:18:06 +04:00
2013-10-29 16:32:27 +04:00
db.Where(User{Name: "Jinzhu"}).FirstOrInit(&user)
2013-11-02 17:02:54 +04:00
//// User{Id: 111, Name: "Jinzhu", Age: 20}
2013-10-29 16:32:27 +04:00
2013-11-02 17:02:54 +04:00
db.FirstOrInit(&user, map[string]interface{}{"name": "jinzhu"})
//// User{Id: 111, Name: "Jinzhu", Age: 20}
```
### FirstOrInit With Attrs
2013-11-03 06:09:56 +04:00
Attr's arguments would be used to initialize struct if no record found, but won't be used for search
2013-11-02 17:02:54 +04:00
```go
db.Where(User{Name: "non_existing"}).Attrs(User{Age: 20}).FirstOrInit(&user)
//// SELECT * FROM USERS WHERE name = 'non_existing';
//// User{Name: "non_existing", Age: 20}
2013-11-03 06:09:56 +04:00
// Above code could be simplified if has only one attribute
db.Where(User{Name: "noexisting_user"}).Attrs("age", 20).FirstOrInit(&user)
2013-11-02 17:02:54 +04:00
2013-11-03 06:09:56 +04:00
// If a record found, Attrs would be just ignored
2013-11-02 17:02:54 +04:00
db.Where(User{Name: "Jinzhu"}).Attrs(User{Age: 30}).FirstOrInit(&user)
//// SELECT * FROM USERS WHERE name = jinzhu';
2013-11-03 06:09:56 +04:00
//// User{Id: 111, Name: "Jinzhu", Age: 20}
2013-11-03 06:18:16 +04:00
```
2013-10-30 11:33:34 +04:00
2013-11-02 17:02:54 +04:00
### FirstOrInit With Assign
2013-11-03 06:09:56 +04:00
Assign's arguments would be used to set the struct even a record found, but won't be used for search
2013-11-02 17:02:54 +04:00
```go
db.Where(User{Name: "non_existing"}).Assign(User{Age: 20}).FirstOrInit(&user)
//// User{Name: "non_existing", Age: 20}
db.Where(User{Name: "Jinzhu"}).Assign(User{Age: 30}).FirstOrInit(&user)
//// User{Id: 111, Name: "Jinzhu", Age: 30}
```
## FirstOrCreate
Try to load the first record, if fails, initialize struct with search conditions and save it
```go
db.FirstOrCreate(&user, User{Name: "non_existing"})
//// User{Id: 112, Name: "non_existing"}
2013-10-29 16:32:27 +04:00
db.Where(User{Name: "Jinzhu"}).FirstOrCreate(&user)
2013-11-02 17:02:54 +04:00
//// User{Id: 111, Name: "Jinzhu"}
db.FirstOrCreate(&user, map[string]interface{}{"name": "jinzhu", "age": 30})
2013-11-03 06:09:56 +04:00
//// user -> User{Id: 111, Name: "jinzhu", Age: 20}
2013-11-02 17:02:54 +04:00
```
### FirstOrCreate With Attrs
2013-10-29 16:32:27 +04:00
2013-11-03 06:09:56 +04:00
Attr's arguments would be used to initialize struct if no record found, but won't be used for search
2013-11-02 17:02:54 +04:00
```go
db.Where(User{Name: "non_existing"}).Attrs(User{Age: 20}).FirstOrCreate(&user)
//// SELECT * FROM users WHERE name = 'non_existing';
//// User{Id: 112, Name: "non_existing", Age: 20}
2013-10-31 05:34:27 +04:00
2013-11-03 06:09:56 +04:00
db.Where(User{Name: "jinzhu"}).Attrs(User{Age: 30}).FirstOrCreate(&user)
//// User{Id: 111, Name: "jinzhu", Age: 20}
2013-11-02 17:02:54 +04:00
```
### FirstOrCreate With Assign
2013-10-31 05:34:27 +04:00
2013-11-02 17:02:54 +04:00
Assign's arguments would be used to initialize the struct if not record found,
2013-11-03 06:49:09 +04:00
2013-11-02 17:02:54 +04:00
If any record found, will assign those values to the record, and save it back to database.
2013-10-31 05:34:27 +04:00
2013-11-02 17:02:54 +04:00
```go
db.Where(User{Name: "non_existing"}).Assign(User{Age: 20}).FirstOrCreate(&user)
//// user -> User{Id: 112, Name: "non_existing", Age: 20}
2013-11-03 06:09:56 +04:00
db.Where(User{Name: "jinzhu"}).Assign(User{Age: 30}).FirstOrCreate(&user)
//// SELECT * FROM users WHERE name = 'jinzhu';
2013-11-02 17:02:54 +04:00
//// UPDATE users SET age=30 WHERE id = 111;
2013-11-03 06:09:56 +04:00
//// User{Id: 111, Name: "jinzhu", Age: 30}
2013-11-02 17:02:54 +04:00
```
2013-11-03 06:09:56 +04:00
## Select
2013-11-02 17:02:54 +04:00
```go
2013-11-03 06:09:56 +04:00
db.Select("name, age").Find(&users)
//// SELECT name, age FROM users;
```
2013-10-30 11:33:34 +04:00
2013-11-03 06:09:56 +04:00
## Order
2013-10-27 17:37:31 +04:00
2013-11-03 06:09:56 +04:00
```go
2013-10-27 17:37:31 +04:00
db.Order("age desc, name").Find(&users)
2013-11-03 06:09:56 +04:00
//// SELECT * FROM users ORDER BY age desc, name;
2013-10-27 18:18:06 +04:00
db.Order("age desc").Order("name").Find(&users)
2013-11-03 06:09:56 +04:00
//// SELECT * FROM users ORDER BY age desc, name;
2013-10-28 05:18:34 +04:00
// ReOrder
db.Order("age desc").Find(&users1).Order("age", true).Find(&users2)
2013-11-03 06:09:56 +04:00
//// SELECT * FROM users ORDER BY age desc; (users1)
//// SELECT * FROM users ORDER BY age; (users2)
```
2013-10-28 05:18:34 +04:00
2013-11-03 06:09:56 +04:00
## Limit
```go
2013-10-27 17:37:31 +04:00
db.Limit(3).Find(&users)
2013-11-03 06:09:56 +04:00
//// SELECT * FROM users LIMIT 3;
2013-10-27 17:37:31 +04:00
2013-11-03 06:09:56 +04:00
// Cleanup limit with -1
db.Limit(10).Find(&users1).Limit(-1).Find(&users2)
//// SELECT * FROM users LIMIT 10; (users1)
//// SELECT * FROM users; (users2)
```
2013-10-27 17:37:31 +04:00
2013-11-03 06:09:56 +04:00
## Offset
2013-10-27 17:37:31 +04:00
2013-11-03 06:09:56 +04:00
```go
db.Offset(3).Find(&users)
//// SELECT * FROM users OFFSET 3;
2013-10-27 17:37:31 +04:00
2013-11-03 06:09:56 +04:00
// Cleanup offset with -1
db.Offset(10).Find(&users1).Offset(-1).Find(&users2)
//// SELECT * FROM users OFFSET 10; (users1)
//// SELECT * FROM users; (users2)
```
2013-10-27 17:37:31 +04:00
2013-11-03 06:09:56 +04:00
## Count
2013-10-27 18:18:06 +04:00
2013-11-03 06:09:56 +04:00
```go
db.Where("name = ?", "jinzhu").Or("name = ?", "jinzhu 2").Find(&users).Count(&count)
//// SELECT * from USERS WHERE name = 'jinzhu' OR name = 'jinzhu 2'; (users)
//// SELECT count(*) FROM users WHERE name = 'jinzhu' OR name = 'jinzhu 2'; (count)
2013-10-27 17:37:31 +04:00
2013-11-03 06:09:56 +04:00
// Set table name with Model
db.Model(User{}).Where("name = ?", "jinzhu").Count(&count)
//// SELECT count(*) FROM users WHERE name = 'jinzhu' OR name = 'jinzhu 2'; (count)
2013-10-27 17:37:31 +04:00
2013-11-03 06:09:56 +04:00
// Set table name with Table
db.Table("deleted_users").Count(&count)
//// SELECT count(*) FROM deleted_users;
```
## Pluck
2013-10-27 18:18:06 +04:00
2013-11-03 06:09:56 +04:00
Get struct's attribute as map
```go
2013-10-27 17:37:31 +04:00
var ages []int64
2013-10-28 05:05:44 +04:00
db.Find(&users).Pluck("age", &ages)
2013-11-03 06:09:56 +04:00
// Set Table With Model
2013-10-27 18:18:06 +04:00
var names []string
db.Model(&User{}).Pluck("name", &names)
2013-11-03 06:09:56 +04:00
//// SELECT name FROM users;
2013-10-27 17:37:31 +04:00
2013-11-03 06:09:56 +04:00
// Set Table With Table
db.Table("deleted_users").Pluck("name", &names)
//// SELECT name FROM deleted_users;
2013-11-11 17:55:44 +04:00
// Pluck more than one column? Do it like this
db.Select("name, age").Find(&users)
2013-11-03 06:09:56 +04:00
```
## Callbacks
2013-10-27 17:37:31 +04:00
2013-11-03 06:09:56 +04:00
Callback is a function defined to a struct, the function would be run when reflect a struct to database.
2013-11-11 15:06:26 +04:00
If a function return error, gorm will prevent future operations and do rollback
2013-11-03 06:09:56 +04:00
Those callbacks are defined now:
`BeforeCreate`, `AfterCreate`
`BeforeUpdate`, `AfterUpdate`
`BeforeSave`, `AfterSave`
`BeforeDelete`, `AfterDelete`
```go
2013-11-11 15:06:26 +04:00
// Won't update readonly user
2013-11-03 06:09:56 +04:00
func (u *User) BeforeUpdate() (err error) {
if u.readonly() {
err = errors.New("Read Only User")
}
return
}
2013-11-11 15:06:26 +04:00
// If have more than 1000 users, will rollback the insertion
func (u *User) AfterCreate() (err error) {
if (u.Id > 1000) { // just an example, don't use Id to count users
err = errors.New("Only 1000 users allowed")
}
return
}
2013-11-03 06:09:56 +04:00
```
2013-10-27 17:37:31 +04:00
2013-11-03 06:09:56 +04:00
## Specify Table Name
2013-11-01 11:01:39 +04:00
2013-11-03 07:32:25 +04:00
```go
2013-11-03 06:09:56 +04:00
// When Create Table from struct
2013-10-28 16:27:25 +04:00
db.Table("deleted_users").CreateTable(&User{})
2013-11-03 06:09:56 +04:00
// When Pluck
2013-10-28 16:27:25 +04:00
db.Table("users").Pluck("age", &ages)
2013-11-03 06:09:56 +04:00
//// SELECT age FROM users;
// When Query
2013-10-28 16:27:25 +04:00
var deleted_users []User
db.Table("deleted_users").Find(&deleted_users)
2013-11-03 06:09:56 +04:00
//// SELECT * FROM deleted_users;
2013-10-28 16:27:25 +04:00
2013-11-03 06:09:56 +04:00
// When Delete
db.Table("deleted_users").Where("name = ?", "jinzhu").Delete()
//// DELETE FROM deleted_users WHERE name = 'jinzhu';
```
2013-10-28 17:52:22 +04:00
### Specify Table Name for Struct
You are possible to specify table name for a struct by defining method TableName
```go
type Cart struct {
}
func (c Cart) TableName() string {
return "shopping_cart"
}
2013-11-06 18:20:26 +04:00
func (u User) TableName() string {
if u.Role == "admin" {
return "admin_users"
} else {
return "users"
}
}
```
2013-11-11 09:16:08 +04:00
## Transaction
```go
tx := db.Begin()
user := User{Name: "transcation"}
tx.Save(&u)
tx.Update("age": 90)
// do whatever
// rollback
tx.Rollback()
// commit
tx.Commit()
```
2013-11-11 13:50:27 +04:00
## Logger
Grom has builtin logger support, enable it with:
```go
db.LogMode(true)
```
2013-11-11 13:51:39 +04:00
![logger](https://raw.github.com/jinzhu/gorm/master/images/logger.png)
2013-11-11 13:50:27 +04:00
```go
// Use your own logger
// Checkout gorm's default logger for how to format messages: https://github.com/jinzhu/gorm/blob/master/logger.go#files
db.SetLogger(log.New(os.Stdout, "\r\n", 0))
// Disable log
db.LogMode(false)
// Enable log for a single operation, make debug easy
db.Debug().Where("name = ?", "jinzhu").First(&User{})
```
2013-11-03 06:09:56 +04:00
## Run Raw SQl
2013-11-03 06:09:56 +04:00
```go
2013-10-27 17:37:31 +04:00
db.Exec("drop table users;")
2013-11-03 06:09:56 +04:00
```
2013-10-28 07:24:51 +04:00
2013-11-03 06:09:56 +04:00
## Error Handling
```go
2013-10-28 07:24:51 +04:00
query := db.Where("name = ?", "jinzhu").First(&user)
query := db.First(&user).Limit(10).Find(&users)
2013-11-03 06:09:56 +04:00
//// query.Error keep the latest error happened
//// query.Errors keep all errors happened
//// If an error happened, gorm will stop do query, insert, update, delete
// I often use below code to do error handling in real applicatoins
err = db.Where("name = ?", "jinzhu").First(&user).Error
2013-10-27 17:37:31 +04:00
```
2013-10-28 04:08:45 +04:00
## Advanced Usage With Query Chain
2013-10-27 18:18:06 +04:00
2013-11-03 06:09:56 +04:00
Already excited about above usage? Let's see some magic!
2013-10-27 18:18:06 +04:00
2013-11-03 06:09:56 +04:00
```go
2013-10-27 18:18:06 +04:00
db.First(&first_article).Count(&total_count).Limit(10).Find(&first_page_articles).Offset(10).Find(&second_page_articles)
2013-11-03 06:09:56 +04:00
//// SELECT * FROM articles LIMIT 1; (first_article)
//// SELECT count(*) FROM articles; (count)
//// SELECT * FROM articles LIMIT 10; (first_page_articles)
//// SELECT * FROM articles LIMIT 10 OFFSET 10; (second_page_articles)
2013-10-27 18:18:06 +04:00
2013-11-03 06:09:56 +04:00
db.Where("created_at > ?", "2013-10-10").Find(&cancelled_orders, "state = ?", "cancelled").Find(&shipped_orders, "state = ?", "shipped")
//// SELECT * FROM orders WHERE created_at > '2013/10/10' AND state = 'cancelled'; (cancelled_orders)
//// SELECT * FROM orders WHERE created_at > '2013/10/10' AND state = 'shipped'; (shipped_orders)
2013-10-27 18:18:06 +04:00
2013-11-03 06:09:56 +04:00
db.Where("product_name = ?", "fancy_product").Find(&orders).Find(&shopping_carts)
//// SELECT * FROM orders WHERE product_name = 'fancy_product'; (orders)
//// SELECT * FROM carts WHERE product_name = 'fancy_product'; (shopping_carts)
// Do you noticed the table is different?
2013-10-27 18:18:06 +04:00
2013-10-28 16:27:25 +04:00
db.Where("mail_type = ?", "TEXT").Find(&users1).Table("deleted_users").First(&user2)
2013-11-03 06:09:56 +04:00
//// SELECT * FROM users WHERE mail_type = 'TEXT'; (users1)
//// SELECT * FROM deleted_users WHERE mail_type = 'TEXT'; (users2)
2013-10-28 16:27:25 +04:00
2013-11-03 06:49:09 +04:00
db.Where("email = ?", "x@example.org").Attrs(User{FromIp: "111.111.111.111"}).FirstOrCreate(&user)
2013-11-03 06:09:56 +04:00
//// SELECT * FROM users WHERE email = 'x@example.org';
//// INSERT INTO "users" (email,from_ip) VALUES ("x@example.org", "111.111.111.111") (if no record found)
2013-10-30 11:33:34 +04:00
2013-10-27 18:18:06 +04:00
// Open your mind, add more cool examples
```
2013-10-26 11:18:44 +04:00
## TODO
2013-11-11 17:55:44 +04:00
* Join, Having, Group, Includes
2013-11-13 20:03:31 +04:00
* Scopes, Valiations
* AlertColumn, DropColumn, AddIndex, RemoveIndex
2013-10-25 12:24:29 +04:00
2013-10-26 11:18:44 +04:00
# Author
2013-10-25 12:24:29 +04:00
2013-11-03 06:09:56 +04:00
**jinzhu**
2013-10-25 12:24:29 +04:00
2013-10-26 11:18:44 +04:00
* <http://github.com/jinzhu>
* <wosmvp@gmail.com>
* <http://twitter.com/zhangjinzhu>
2013-11-12 03:13:58 +04:00
## License
Released under the [MIT License](http://www.opensource.org/licenses/MIT).