gdb_model.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  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. "context"
  9. "fmt"
  10. "github.com/gogf/gf/util/gconv"
  11. "time"
  12. "github.com/gogf/gf/text/gregex"
  13. "github.com/gogf/gf/text/gstr"
  14. )
  15. // Model is core struct implementing the DAO for ORM.
  16. type Model struct {
  17. db DB // Underlying DB interface.
  18. tx *TX // Underlying TX interface.
  19. rawSql string // rawSql is the raw SQL string which marks a raw SQL based Model not a table based Model.
  20. schema string // Custom database schema.
  21. linkType int // Mark for operation on master or slave.
  22. tablesInit string // Table names when model initialization.
  23. tables string // Operation table names, which can be more than one table names and aliases, like: "user", "user u", "user u, user_detail ud".
  24. fields string // Operation fields, multiple fields joined using char ','.
  25. fieldsEx string // Excluded operation fields, multiple fields joined using char ','.
  26. withArray []interface{} // Arguments for With feature.
  27. withAll bool // Enable model association operations on all objects that have "with" tag in the struct.
  28. extraArgs []interface{} // Extra custom arguments for sql, which are prepended to the arguments before sql committed to underlying driver.
  29. whereHolder []ModelWhereHolder // Condition strings for where operation.
  30. groupBy string // Used for "group by" statement.
  31. orderBy string // Used for "order by" statement.
  32. having []interface{} // Used for "having..." statement.
  33. start int // Used for "select ... start, limit ..." statement.
  34. limit int // Used for "select ... start, limit ..." statement.
  35. option int // Option for extra operation features.
  36. offset int // Offset statement for some databases grammar.
  37. data interface{} // Data for operation, which can be type of map/[]map/struct/*struct/string, etc.
  38. batch int // Batch number for batch Insert/Replace/Save operations.
  39. filter bool // Filter data and where key-value pairs according to the fields of the table.
  40. distinct string // Force the query to only return distinct results.
  41. lockInfo string // Lock for update or in shared lock.
  42. cacheEnabled bool // Enable sql result cache feature.
  43. cacheDuration time.Duration // Cache TTL duration (< 1 for removing cache, >= 0 for saving cache).
  44. cacheName string // Cache name for custom operation.
  45. unscoped bool // Disables soft deleting features when select/delete operations.
  46. safe bool // If true, it clones and returns a new model object whenever operation done; or else it changes the attribute of current model.
  47. onDuplicate interface{} // onDuplicate is used for ON "DUPLICATE KEY UPDATE" statement.
  48. onDuplicateEx interface{} // onDuplicateEx is used for excluding some columns ON "DUPLICATE KEY UPDATE" statement.
  49. }
  50. // ModelHandler is a function that handles given Model and returns a new Model that is custom modified.
  51. type ModelHandler func(m *Model) *Model
  52. // ChunkHandler is a function that is used in function Chunk, which handles given Result and error.
  53. // It returns true if it wants continue chunking, or else it returns false to stop chunking.
  54. type ChunkHandler func(result Result, err error) bool
  55. // ModelWhereHolder is the holder for where condition preparing.
  56. type ModelWhereHolder struct {
  57. Operator int // Operator for this holder.
  58. Where interface{} // Where parameter, which can commonly be type of string/map/struct.
  59. Args []interface{} // Arguments for where parameter.
  60. }
  61. const (
  62. linkTypeMaster = 1
  63. linkTypeSlave = 2
  64. whereHolderOperatorWhere = 1
  65. whereHolderOperatorAnd = 2
  66. whereHolderOperatorOr = 3
  67. defaultFields = "*"
  68. )
  69. // Table is alias of Core.Model.
  70. // See Core.Model.
  71. // Deprecated, use Model instead.
  72. func (c *Core) Table(tableNameQueryOrStruct ...interface{}) *Model {
  73. return c.db.Model(tableNameQueryOrStruct...)
  74. }
  75. // Model creates and returns a new ORM model from given schema.
  76. // The parameter `tableNameQueryOrStruct` can be more than one table names, and also alias name, like:
  77. // 1. Model names:
  78. // db.Model("user")
  79. // db.Model("user u")
  80. // db.Model("user, user_detail")
  81. // db.Model("user u, user_detail ud")
  82. // 2. Model name with alias:
  83. // db.Model("user", "u")
  84. // 3. Model name with sub-query:
  85. // db.Model("? AS a, ? AS b", subQuery1, subQuery2)
  86. func (c *Core) Model(tableNameQueryOrStruct ...interface{}) *Model {
  87. var (
  88. tableStr string
  89. tableName string
  90. extraArgs []interface{}
  91. )
  92. // Model creation with sub-query.
  93. if len(tableNameQueryOrStruct) > 1 {
  94. conditionStr := gconv.String(tableNameQueryOrStruct[0])
  95. if gstr.Contains(conditionStr, "?") {
  96. tableStr, extraArgs = formatWhere(c.db, formatWhereInput{
  97. Where: conditionStr,
  98. Args: tableNameQueryOrStruct[1:],
  99. OmitNil: false,
  100. OmitEmpty: false,
  101. Schema: "",
  102. Table: "",
  103. })
  104. }
  105. }
  106. // Normal model creation.
  107. if tableStr == "" {
  108. tableNames := make([]string, len(tableNameQueryOrStruct))
  109. for k, v := range tableNameQueryOrStruct {
  110. if s, ok := v.(string); ok {
  111. tableNames[k] = s
  112. } else if tableName = getTableNameFromOrmTag(v); tableName != "" {
  113. tableNames[k] = tableName
  114. }
  115. }
  116. if len(tableNames) > 1 {
  117. tableStr = fmt.Sprintf(
  118. `%s AS %s`, c.QuotePrefixTableName(tableNames[0]), c.QuoteWord(tableNames[1]),
  119. )
  120. } else if len(tableNames) == 1 {
  121. tableStr = c.QuotePrefixTableName(tableNames[0])
  122. }
  123. }
  124. return &Model{
  125. db: c.db,
  126. tablesInit: tableStr,
  127. tables: tableStr,
  128. fields: defaultFields,
  129. start: -1,
  130. offset: -1,
  131. filter: true,
  132. extraArgs: extraArgs,
  133. }
  134. }
  135. // Raw creates and returns a model based on a raw sql not a table.
  136. // Example:
  137. // db.Raw("SELECT * FROM `user` WHERE `name` = ?", "john").Scan(&result)
  138. func (c *Core) Raw(rawSql string, args ...interface{}) *Model {
  139. model := c.Model()
  140. model.rawSql = rawSql
  141. model.extraArgs = args
  142. return model
  143. }
  144. // Raw creates and returns a model based on a raw sql not a table.
  145. // Example:
  146. // db.Raw("SELECT * FROM `user` WHERE `name` = ?", "john").Scan(&result)
  147. // See Core.Raw.
  148. func (m *Model) Raw(rawSql string, args ...interface{}) *Model {
  149. model := m.db.Raw(rawSql, args...)
  150. model.db = m.db
  151. model.tx = m.tx
  152. return model
  153. }
  154. func (tx *TX) Raw(rawSql string, args ...interface{}) *Model {
  155. return tx.Model().Raw(rawSql, args...)
  156. }
  157. // With creates and returns an ORM model based on meta data of given object.
  158. func (c *Core) With(objects ...interface{}) *Model {
  159. return c.db.Model().With(objects...)
  160. }
  161. // Model acts like Core.Model except it operates on transaction.
  162. // See Core.Model.
  163. func (tx *TX) Model(tableNameQueryOrStruct ...interface{}) *Model {
  164. model := tx.db.Model(tableNameQueryOrStruct...)
  165. model.db = tx.db
  166. model.tx = tx
  167. return model
  168. }
  169. // With acts like Core.With except it operates on transaction.
  170. // See Core.With.
  171. func (tx *TX) With(object interface{}) *Model {
  172. return tx.Model().With(object)
  173. }
  174. // Ctx sets the context for current operation.
  175. func (m *Model) Ctx(ctx context.Context) *Model {
  176. if ctx == nil {
  177. return m
  178. }
  179. model := m.getModel()
  180. model.db = model.db.Ctx(ctx)
  181. if m.tx != nil {
  182. model.tx = model.tx.Ctx(ctx)
  183. }
  184. return model
  185. }
  186. // GetCtx returns the context for current Model.
  187. // It returns `context.Background()` is there's no context previously set.
  188. func (m *Model) GetCtx() context.Context {
  189. if m.tx != nil && m.tx.ctx != nil {
  190. return m.tx.ctx
  191. }
  192. return m.db.GetCtx()
  193. }
  194. // As sets an alias name for current table.
  195. func (m *Model) As(as string) *Model {
  196. if m.tables != "" {
  197. model := m.getModel()
  198. split := " JOIN "
  199. if gstr.ContainsI(model.tables, split) {
  200. // For join table.
  201. array := gstr.Split(model.tables, split)
  202. array[len(array)-1], _ = gregex.ReplaceString(`(.+) ON`, fmt.Sprintf(`$1 AS %s ON`, as), array[len(array)-1])
  203. model.tables = gstr.Join(array, split)
  204. } else {
  205. // For base table.
  206. model.tables = gstr.TrimRight(model.tables) + " AS " + as
  207. }
  208. return model
  209. }
  210. return m
  211. }
  212. // DB sets/changes the db object for current operation.
  213. func (m *Model) DB(db DB) *Model {
  214. model := m.getModel()
  215. model.db = db
  216. return model
  217. }
  218. // TX sets/changes the transaction for current operation.
  219. func (m *Model) TX(tx *TX) *Model {
  220. model := m.getModel()
  221. model.db = tx.db
  222. model.tx = tx
  223. return model
  224. }
  225. // Schema sets the schema for current operation.
  226. func (m *Model) Schema(schema string) *Model {
  227. model := m.getModel()
  228. model.schema = schema
  229. return model
  230. }
  231. // Clone creates and returns a new model which is a clone of current model.
  232. // Note that it uses deep-copy for the clone.
  233. func (m *Model) Clone() *Model {
  234. newModel := (*Model)(nil)
  235. if m.tx != nil {
  236. newModel = m.tx.Model(m.tablesInit)
  237. } else {
  238. newModel = m.db.Model(m.tablesInit)
  239. }
  240. *newModel = *m
  241. // Shallow copy slice attributes.
  242. if n := len(m.extraArgs); n > 0 {
  243. newModel.extraArgs = make([]interface{}, n)
  244. copy(newModel.extraArgs, m.extraArgs)
  245. }
  246. if n := len(m.whereHolder); n > 0 {
  247. newModel.whereHolder = make([]ModelWhereHolder, n)
  248. copy(newModel.whereHolder, m.whereHolder)
  249. }
  250. if n := len(m.withArray); n > 0 {
  251. newModel.withArray = make([]interface{}, n)
  252. copy(newModel.withArray, m.withArray)
  253. }
  254. return newModel
  255. }
  256. // Master marks the following operation on master node.
  257. func (m *Model) Master() *Model {
  258. model := m.getModel()
  259. model.linkType = linkTypeMaster
  260. return model
  261. }
  262. // Slave marks the following operation on slave node.
  263. // Note that it makes sense only if there's any slave node configured.
  264. func (m *Model) Slave() *Model {
  265. model := m.getModel()
  266. model.linkType = linkTypeSlave
  267. return model
  268. }
  269. // Safe marks this model safe or unsafe. If safe is true, it clones and returns a new model object
  270. // whenever the operation done, or else it changes the attribute of current model.
  271. func (m *Model) Safe(safe ...bool) *Model {
  272. if len(safe) > 0 {
  273. m.safe = safe[0]
  274. } else {
  275. m.safe = true
  276. }
  277. return m
  278. }
  279. // Args sets custom arguments for model operation.
  280. func (m *Model) Args(args ...interface{}) *Model {
  281. model := m.getModel()
  282. model.extraArgs = append(model.extraArgs, args)
  283. return model
  284. }
  285. // Handler calls each of `handlers` on current Model and returns a new Model.
  286. // ModelHandler is a function that handles given Model and returns a new Model that is custom modified.
  287. func (m *Model) Handler(handlers ...ModelHandler) *Model {
  288. model := m.getModel()
  289. for _, handler := range handlers {
  290. model = handler(model)
  291. }
  292. return model
  293. }