gdb_model_insert.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
  2. //
  3. // This Source Code Form is subject to the terms of the MIT License.
  4. // If a copy of the MIT was not distributed with this file,
  5. // You can obtain one at https://github.com/gogf/gf.
  6. package gdb
  7. import (
  8. "database/sql"
  9. "github.com/gogf/gf/container/gset"
  10. "github.com/gogf/gf/errors/gcode"
  11. "reflect"
  12. "github.com/gogf/gf/errors/gerror"
  13. "github.com/gogf/gf/os/gtime"
  14. "github.com/gogf/gf/text/gstr"
  15. "github.com/gogf/gf/util/gconv"
  16. "github.com/gogf/gf/util/gutil"
  17. )
  18. // Batch sets the batch operation number for the model.
  19. func (m *Model) Batch(batch int) *Model {
  20. model := m.getModel()
  21. model.batch = batch
  22. return model
  23. }
  24. // Data sets the operation data for the model.
  25. // The parameter `data` can be type of string/map/gmap/slice/struct/*struct, etc.
  26. // Note that, it uses shallow value copying for `data` if `data` is type of map/slice
  27. // to avoid changing it inside function.
  28. // Eg:
  29. // Data("uid=10000")
  30. // Data("uid", 10000)
  31. // Data("uid=? AND name=?", 10000, "john")
  32. // Data(g.Map{"uid": 10000, "name":"john"})
  33. // Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
  34. func (m *Model) Data(data ...interface{}) *Model {
  35. model := m.getModel()
  36. if len(data) > 1 {
  37. if s := gconv.String(data[0]); gstr.Contains(s, "?") {
  38. model.data = s
  39. model.extraArgs = data[1:]
  40. } else {
  41. m := make(map[string]interface{})
  42. for i := 0; i < len(data); i += 2 {
  43. m[gconv.String(data[i])] = data[i+1]
  44. }
  45. model.data = m
  46. }
  47. } else {
  48. switch params := data[0].(type) {
  49. case Result:
  50. model.data = params.List()
  51. case Record:
  52. model.data = params.Map()
  53. case List:
  54. list := make(List, len(params))
  55. for k, v := range params {
  56. list[k] = gutil.MapCopy(v)
  57. }
  58. model.data = list
  59. case Map:
  60. model.data = gutil.MapCopy(params)
  61. default:
  62. var (
  63. rv = reflect.ValueOf(params)
  64. kind = rv.Kind()
  65. )
  66. if kind == reflect.Ptr {
  67. rv = rv.Elem()
  68. kind = rv.Kind()
  69. }
  70. switch kind {
  71. case reflect.Slice, reflect.Array:
  72. list := make(List, rv.Len())
  73. for i := 0; i < rv.Len(); i++ {
  74. list[i] = ConvertDataForTableRecord(rv.Index(i).Interface())
  75. }
  76. model.data = list
  77. case reflect.Map:
  78. model.data = ConvertDataForTableRecord(data[0])
  79. case reflect.Struct:
  80. if v, ok := data[0].(apiInterfaces); ok {
  81. var (
  82. array = v.Interfaces()
  83. list = make(List, len(array))
  84. )
  85. for i := 0; i < len(array); i++ {
  86. list[i] = ConvertDataForTableRecord(array[i])
  87. }
  88. model.data = list
  89. } else {
  90. model.data = ConvertDataForTableRecord(data[0])
  91. }
  92. default:
  93. model.data = data[0]
  94. }
  95. }
  96. }
  97. return model
  98. }
  99. // OnDuplicate sets the operations when columns conflicts occurs.
  100. // In MySQL, this is used for "ON DUPLICATE KEY UPDATE" statement.
  101. // The parameter `onDuplicate` can be type of string/Raw/*Raw/map/slice.
  102. // Example:
  103. // OnDuplicate("nickname, age")
  104. // OnDuplicate("nickname", "age")
  105. // OnDuplicate(g.Map{
  106. // "nickname": gdb.Raw("CONCAT('name_', VALUES(`nickname`))"),
  107. // })
  108. // OnDuplicate(g.Map{
  109. // "nickname": "passport",
  110. // })
  111. func (m *Model) OnDuplicate(onDuplicate ...interface{}) *Model {
  112. model := m.getModel()
  113. if len(onDuplicate) > 1 {
  114. model.onDuplicate = onDuplicate
  115. } else {
  116. model.onDuplicate = onDuplicate[0]
  117. }
  118. return model
  119. }
  120. // OnDuplicateEx sets the excluding columns for operations when columns conflicts occurs.
  121. // In MySQL, this is used for "ON DUPLICATE KEY UPDATE" statement.
  122. // The parameter `onDuplicateEx` can be type of string/map/slice.
  123. // Example:
  124. // OnDuplicateEx("passport, password")
  125. // OnDuplicateEx("passport", "password")
  126. // OnDuplicateEx(g.Map{
  127. // "passport": "",
  128. // "password": "",
  129. // })
  130. func (m *Model) OnDuplicateEx(onDuplicateEx ...interface{}) *Model {
  131. model := m.getModel()
  132. if len(onDuplicateEx) > 1 {
  133. model.onDuplicateEx = onDuplicateEx
  134. } else {
  135. model.onDuplicateEx = onDuplicateEx[0]
  136. }
  137. return model
  138. }
  139. // Insert does "INSERT INTO ..." statement for the model.
  140. // The optional parameter `data` is the same as the parameter of Model.Data function,
  141. // see Model.Data.
  142. func (m *Model) Insert(data ...interface{}) (result sql.Result, err error) {
  143. if len(data) > 0 {
  144. return m.Data(data...).Insert()
  145. }
  146. return m.doInsertWithOption(insertOptionDefault)
  147. }
  148. // InsertAndGetId performs action Insert and returns the last insert id that automatically generated.
  149. func (m *Model) InsertAndGetId(data ...interface{}) (lastInsertId int64, err error) {
  150. if len(data) > 0 {
  151. return m.Data(data...).InsertAndGetId()
  152. }
  153. result, err := m.doInsertWithOption(insertOptionDefault)
  154. if err != nil {
  155. return 0, err
  156. }
  157. return result.LastInsertId()
  158. }
  159. // InsertIgnore does "INSERT IGNORE INTO ..." statement for the model.
  160. // The optional parameter `data` is the same as the parameter of Model.Data function,
  161. // see Model.Data.
  162. func (m *Model) InsertIgnore(data ...interface{}) (result sql.Result, err error) {
  163. if len(data) > 0 {
  164. return m.Data(data...).InsertIgnore()
  165. }
  166. return m.doInsertWithOption(insertOptionIgnore)
  167. }
  168. // Replace does "REPLACE INTO ..." statement for the model.
  169. // The optional parameter `data` is the same as the parameter of Model.Data function,
  170. // see Model.Data.
  171. func (m *Model) Replace(data ...interface{}) (result sql.Result, err error) {
  172. if len(data) > 0 {
  173. return m.Data(data...).Replace()
  174. }
  175. return m.doInsertWithOption(insertOptionReplace)
  176. }
  177. // Save does "INSERT INTO ... ON DUPLICATE KEY UPDATE..." statement for the model.
  178. // The optional parameter `data` is the same as the parameter of Model.Data function,
  179. // see Model.Data.
  180. //
  181. // It updates the record if there's primary or unique index in the saving data,
  182. // or else it inserts a new record into the table.
  183. func (m *Model) Save(data ...interface{}) (result sql.Result, err error) {
  184. if len(data) > 0 {
  185. return m.Data(data...).Save()
  186. }
  187. return m.doInsertWithOption(insertOptionSave)
  188. }
  189. // doInsertWithOption inserts data with option parameter.
  190. func (m *Model) doInsertWithOption(insertOption int) (result sql.Result, err error) {
  191. defer func() {
  192. if err == nil {
  193. m.checkAndRemoveCache()
  194. }
  195. }()
  196. if m.data == nil {
  197. return nil, gerror.NewCode(gcode.CodeMissingParameter, "inserting into table with empty data")
  198. }
  199. var (
  200. list List
  201. nowString = gtime.Now().String()
  202. fieldNameCreate = m.getSoftFieldNameCreated()
  203. fieldNameUpdate = m.getSoftFieldNameUpdated()
  204. )
  205. newData, err := m.filterDataForInsertOrUpdate(m.data)
  206. if err != nil {
  207. return nil, err
  208. }
  209. // It converts any data to List type for inserting.
  210. switch value := newData.(type) {
  211. case Result:
  212. list = value.List()
  213. case Record:
  214. list = List{value.Map()}
  215. case List:
  216. list = value
  217. for i, v := range list {
  218. list[i] = ConvertDataForTableRecord(v)
  219. }
  220. case Map:
  221. list = List{ConvertDataForTableRecord(value)}
  222. default:
  223. var (
  224. rv = reflect.ValueOf(newData)
  225. kind = rv.Kind()
  226. )
  227. if kind == reflect.Ptr {
  228. rv = rv.Elem()
  229. kind = rv.Kind()
  230. }
  231. switch kind {
  232. // If it's slice type, it then converts it to List type.
  233. case reflect.Slice, reflect.Array:
  234. list = make(List, rv.Len())
  235. for i := 0; i < rv.Len(); i++ {
  236. list[i] = ConvertDataForTableRecord(rv.Index(i).Interface())
  237. }
  238. case reflect.Map:
  239. list = List{ConvertDataForTableRecord(value)}
  240. case reflect.Struct:
  241. if v, ok := value.(apiInterfaces); ok {
  242. var (
  243. array = v.Interfaces()
  244. )
  245. list = make(List, len(array))
  246. for i := 0; i < len(array); i++ {
  247. list[i] = ConvertDataForTableRecord(array[i])
  248. }
  249. } else {
  250. list = List{ConvertDataForTableRecord(value)}
  251. }
  252. default:
  253. return result, gerror.NewCodef(gcode.CodeInvalidParameter, "unsupported list type:%v", kind)
  254. }
  255. }
  256. if len(list) < 1 {
  257. return result, gerror.NewCode(gcode.CodeMissingParameter, "data list cannot be empty")
  258. }
  259. // Automatic handling for creating/updating time.
  260. if !m.unscoped && (fieldNameCreate != "" || fieldNameUpdate != "") {
  261. for k, v := range list {
  262. if fieldNameCreate != "" {
  263. v[fieldNameCreate] = nowString
  264. }
  265. if fieldNameUpdate != "" {
  266. v[fieldNameUpdate] = nowString
  267. }
  268. list[k] = v
  269. }
  270. }
  271. // Format DoInsertOption, especially for "ON DUPLICATE KEY UPDATE" statement.
  272. columnNames := make([]string, 0, len(list[0]))
  273. for k, _ := range list[0] {
  274. columnNames = append(columnNames, k)
  275. }
  276. doInsertOption, err := m.formatDoInsertOption(insertOption, columnNames)
  277. if err != nil {
  278. return result, err
  279. }
  280. return m.db.DoInsert(m.GetCtx(), m.getLink(true), m.tables, list, doInsertOption)
  281. }
  282. func (m *Model) formatDoInsertOption(insertOption int, columnNames []string) (option DoInsertOption, err error) {
  283. option = DoInsertOption{
  284. InsertOption: insertOption,
  285. BatchCount: m.getBatch(),
  286. }
  287. if insertOption == insertOptionSave {
  288. onDuplicateExKeys, err := m.formatOnDuplicateExKeys(m.onDuplicateEx)
  289. if err != nil {
  290. return option, err
  291. }
  292. var (
  293. onDuplicateExKeySet = gset.NewStrSetFrom(onDuplicateExKeys)
  294. )
  295. if m.onDuplicate != nil {
  296. switch m.onDuplicate.(type) {
  297. case Raw, *Raw:
  298. option.OnDuplicateStr = gconv.String(m.onDuplicate)
  299. default:
  300. var (
  301. reflectValue = reflect.ValueOf(m.onDuplicate)
  302. reflectKind = reflectValue.Kind()
  303. )
  304. for reflectKind == reflect.Ptr {
  305. reflectValue = reflectValue.Elem()
  306. reflectKind = reflectValue.Kind()
  307. }
  308. switch reflectKind {
  309. case reflect.String:
  310. option.OnDuplicateMap = make(map[string]interface{})
  311. for _, v := range gstr.SplitAndTrim(reflectValue.String(), ",") {
  312. if onDuplicateExKeySet.Contains(v) {
  313. continue
  314. }
  315. option.OnDuplicateMap[v] = v
  316. }
  317. case reflect.Map:
  318. option.OnDuplicateMap = make(map[string]interface{})
  319. for k, v := range gconv.Map(m.onDuplicate) {
  320. if onDuplicateExKeySet.Contains(k) {
  321. continue
  322. }
  323. option.OnDuplicateMap[k] = v
  324. }
  325. case reflect.Slice, reflect.Array:
  326. option.OnDuplicateMap = make(map[string]interface{})
  327. for _, v := range gconv.Strings(m.onDuplicate) {
  328. if onDuplicateExKeySet.Contains(v) {
  329. continue
  330. }
  331. option.OnDuplicateMap[v] = v
  332. }
  333. default:
  334. return option, gerror.NewCodef(
  335. gcode.CodeInvalidParameter,
  336. `unsupported OnDuplicate parameter type "%s"`,
  337. reflect.TypeOf(m.onDuplicate),
  338. )
  339. }
  340. }
  341. } else if onDuplicateExKeySet.Size() > 0 {
  342. option.OnDuplicateMap = make(map[string]interface{})
  343. for _, v := range columnNames {
  344. if onDuplicateExKeySet.Contains(v) {
  345. continue
  346. }
  347. option.OnDuplicateMap[v] = v
  348. }
  349. }
  350. }
  351. return
  352. }
  353. func (m *Model) formatOnDuplicateExKeys(onDuplicateEx interface{}) ([]string, error) {
  354. if onDuplicateEx == nil {
  355. return nil, nil
  356. }
  357. var (
  358. reflectValue = reflect.ValueOf(onDuplicateEx)
  359. reflectKind = reflectValue.Kind()
  360. )
  361. for reflectKind == reflect.Ptr {
  362. reflectValue = reflectValue.Elem()
  363. reflectKind = reflectValue.Kind()
  364. }
  365. switch reflectKind {
  366. case reflect.String:
  367. return gstr.SplitAndTrim(reflectValue.String(), ","), nil
  368. case reflect.Map:
  369. return gutil.Keys(onDuplicateEx), nil
  370. case reflect.Slice, reflect.Array:
  371. return gconv.Strings(onDuplicateEx), nil
  372. default:
  373. return nil, gerror.NewCodef(
  374. gcode.CodeInvalidParameter,
  375. `unsupported OnDuplicateEx parameter type "%s"`,
  376. reflect.TypeOf(onDuplicateEx),
  377. )
  378. }
  379. }
  380. func (m *Model) getBatch() int {
  381. batch := defaultBatchNumber
  382. if m.batch > 0 {
  383. batch = m.batch
  384. }
  385. return batch
  386. }