callbacks.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. package gorm
  2. import (
  3. "errors"
  4. "fmt"
  5. "reflect"
  6. "time"
  7. "github.com/jinzhu/gorm/logger"
  8. "github.com/jinzhu/gorm/schema"
  9. "github.com/jinzhu/gorm/utils"
  10. )
  11. func initializeCallbacks(db *DB) *callbacks {
  12. return &callbacks{
  13. processors: map[string]*processor{
  14. "create": &processor{db: db},
  15. "query": &processor{db: db},
  16. "update": &processor{db: db},
  17. "delete": &processor{db: db},
  18. "row": &processor{db: db},
  19. "raw": &processor{db: db},
  20. },
  21. }
  22. }
  23. // callbacks gorm callbacks manager
  24. type callbacks struct {
  25. processors map[string]*processor
  26. }
  27. type processor struct {
  28. db *DB
  29. fns []func(*DB)
  30. callbacks []*callback
  31. }
  32. type callback struct {
  33. name string
  34. before string
  35. after string
  36. remove bool
  37. replace bool
  38. match func(*DB) bool
  39. handler func(*DB)
  40. processor *processor
  41. }
  42. func (cs *callbacks) Create() *processor {
  43. return cs.processors["create"]
  44. }
  45. func (cs *callbacks) Query() *processor {
  46. return cs.processors["query"]
  47. }
  48. func (cs *callbacks) Update() *processor {
  49. return cs.processors["update"]
  50. }
  51. func (cs *callbacks) Delete() *processor {
  52. return cs.processors["delete"]
  53. }
  54. func (cs *callbacks) Row() *processor {
  55. return cs.processors["row"]
  56. }
  57. func (cs *callbacks) Raw() *processor {
  58. return cs.processors["raw"]
  59. }
  60. func (p *processor) Execute(db *DB) {
  61. curTime := time.Now()
  62. if stmt := db.Statement; stmt != nil {
  63. if stmt.Model == nil {
  64. stmt.Model = stmt.Dest
  65. }
  66. if stmt.Model != nil {
  67. if err := stmt.Parse(stmt.Model); err != nil && (!errors.Is(err, schema.ErrUnsupportedDataType) || stmt.Table == "") {
  68. db.AddError(err)
  69. }
  70. }
  71. stmt.ReflectValue = reflect.Indirect(reflect.ValueOf(stmt.Dest))
  72. }
  73. for _, f := range p.fns {
  74. f(db)
  75. }
  76. if stmt := db.Statement; stmt != nil {
  77. db.Logger.Trace(curTime, func() (string, int64) {
  78. return db.Dialector.Explain(stmt.SQL.String(), stmt.Vars...), db.RowsAffected
  79. }, db.Error)
  80. }
  81. }
  82. func (p *processor) Get(name string) func(*DB) {
  83. for i := len(p.callbacks) - 1; i >= 0; i-- {
  84. if v := p.callbacks[i]; v.name == name && !v.remove {
  85. return v.handler
  86. }
  87. }
  88. return nil
  89. }
  90. func (p *processor) Before(name string) *callback {
  91. return &callback{before: name, processor: p}
  92. }
  93. func (p *processor) After(name string) *callback {
  94. return &callback{after: name, processor: p}
  95. }
  96. func (p *processor) Match(fc func(*DB) bool) *callback {
  97. return &callback{match: fc, processor: p}
  98. }
  99. func (p *processor) Register(name string, fn func(*DB)) error {
  100. return (&callback{processor: p}).Register(name, fn)
  101. }
  102. func (p *processor) Remove(name string) error {
  103. return (&callback{processor: p}).Remove(name)
  104. }
  105. func (p *processor) Replace(name string, fn func(*DB)) error {
  106. return (&callback{processor: p}).Replace(name, fn)
  107. }
  108. func (p *processor) compile() (err error) {
  109. var callbacks []*callback
  110. for _, callback := range p.callbacks {
  111. if callback.match == nil || callback.match(p.db) {
  112. callbacks = append(callbacks, callback)
  113. }
  114. }
  115. if p.fns, err = sortCallbacks(p.callbacks); err != nil {
  116. logger.Default.Error("Got error when compile callbacks, got %v", err)
  117. }
  118. return
  119. }
  120. func (c *callback) Before(name string) *callback {
  121. c.before = name
  122. return c
  123. }
  124. func (c *callback) After(name string) *callback {
  125. c.after = name
  126. return c
  127. }
  128. func (c *callback) Register(name string, fn func(*DB)) error {
  129. c.name = name
  130. c.handler = fn
  131. c.processor.callbacks = append(c.processor.callbacks, c)
  132. return c.processor.compile()
  133. }
  134. func (c *callback) Remove(name string) error {
  135. logger.Default.Warn("removing callback `%v` from %v\n", name, utils.FileWithLineNum())
  136. c.name = name
  137. c.remove = true
  138. c.processor.callbacks = append(c.processor.callbacks, c)
  139. return c.processor.compile()
  140. }
  141. func (c *callback) Replace(name string, fn func(*DB)) error {
  142. logger.Default.Info("replacing callback `%v` from %v\n", name, utils.FileWithLineNum())
  143. c.name = name
  144. c.handler = fn
  145. c.replace = true
  146. c.processor.callbacks = append(c.processor.callbacks, c)
  147. return c.processor.compile()
  148. }
  149. // getRIndex get right index from string slice
  150. func getRIndex(strs []string, str string) int {
  151. for i := len(strs) - 1; i >= 0; i-- {
  152. if strs[i] == str {
  153. return i
  154. }
  155. }
  156. return -1
  157. }
  158. func sortCallbacks(cs []*callback) (fns []func(*DB), err error) {
  159. var (
  160. names, sorted []string
  161. sortCallback func(*callback) error
  162. )
  163. for _, c := range cs {
  164. // show warning message the callback name already exists
  165. if idx := getRIndex(names, c.name); idx > -1 && !c.replace && !c.remove && !cs[idx].remove {
  166. logger.Default.Warn("duplicated callback `%v` from %v\n", c.name, utils.FileWithLineNum())
  167. }
  168. names = append(names, c.name)
  169. }
  170. sortCallback = func(c *callback) error {
  171. if c.before != "" { // if defined before callback
  172. if sortedIdx := getRIndex(sorted, c.before); sortedIdx != -1 {
  173. if curIdx := getRIndex(sorted, c.name); curIdx == -1 {
  174. // if before callback already sorted, append current callback just after it
  175. sorted = append(sorted[:sortedIdx], append([]string{c.name}, sorted[sortedIdx:]...)...)
  176. } else if curIdx > sortedIdx {
  177. return fmt.Errorf("conflicting callback %v with before %v", c.name, c.before)
  178. }
  179. } else if idx := getRIndex(names, c.before); idx != -1 {
  180. // if before callback exists
  181. cs[idx].after = c.name
  182. }
  183. }
  184. if c.after != "" { // if defined after callback
  185. if sortedIdx := getRIndex(sorted, c.after); sortedIdx != -1 {
  186. if curIdx := getRIndex(sorted, c.name); curIdx == -1 {
  187. // if after callback sorted, append current callback to last
  188. sorted = append(sorted, c.name)
  189. } else if curIdx < sortedIdx {
  190. return fmt.Errorf("conflicting callback %v with before %v", c.name, c.after)
  191. }
  192. } else if idx := getRIndex(names, c.after); idx != -1 {
  193. // if after callback exists but haven't sorted
  194. // set after callback's before callback to current callback
  195. after := cs[idx]
  196. if after.before == "" {
  197. after.before = c.name
  198. }
  199. if err := sortCallback(after); err != nil {
  200. return err
  201. }
  202. if err := sortCallback(c); err != nil {
  203. return err
  204. }
  205. }
  206. }
  207. // if current callback haven't been sorted, append it to last
  208. if getRIndex(sorted, c.name) == -1 {
  209. sorted = append(sorted, c.name)
  210. }
  211. return nil
  212. }
  213. for _, c := range cs {
  214. if err = sortCallback(c); err != nil {
  215. return
  216. }
  217. }
  218. for _, name := range sorted {
  219. if idx := getRIndex(names, name); !cs[idx].remove {
  220. fns = append(fns, cs[idx].handler)
  221. }
  222. }
  223. return
  224. }