gdb_model.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  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. partition string // Partition table partition name.
  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, which is mainly for indicating cache duration(especially 0) usage.
  43. cacheOption CacheOption // Cache option for query statement.
  44. hookHandler HookHandler // Hook functions for model hook feature.
  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. tableAliasMap map[string]string // Table alias to true table name, usually used in join statements.
  50. }
  51. // ModelHandler is a function that handles given Model and returns a new Model that is custom modified.
  52. type ModelHandler func(m *Model) *Model
  53. // ChunkHandler is a function that is used in function Chunk, which handles given Result and error.
  54. // It returns true if it wants to continue chunking, or else it returns false to stop chunking.
  55. type ChunkHandler func(result Result, err error) bool
  56. const (
  57. linkTypeMaster = 1
  58. linkTypeSlave = 2
  59. defaultFields = "*"
  60. whereHolderOperatorWhere = 1
  61. whereHolderOperatorAnd = 2
  62. whereHolderOperatorOr = 3
  63. whereHolderTypeDefault = "Default"
  64. whereHolderTypeNoArgs = "NoArgs"
  65. whereHolderTypeIn = "In"
  66. )
  67. // Model creates and returns a new ORM model from given schema.
  68. // The parameter `tableNameQueryOrStruct` can be more than one table names, and also alias name, like:
  69. // 1. Model names:
  70. // db.Model("user")
  71. // db.Model("user u")
  72. // db.Model("user, user_detail")
  73. // db.Model("user u, user_detail ud")
  74. // 2. Model name with alias:
  75. // db.Model("user", "u")
  76. // 3. Model name with sub-query:
  77. // db.Model("? AS a, ? AS b", subQuery1, subQuery2)
  78. func (c *Core) Model(tableNameQueryOrStruct ...interface{}) *Model {
  79. var (
  80. ctx = c.db.GetCtx()
  81. tableStr string
  82. tableName string
  83. extraArgs []interface{}
  84. )
  85. // Model creation with sub-query.
  86. if len(tableNameQueryOrStruct) > 1 {
  87. conditionStr := gconv.String(tableNameQueryOrStruct[0])
  88. if gstr.Contains(conditionStr, "?") {
  89. whereHolder := WhereHolder{
  90. Where: conditionStr,
  91. Args: tableNameQueryOrStruct[1:],
  92. }
  93. tableStr, extraArgs = formatWhereHolder(ctx, c.db, formatWhereHolderInput{
  94. WhereHolder: whereHolder,
  95. OmitNil: false,
  96. OmitEmpty: false,
  97. Schema: "",
  98. Table: "",
  99. })
  100. }
  101. }
  102. // Normal model creation.
  103. if tableStr == "" {
  104. tableNames := make([]string, len(tableNameQueryOrStruct))
  105. for k, v := range tableNameQueryOrStruct {
  106. if s, ok := v.(string); ok {
  107. tableNames[k] = s
  108. } else if tableName = getTableNameFromOrmTag(v); tableName != "" {
  109. tableNames[k] = tableName
  110. }
  111. }
  112. if len(tableNames) > 1 {
  113. tableStr = fmt.Sprintf(
  114. `%s AS %s`, c.QuotePrefixTableName(tableNames[0]), c.QuoteWord(tableNames[1]),
  115. )
  116. } else if len(tableNames) == 1 {
  117. tableStr = c.QuotePrefixTableName(tableNames[0])
  118. }
  119. }
  120. m := &Model{
  121. db: c.db,
  122. schema: c.schema,
  123. tablesInit: tableStr,
  124. tables: tableStr,
  125. fields: defaultFields,
  126. start: -1,
  127. offset: -1,
  128. filter: true,
  129. extraArgs: extraArgs,
  130. tableAliasMap: make(map[string]string),
  131. }
  132. m.whereBuilder = m.Builder()
  133. if defaultModelSafe {
  134. m.safe = true
  135. }
  136. return m
  137. }
  138. // Raw creates and returns a model based on a raw sql not a table.
  139. // Example:
  140. //
  141. // db.Raw("SELECT * FROM `user` WHERE `name` = ?", "john").Scan(&result)
  142. func (c *Core) Raw(rawSql string, args ...interface{}) *Model {
  143. model := c.Model()
  144. model.rawSql = rawSql
  145. model.extraArgs = args
  146. return model
  147. }
  148. // Raw sets current model as a raw sql model.
  149. // Example:
  150. //
  151. // db.Raw("SELECT * FROM `user` WHERE `name` = ?", "john").Scan(&result)
  152. //
  153. // See Core.Raw.
  154. func (m *Model) Raw(rawSql string, args ...interface{}) *Model {
  155. model := m.db.Raw(rawSql, args...)
  156. model.db = m.db
  157. model.tx = m.tx
  158. return model
  159. }
  160. func (tx *TXCore) Raw(rawSql string, args ...interface{}) *Model {
  161. return tx.Model().Raw(rawSql, args...)
  162. }
  163. // With creates and returns an ORM model based on metadata of given object.
  164. func (c *Core) With(objects ...interface{}) *Model {
  165. return c.db.Model().With(objects...)
  166. }
  167. // Partition sets Partition name.
  168. // Example:
  169. // dao.User.Ctx(ctx).Partition("p1","p2","p3").All()
  170. func (m *Model) Partition(partitions ...string) *Model {
  171. model := m.getModel()
  172. model.partition = gstr.Join(partitions, ",")
  173. return model
  174. }
  175. // Model acts like Core.Model except it operates on transaction.
  176. // See Core.Model.
  177. func (tx *TXCore) Model(tableNameQueryOrStruct ...interface{}) *Model {
  178. model := tx.db.Model(tableNameQueryOrStruct...)
  179. model.db = tx.db
  180. model.tx = tx
  181. return model
  182. }
  183. // With acts like Core.With except it operates on transaction.
  184. // See Core.With.
  185. func (tx *TXCore) With(object interface{}) *Model {
  186. return tx.Model().With(object)
  187. }
  188. // Ctx sets the context for current operation.
  189. func (m *Model) Ctx(ctx context.Context) *Model {
  190. if ctx == nil {
  191. return m
  192. }
  193. model := m.getModel()
  194. model.db = model.db.Ctx(ctx)
  195. if m.tx != nil {
  196. model.tx = model.tx.Ctx(ctx)
  197. }
  198. return model
  199. }
  200. // GetCtx returns the context for current Model.
  201. // It returns `context.Background()` is there's no context previously set.
  202. func (m *Model) GetCtx() context.Context {
  203. if m.tx != nil && m.tx.GetCtx() != nil {
  204. return m.tx.GetCtx()
  205. }
  206. return m.db.GetCtx()
  207. }
  208. // As sets an alias name for current table.
  209. func (m *Model) As(as string) *Model {
  210. if m.tables != "" {
  211. model := m.getModel()
  212. split := " JOIN "
  213. if gstr.ContainsI(model.tables, split) {
  214. // For join table.
  215. array := gstr.Split(model.tables, split)
  216. array[len(array)-1], _ = gregex.ReplaceString(`(.+) ON`, fmt.Sprintf(`$1 AS %s ON`, as), array[len(array)-1])
  217. model.tables = gstr.Join(array, split)
  218. } else {
  219. // For base table.
  220. model.tables = gstr.TrimRight(model.tables) + " AS " + as
  221. }
  222. return model
  223. }
  224. return m
  225. }
  226. // DB sets/changes the db object for current operation.
  227. func (m *Model) DB(db DB) *Model {
  228. model := m.getModel()
  229. model.db = db
  230. return model
  231. }
  232. // TX sets/changes the transaction for current operation.
  233. func (m *Model) TX(tx TX) *Model {
  234. model := m.getModel()
  235. model.db = tx.GetDB()
  236. model.tx = tx
  237. return model
  238. }
  239. // Schema sets the schema for current operation.
  240. func (m *Model) Schema(schema string) *Model {
  241. model := m.getModel()
  242. model.schema = schema
  243. return model
  244. }
  245. // Clone creates and returns a new model which is a Clone of current model.
  246. // Note that it uses deep-copy for the Clone.
  247. func (m *Model) Clone() *Model {
  248. newModel := (*Model)(nil)
  249. if m.tx != nil {
  250. newModel = m.tx.Model(m.tablesInit)
  251. } else {
  252. newModel = m.db.Model(m.tablesInit)
  253. }
  254. // Basic attributes copy.
  255. *newModel = *m
  256. // WhereBuilder copy, note the attribute pointer.
  257. newModel.whereBuilder = m.whereBuilder.Clone()
  258. newModel.whereBuilder.model = newModel
  259. // Shallow copy slice attributes.
  260. if n := len(m.extraArgs); n > 0 {
  261. newModel.extraArgs = make([]interface{}, n)
  262. copy(newModel.extraArgs, m.extraArgs)
  263. }
  264. if n := len(m.withArray); n > 0 {
  265. newModel.withArray = make([]interface{}, n)
  266. copy(newModel.withArray, m.withArray)
  267. }
  268. return newModel
  269. }
  270. // Master marks the following operation on master node.
  271. func (m *Model) Master() *Model {
  272. model := m.getModel()
  273. model.linkType = linkTypeMaster
  274. return model
  275. }
  276. // Slave marks the following operation on slave node.
  277. // Note that it makes sense only if there's any slave node configured.
  278. func (m *Model) Slave() *Model {
  279. model := m.getModel()
  280. model.linkType = linkTypeSlave
  281. return model
  282. }
  283. // Safe marks this model safe or unsafe. If safe is true, it clones and returns a new model object
  284. // whenever the operation done, or else it changes the attribute of current model.
  285. func (m *Model) Safe(safe ...bool) *Model {
  286. if len(safe) > 0 {
  287. m.safe = safe[0]
  288. } else {
  289. m.safe = true
  290. }
  291. return m
  292. }
  293. // Args sets custom arguments for model operation.
  294. func (m *Model) Args(args ...interface{}) *Model {
  295. model := m.getModel()
  296. model.extraArgs = append(model.extraArgs, args)
  297. return model
  298. }
  299. // Handler calls each of `handlers` on current Model and returns a new Model.
  300. // ModelHandler is a function that handles given Model and returns a new Model that is custom modified.
  301. func (m *Model) Handler(handlers ...ModelHandler) *Model {
  302. model := m.getModel()
  303. for _, handler := range handlers {
  304. model = handler(model)
  305. }
  306. return model
  307. }