-
-
Notifications
You must be signed in to change notification settings - Fork 4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Update func comments in chainable_api and FirstOr_ (#5935)
Add comments to functions in chainable_api. Depending on the method, these comments add some additional context or details that are relevant when reading the function, link to the actual docs at gorm.io/docs, or provide examples of use. These comments should make GORM much more pleasant to use with an IDE that provides hoverable comments, and are minimal examples. Also add in-code documentation to FirstOrInit and FirstOrCreate. Almost all examples are directly pulled from the docs, with short comments explaining the code. Most examples omit the `db.Model(&User{})` for brevity, and would not actually work. Co-authored-by: Nate Armstrong <[email protected]>
- Loading branch information
1 parent
4ec73c9
commit f3c6fc2
Showing
2 changed files
with
124 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,7 +13,7 @@ import ( | |
// | ||
// // update all users's name to `hello` | ||
// db.Model(&User{}).Update("name", "hello") | ||
// // if user's primary key is non-blank, will use it as condition, then will only update the user's name to `hello` | ||
// // if user's primary key is non-blank, will use it as condition, then will only update that user's name to `hello` | ||
// db.Model(&user).Update("name", "hello") | ||
func (db *DB) Model(value interface{}) (tx *DB) { | ||
tx = db.getInstance() | ||
|
@@ -22,6 +22,19 @@ func (db *DB) Model(value interface{}) (tx *DB) { | |
} | ||
|
||
// Clauses Add clauses | ||
// | ||
// This supports both standard clauses (clause.OrderBy, clause.Limit, clause.Where) and more | ||
// advanced techniques like specifying lock strength and optimizer hints. See the | ||
// [docs] for more depth. | ||
// | ||
// // add a simple limit clause | ||
// db.Clauses(clause.Limit{Limit: 1}).Find(&User{}) | ||
// // tell the optimizer to use the `idx_user_name` index | ||
// db.Clauses(hints.UseIndex("idx_user_name")).Find(&User{}) | ||
// // specify the lock strength to UPDATE | ||
// db.Clauses(clause.Locking{Strength: "UPDATE"}).Find(&users) | ||
// | ||
// [docs]: https://gorm.io/docs/sql_builder.html#Clauses | ||
func (db *DB) Clauses(conds ...clause.Expression) (tx *DB) { | ||
tx = db.getInstance() | ||
var whereConds []interface{} | ||
|
@@ -45,6 +58,9 @@ func (db *DB) Clauses(conds ...clause.Expression) (tx *DB) { | |
var tableRegexp = regexp.MustCompile(`(?i).+? AS (\w+)\s*(?:$|,)`) | ||
|
||
// Table specify the table you would like to run db operations | ||
// | ||
// // Get a user | ||
// db.Table("users").take(&result) | ||
func (db *DB) Table(name string, args ...interface{}) (tx *DB) { | ||
tx = db.getInstance() | ||
if strings.Contains(name, " ") || strings.Contains(name, "`") || len(args) > 0 { | ||
|
@@ -66,6 +82,11 @@ func (db *DB) Table(name string, args ...interface{}) (tx *DB) { | |
} | ||
|
||
// Distinct specify distinct fields that you want querying | ||
// | ||
// // Select distinct names of users | ||
// db.Distinct("name").Find(&results) | ||
// // Select distinct name/age pairs from users | ||
// db.Distinct("name", "age").Find(&results) | ||
func (db *DB) Distinct(args ...interface{}) (tx *DB) { | ||
tx = db.getInstance() | ||
tx.Statement.Distinct = true | ||
|
@@ -76,6 +97,14 @@ func (db *DB) Distinct(args ...interface{}) (tx *DB) { | |
} | ||
|
||
// Select specify fields that you want when querying, creating, updating | ||
// | ||
// Use Select when you only want a subset of the fields. By default, GORM will select all fields. | ||
// Select accepts both string arguments and arrays. | ||
// | ||
// // Select name and age of user using multiple arguments | ||
// db.Select("name", "age").Find(&users) | ||
// // Select name and age of user using an array | ||
// db.Select([]string{"name", "age"}).Find(&users) | ||
func (db *DB) Select(query interface{}, args ...interface{}) (tx *DB) { | ||
tx = db.getInstance() | ||
|
||
|
@@ -153,6 +182,17 @@ func (db *DB) Omit(columns ...string) (tx *DB) { | |
} | ||
|
||
// Where add conditions | ||
// | ||
// See the [docs] for details on the various formats that where clauses can take. By default, where clauses chain with AND. | ||
// | ||
// // Find the first user with name jinzhu | ||
// db.Where("name = ?", "jinzhu").First(&user) | ||
// // Find the first user with name jinzhu and age 20 | ||
// db.Where(&User{Name: "jinzhu", Age: 20}).First(&user) | ||
// // Find the first user with name jinzhu and age not equal to 20 | ||
// db.Where("name = ?", "jinzhu").Where("age <> ?", "20").First(&user) | ||
// | ||
// [docs]: https://gorm.io/docs/query.html#Conditions | ||
func (db *DB) Where(query interface{}, args ...interface{}) (tx *DB) { | ||
tx = db.getInstance() | ||
if conds := tx.Statement.BuildCondition(query, args...); len(conds) > 0 { | ||
|
@@ -162,6 +202,11 @@ func (db *DB) Where(query interface{}, args ...interface{}) (tx *DB) { | |
} | ||
|
||
// Not add NOT conditions | ||
// | ||
// Not works similarly to where, and has the same syntax. | ||
// | ||
// // Find the first user with name not equal to jinzhu | ||
// db.Not("name = ?", "jinzhu").First(&user) | ||
func (db *DB) Not(query interface{}, args ...interface{}) (tx *DB) { | ||
tx = db.getInstance() | ||
if conds := tx.Statement.BuildCondition(query, args...); len(conds) > 0 { | ||
|
@@ -171,6 +216,11 @@ func (db *DB) Not(query interface{}, args ...interface{}) (tx *DB) { | |
} | ||
|
||
// Or add OR conditions | ||
// | ||
// Or is used to chain together queries with an OR. | ||
// | ||
// // Find the first user with name equal to jinzhu or john | ||
// db.Where("name = ?", "jinzhu").Or("name = ?", "john").First(&user) | ||
func (db *DB) Or(query interface{}, args ...interface{}) (tx *DB) { | ||
tx = db.getInstance() | ||
if conds := tx.Statement.BuildCondition(query, args...); len(conds) > 0 { | ||
|
@@ -203,6 +253,9 @@ func (db *DB) Joins(query string, args ...interface{}) (tx *DB) { | |
} | ||
|
||
// Group specify the group method on the find | ||
// | ||
// // Select the sum age of users with given names | ||
// db.Model(&User{}).Select("name, sum(age) as total").Group("name").Find(&results) | ||
func (db *DB) Group(name string) (tx *DB) { | ||
tx = db.getInstance() | ||
|
||
|
@@ -214,6 +267,9 @@ func (db *DB) Group(name string) (tx *DB) { | |
} | ||
|
||
// Having specify HAVING conditions for GROUP BY | ||
// | ||
// // Select the sum age of users with name jinzhu | ||
// db.Model(&User{}).Select("name, sum(age) as total").Group("name").Having("name = ?", "jinzhu").Find(&result) | ||
func (db *DB) Having(query interface{}, args ...interface{}) (tx *DB) { | ||
tx = db.getInstance() | ||
tx.Statement.AddClause(clause.GroupBy{ | ||
|
@@ -222,7 +278,7 @@ func (db *DB) Having(query interface{}, args ...interface{}) (tx *DB) { | |
return | ||
} | ||
|
||
// Order specify order when retrieve records from database | ||
// Order specify order when retrieving records from database | ||
// | ||
// db.Order("name DESC") | ||
// db.Order(clause.OrderByColumn{Column: clause.Column{Name: "name"}, Desc: true}) | ||
|
@@ -247,13 +303,27 @@ func (db *DB) Order(value interface{}) (tx *DB) { | |
} | ||
|
||
// Limit specify the number of records to be retrieved | ||
// | ||
// Limit conditions can be cancelled by using `Limit(-1)`. | ||
// | ||
// // retrieve 3 users | ||
// db.Limit(3).Find(&users) | ||
// // retrieve 3 users into users1, and all users into users2 | ||
// db.Limit(3).Find(&users1).Limit(-1).Find(&users2) | ||
func (db *DB) Limit(limit int) (tx *DB) { | ||
tx = db.getInstance() | ||
tx.Statement.AddClause(clause.Limit{Limit: &limit}) | ||
return | ||
} | ||
|
||
// Offset specify the number of records to skip before starting to return the records | ||
// | ||
// Offset conditions can be cancelled by using `Offset(-1)`. | ||
// | ||
// // select the third user | ||
// db.Offset(2).First(&user) | ||
// // select the first user by cancelling an earlier chained offset | ||
// db.Offset(5).Offset(-1).First(&user) | ||
func (db *DB) Offset(offset int) (tx *DB) { | ||
tx = db.getInstance() | ||
tx.Statement.AddClause(clause.Limit{Offset: offset}) | ||
|
@@ -281,6 +351,7 @@ func (db *DB) Scopes(funcs ...func(*DB) *DB) (tx *DB) { | |
|
||
// Preload preload associations with given conditions | ||
// | ||
// // get all users, and preload all non-cancelled orders | ||
// db.Preload("Orders", "state NOT IN (?)", "cancelled").Find(&users) | ||
func (db *DB) Preload(query string, args ...interface{}) (tx *DB) { | ||
tx = db.getInstance() | ||
|
@@ -291,12 +362,41 @@ func (db *DB) Preload(query string, args ...interface{}) (tx *DB) { | |
return | ||
} | ||
|
||
// Attrs provide attributes used in [FirstOrCreate] or [FirstOrInit] | ||
// | ||
// Attrs only adds attributes if the record is not found. | ||
// | ||
// // assign an email if the record is not found | ||
// db.Where(User{Name: "non_existing"}).Attrs(User{Email: "[email protected]"}).FirstOrInit(&user) | ||
// // user -> User{Name: "non_existing", Email: "[email protected]"} | ||
// | ||
// // assign an email if the record is not found, otherwise ignore provided email | ||
// db.Where(User{Name: "jinzhu"}).Attrs(User{Email: "[email protected]"}).FirstOrInit(&user) | ||
// // user -> User{Name: "jinzhu", Age: 20} | ||
// | ||
// [FirstOrCreate]: https://gorm.io/docs/advanced_query.html#FirstOrCreate | ||
// [FirstOrInit]: https://gorm.io/docs/advanced_query.html#FirstOrInit | ||
func (db *DB) Attrs(attrs ...interface{}) (tx *DB) { | ||
tx = db.getInstance() | ||
tx.Statement.attrs = attrs | ||
return | ||
} | ||
|
||
// Assign provide attributes used in [FirstOrCreate] or [FirstOrInit] | ||
// | ||
// Assign adds attributes even if the record is found. If using FirstOrCreate, this means that | ||
// records will be updated even if they are found. | ||
// | ||
// // assign an email regardless of if the record is not found | ||
// db.Where(User{Name: "non_existing"}).Assign(User{Email: "[email protected]"}).FirstOrInit(&user) | ||
// // user -> User{Name: "non_existing", Email: "[email protected]"} | ||
// | ||
// // assign email regardless of if record is found | ||
// db.Where(User{Name: "jinzhu"}).Assign(User{Email: "[email protected]"}).FirstOrInit(&user) | ||
// // user -> User{Name: "jinzhu", Age: 20, Email: "[email protected]"} | ||
// | ||
// [FirstOrCreate]: https://gorm.io/docs/advanced_query.html#FirstOrCreate | ||
// [FirstOrInit]: https://gorm.io/docs/advanced_query.html#FirstOrInit | ||
func (db *DB) Assign(attrs ...interface{}) (tx *DB) { | ||
tx = db.getInstance() | ||
tx.Statement.assigns = attrs | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -294,6 +294,16 @@ func (db *DB) assignInterfacesToValue(values ...interface{}) { | |
|
||
// FirstOrInit finds the first matching record, otherwise if not found initializes a new instance with given conds. | ||
// Each conds must be a struct or map. | ||
// | ||
// FirstOrInit never modifies the database. It is often used with Assign and Attrs. | ||
// | ||
// // assign an email if the record is not found | ||
// db.Where(User{Name: "non_existing"}).Attrs(User{Email: "[email protected]"}).FirstOrInit(&user) | ||
// // user -> User{Name: "non_existing", Email: "[email protected]"} | ||
// | ||
// // assign email regardless of if record is found | ||
// db.Where(User{Name: "jinzhu"}).Assign(User{Email: "[email protected]"}).FirstOrInit(&user) | ||
// // user -> User{Name: "jinzhu", Age: 20, Email: "[email protected]"} | ||
func (db *DB) FirstOrInit(dest interface{}, conds ...interface{}) (tx *DB) { | ||
queryTx := db.Limit(1).Order(clause.OrderByColumn{ | ||
Column: clause.Column{Table: clause.CurrentTable, Name: clause.PrimaryKey}, | ||
|
@@ -321,6 +331,18 @@ func (db *DB) FirstOrInit(dest interface{}, conds ...interface{}) (tx *DB) { | |
|
||
// FirstOrCreate finds the first matching record, otherwise if not found creates a new instance with given conds. | ||
// Each conds must be a struct or map. | ||
// | ||
// Using FirstOrCreate in conjunction with Assign will result in an update to the database even if the record exists. | ||
// | ||
// // assign an email if the record is not found | ||
// result := db.Where(User{Name: "non_existing"}).Attrs(User{Email: "[email protected]"}).FirstOrCreate(&user) | ||
// // user -> User{Name: "non_existing", Email: "[email protected]"} | ||
// // result.RowsAffected -> 1 | ||
// | ||
// // assign email regardless of if record is found | ||
// result := db.Where(User{Name: "jinzhu"}).Assign(User{Email: "[email protected]"}).FirstOrCreate(&user) | ||
// // user -> User{Name: "jinzhu", Age: 20, Email: "[email protected]"} | ||
// // result.RowsAffected -> 1 | ||
func (db *DB) FirstOrCreate(dest interface{}, conds ...interface{}) (tx *DB) { | ||
tx = db.getInstance() | ||
queryTx := db.Session(&Session{}).Limit(1).Order(clause.OrderByColumn{ | ||
|