gdb_model_utility.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  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. "time"
  9. "github.com/gogf/gf/container/gset"
  10. "github.com/gogf/gf/internal/empty"
  11. "github.com/gogf/gf/os/gtime"
  12. "github.com/gogf/gf/text/gregex"
  13. "github.com/gogf/gf/text/gstr"
  14. "github.com/gogf/gf/util/gutil"
  15. )
  16. // TableFields retrieves and returns the fields information of specified table of current
  17. // schema.
  18. //
  19. // Also see DriverMysql.TableFields.
  20. func (m *Model) TableFields(tableStr string, schema ...string) (fields map[string]*TableField, err error) {
  21. useSchema := m.schema
  22. if len(schema) > 0 && schema[0] != "" {
  23. useSchema = schema[0]
  24. }
  25. return m.db.TableFields(m.GetCtx(), m.guessPrimaryTableName(tableStr), useSchema)
  26. }
  27. // getModel creates and returns a cloned model of current model if `safe` is true, or else it returns
  28. // the current model.
  29. func (m *Model) getModel() *Model {
  30. if !m.safe {
  31. return m
  32. } else {
  33. return m.Clone()
  34. }
  35. }
  36. // mappingAndFilterToTableFields mappings and changes given field name to really table field name.
  37. // Eg:
  38. // ID -> id
  39. // NICK_Name -> nickname
  40. func (m *Model) mappingAndFilterToTableFields(fields []string, filter bool) []string {
  41. fieldsMap, err := m.TableFields(m.tablesInit)
  42. if err != nil || len(fieldsMap) == 0 {
  43. return fields
  44. }
  45. var (
  46. inputFieldsArray = gstr.SplitAndTrim(gstr.Join(fields, ","), ",")
  47. outputFieldsArray = make([]string, 0, len(inputFieldsArray))
  48. )
  49. fieldsKeyMap := make(map[string]interface{}, len(fieldsMap))
  50. for k, _ := range fieldsMap {
  51. fieldsKeyMap[k] = nil
  52. }
  53. for _, field := range inputFieldsArray {
  54. if _, ok := fieldsKeyMap[field]; !ok {
  55. if !gregex.IsMatchString(regularFieldNameWithoutDotRegPattern, field) {
  56. // Eg: user.id, user.name
  57. outputFieldsArray = append(outputFieldsArray, field)
  58. continue
  59. } else {
  60. // Eg: id, name
  61. if foundKey, _ := gutil.MapPossibleItemByKey(fieldsKeyMap, field); foundKey != "" {
  62. outputFieldsArray = append(outputFieldsArray, foundKey)
  63. } else if !filter {
  64. outputFieldsArray = append(outputFieldsArray, field)
  65. }
  66. }
  67. } else {
  68. outputFieldsArray = append(outputFieldsArray, field)
  69. }
  70. }
  71. return outputFieldsArray
  72. }
  73. // filterDataForInsertOrUpdate does filter feature with data for inserting/updating operations.
  74. // Note that, it does not filter list item, which is also type of map, for "omit empty" feature.
  75. func (m *Model) filterDataForInsertOrUpdate(data interface{}) (interface{}, error) {
  76. var err error
  77. switch value := data.(type) {
  78. case List:
  79. for k, item := range value {
  80. value[k], err = m.doMappingAndFilterForInsertOrUpdateDataMap(item, false)
  81. if err != nil {
  82. return nil, err
  83. }
  84. }
  85. return value, nil
  86. case Map:
  87. return m.doMappingAndFilterForInsertOrUpdateDataMap(value, true)
  88. default:
  89. return data, nil
  90. }
  91. }
  92. // doMappingAndFilterForInsertOrUpdateDataMap does the filter features for map.
  93. // Note that, it does not filter list item, which is also type of map, for "omit empty" feature.
  94. func (m *Model) doMappingAndFilterForInsertOrUpdateDataMap(data Map, allowOmitEmpty bool) (Map, error) {
  95. var err error
  96. data, err = m.db.GetCore().mappingAndFilterData(
  97. m.schema, m.guessPrimaryTableName(m.tablesInit), data, m.filter,
  98. )
  99. if err != nil {
  100. return nil, err
  101. }
  102. // Remove key-value pairs of which the value is nil.
  103. if allowOmitEmpty && m.option&optionOmitNilData > 0 {
  104. tempMap := make(Map, len(data))
  105. for k, v := range data {
  106. if empty.IsNil(v) {
  107. continue
  108. }
  109. tempMap[k] = v
  110. }
  111. data = tempMap
  112. }
  113. // Remove key-value pairs of which the value is empty.
  114. if allowOmitEmpty && m.option&optionOmitEmptyData > 0 {
  115. tempMap := make(Map, len(data))
  116. for k, v := range data {
  117. if empty.IsEmpty(v) {
  118. continue
  119. }
  120. // Special type filtering.
  121. switch r := v.(type) {
  122. case time.Time:
  123. if r.IsZero() {
  124. continue
  125. }
  126. case *time.Time:
  127. if r.IsZero() {
  128. continue
  129. }
  130. case gtime.Time:
  131. if r.IsZero() {
  132. continue
  133. }
  134. case *gtime.Time:
  135. if r.IsZero() {
  136. continue
  137. }
  138. }
  139. tempMap[k] = v
  140. }
  141. data = tempMap
  142. }
  143. if len(m.fields) > 0 && m.fields != "*" {
  144. // Keep specified fields.
  145. var (
  146. set = gset.NewStrSetFrom(gstr.SplitAndTrim(m.fields, ","))
  147. charL, charR = m.db.GetChars()
  148. chars = charL + charR
  149. )
  150. set.Walk(func(item string) string {
  151. return gstr.Trim(item, chars)
  152. })
  153. for k := range data {
  154. k = gstr.Trim(k, chars)
  155. if !set.Contains(k) {
  156. delete(data, k)
  157. }
  158. }
  159. } else if len(m.fieldsEx) > 0 {
  160. // Filter specified fields.
  161. for _, v := range gstr.SplitAndTrim(m.fieldsEx, ",") {
  162. delete(data, v)
  163. }
  164. }
  165. return data, nil
  166. }
  167. // getLink returns the underlying database link object with configured `linkType` attribute.
  168. // The parameter `master` specifies whether using the master node if master-slave configured.
  169. func (m *Model) getLink(master bool) Link {
  170. if m.tx != nil {
  171. return &txLink{m.tx.tx}
  172. }
  173. linkType := m.linkType
  174. if linkType == 0 {
  175. if master {
  176. linkType = linkTypeMaster
  177. } else {
  178. linkType = linkTypeSlave
  179. }
  180. }
  181. switch linkType {
  182. case linkTypeMaster:
  183. link, err := m.db.GetCore().MasterLink(m.schema)
  184. if err != nil {
  185. panic(err)
  186. }
  187. return link
  188. case linkTypeSlave:
  189. link, err := m.db.GetCore().SlaveLink(m.schema)
  190. if err != nil {
  191. panic(err)
  192. }
  193. return link
  194. }
  195. return nil
  196. }
  197. // getPrimaryKey retrieves and returns the primary key name of the model table.
  198. // It parses m.tables to retrieve the primary table name, supporting m.tables like:
  199. // "user", "user u", "user as u, user_detail as ud".
  200. func (m *Model) getPrimaryKey() string {
  201. table := gstr.SplitAndTrim(m.tablesInit, " ")[0]
  202. tableFields, err := m.TableFields(table)
  203. if err != nil {
  204. return ""
  205. }
  206. for name, field := range tableFields {
  207. if gstr.ContainsI(field.Key, "pri") {
  208. return name
  209. }
  210. }
  211. return ""
  212. }
  213. // mergeArguments creates and returns new arguments by merging <m.extraArgs> and given `args`.
  214. func (m *Model) mergeArguments(args []interface{}) []interface{} {
  215. if len(m.extraArgs) > 0 {
  216. newArgs := make([]interface{}, len(m.extraArgs)+len(args))
  217. copy(newArgs, m.extraArgs)
  218. copy(newArgs[len(m.extraArgs):], args)
  219. return newArgs
  220. }
  221. return args
  222. }