gdb_model_time.go 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. // Copyright GoFrame Author(https://github.com/gogf/gf). 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. "fmt"
  9. "github.com/gogf/gf/container/garray"
  10. "github.com/gogf/gf/text/gregex"
  11. "github.com/gogf/gf/text/gstr"
  12. "github.com/gogf/gf/util/gconv"
  13. "github.com/gogf/gf/util/gutil"
  14. )
  15. var (
  16. createdFiledNames = []string{"created_at", "create_at"} // Default filed names of table for automatic-filled created datetime.
  17. updatedFiledNames = []string{"updated_at", "update_at"} // Default filed names of table for automatic-filled updated datetime.
  18. deletedFiledNames = []string{"deleted_at", "delete_at"} // Default filed names of table for automatic-filled deleted datetime.
  19. )
  20. // Unscoped disables the auto-update time feature for insert, update and delete options.
  21. func (m *Model) Unscoped() *Model {
  22. model := m.getModel()
  23. model.unscoped = true
  24. return model
  25. }
  26. // getSoftFieldNameCreate checks and returns the field name for record creating time.
  27. // If there's no field name for storing creating time, it returns an empty string.
  28. // It checks the key with or without cases or chars '-'/'_'/'.'/' '.
  29. func (m *Model) getSoftFieldNameCreated(table ...string) string {
  30. // It checks whether this feature disabled.
  31. if m.db.GetConfig().TimeMaintainDisabled {
  32. return ""
  33. }
  34. tableName := ""
  35. if len(table) > 0 {
  36. tableName = table[0]
  37. } else {
  38. tableName = m.getPrimaryTableName()
  39. }
  40. config := m.db.GetConfig()
  41. if config.CreatedAt != "" {
  42. return m.getSoftFieldName(tableName, []string{config.CreatedAt})
  43. }
  44. return m.getSoftFieldName(tableName, createdFiledNames)
  45. }
  46. // getSoftFieldNameUpdate checks and returns the field name for record updating time.
  47. // If there's no field name for storing updating time, it returns an empty string.
  48. // It checks the key with or without cases or chars '-'/'_'/'.'/' '.
  49. func (m *Model) getSoftFieldNameUpdated(table ...string) (field string) {
  50. // It checks whether this feature disabled.
  51. if m.db.GetConfig().TimeMaintainDisabled {
  52. return ""
  53. }
  54. tableName := ""
  55. if len(table) > 0 {
  56. tableName = table[0]
  57. } else {
  58. tableName = m.getPrimaryTableName()
  59. }
  60. config := m.db.GetConfig()
  61. if config.UpdatedAt != "" {
  62. return m.getSoftFieldName(tableName, []string{config.UpdatedAt})
  63. }
  64. return m.getSoftFieldName(tableName, updatedFiledNames)
  65. }
  66. // getSoftFieldNameDelete checks and returns the field name for record deleting time.
  67. // If there's no field name for storing deleting time, it returns an empty string.
  68. // It checks the key with or without cases or chars '-'/'_'/'.'/' '.
  69. func (m *Model) getSoftFieldNameDeleted(table ...string) (field string) {
  70. // It checks whether this feature disabled.
  71. if m.db.GetConfig().TimeMaintainDisabled {
  72. return ""
  73. }
  74. tableName := ""
  75. if len(table) > 0 {
  76. tableName = table[0]
  77. } else {
  78. tableName = m.getPrimaryTableName()
  79. }
  80. config := m.db.GetConfig()
  81. if config.UpdatedAt != "" {
  82. return m.getSoftFieldName(tableName, []string{config.DeletedAt})
  83. }
  84. return m.getSoftFieldName(tableName, deletedFiledNames)
  85. }
  86. // getSoftFieldName retrieves and returns the field name of the table for possible key.
  87. func (m *Model) getSoftFieldName(table string, keys []string) (field string) {
  88. fieldsMap, _ := m.db.TableFields(table)
  89. if len(fieldsMap) > 0 {
  90. for _, key := range keys {
  91. field, _ = gutil.MapPossibleItemByKey(
  92. gconv.Map(fieldsMap), key,
  93. )
  94. if field != "" {
  95. return
  96. }
  97. }
  98. }
  99. return
  100. }
  101. // getConditionForSoftDeleting retrieves and returns the condition string for soft deleting.
  102. // It supports multiple tables string like:
  103. // "user u, user_detail ud"
  104. // "user u LEFT JOIN user_detail ud ON(ud.uid=u.uid)"
  105. // "user LEFT JOIN user_detail ON(user_detail.uid=user.uid)"
  106. // "user u LEFT JOIN user_detail ud ON(ud.uid=u.uid) LEFT JOIN user_stats us ON(us.uid=u.uid)"
  107. func (m *Model) getConditionForSoftDeleting() string {
  108. if m.unscoped {
  109. return ""
  110. }
  111. conditionArray := garray.NewStrArray()
  112. if gstr.Contains(m.tables, " JOIN ") {
  113. // Base table.
  114. match, _ := gregex.MatchString(`(.+?) [A-Z]+ JOIN`, m.tables)
  115. conditionArray.Append(m.getConditionOfTableStringForSoftDeleting(match[1]))
  116. // Multiple joined tables, exclude the sub query sql which contains char '(' and ')'.
  117. matches, _ := gregex.MatchAllString(`JOIN ([^()]+?) ON`, m.tables)
  118. for _, match := range matches {
  119. conditionArray.Append(m.getConditionOfTableStringForSoftDeleting(match[1]))
  120. }
  121. }
  122. if conditionArray.Len() == 0 && gstr.Contains(m.tables, ",") {
  123. // Multiple base tables.
  124. for _, s := range gstr.SplitAndTrim(m.tables, ",") {
  125. conditionArray.Append(m.getConditionOfTableStringForSoftDeleting(s))
  126. }
  127. }
  128. conditionArray.FilterEmpty()
  129. if conditionArray.Len() > 0 {
  130. return conditionArray.Join(" AND ")
  131. }
  132. // Only one table.
  133. if fieldName := m.getSoftFieldNameDeleted(); fieldName != "" {
  134. return fmt.Sprintf(`%s IS NULL`, m.db.QuoteWord(fieldName))
  135. }
  136. return ""
  137. }
  138. // getConditionOfTableStringForSoftDeleting does something as its name describes.
  139. func (m *Model) getConditionOfTableStringForSoftDeleting(s string) string {
  140. var (
  141. field = ""
  142. table = ""
  143. array1 = gstr.SplitAndTrim(s, " ")
  144. array2 = gstr.SplitAndTrim(array1[0], ".")
  145. )
  146. if len(array2) >= 2 {
  147. table = array2[1]
  148. } else {
  149. table = array2[0]
  150. }
  151. field = m.getSoftFieldNameDeleted(table)
  152. if field == "" {
  153. return ""
  154. }
  155. if len(array1) >= 3 {
  156. return fmt.Sprintf(`%s.%s IS NULL`, m.db.QuoteWord(array1[2]), m.db.QuoteWord(field))
  157. }
  158. if len(array1) >= 2 {
  159. return fmt.Sprintf(`%s.%s IS NULL`, m.db.QuoteWord(array1[1]), m.db.QuoteWord(field))
  160. }
  161. return fmt.Sprintf(`%s.%s IS NULL`, m.db.QuoteWord(table), m.db.QuoteWord(field))
  162. }
  163. // getPrimaryTableName parses and returns the primary table name.
  164. func (m *Model) getPrimaryTableName() string {
  165. array1 := gstr.SplitAndTrim(m.tables, ",")
  166. array2 := gstr.SplitAndTrim(array1[0], " ")
  167. array3 := gstr.SplitAndTrim(array2[0], ".")
  168. if len(array3) >= 2 {
  169. return array3[1]
  170. }
  171. return array3[0]
  172. }