main.go 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817
  1. package gorm
  2. import (
  3. "context"
  4. "database/sql"
  5. "errors"
  6. "fmt"
  7. "reflect"
  8. "strings"
  9. "sync"
  10. "time"
  11. )
  12. // DB contains information for current db connection
  13. type DB struct {
  14. Value interface{}
  15. Error error
  16. RowsAffected int64
  17. // single db
  18. db SQLCommon
  19. blockGlobalUpdate bool
  20. logMode logModeValue
  21. logger logger
  22. search *search
  23. values sync.Map
  24. // global db
  25. parent *DB
  26. callbacks *Callback
  27. dialect Dialect
  28. singularTable bool
  29. }
  30. type logModeValue int
  31. const (
  32. defaultLogMode logModeValue = iota
  33. noLogMode
  34. detailedLogMode
  35. )
  36. // Open initialize a new db connection, need to import driver first, e.g:
  37. //
  38. // import _ "github.com/go-sql-driver/mysql"
  39. // func main() {
  40. // db, err := gorm.Open("mysql", "user:password@/dbname?charset=utf8&parseTime=True&loc=Local")
  41. // }
  42. // GORM has wrapped some drivers, for easier to remember driver's import path, so you could import the mysql driver with
  43. // import _ "github.com/jinzhu/gorm/dialects/mysql"
  44. // // import _ "github.com/jinzhu/gorm/dialects/postgres"
  45. // // import _ "github.com/jinzhu/gorm/dialects/sqlite"
  46. // // import _ "github.com/jinzhu/gorm/dialects/mssql"
  47. func Open(dialect string, args ...interface{}) (db *DB, err error) {
  48. if len(args) == 0 {
  49. err = errors.New("invalid database source")
  50. return nil, err
  51. }
  52. var source string
  53. var dbSQL SQLCommon
  54. var ownDbSQL bool
  55. switch value := args[0].(type) {
  56. case string:
  57. var driver = dialect
  58. if len(args) == 1 {
  59. source = value
  60. } else if len(args) >= 2 {
  61. driver = value
  62. source = args[1].(string)
  63. }
  64. dbSQL, err = sql.Open(driver, source)
  65. ownDbSQL = true
  66. case SQLCommon:
  67. dbSQL = value
  68. ownDbSQL = false
  69. default:
  70. return nil, fmt.Errorf("invalid database source: %v is not a valid type", value)
  71. }
  72. db = &DB{
  73. db: dbSQL,
  74. logger: defaultLogger,
  75. callbacks: DefaultCallback,
  76. dialect: newDialect(dialect, dbSQL),
  77. }
  78. db.parent = db
  79. if err != nil {
  80. return
  81. }
  82. // Send a ping to make sure the database connection is alive.
  83. if d, ok := dbSQL.(*sql.DB); ok {
  84. if err = d.Ping(); err != nil && ownDbSQL {
  85. d.Close()
  86. }
  87. }
  88. return
  89. }
  90. // New clone a new db connection without search conditions
  91. func (s *DB) New() *DB {
  92. clone := s.clone()
  93. clone.search = nil
  94. clone.Value = nil
  95. return clone
  96. }
  97. type closer interface {
  98. Close() error
  99. }
  100. // Close close current db connection. If database connection is not an io.Closer, returns an error.
  101. func (s *DB) Close() error {
  102. if db, ok := s.parent.db.(closer); ok {
  103. return db.Close()
  104. }
  105. return errors.New("can't close current db")
  106. }
  107. // DB get `*sql.DB` from current connection
  108. // If the underlying database connection is not a *sql.DB, returns nil
  109. func (s *DB) DB() *sql.DB {
  110. db, _ := s.db.(*sql.DB)
  111. return db
  112. }
  113. // CommonDB return the underlying `*sql.DB` or `*sql.Tx` instance, mainly intended to allow coexistence with legacy non-GORM code.
  114. func (s *DB) CommonDB() SQLCommon {
  115. return s.db
  116. }
  117. // Dialect get dialect
  118. func (s *DB) Dialect() Dialect {
  119. return s.dialect
  120. }
  121. // Callback return `Callbacks` container, you could add/change/delete callbacks with it
  122. // db.Callback().Create().Register("update_created_at", updateCreated)
  123. // Refer https://jinzhu.github.io/gorm/development.html#callbacks
  124. func (s *DB) Callback() *Callback {
  125. s.parent.callbacks = s.parent.callbacks.clone()
  126. return s.parent.callbacks
  127. }
  128. // SetLogger replace default logger
  129. func (s *DB) SetLogger(log logger) {
  130. s.logger = log
  131. }
  132. // LogMode set log mode, `true` for detailed logs, `false` for no log, default, will only print error logs
  133. func (s *DB) LogMode(enable bool) *DB {
  134. if enable {
  135. s.logMode = detailedLogMode
  136. } else {
  137. s.logMode = noLogMode
  138. }
  139. return s
  140. }
  141. // BlockGlobalUpdate if true, generates an error on update/delete without where clause.
  142. // This is to prevent eventual error with empty objects updates/deletions
  143. func (s *DB) BlockGlobalUpdate(enable bool) *DB {
  144. s.blockGlobalUpdate = enable
  145. return s
  146. }
  147. // HasBlockGlobalUpdate return state of block
  148. func (s *DB) HasBlockGlobalUpdate() bool {
  149. return s.blockGlobalUpdate
  150. }
  151. // SingularTable use singular table by default
  152. func (s *DB) SingularTable(enable bool) {
  153. modelStructsMap = sync.Map{}
  154. s.parent.singularTable = enable
  155. }
  156. // NewScope create a scope for current operation
  157. func (s *DB) NewScope(value interface{}) *Scope {
  158. dbClone := s.clone()
  159. dbClone.Value = value
  160. return &Scope{db: dbClone, Search: dbClone.search, Value: value}
  161. }
  162. // QueryExpr returns the query as expr object
  163. func (s *DB) QueryExpr() *expr {
  164. scope := s.NewScope(s.Value)
  165. scope.InstanceSet("skip_bindvar", true)
  166. scope.prepareQuerySQL()
  167. return Expr(scope.SQL, scope.SQLVars...)
  168. }
  169. // SubQuery returns the query as sub query
  170. func (s *DB) SubQuery() *expr {
  171. scope := s.NewScope(s.Value)
  172. scope.InstanceSet("skip_bindvar", true)
  173. scope.prepareQuerySQL()
  174. return Expr(fmt.Sprintf("(%v)", scope.SQL), scope.SQLVars...)
  175. }
  176. // Where return a new relation, filter records with given conditions, accepts `map`, `struct` or `string` as conditions, refer http://jinzhu.github.io/gorm/crud.html#query
  177. func (s *DB) Where(query interface{}, args ...interface{}) *DB {
  178. return s.clone().search.Where(query, args...).db
  179. }
  180. func (s *DB) Ctx(ctx context.Context) *DB {
  181. return s.clone().search.Ctx(ctx).db
  182. }
  183. // Or filter records that match before conditions or this one, similar to `Where`
  184. func (s *DB) Or(query interface{}, args ...interface{}) *DB {
  185. return s.clone().search.Or(query, args...).db
  186. }
  187. // Not filter records that don't match current conditions, similar to `Where`
  188. func (s *DB) Not(query interface{}, args ...interface{}) *DB {
  189. return s.clone().search.Not(query, args...).db
  190. }
  191. // Limit specify the number of records to be retrieved
  192. func (s *DB) Limit(limit interface{}) *DB {
  193. return s.clone().search.Limit(limit).db
  194. }
  195. // Offset specify the number of records to skip before starting to return the records
  196. func (s *DB) Offset(offset interface{}) *DB {
  197. return s.clone().search.Offset(offset).db
  198. }
  199. // Order specify order when retrieve records from database, set reorder to `true` to overwrite defined conditions
  200. // db.Order("name DESC")
  201. // db.Order("name DESC", true) // reorder
  202. // db.Order(gorm.Expr("name = ? DESC", "first")) // sql expression
  203. func (s *DB) Order(value interface{}, reorder ...bool) *DB {
  204. return s.clone().search.Order(value, reorder...).db
  205. }
  206. // Select specify fields that you want to retrieve from database when querying, by default, will select all fields;
  207. // When creating/updating, specify fields that you want to save to database
  208. func (s *DB) Select(query interface{}, args ...interface{}) *DB {
  209. return s.clone().search.Select(query, args...).db
  210. }
  211. // Omit specify fields that you want to ignore when saving to database for creating, updating
  212. func (s *DB) Omit(columns ...string) *DB {
  213. return s.clone().search.Omit(columns...).db
  214. }
  215. // Group specify the group method on the find
  216. func (s *DB) Group(query string) *DB {
  217. return s.clone().search.Group(query).db
  218. }
  219. // Having specify HAVING conditions for GROUP BY
  220. func (s *DB) Having(query interface{}, values ...interface{}) *DB {
  221. return s.clone().search.Having(query, values...).db
  222. }
  223. // Joins specify Joins conditions
  224. // db.Joins("JOIN emails ON emails.user_id = users.id AND emails.email = ?", "jinzhu@example.org").Find(&user)
  225. func (s *DB) Joins(query string, args ...interface{}) *DB {
  226. return s.clone().search.Joins(query, args...).db
  227. }
  228. // Scopes pass current database connection to arguments `func(*DB) *DB`, which could be used to add conditions dynamically
  229. // func AmountGreaterThan1000(db *gorm.DB) *gorm.DB {
  230. // return db.Where("amount > ?", 1000)
  231. // }
  232. //
  233. // func OrderStatus(status []string) func (db *gorm.DB) *gorm.DB {
  234. // return func (db *gorm.DB) *gorm.DB {
  235. // return db.Scopes(AmountGreaterThan1000).Where("status in (?)", status)
  236. // }
  237. // }
  238. //
  239. // db.Scopes(AmountGreaterThan1000, OrderStatus([]string{"paid", "shipped"})).Find(&orders)
  240. // Refer https://jinzhu.github.io/gorm/crud.html#scopes
  241. func (s *DB) Scopes(funcs ...func(*DB) *DB) *DB {
  242. for _, f := range funcs {
  243. s = f(s)
  244. }
  245. return s
  246. }
  247. // Unscoped return all record including deleted record, refer Soft Delete https://jinzhu.github.io/gorm/crud.html#soft-delete
  248. func (s *DB) Unscoped() *DB {
  249. return s.clone().search.unscoped().db
  250. }
  251. // Attrs initialize struct with argument if record not found with `FirstOrInit` https://jinzhu.github.io/gorm/crud.html#firstorinit or `FirstOrCreate` https://jinzhu.github.io/gorm/crud.html#firstorcreate
  252. func (s *DB) Attrs(attrs ...interface{}) *DB {
  253. return s.clone().search.Attrs(attrs...).db
  254. }
  255. // Assign assign result with argument regardless it is found or not with `FirstOrInit` https://jinzhu.github.io/gorm/crud.html#firstorinit or `FirstOrCreate` https://jinzhu.github.io/gorm/crud.html#firstorcreate
  256. func (s *DB) Assign(attrs ...interface{}) *DB {
  257. return s.clone().search.Assign(attrs...).db
  258. }
  259. // First find first record that match given conditions, order by primary key
  260. func (s *DB) First(out interface{}, where ...interface{}) *DB {
  261. newScope := s.NewScope(out)
  262. newScope.Search.Limit(1)
  263. return newScope.Set("gorm:order_by_primary_key", "ASC").
  264. inlineCondition(where...).callCallbacks(s.parent.callbacks.queries).db
  265. }
  266. // Take return a record that match given conditions, the order will depend on the database implementation
  267. func (s *DB) Take(out interface{}, where ...interface{}) *DB {
  268. newScope := s.NewScope(out)
  269. newScope.Search.Limit(1)
  270. return newScope.inlineCondition(where...).callCallbacks(s.parent.callbacks.queries).db
  271. }
  272. // Last find last record that match given conditions, order by primary key
  273. func (s *DB) Last(out interface{}, where ...interface{}) *DB {
  274. newScope := s.NewScope(out)
  275. newScope.Search.Limit(1)
  276. return newScope.Set("gorm:order_by_primary_key", "DESC").
  277. inlineCondition(where...).callCallbacks(s.parent.callbacks.queries).db
  278. }
  279. // Find find records that match given conditions
  280. func (s *DB) Find(out interface{}, where ...interface{}) *DB {
  281. return s.NewScope(out).inlineCondition(where...).callCallbacks(s.parent.callbacks.queries).db
  282. }
  283. //Preloads preloads relations, don`t touch out
  284. func (s *DB) Preloads(out interface{}) *DB {
  285. return s.NewScope(out).InstanceSet("gorm:only_preload", 1).callCallbacks(s.parent.callbacks.queries).db
  286. }
  287. // Scan scan value to a struct
  288. func (s *DB) Scan(dest interface{}) *DB {
  289. return s.NewScope(s.Value).Set("gorm:query_destination", dest).callCallbacks(s.parent.callbacks.queries).db
  290. }
  291. // Row return `*sql.Row` with given conditions
  292. func (s *DB) Row() *sql.Row {
  293. return s.NewScope(s.Value).row()
  294. }
  295. // Rows return `*sql.Rows` with given conditions
  296. func (s *DB) Rows() (*sql.Rows, error) {
  297. return s.NewScope(s.Value).rows()
  298. }
  299. // ScanRows scan `*sql.Rows` to give struct
  300. func (s *DB) ScanRows(rows *sql.Rows, result interface{}) error {
  301. var (
  302. scope = s.NewScope(result)
  303. clone = scope.db
  304. columns, err = rows.Columns()
  305. )
  306. if clone.AddError(err) == nil {
  307. scope.scan(rows, columns, scope.Fields())
  308. }
  309. return clone.Error
  310. }
  311. // Pluck used to query single column from a model as a map
  312. // var ages []int64
  313. // db.Find(&users).Pluck("age", &ages)
  314. func (s *DB) Pluck(column string, value interface{}) *DB {
  315. return s.NewScope(s.Value).pluck(column, value).db
  316. }
  317. // Count get how many records for a model
  318. func (s *DB) Count(value interface{}) *DB {
  319. return s.NewScope(s.Value).count(value).db
  320. }
  321. // Related get related associations
  322. func (s *DB) Related(value interface{}, foreignKeys ...string) *DB {
  323. return s.NewScope(s.Value).related(value, foreignKeys...).db
  324. }
  325. // FirstOrInit find first matched record or initialize a new one with given conditions (only works with struct, map conditions)
  326. // https://jinzhu.github.io/gorm/crud.html#firstorinit
  327. func (s *DB) FirstOrInit(out interface{}, where ...interface{}) *DB {
  328. c := s.clone()
  329. if result := c.First(out, where...); result.Error != nil {
  330. if !result.RecordNotFound() {
  331. return result
  332. }
  333. c.NewScope(out).inlineCondition(where...).initialize()
  334. } else {
  335. c.NewScope(out).updatedAttrsWithValues(c.search.assignAttrs)
  336. }
  337. return c
  338. }
  339. // FirstOrCreate find first matched record or create a new one with given conditions (only works with struct, map conditions)
  340. // https://jinzhu.github.io/gorm/crud.html#firstorcreate
  341. func (s *DB) FirstOrCreate(out interface{}, where ...interface{}) *DB {
  342. c := s.clone()
  343. if result := s.First(out, where...); result.Error != nil {
  344. if !result.RecordNotFound() {
  345. return result
  346. }
  347. return c.NewScope(out).inlineCondition(where...).initialize().callCallbacks(c.parent.callbacks.creates).db
  348. } else if len(c.search.assignAttrs) > 0 {
  349. return c.NewScope(out).InstanceSet("gorm:update_interface", c.search.assignAttrs).callCallbacks(c.parent.callbacks.updates).db
  350. }
  351. return c
  352. }
  353. // Update update attributes with callbacks, refer: https://jinzhu.github.io/gorm/crud.html#update
  354. func (s *DB) Update(attrs ...interface{}) *DB {
  355. return s.Updates(toSearchableMap(attrs...), true)
  356. }
  357. // Updates update attributes with callbacks, refer: https://jinzhu.github.io/gorm/crud.html#update
  358. func (s *DB) Updates(values interface{}, ignoreProtectedAttrs ...bool) *DB {
  359. return s.NewScope(s.Value).
  360. Set("gorm:ignore_protected_attrs", len(ignoreProtectedAttrs) > 0).
  361. InstanceSet("gorm:update_interface", values).
  362. callCallbacks(s.parent.callbacks.updates).db
  363. }
  364. // UpdateColumn update attributes without callbacks, refer: https://jinzhu.github.io/gorm/crud.html#update
  365. func (s *DB) UpdateColumn(attrs ...interface{}) *DB {
  366. return s.UpdateColumns(toSearchableMap(attrs...))
  367. }
  368. // UpdateColumns update attributes without callbacks, refer: https://jinzhu.github.io/gorm/crud.html#update
  369. func (s *DB) UpdateColumns(values interface{}) *DB {
  370. return s.NewScope(s.Value).
  371. Set("gorm:update_column", true).
  372. Set("gorm:save_associations", false).
  373. InstanceSet("gorm:update_interface", values).
  374. callCallbacks(s.parent.callbacks.updates).db
  375. }
  376. // Save update value in database, if the value doesn't have primary key, will insert it
  377. func (s *DB) Save(value interface{}) *DB {
  378. scope := s.NewScope(value)
  379. if !scope.PrimaryKeyZero() {
  380. newDB := scope.callCallbacks(s.parent.callbacks.updates).db
  381. if newDB.Error == nil && newDB.RowsAffected == 0 {
  382. return s.New().FirstOrCreate(value)
  383. }
  384. return newDB
  385. }
  386. return scope.callCallbacks(s.parent.callbacks.creates).db
  387. }
  388. // Create insert the value into database
  389. func (s *DB) Create(value interface{}) *DB {
  390. scope := s.NewScope(value)
  391. return scope.callCallbacks(s.parent.callbacks.creates).db
  392. }
  393. // Delete delete value match given conditions, if the value has primary key, then will including the primary key as condition
  394. func (s *DB) Delete(value interface{}, where ...interface{}) *DB {
  395. return s.NewScope(value).inlineCondition(where...).callCallbacks(s.parent.callbacks.deletes).db
  396. }
  397. // Raw use raw sql as conditions, won't run it unless invoked by other methods
  398. // db.Raw("SELECT name, age FROM users WHERE name = ?", 3).Scan(&result)
  399. func (s *DB) Raw(sql string, values ...interface{}) *DB {
  400. return s.clone().search.Raw(true).Where(sql, values...).db
  401. }
  402. // Exec execute raw sql
  403. func (s *DB) Exec(sql string, values ...interface{}) *DB {
  404. scope := s.NewScope(nil)
  405. generatedSQL := scope.buildCondition(map[string]interface{}{"query": sql, "args": values}, true)
  406. generatedSQL = strings.TrimSuffix(strings.TrimPrefix(generatedSQL, "("), ")")
  407. scope.Raw(generatedSQL)
  408. return scope.Exec().db
  409. }
  410. // Model specify the model you would like to run db operations
  411. // // update all users's name to `hello`
  412. // db.Model(&User{}).Update("name", "hello")
  413. // // if user's primary key is non-blank, will use it as condition, then will only update the user's name to `hello`
  414. // db.Model(&user).Update("name", "hello")
  415. func (s *DB) Model(value interface{}) *DB {
  416. c := s.clone()
  417. c.Value = value
  418. return c
  419. }
  420. // Table specify the table you would like to run db operations
  421. func (s *DB) Table(name string) *DB {
  422. clone := s.clone()
  423. clone.search.Table(name)
  424. clone.Value = nil
  425. return clone
  426. }
  427. // Debug start debug mode
  428. func (s *DB) Debug() *DB {
  429. return s.clone().LogMode(true)
  430. }
  431. // Begin begin a transaction
  432. func (s *DB) Begin() *DB {
  433. c := s.clone()
  434. if db, ok := c.db.(sqlDb); ok && db != nil {
  435. tx, err := db.Begin()
  436. c.db = interface{}(tx).(SQLCommon)
  437. c.dialect.SetDB(c.db)
  438. c.AddError(err)
  439. } else {
  440. c.AddError(ErrCantStartTransaction)
  441. }
  442. return c
  443. }
  444. // Commit commit a transaction
  445. func (s *DB) Commit() *DB {
  446. var emptySQLTx *sql.Tx
  447. if db, ok := s.db.(sqlTx); ok && db != nil && db != emptySQLTx {
  448. s.AddError(db.Commit())
  449. } else {
  450. s.AddError(ErrInvalidTransaction)
  451. }
  452. return s
  453. }
  454. // Rollback rollback a transaction
  455. func (s *DB) Rollback() *DB {
  456. var emptySQLTx *sql.Tx
  457. if db, ok := s.db.(sqlTx); ok && db != nil && db != emptySQLTx {
  458. s.AddError(db.Rollback())
  459. } else {
  460. s.AddError(ErrInvalidTransaction)
  461. }
  462. return s
  463. }
  464. // NewRecord check if value's primary key is blank
  465. func (s *DB) NewRecord(value interface{}) bool {
  466. return s.NewScope(value).PrimaryKeyZero()
  467. }
  468. // RecordNotFound check if returning ErrRecordNotFound error
  469. func (s *DB) RecordNotFound() bool {
  470. for _, err := range s.GetErrors() {
  471. if err == ErrRecordNotFound {
  472. return true
  473. }
  474. }
  475. return false
  476. }
  477. // CreateTable create table for models
  478. func (s *DB) CreateTable(models ...interface{}) *DB {
  479. db := s.Unscoped()
  480. for _, model := range models {
  481. db = db.NewScope(model).createTable().db
  482. }
  483. return db
  484. }
  485. // DropTable drop table for models
  486. func (s *DB) DropTable(values ...interface{}) *DB {
  487. db := s.clone()
  488. for _, value := range values {
  489. if tableName, ok := value.(string); ok {
  490. db = db.Table(tableName)
  491. }
  492. db = db.NewScope(value).dropTable().db
  493. }
  494. return db
  495. }
  496. // DropTableIfExists drop table if it is exist
  497. func (s *DB) DropTableIfExists(values ...interface{}) *DB {
  498. db := s.clone()
  499. for _, value := range values {
  500. if s.HasTable(value) {
  501. db.AddError(s.DropTable(value).Error)
  502. }
  503. }
  504. return db
  505. }
  506. // HasTable check has table or not
  507. func (s *DB) HasTable(value interface{}) bool {
  508. var (
  509. scope = s.NewScope(value)
  510. tableName string
  511. )
  512. if name, ok := value.(string); ok {
  513. tableName = name
  514. } else {
  515. tableName = scope.TableName()
  516. }
  517. has := scope.Dialect().HasTable(tableName)
  518. s.AddError(scope.db.Error)
  519. return has
  520. }
  521. // AutoMigrate run auto migration for given models, will only add missing fields, won't delete/change current data
  522. func (s *DB) AutoMigrate(values ...interface{}) *DB {
  523. db := s.Unscoped()
  524. for _, value := range values {
  525. db = db.NewScope(value).autoMigrate().db
  526. }
  527. return db
  528. }
  529. // ModifyColumn modify column to type
  530. func (s *DB) ModifyColumn(column string, typ string) *DB {
  531. scope := s.NewScope(s.Value)
  532. scope.modifyColumn(column, typ)
  533. return scope.db
  534. }
  535. // DropColumn drop a column
  536. func (s *DB) DropColumn(column string) *DB {
  537. scope := s.NewScope(s.Value)
  538. scope.dropColumn(column)
  539. return scope.db
  540. }
  541. // AddIndex add index for columns with given name
  542. func (s *DB) AddIndex(indexName string, columns ...string) *DB {
  543. scope := s.Unscoped().NewScope(s.Value)
  544. scope.addIndex(false, indexName, columns...)
  545. return scope.db
  546. }
  547. // AddUniqueIndex add unique index for columns with given name
  548. func (s *DB) AddUniqueIndex(indexName string, columns ...string) *DB {
  549. scope := s.Unscoped().NewScope(s.Value)
  550. scope.addIndex(true, indexName, columns...)
  551. return scope.db
  552. }
  553. // RemoveIndex remove index with name
  554. func (s *DB) RemoveIndex(indexName string) *DB {
  555. scope := s.NewScope(s.Value)
  556. scope.removeIndex(indexName)
  557. return scope.db
  558. }
  559. // AddForeignKey Add foreign key to the given scope, e.g:
  560. // db.Model(&User{}).AddForeignKey("city_id", "cities(id)", "RESTRICT", "RESTRICT")
  561. func (s *DB) AddForeignKey(field string, dest string, onDelete string, onUpdate string) *DB {
  562. scope := s.NewScope(s.Value)
  563. scope.addForeignKey(field, dest, onDelete, onUpdate)
  564. return scope.db
  565. }
  566. // RemoveForeignKey Remove foreign key from the given scope, e.g:
  567. // db.Model(&User{}).RemoveForeignKey("city_id", "cities(id)")
  568. func (s *DB) RemoveForeignKey(field string, dest string) *DB {
  569. scope := s.clone().NewScope(s.Value)
  570. scope.removeForeignKey(field, dest)
  571. return scope.db
  572. }
  573. // Association start `Association Mode` to handler relations things easir in that mode, refer: https://jinzhu.github.io/gorm/associations.html#association-mode
  574. func (s *DB) Association(column string) *Association {
  575. var err error
  576. var scope = s.Set("gorm:association:source", s.Value).NewScope(s.Value)
  577. if primaryField := scope.PrimaryField(); primaryField.IsBlank {
  578. err = errors.New("primary key can't be nil")
  579. } else {
  580. if field, ok := scope.FieldByName(column); ok {
  581. if field.Relationship == nil || len(field.Relationship.ForeignFieldNames) == 0 {
  582. err = fmt.Errorf("invalid association %v for %v", column, scope.IndirectValue().Type())
  583. } else {
  584. return &Association{scope: scope, column: column, field: field}
  585. }
  586. } else {
  587. err = fmt.Errorf("%v doesn't have column %v", scope.IndirectValue().Type(), column)
  588. }
  589. }
  590. return &Association{Error: err}
  591. }
  592. // Preload preload associations with given conditions
  593. // db.Preload("Orders", "state NOT IN (?)", "cancelled").Find(&users)
  594. func (s *DB) Preload(column string, conditions ...interface{}) *DB {
  595. return s.clone().search.Preload(column, conditions...).db
  596. }
  597. // Set set setting by name, which could be used in callbacks, will clone a new db, and update its setting
  598. func (s *DB) Set(name string, value interface{}) *DB {
  599. return s.clone().InstantSet(name, value)
  600. }
  601. // InstantSet instant set setting, will affect current db
  602. func (s *DB) InstantSet(name string, value interface{}) *DB {
  603. s.values.Store(name, value)
  604. return s
  605. }
  606. // Get get setting by name
  607. func (s *DB) Get(name string) (value interface{}, ok bool) {
  608. value, ok = s.values.Load(name)
  609. return
  610. }
  611. // SetJoinTableHandler set a model's join table handler for a relation
  612. func (s *DB) SetJoinTableHandler(source interface{}, column string, handler JoinTableHandlerInterface) {
  613. scope := s.NewScope(source)
  614. for _, field := range scope.GetModelStruct().StructFields {
  615. if field.Name == column || field.DBName == column {
  616. if many2many, _ := field.TagSettingsGet("MANY2MANY"); many2many != "" {
  617. source := (&Scope{Value: source}).GetModelStruct().ModelType
  618. destination := (&Scope{Value: reflect.New(field.Struct.Type).Interface()}).GetModelStruct().ModelType
  619. handler.Setup(field.Relationship, many2many, source, destination)
  620. field.Relationship.JoinTableHandler = handler
  621. if table := handler.Table(s); scope.Dialect().HasTable(table) {
  622. s.Table(table).AutoMigrate(handler)
  623. }
  624. }
  625. }
  626. }
  627. }
  628. // AddError add error to the db
  629. func (s *DB) AddError(err error) error {
  630. if err != nil {
  631. if err != ErrRecordNotFound {
  632. if s.logMode == defaultLogMode {
  633. go s.print(fileWithLineNum(), err)
  634. } else {
  635. s.log(err)
  636. }
  637. errors := Errors(s.GetErrors())
  638. errors = errors.Add(err)
  639. if len(errors) > 1 {
  640. err = errors
  641. }
  642. }
  643. s.Error = err
  644. }
  645. return err
  646. }
  647. // GetErrors get happened errors from the db
  648. func (s *DB) GetErrors() []error {
  649. if errs, ok := s.Error.(Errors); ok {
  650. return errs
  651. } else if s.Error != nil {
  652. return []error{s.Error}
  653. }
  654. return []error{}
  655. }
  656. ////////////////////////////////////////////////////////////////////////////////
  657. // Private Methods For DB
  658. ////////////////////////////////////////////////////////////////////////////////
  659. func (s *DB) clone() *DB {
  660. db := &DB{
  661. db: s.db,
  662. parent: s.parent,
  663. logger: s.logger,
  664. logMode: s.logMode,
  665. Value: s.Value,
  666. Error: s.Error,
  667. blockGlobalUpdate: s.blockGlobalUpdate,
  668. dialect: newDialect(s.dialect.GetName(), s.db),
  669. }
  670. s.values.Range(func(k, v interface{}) bool {
  671. db.values.Store(k, v)
  672. return true
  673. })
  674. if s.search == nil {
  675. db.search = &search{limit: -1, offset: -1}
  676. } else {
  677. db.search = s.search.clone()
  678. }
  679. db.search.db = db
  680. return db
  681. }
  682. func (s *DB) print(v ...interface{}) {
  683. s.logger.Print(v...)
  684. }
  685. func (s *DB) log(v ...interface{}) {
  686. if s.logMode == detailedLogMode {
  687. if s.search.ctx == nil {
  688. s.print("log", nil, fileWithLineNum(), v)
  689. } else if reflect.ValueOf(s.search.ctx).IsNil() {
  690. s.print("log", nil, fileWithLineNum(), v)
  691. } else {
  692. s.print("log", s.search.ctx, fileWithLineNum(), v)
  693. }
  694. }
  695. }
  696. func (s *DB) slog(sql string, t time.Time, vars ...interface{}) {
  697. if s.logMode == detailedLogMode {
  698. if s.search.ctx == nil {
  699. s.print("sql", fileWithLineNum(), NowFunc().Sub(t), sql, vars, s.RowsAffected)
  700. } else if reflect.ValueOf(s.search.ctx).IsNil() {
  701. s.print("sql", fileWithLineNum(), NowFunc().Sub(t), sql, vars, s.RowsAffected)
  702. } else if s.search.ctx.Value("NOLOGFlAG") != true {
  703. s.print("sql", fileWithLineNum(), NowFunc().Sub(t), sql, vars, s.RowsAffected, s.search.ctx)
  704. }
  705. }
  706. }