mirror of https://github.com/go-gorm/gorm.git
Update README
This commit is contained in:
parent
aa352d405b
commit
b4981259de
384
README.md
384
README.md
|
@ -6,167 +6,306 @@ Yet Another ORM library for Go, aims for developer friendly
|
||||||
|
|
||||||
* CURD
|
* CURD
|
||||||
* Chainable API
|
* Chainable API
|
||||||
|
* Embedded structs support
|
||||||
* Before/After Create/Save/Update/Delete Callbacks
|
* Before/After Create/Save/Update/Delete Callbacks
|
||||||
* Order/Select/Limit/Offset Support
|
|
||||||
* Update, Updates Like Rails's update_attribute, update_attributes
|
* Update, Updates Like Rails's update_attribute, update_attributes
|
||||||
* FirstOrInit, FirstOrCreate Like Rails's first_or_initialize, first_or_create
|
* FirstOrInit, FirstOrCreate Like Rails's first_or_initialize, first_or_create
|
||||||
* Dynamically set table name when search, update, delete...
|
* Order/Select/Limit/Offset Support
|
||||||
* Automatically CreatedAt, UpdatedAt
|
* Automatically CreatedAt, UpdatedAt
|
||||||
* Soft Delete
|
* Soft Delete
|
||||||
* Create table from struct
|
* Create/Drop table from struct
|
||||||
|
* Dynamically set table name when search, create, update, delete...
|
||||||
* Prevent SQL Injection
|
* Prevent SQL Injection
|
||||||
* Goroutines friendly
|
* Goroutines friendly
|
||||||
* Database Pool
|
* Database Pool
|
||||||
|
* Convention Over Configuration (CoC)
|
||||||
|
|
||||||
## Basic Usage
|
## Basic Usage
|
||||||
|
|
||||||
```go
|
## Opening a Database
|
||||||
db, _ = Open("postgres", "user=gorm dbname=gorm sslmode=disable")
|
|
||||||
|
|
||||||
type User struct {
|
```go
|
||||||
Id int64
|
db, err = Open("postgres", "user=gorm dbname=gorm sslmode=disable")
|
||||||
Age int64
|
|
||||||
Birthday time.Time
|
// Gorm is goroutines friendly, so you can create a global variable to keep the connection and use it everywhere
|
||||||
Name string
|
|
||||||
CreatedAt time.Time
|
var DB gorm.DB
|
||||||
UpdatedAt time.Time
|
|
||||||
|
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))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set database pool
|
// Set the maximum idle database connections
|
||||||
db.SetPool(10)
|
db.SetPool(100)
|
||||||
|
```
|
||||||
|
|
||||||
// Create
|
## Conventions
|
||||||
user = User{Name: "jinzhu", Age: 18, Birthday: time.Now()}
|
|
||||||
|
```go
|
||||||
|
type User struct { // TableName: `users`, gorm will pluralize struct name as table name
|
||||||
|
Id int64 // Id: Database Primary key
|
||||||
|
Birthday time.Time // Time
|
||||||
|
Age int64
|
||||||
|
Name string
|
||||||
|
CreatedAt time.Time // CreatedAt: Time of record is created, will be insert automatically
|
||||||
|
UpdatedAt time.Time // UpdatedAt: Time of record is updated, will be updated automatically
|
||||||
|
DeletedAt time.Time // DeletedAt: Time of record is deleted, refer Soft Delete for more
|
||||||
|
Email []Email // Embedded structs
|
||||||
|
BillingAddress Address // Embedded struct
|
||||||
|
BillingAddressId int64 // Embedded struct's foreign key
|
||||||
|
ShippingAddress Address // Embedded struct
|
||||||
|
ShippingAddressId int64 // Embedded struct's foreign key
|
||||||
|
}
|
||||||
|
|
||||||
|
type Email struct { // TableName: `emails`
|
||||||
|
Id int64
|
||||||
|
UserId int64 // Foreign key for above embedded structs
|
||||||
|
Email string
|
||||||
|
Subscribed bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type Address struct { // TableName: `addresses`
|
||||||
|
Id int64
|
||||||
|
Address1 string
|
||||||
|
Address2 string
|
||||||
|
Post string
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Struct & Database Mapping
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Create table from struct
|
||||||
|
db.CreateTable(User{})
|
||||||
|
|
||||||
|
// Drop table
|
||||||
|
db.DropTable(User{})
|
||||||
|
```
|
||||||
|
|
||||||
|
## Create
|
||||||
|
|
||||||
|
```go
|
||||||
|
user := User{Name: "jinzhu", Age: 18, Birthday: time.Now()}
|
||||||
db.Save(&user)
|
db.Save(&user)
|
||||||
|
```
|
||||||
|
|
||||||
// Update
|
## Update
|
||||||
|
|
||||||
|
```go
|
||||||
user.Name = "jinzhu 2"
|
user.Name = "jinzhu 2"
|
||||||
db.Save(&user)
|
db.Save(&user)
|
||||||
|
```
|
||||||
|
|
||||||
// Delete
|
## Delete
|
||||||
|
|
||||||
|
```go
|
||||||
db.Delete(&user)
|
db.Delete(&user)
|
||||||
|
```
|
||||||
|
|
||||||
// Get First matched record
|
## Query
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Get the first record
|
||||||
|
db.First(&user)
|
||||||
|
//// SELECT * FROM USERS LIMIT 1;
|
||||||
|
|
||||||
|
// Get All records
|
||||||
|
db.Find(&users)
|
||||||
|
//// SELECT * FROM USERS;
|
||||||
|
|
||||||
|
// Using a Primary Key
|
||||||
|
db.First(&user, 10)
|
||||||
|
//// SELECT * FROM USERS WHERE id = 10;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Where (SQL like condition)
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Get the first matched record
|
||||||
db.Where("name = ?", "jinzhu").First(&user)
|
db.Where("name = ?", "jinzhu").First(&user)
|
||||||
|
//// SELECT * FROM users WHERE name = 'jinzhu' limit 1;
|
||||||
|
|
||||||
// Get All matched records
|
// Get all matched records
|
||||||
db.Where("name = ?", "jinzhu").Find(&users)
|
db.Where("name = ?", "jinzhu").Find(&users)
|
||||||
|
//// SELECT * FROM users WHERE name = 'jinzhu';
|
||||||
|
|
||||||
// Advanced Where Usage
|
|
||||||
db.Where("name <> ?", "jinzhu").Find(&users)
|
db.Where("name <> ?", "jinzhu").Find(&users)
|
||||||
//// users -> select * from users name <> 'jinzhu';
|
//// SELECT * FROM users WHERE name <> 'jinzhu';
|
||||||
db.Where(20).First(&user)
|
|
||||||
//// users -> select * from users where id = 20;
|
// IN
|
||||||
db.Where([]int64{20, 21, 22}).Find(&user)
|
|
||||||
//// users -> select * from users where id in (20, 21, 22);
|
|
||||||
db.Where("name = ? and age >= ?", "jinzhu", "22").Find(&users)
|
|
||||||
//// users -> select * from users name = 'jinzhu' and age >= 22;
|
|
||||||
db.Where("name in (?)", []string["jinzhu", "jinzhu 2"]).Find(&users)
|
db.Where("name in (?)", []string["jinzhu", "jinzhu 2"]).Find(&users)
|
||||||
//// users -> select * from users name in ('jinzhu', 'jinzhu 2');
|
//// SELECT * FROM users WHERE name IN ('jinzhu', 'jinzhu 2');
|
||||||
|
|
||||||
|
// IN For Primary Key
|
||||||
|
db.Where([]int64{20, 21, 22}).Find(&users)
|
||||||
|
//// SELECT * FROM users WHERE id IN (20, 21, 22);
|
||||||
|
|
||||||
|
// LIKE
|
||||||
db.Where("name LIKE ?", "%jin%").Find(&users)
|
db.Where("name LIKE ?", "%jin%").Find(&users)
|
||||||
//// users -> select * from users name LIKE "%jinzhu%";
|
//// 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;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Where (Struct & Map)
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Search with struct
|
||||||
db.Where(&User{Name: "jinzhu", Age: 20}).First(&user)
|
db.Where(&User{Name: "jinzhu", Age: 20}).First(&user)
|
||||||
//// user -> select * from users name = "jinzhu" and age = 20 limit 1;
|
//// SELECT * FROM users WHERE name = "jinzhu" AND age = 20 LIMIT 1;
|
||||||
db.Where(map[string]interface{}{"name": "jinzhu", "age": 20}).First(&user)
|
|
||||||
//// user -> select * from users name = "jinzhu" and age = 20 limit 1;
|
|
||||||
db.Where("birthday < ?", time.Now()).Find(&users)
|
|
||||||
|
|
||||||
// Not
|
// Search with map
|
||||||
db.Not([]int64{1,2,3}).First(&user)
|
db.Where(map[string]interface{}{"name": "jinzhu", "age": 20}).Find(&users)
|
||||||
//// user -> select * from users where id NOT IN (1,2,3)
|
//// SELECT * FROM users WHERE name = "jinzhu" AND age = 20;
|
||||||
db.Not([]int64{}).First(&user)
|
```
|
||||||
//// user -> select * from users;
|
|
||||||
|
### Not
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Not Equal
|
||||||
db.Not("name", "jinzhu").First(&user)
|
db.Not("name", "jinzhu").First(&user)
|
||||||
//// user -> select * from users where name <> "jinzhu"
|
//// SELECT * FROM users WHERE name <> "jinzhu" LIMIT 1;
|
||||||
|
|
||||||
|
// 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
|
||||||
|
db.Not([]int64{1,2,3}).First(&user)
|
||||||
|
//// SELECT * FROM users WHERE id NOT IN (1,2,3);
|
||||||
|
|
||||||
|
db.Not([]int64{}).First(&user)
|
||||||
|
//// SELECT * FROM users;
|
||||||
|
|
||||||
|
// Normal SQL
|
||||||
db.Not("name = ?", "jinzhu").First(&user)
|
db.Not("name = ?", "jinzhu").First(&user)
|
||||||
//// user -> select * from users where NOT(name = "jinzhu")
|
//// SELECT * FROM users WHERE NOT(name = "jinzhu");
|
||||||
db.Not("name <> ?", "jinzhu").First(&user)
|
|
||||||
//// user -> select * from users where NOT(name <> "jinzhu")
|
// Not With Struct
|
||||||
db.Not("name", []string{"jinzhu", "jinzhu 2"}).First(&user)
|
|
||||||
//// user -> select * from users where name NOT IN ("jinzhu", "jinzhu 2")
|
|
||||||
db.Not(User{Name: "jinzhu"}).First(&user)
|
db.Not(User{Name: "jinzhu"}).First(&user)
|
||||||
//// user -> select * from users where name <> "jinzhu";
|
//// SELECT * FROM users WHERE name <> "jinzhu";
|
||||||
|
```
|
||||||
|
|
||||||
// Inline search condition
|
### Inline Search Condition
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Find with primary key
|
||||||
db.First(&user, 23)
|
db.First(&user, 23)
|
||||||
//// user -> select * from users where id = 23 limit 1;
|
//// SELECT * FROM users WHERE id = 23 LIMIT 1;
|
||||||
db.First(&user, "name = ?", "jinzhu")
|
|
||||||
//// user -> select * from users where name = "jinzhu" limit 1;
|
// Normal SQL
|
||||||
db.Find(&users, "name = ?", "jinzhu")
|
db.Find(&user, "name = ?", "jinzhu")
|
||||||
//// users -> select * from users where name = "jinzhu";
|
//// SELECT * FROM users WHERE name = "jinzhu";
|
||||||
|
|
||||||
|
// Multiple Conditions
|
||||||
db.Find(&users, "name <> ? and age > ?", "jinzhu", 20)
|
db.Find(&users, "name <> ? and age > ?", "jinzhu", 20)
|
||||||
//// users -> select * from users where name <> "jinzhu" and age > 20;
|
//// SELECT * FROM users WHERE name <> "jinzhu" AND age > 20;
|
||||||
db.Find(&users, &User{Age: 20})
|
|
||||||
//// users -> select * from users where age = 20;
|
// Inline Search With Struct
|
||||||
|
db.Find(&users, User{Age: 20})
|
||||||
|
//// SELECT * FROM users WHERE age = 20;
|
||||||
|
|
||||||
|
// Inline Search With Map
|
||||||
db.Find(&users, map[string]interface{}{"age": 20})
|
db.Find(&users, map[string]interface{}{"age": 20})
|
||||||
//// users -> select * from users where age = 20;
|
//// SELECT * FROM users WHERE age = 20;
|
||||||
|
```
|
||||||
|
|
||||||
|
## FirstOrInit
|
||||||
|
|
||||||
|
Try to load the first record, if fails, initialize struct with search conditions.
|
||||||
|
(only support map or struct conditions, SQL like conditions are not supported)
|
||||||
|
|
||||||
|
```go
|
||||||
|
db.FirstOrInit(&user, User{Name: "non_existing"})
|
||||||
|
//// User{Name: "non_existing"}
|
||||||
|
|
||||||
// FirstOrInit
|
|
||||||
db.FirstOrInit(&user, User{Name: "noexisting_user"})
|
|
||||||
//// user -> User{Name: "noexisting_user"}
|
|
||||||
db.Where(User{Name: "Jinzhu"}).FirstOrInit(&user)
|
db.Where(User{Name: "Jinzhu"}).FirstOrInit(&user)
|
||||||
//// user -> User{Id: 111, Name: "Jinzhu"}
|
|
||||||
db.FirstOrInit(&user, map[string]interface{}{"name": "jinzhu", "age": 20})
|
|
||||||
//// user -> User{Id: 111, Name: "Jinzhu", Age: 20}
|
|
||||||
|
|
||||||
// FirstOrInit With Attrs
|
|
||||||
db.Where(User{Name: "noexisting_user"}).Attrs(User{Age: 20}).FirstOrInit(&user)
|
|
||||||
//// user -> select * from users where name = 'noexisting_user';
|
|
||||||
//// If no record found, will assign the attrs to user, so user become:
|
|
||||||
//// User{Name: "noexisting_user", Age: 20}
|
|
||||||
db.Where(User{Name: "noexisting_user"}).Attrs("age", 20).FirstOrInit(&user)
|
|
||||||
// Same as above
|
|
||||||
db.Where(User{Name: "Jinzhu"}).Attrs(User{Age: 20}).FirstOrInit(&user)
|
|
||||||
//// user -> select * from users where name = 'jinzhu';
|
|
||||||
//// If found the user, will ingore the attrs:
|
|
||||||
//// User{Id: 111, Name: "Jinzhu", Age: 18}
|
|
||||||
|
|
||||||
// FirstOrInit With Assign
|
|
||||||
db.Where(User{Name: "noexisting_user"}).Assign(User{Age: 20}).FirstOrInit(&user)
|
|
||||||
//// user -> select * from users where name = 'noexisting_user';
|
|
||||||
//// If no record found, will assign the value to user, so user become:
|
|
||||||
//// User{Name: "noexisting_user", Age: 20} (same as FirstOrInit With Attrs)
|
|
||||||
db.Where(User{Name: "noexisting_user"}).Assign("age", 20).FirstOrInit(&user)
|
|
||||||
// Same as above
|
|
||||||
//// user -> User{Name: "noexisting_user", Age: 20}
|
|
||||||
db.Where(User{Name: "Jinzhu"}).Assign(User{Age: 20}).FirstOrInit(&user)
|
|
||||||
//// user -> select * from users where name = 'jinzhu';
|
|
||||||
//// If found the user, will assign the value to user, so user become: (different with FirstOrInit With Attrs)
|
|
||||||
//// User{Id: 111, Name: "Jinzhu", Age: 20}
|
//// User{Id: 111, Name: "Jinzhu", Age: 20}
|
||||||
|
|
||||||
// FirstOrCreate
|
db.FirstOrInit(&user, map[string]interface{}{"name": "jinzhu"})
|
||||||
db.FirstOrCreate(&user, User{Name: "noexisting_user"})
|
//// User{Id: 111, Name: "Jinzhu", Age: 20}
|
||||||
//// user -> User{Id: 112, Name: "noexisting_user"}
|
```
|
||||||
|
|
||||||
|
### FirstOrInit With Attrs
|
||||||
|
|
||||||
|
Attr's arguments would be used to initialize struct if not record found, but won't be used for search
|
||||||
|
|
||||||
|
```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}
|
||||||
|
|
||||||
|
// Above code could be simplified if have only one attribute
|
||||||
|
db.Where(User{Name: "noexisting_user"}).Attrs("age", 20).FirstOrInit(&user)
|
||||||
|
|
||||||
|
// If record found, Attrs would be ignored
|
||||||
|
db.Where(User{Name: "Jinzhu"}).Attrs(User{Age: 30}).FirstOrInit(&user)
|
||||||
|
//// SELECT * FROM USERS WHERE name = jinzhu';
|
||||||
|
//// User{Id: 111, Name: "Jinzhu", Age: 20}
|
||||||
|
|
||||||
|
### FirstOrInit With Assign
|
||||||
|
|
||||||
|
Assign's arguments would be used to set the struct even record found, but won't be used for search
|
||||||
|
|
||||||
|
```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"}
|
||||||
|
|
||||||
db.Where(User{Name: "Jinzhu"}).FirstOrCreate(&user)
|
db.Where(User{Name: "Jinzhu"}).FirstOrCreate(&user)
|
||||||
//// user -> User{Id: 111, Name: "Jinzhu"}
|
//// User{Id: 111, Name: "Jinzhu"}
|
||||||
db.FirstOrCreate(&user, map[string]interface{}{"name": "jinzhu", "age": 20})
|
|
||||||
//// user -> User{Id: 111, Name: "Jinzhu", Age: 20}
|
|
||||||
|
|
||||||
|
db.FirstOrCreate(&user, map[string]interface{}{"name": "jinzhu", "age": 30})
|
||||||
|
//// user -> User{Id: 111, Name: "Jinzhu", Age: 20}
|
||||||
|
```
|
||||||
|
|
||||||
|
### FirstOrCreate With Attrs
|
||||||
|
|
||||||
|
Attr's arguments would be used to initialize struct if not record found, but won't be used for search
|
||||||
|
|
||||||
|
```go
|
||||||
// FirstOrCreate With Attrs
|
// FirstOrCreate With Attrs
|
||||||
db.Where(User{Name: "noexisting_user"}).Attrs(User{Age: 20}).FirstOrCreate(&user)
|
db.Where(User{Name: "non_existing"}).Attrs(User{Age: 20}).FirstOrCreate(&user)
|
||||||
//// user -> select * from users where name = 'noexisting_user';
|
//// SELECT * FROM users WHERE name = 'non_existing';
|
||||||
//// If not record found, will assing the attrs to the user first, then create it
|
//// User{Id: 112, Name: "non_existing", Age: 20}
|
||||||
//// Same as db.Where(User{Name: "noexisting_user"}).FirstOrCreate(&user).Update("age": 20), but one less sql
|
|
||||||
db.Where(User{Name: "noexisting_user"}).Attrs("age", 20).FirstOrCreate(&user)
|
|
||||||
// Save as above
|
|
||||||
//// user -> User{Id: 112, Name: "noexisting_user", Age: 20}
|
|
||||||
db.Where(User{Name: "Jinzhu"}).Attrs(User{Age: 20}).FirstOrCreate(&user)
|
|
||||||
//// user -> select * from users where name = 'jinzhu';
|
|
||||||
//// If found any record, will ignore the attrs
|
|
||||||
//// user -> User{Id: 111, Name: "Jinzhu", Age: 18}
|
|
||||||
|
|
||||||
// FirstOrCreate With Assign
|
db.Where(User{Name: "Jinzhu"}).Attrs(User{Age: 30}).FirstOrCreate(&user)
|
||||||
db.Where(User{Name: "noexisting_user"}).Assign(User{Age: 20}).FirstOrCreate(&user)
|
//// User{Id: 111, Name: "Jinzhu", Age: 20}
|
||||||
//// user -> select * from users where name = 'noexisting_user';
|
```
|
||||||
//// If not record found, will assing the value to the user first, then create it
|
|
||||||
//// user -> User{Id: 112, Name: "noexisting_user", Age: 20} (Same as FirstOrCreate With Attrs)
|
|
||||||
db.Where(User{Name: "Jinzhu"}).Assign(User{Age: 20}).FirstOrCreate(&user)
|
|
||||||
//// user -> select * from users where name = 'jinzhu';
|
|
||||||
//// If any record found, will assing the value to the user and update it
|
|
||||||
//// UPDATE users SET age=20 WHERE id = 111;
|
|
||||||
//// user -> User{Id: 111, Name: "Jinzhu", Age: 20}
|
|
||||||
|
|
||||||
|
### FirstOrCreate With Assign
|
||||||
|
|
||||||
|
Assign's arguments would be used to initialize the struct if not record found,
|
||||||
|
If any record found, will assign those values to the record, and save it back to database.
|
||||||
|
|
||||||
|
```go
|
||||||
|
db.Where(User{Name: "non_existing"}).Assign(User{Age: 20}).FirstOrCreate(&user)
|
||||||
|
//// user -> User{Id: 112, Name: "non_existing", Age: 20}
|
||||||
|
|
||||||
|
db.Where(User{Name: "Jinzhu"}).Assign(User{Age: 30}).FirstOrCreate(&user)
|
||||||
|
//// UPDATE users SET age=30 WHERE id = 111;
|
||||||
|
//// User{Id: 111, Name: "Jinzhu", Age: 30}
|
||||||
|
```
|
||||||
|
|
||||||
|
### SELECT
|
||||||
|
|
||||||
|
```go
|
||||||
//// user -> User{Id: 111, Name: "Jinzhu", Age: 18}
|
//// user -> User{Id: 111, Name: "Jinzhu", Age: 18}
|
||||||
//// You must noticed that the Attrs is similar to FirstOrInit with Attrs, yes?
|
//// You must noticed that the Attrs is similar to FirstOrInit with Attrs, yes?
|
||||||
|
|
||||||
|
@ -227,10 +366,10 @@ Below callbacks are defined now:
|
||||||
Callbacks is a function defined to a model, if the function return error, will prevent the database operations.
|
Callbacks is a function defined to a model, if the function return error, will prevent the database operations.
|
||||||
|
|
||||||
func (u *User) BeforeUpdate() (err error) {
|
func (u *User) BeforeUpdate() (err error) {
|
||||||
if u.readonly() {
|
if u.readonly() {
|
||||||
err = errors.New("Read Only User")
|
err = errors.New("Read Only User")
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pluck (get users's age as map)
|
// Pluck (get users's age as map)
|
||||||
|
@ -282,11 +421,11 @@ db.First(&user, 20).Updates(User{Name: "hello", Age: 18})
|
||||||
// Soft Delete
|
// Soft Delete
|
||||||
// For those struct have DeletedAt field, they will get soft delete ability automatically!
|
// For those struct have DeletedAt field, they will get soft delete ability automatically!
|
||||||
type Order struct {
|
type Order struct {
|
||||||
Id int64
|
Id int64
|
||||||
Amount int64
|
Amount int64
|
||||||
CreatedAt time.Time
|
CreatedAt time.Time
|
||||||
UpdatedAt time.Time
|
UpdatedAt time.Time
|
||||||
DeletedAt time.Time
|
DeletedAt time.Time
|
||||||
}
|
}
|
||||||
order := order{Id:10}
|
order := order{Id:10}
|
||||||
db.Delete(&order)
|
db.Delete(&order)
|
||||||
|
@ -350,7 +489,6 @@ db.Where("email = ?", "x@example.org"').Attrs(User{FromIp: "111.111.111.111"}).F
|
||||||
```
|
```
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
* SubStruct
|
|
||||||
* Index, Unique, Valiations
|
* Index, Unique, Valiations
|
||||||
* Auto Migration
|
* Auto Migration
|
||||||
* SQL Log
|
* SQL Log
|
||||||
|
|
46
gorm_test.go
46
gorm_test.go
|
@ -12,12 +12,32 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
Id int64
|
Id int64 // Id: Primary key
|
||||||
|
Birthday time.Time // Time
|
||||||
Age int64
|
Age int64
|
||||||
Birthday time.Time
|
|
||||||
Name string
|
Name string
|
||||||
CreatedAt time.Time
|
CreatedAt time.Time // CreatedAt: Time of record is created, will be insert automatically
|
||||||
UpdatedAt time.Time
|
UpdatedAt time.Time // UpdatedAt: Time of record is updated, will be updated automatically
|
||||||
|
DeletedAt time.Time // DeletedAt: Time of record is deleted, refer Soft Delete for more
|
||||||
|
Email []Email // Embedded structs
|
||||||
|
BillingAddress Address // Embedded struct
|
||||||
|
BillingAddressId int64 // Embedded struct's foreign key
|
||||||
|
ShippingAddress Address // Embedded struct
|
||||||
|
ShippingAddressId int64 // Embedded struct's foreign key
|
||||||
|
}
|
||||||
|
|
||||||
|
type Email struct {
|
||||||
|
Id int64
|
||||||
|
UserId int64 // Foreign key for above embedded structs
|
||||||
|
Email string
|
||||||
|
Subscribed bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type Address struct {
|
||||||
|
Id int64
|
||||||
|
Address1 string
|
||||||
|
Address2 string
|
||||||
|
Post string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Product struct {
|
type Product struct {
|
||||||
|
@ -1004,10 +1024,12 @@ type Category struct {
|
||||||
type Post struct {
|
type Post struct {
|
||||||
Id int64
|
Id int64
|
||||||
CategoryId int64
|
CategoryId int64
|
||||||
|
MainCategoryId int64
|
||||||
Title string
|
Title string
|
||||||
Body string
|
Body string
|
||||||
Comments []Comment
|
Comments []Comment
|
||||||
Category Category
|
Category Category
|
||||||
|
MainCategory Category
|
||||||
}
|
}
|
||||||
|
|
||||||
type Comment struct {
|
type Comment struct {
|
||||||
|
@ -1031,6 +1053,7 @@ func TestSubStruct(t *testing.T) {
|
||||||
Body: "body 1",
|
Body: "body 1",
|
||||||
Comments: []Comment{{Content: "Comment 1"}, {Content: "Comment 2"}},
|
Comments: []Comment{{Content: "Comment 1"}, {Content: "Comment 2"}},
|
||||||
Category: Category{Name: "Category 1"},
|
Category: Category{Name: "Category 1"},
|
||||||
|
MainCategory: Category{Name: "Main Category 1"},
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := db.Save(&post).Error; err != nil {
|
if err := db.Save(&post).Error; err != nil {
|
||||||
|
@ -1043,7 +1066,7 @@ func TestSubStruct(t *testing.T) {
|
||||||
|
|
||||||
var p Post
|
var p Post
|
||||||
db.First(&p, post.Id)
|
db.First(&p, post.Id)
|
||||||
if post.CategoryId == 0 || p.CategoryId == 0 {
|
if post.CategoryId == 0 || p.CategoryId == 0 || post.MainCategoryId == 0 || p.MainCategoryId == 0 {
|
||||||
t.Errorf("Category Id should exist")
|
t.Errorf("Category Id should exist")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1066,3 +1089,16 @@ func TestSubStruct(t *testing.T) {
|
||||||
comment3 := Comment{Content: "Comment 3", Post: Post{Title: "Title 3", Body: "Body 3"}}
|
comment3 := Comment{Content: "Comment 3", Post: Post{Title: "Title 3", Body: "Body 3"}}
|
||||||
db.Save(&comment3)
|
db.Save(&comment3)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestT(t *testing.T) {
|
||||||
|
user := User{Name: "jinzhu", Age: 18, Birthday: time.Now()}
|
||||||
|
db.Save(&user)
|
||||||
|
|
||||||
|
var user2 User
|
||||||
|
db.Where("name in (?)", []string{"1,2"}).First(&user2).Update("name", "hhh")
|
||||||
|
debug(user2)
|
||||||
|
|
||||||
|
var users []User
|
||||||
|
db.Find(&users, User{Age: 20})
|
||||||
|
debug(users)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue