318 lines
8.6 KiB
Go
318 lines
8.6 KiB
Go
package gorm
|
|
|
|
// Where add condition
|
|
func (s *DB) Where(query interface{}, args ...interface{}) *DB {
|
|
tx := s.init()
|
|
tx.Statement.AddConditions(tx.Statement.BuildCondition(query, args...))
|
|
return tx
|
|
}
|
|
|
|
// Not add NOT condition
|
|
func (s *DB) Not(query interface{}, args ...interface{}) *DB {
|
|
tx := s.init()
|
|
tx.Statement.AddConditions(Not([]ConditionInterface{tx.Statement.BuildCondition(query, args...)}))
|
|
return tx
|
|
}
|
|
|
|
// And add AND conditions
|
|
func (s *DB) And(conds ...ConditionInterface) *DB {
|
|
tx := s.init()
|
|
tx.Statement.AddConditions(And(conds))
|
|
return tx
|
|
}
|
|
|
|
// Or add OR conditions
|
|
func (s *DB) Or(conds ...ConditionInterface) *DB {
|
|
tx := s.init()
|
|
tx.Statement.AddConditions(Or(conds))
|
|
return tx
|
|
}
|
|
|
|
// Joins specify Joins conditions
|
|
// db.Joins("JOIN emails ON emails.user_id = users.id AND emails.email = ?", "jinzhu@example.org").Find(&user)
|
|
func (s *DB) Joins(query string, args ...interface{}) *DB {
|
|
tx := s.init()
|
|
// FIXME
|
|
tx.Statement.Joins = append(tx.Statement.Joins, Join{Conditions: []ConditionInterface{tx.Statement.BuildCondition(query, args...)}})
|
|
return tx
|
|
}
|
|
|
|
// Group specify the group method on the find
|
|
func (s *DB) Group(column string) *DB {
|
|
tx := s.init()
|
|
tx.Statement.GroupBy.GroupByColumns = append(tx.Statement.GroupBy.GroupByColumns, column)
|
|
return tx
|
|
}
|
|
|
|
// Having specify HAVING conditions for GROUP BY
|
|
func (s *DB) Having(query interface{}, args ...interface{}) *DB {
|
|
tx := s.init()
|
|
tx.Statement.GroupBy.Having = append(tx.Statement.GroupBy.Having, tx.Statement.BuildCondition(query, args...))
|
|
return tx
|
|
}
|
|
|
|
// Order specify order when retrieve records from database
|
|
// db.Order("name DESC")
|
|
// db.Order(gorm.Expr("name = ? DESC", "first")) // sql expression
|
|
func (s *DB) Order(value interface{}) *DB {
|
|
tx := s.init()
|
|
tx.Statement.OrderBy = append(tx.Statement.OrderBy, value)
|
|
return tx
|
|
}
|
|
|
|
// Reorder works like Order, but will overwrite current order information
|
|
func (s *DB) Reorder(value interface{}) *DB {
|
|
tx := s.init()
|
|
tx.Statement.OrderBy = []OrderCondition{value}
|
|
return tx
|
|
}
|
|
|
|
// Limit specify the number of records to be retrieved
|
|
func (s *DB) Limit(limit int64) *DB {
|
|
tx := s.init()
|
|
if limit < 0 {
|
|
tx.Statement.Limit.Limit = nil
|
|
} else {
|
|
tx.Statement.Limit.Limit = &limit
|
|
}
|
|
return tx
|
|
}
|
|
|
|
// Offset specify the number of records to skip before starting to return the records
|
|
func (s *DB) Offset(offset int64) *DB {
|
|
tx := s.init()
|
|
if offset < 0 {
|
|
tx.Statement.Limit.Offset = nil
|
|
} else {
|
|
tx.Statement.Limit.Offset = &offset
|
|
}
|
|
return tx
|
|
}
|
|
|
|
// Select specify fields that you want when querying, creating, updating
|
|
func (s *DB) Select(query interface{}, args ...interface{}) *DB {
|
|
tx := s.init()
|
|
|
|
switch value := query.(type) {
|
|
case string:
|
|
tx.Statement.Select.Columns = []string{value}
|
|
case []string:
|
|
tx.Statement.Select.Columns = value
|
|
default:
|
|
tx.AddError(ErrUnsupportedSelect)
|
|
}
|
|
tx.Statement.Select.Args = args
|
|
return tx
|
|
}
|
|
|
|
// Omit specify fields that you want to ignore when creating, updating and querying
|
|
func (s *DB) Omit(columns ...string) *DB {
|
|
tx := s.init()
|
|
tx.Statement.Omit = columns
|
|
return tx
|
|
}
|
|
|
|
// First find first record that match given conditions, order by primary key
|
|
func (s *DB) First(out interface{}, where ...interface{}) *DB {
|
|
conds := []interface{}{Limit{Limit: &one}, Settings{"gorm:order_by_primary_key": "ASC"}}
|
|
if len(where) > 0 {
|
|
conds = append(conds, s.Statement.BuildCondition(where[0], where[1:]...))
|
|
}
|
|
return s.Find(out, conds...)
|
|
}
|
|
|
|
// Take return a record that match given conditions, the order will depend on the database implementation
|
|
func (s *DB) Take(out interface{}, where ...interface{}) *DB {
|
|
conds := []interface{}{Limit{Limit: &one}}
|
|
if len(where) > 0 {
|
|
conds = append(conds, s.Statement.BuildCondition(where[0], where[1:]...))
|
|
}
|
|
return s.Find(out, conds...)
|
|
}
|
|
|
|
// Last find last record that match given conditions, order by primary key
|
|
func (s *DB) Last(out interface{}, where ...interface{}) *DB {
|
|
conds := []interface{}{Limit{Limit: &one}, Settings{"gorm:order_by_primary_key": "DESC"}}
|
|
if len(where) > 0 {
|
|
conds = append(conds, s.Statement.BuildCondition(where[0], where[1:]...))
|
|
}
|
|
return s.Find(out, conds...)
|
|
}
|
|
|
|
// Find find records that match given conditions
|
|
func (s *DB) Find(out interface{}, where ...interface{}) *DB {
|
|
tx := s.init()
|
|
stmt := tx.Statement
|
|
stmt.Dest = out
|
|
|
|
// has inline condition
|
|
if len(where) > 0 {
|
|
clone := tx.clone()
|
|
stmt = s.Statement.Clone()
|
|
stmt.Conditions = append(stmt.Conditions, s.Statement.BuildCondition(where[0], where[1:]...))
|
|
tx.AddError(clone.Dialect().Query(clone))
|
|
tx.AddError(clone.Error)
|
|
} else {
|
|
tx.AddError(tx.Dialect().Query(tx))
|
|
}
|
|
|
|
return tx
|
|
}
|
|
|
|
// Scan scan value to a struct
|
|
func (s *DB) Scan(dest interface{}) *DB {
|
|
var (
|
|
tx = s.init()
|
|
stmt = tx.Statement.Clone()
|
|
)
|
|
|
|
stmt.Table = stmt.Dest
|
|
stmt.Dest = dest
|
|
tx.AddError(tx.Dialect().Query(tx))
|
|
return tx
|
|
}
|
|
|
|
// Create insert the value into database
|
|
func (s *DB) Create(value interface{}) *DB {
|
|
tx := s.init()
|
|
tx.Statement.Dest = value
|
|
tx.AddError(tx.Dialect().Insert(tx))
|
|
return tx
|
|
}
|
|
|
|
// Save update value in database, if the value doesn't have primary key, will insert it
|
|
func (s *DB) Save(value interface{}) *DB {
|
|
tx := s.init()
|
|
tx.Statement.Dest = value
|
|
// FIXME check primary key has value or not
|
|
tx.AddError(tx.Dialect().Update(tx))
|
|
return tx
|
|
}
|
|
|
|
// Update update attributes with callbacks, refer: https://jinzhu.github.io/gorm/crud.html#update
|
|
func (s *DB) Update(column string, value interface{}) *DB {
|
|
tx := s.init()
|
|
tx.Statement.Assignments = append(tx.Statement.Assignments, Assignment{Column: column, Value: value})
|
|
tx.AddError(tx.Dialect().Update(tx))
|
|
return tx
|
|
}
|
|
|
|
// Updates update attributes with callbacks, refer: https://jinzhu.github.io/gorm/crud.html#update
|
|
func (s *DB) Updates(values interface{}) *DB {
|
|
tx := s.init()
|
|
tx.Statement.Assignments = append(tx.Statement.Assignments, Assignment{Value: values})
|
|
tx.AddError(tx.Dialect().Update(tx))
|
|
return tx
|
|
}
|
|
|
|
// Delete delete value match given conditions, if the value has primary key, then will including the primary key as condition
|
|
func (s *DB) Delete(value interface{}, where ...interface{}) *DB {
|
|
tx := s.init()
|
|
stmt := tx.Statement
|
|
stmt.Dest = value
|
|
|
|
// has inline condition
|
|
if len(where) > 0 {
|
|
clone := tx.clone()
|
|
stmt = s.Statement.Clone()
|
|
stmt.Conditions = append(stmt.Conditions, s.Statement.BuildCondition(where[0], where[1:]...))
|
|
tx.AddError(clone.Dialect().Update(clone))
|
|
tx.AddError(clone.Error)
|
|
} else {
|
|
tx.AddError(tx.Dialect().Update(tx))
|
|
}
|
|
|
|
return tx
|
|
}
|
|
|
|
// Model specify the model you would like to run db operations
|
|
// // 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`
|
|
// db.Model(&user).Update("name", "hello")
|
|
func (s *DB) Model(value interface{}) *DB {
|
|
tx := s.init()
|
|
tx.Statement.Dest = value
|
|
return tx
|
|
}
|
|
|
|
// Table specify the table you would like to run db operations
|
|
func (s *DB) Table(name string) *DB {
|
|
tx := s.init()
|
|
tx.Statement.Table = name
|
|
return tx
|
|
}
|
|
|
|
// AddError add error to the db
|
|
func (s *DB) AddError(err error) {
|
|
if err != nil {
|
|
if err != ErrRecordNotFound {
|
|
s.Config.Logger.Error(err)
|
|
}
|
|
|
|
if errs := s.GetErrors(); len(errs) == 0 {
|
|
s.Error = err
|
|
} else {
|
|
s.Error = Errors(errs).Add(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// GetErrors get happened errors from the db
|
|
func (s *DB) GetErrors() []error {
|
|
if errs, ok := s.Error.(Errors); ok {
|
|
return errs
|
|
} else if s.Error != nil {
|
|
return []error{s.Error}
|
|
}
|
|
return []error{}
|
|
}
|
|
|
|
// Dialect return DB dialect
|
|
func (s *DB) Dialect() Dialect {
|
|
if s.TxDialect != nil {
|
|
return s.TxDialect
|
|
}
|
|
return s.Config.Dialect
|
|
}
|
|
|
|
// Scopes pass current database connection to arguments `func(*DB) *DB`, which could be used to add conditions dynamically
|
|
// func AmountGreaterThan1000(db *gorm.DB) *gorm.DB {
|
|
// return db.Where("amount > ?", 1000)
|
|
// }
|
|
//
|
|
// func OrderStatus(status []string) func (db *gorm.DB) *gorm.DB {
|
|
// return func (db *gorm.DB) *gorm.DB {
|
|
// return db.Scopes(AmountGreaterThan1000).Where("status in (?)", status)
|
|
// }
|
|
// }
|
|
//
|
|
// db.Scopes(AmountGreaterThan1000, OrderStatus([]string{"paid", "shipped"})).Find(&orders)
|
|
// Refer https://jinzhu.github.io/gorm/crud.html#scopes
|
|
func (s *DB) Scopes(funcs ...func(*DB) *DB) *DB {
|
|
for _, f := range funcs {
|
|
s = f(s)
|
|
}
|
|
return s
|
|
}
|
|
|
|
// init init DB
|
|
func (s *DB) init() *DB {
|
|
if s.Statement == nil {
|
|
return &DB{
|
|
TxDialect: s.TxDialect,
|
|
Statement: &Statement{},
|
|
Config: s.Config,
|
|
}
|
|
}
|
|
return s
|
|
}
|
|
|
|
func (s *DB) clone() *DB {
|
|
return &DB{
|
|
TxDialect: s.TxDialect,
|
|
Statement: s.Statement,
|
|
Config: s.Config,
|
|
}
|
|
}
|