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 <nate.armstrong@eluv.io>
			
			
This commit is contained in:
		
							parent
							
								
									4ec73c9bf4
								
							
						
					
					
						commit
						f3c6fc2533
					
				
							
								
								
									
										104
									
								
								chainable_api.go
									
									
									
									
									
								
							
							
						
						
									
										104
									
								
								chainable_api.go
									
									
									
									
									
								
							| @ -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,6 +303,13 @@ 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}) | ||||
| @ -254,6 +317,13 @@ func (db *DB) Limit(limit int) (tx *DB) { | ||||
| } | ||||
| 
 | ||||
| // 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: "fake@fake.org"}).FirstOrInit(&user)
 | ||||
| //	// user -> User{Name: "non_existing", Email: "fake@fake.org"}
 | ||||
| //
 | ||||
| //	// assign an email if the record is not found, otherwise ignore provided email
 | ||||
| //	db.Where(User{Name: "jinzhu"}).Attrs(User{Email: "fake@fake.org"}).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: "fake@fake.org"}).FirstOrInit(&user)
 | ||||
| //	// user -> User{Name: "non_existing", Email: "fake@fake.org"}
 | ||||
| //
 | ||||
| //	// assign email regardless of if record is found
 | ||||
| //	db.Where(User{Name: "jinzhu"}).Assign(User{Email: "fake@fake.org"}).FirstOrInit(&user)
 | ||||
| //	// user -> User{Name: "jinzhu", Age: 20, Email: "fake@fake.org"}
 | ||||
| //
 | ||||
| // [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 | ||||
|  | ||||
| @ -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: "fake@fake.org"}).FirstOrInit(&user)
 | ||||
| //	// user -> User{Name: "non_existing", Email: "fake@fake.org"}
 | ||||
| //
 | ||||
| //	// assign email regardless of if record is found
 | ||||
| //	db.Where(User{Name: "jinzhu"}).Assign(User{Email: "fake@fake.org"}).FirstOrInit(&user)
 | ||||
| //	// user -> User{Name: "jinzhu", Age: 20, Email: "fake@fake.org"}
 | ||||
| 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: "fake@fake.org"}).FirstOrCreate(&user)
 | ||||
| //	// user -> User{Name: "non_existing", Email: "fake@fake.org"}
 | ||||
| //	// result.RowsAffected -> 1
 | ||||
| //
 | ||||
| //	// assign email regardless of if record is found
 | ||||
| //	result := db.Where(User{Name: "jinzhu"}).Assign(User{Email: "fake@fake.org"}).FirstOrCreate(&user)
 | ||||
| //	// user -> User{Name: "jinzhu", Age: 20, Email: "fake@fake.org"}
 | ||||
| //	// 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{ | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Nate Armstrong
						Nate Armstrong