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