model.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. package lxDb
  2. import (
  3. "fmt"
  4. "git.listensoft.net/tool/lxutils/lxUtil"
  5. "gorm.io/gorm"
  6. "reflect"
  7. "strings"
  8. "time"
  9. )
  10. type BaseModel struct {
  11. ID uint `json:"id" gorm:"primaryKey"` // old version is: gorm:"primary_key", TODO: 兼容旧的 有没有影响?
  12. CreatedAt time.Time `json:"createdAt"`
  13. UpdatedAt time.Time `json:"updatedAt"`
  14. CreatedBy uint `json:"createdBy"`
  15. UpdatedBy uint `json:"updatedBy"`
  16. }
  17. // BaseModel2 带操作人ID的BaseModel
  18. type BaseModel2 struct {
  19. BaseModel
  20. CreatedBy uint `json:"createdBy"`
  21. UpdatedBy uint `json:"updatedBy"`
  22. //DeletedBy uint `json:"-"`
  23. }
  24. //func (m BaseModel)AsID (id uint) {
  25. // m.ID = id
  26. //}
  27. // NewModel 返回被 uid 填充的 model
  28. //func NewModel(uid uint) Model {
  29. // return Model{CreatedBy: uid, UpdatedBy: uid}
  30. //}
  31. // Condition 查询条件
  32. type Condition struct {
  33. Field string // 字段
  34. Operator string // 操作类型
  35. Arg interface{} // 值
  36. }
  37. // PaginationQuery 查询条件
  38. // TODO: 考虑在包之外使用方法修改属性而不是直接操作属性
  39. // TODO: 考虑要明确指定不分页查询, 否则就强制分页, 以免误查大量数据, 但是给非前端调用带来麻烦
  40. // TODO: 要明确指定是不分页查询, 默认“下一页”不查询total. 考虑前端使用的友好性,及可配置化(config)
  41. type PaginationQuery struct {
  42. Conditions []Condition `json:"-"` // 查询条件
  43. OrderBy string `json:"orderBy"` // 排序 会被直接拼接到 sql 里 // TODO: 这个会保留吗, 支持特殊的自定义排序.
  44. Orders []string `json:"orders"` // 排序 会被直接拼接到 sql 里 // TODO: 支持多条件排序 string 还是对象? 还未做
  45. Offset int `json:"page"` // 第几页
  46. Limit int `json:"limit"` // 一页几条数据 or size ? // TODO:
  47. NoTotal bool `json:"noTotal"` // 不需要记录条数, true: 不查询Total
  48. Total int `json:"total"` // 记录条数
  49. Summary string `json:"summary"` // 汇总字段,如: "inAmt,inCount"
  50. SummarySql []string `json:"-"` // 汇总子sql, 如: ["SUM(int_amt) AS inAmt", "SUM(int_count) AS inCount"]
  51. SummaryResult map[string]interface{} `json:"summaryResult"` // 汇总结果
  52. }
  53. // Eq equal 等于
  54. func (q *PaginationQuery) Eq(field string, arg interface{}) {
  55. q.Conditions = append(q.Conditions, Condition{Field: field, Operator: "eq", Arg: arg})
  56. }
  57. // Ne not equal 不等于
  58. func (q *PaginationQuery) Ne(field string, arg interface{}) {
  59. q.Conditions = append(q.Conditions, Condition{Field: field, Operator: "ne", Arg: arg})
  60. }
  61. // Lt less than 小于
  62. func (q *PaginationQuery) Lt(field string, arg interface{}) {
  63. q.Conditions = append(q.Conditions, Condition{Field: field, Operator: "lt", Arg: arg})
  64. }
  65. // Le less equal 小于等于
  66. func (q *PaginationQuery) Le(field string, arg interface{}) {
  67. q.Conditions = append(q.Conditions, Condition{Field: field, Operator: "le", Arg: arg})
  68. }
  69. // Gt greater than 大于
  70. func (q *PaginationQuery) Gt(field string, arg interface{}) {
  71. q.Conditions = append(q.Conditions, Condition{Field: field, Operator: "gt", Arg: arg})
  72. }
  73. // Ge greater equal 大于等于
  74. func (q *PaginationQuery) Ge(field string, arg interface{}) {
  75. q.Conditions = append(q.Conditions, Condition{Field: field, Operator: "ge", Arg: arg})
  76. }
  77. // Like 包含 LIKE '%arg%'
  78. func (q *PaginationQuery) Like(field string, arg interface{}) {
  79. q.Conditions = append(q.Conditions, Condition{Field: field, Operator: "like", Arg: arg})
  80. }
  81. // Like2 自指定包含方式 LIKE 'arg'. arg是灵活的, 如: 前匹配abs%, 后匹配%abc, 通配符'_1_'
  82. func (q *PaginationQuery) Like2(field string, value interface{}) {
  83. q.Conditions = append(q.Conditions, Condition{Field: field, Operator: "like2", Arg: value})
  84. }
  85. func (q *PaginationQuery) NotLike(field string, value interface{}) {
  86. q.Conditions = append(q.Conditions, Condition{Field: field, Operator: "notlike", Arg: value})
  87. }
  88. // In IN (...)
  89. func (q *PaginationQuery) In(field string, arg interface{}) {
  90. q.Conditions = append(q.Conditions, Condition{Field: field, Operator: "in", Arg: arg})
  91. }
  92. // Between BETWEEN v1 AND v2
  93. func (q *PaginationQuery) Between(field string, v1, v2 interface{}) {
  94. q.Conditions = append(q.Conditions, Condition{Field: field, Operator: "between", Arg: [2]interface{}{v1, v2}})
  95. }
  96. // Or OR
  97. func (q *PaginationQuery) Or(field string, arg interface{}) {
  98. q.Conditions = append(q.Conditions, Condition{Field: field, Operator: "or", Arg: arg})
  99. }
  100. // Ors Deprecated: replaced by And 自定义条件, 如: (length(field) = 4 OR length(field) = 6)
  101. func (q *PaginationQuery) Ors(condition string) {
  102. q.And("(" + condition + ")")
  103. }
  104. // And 自定义条件, 如: (length(field) = 4 OR length(field) = 6)
  105. func (q *PaginationQuery) And(condition string) {
  106. q.Conditions = append(q.Conditions, Condition{Field: condition, Operator: "and"})
  107. }
  108. // Group GROUP BY
  109. func (q *PaginationQuery) Group(field string) {
  110. q.Conditions = append(q.Conditions, Condition{Field: field, Operator: "group"})
  111. }
  112. // Join JOIN table_name ON
  113. func (q *PaginationQuery) Join(joinSql string, args ...interface{}) {
  114. q.Conditions = append(q.Conditions, Condition{Field: joinSql, Operator: "join", Arg: args})
  115. }
  116. // Select 要查询的字段. 可以将字段都写在第一个参数, 也可以作为多个参数传递. ("aa, bb, cc") == ("aa", "bb", "cc")
  117. func (q *PaginationQuery) Select(query string, args ...interface{}) {
  118. q.Conditions = append(q.Conditions, Condition{Field: query, Operator: "select", Arg: args})
  119. }
  120. // Build 构造查询条件
  121. func (q *PaginationQuery) Build(tx *gorm.DB) *gorm.DB {
  122. for _, con := range q.Conditions {
  123. switch con.Operator {
  124. case "eq":
  125. field := fmt.Sprintf("%s = ?", con.Field)
  126. tx = tx.Where(field, con.Arg)
  127. case "ne":
  128. field := fmt.Sprintf("%s <> ?", con.Field)
  129. tx = tx.Where(field, con.Arg)
  130. case "lt":
  131. field := fmt.Sprintf("%s < ?", con.Field)
  132. tx = tx.Where(field, con.Arg)
  133. case "le":
  134. field := fmt.Sprintf("%s <= ?", con.Field)
  135. tx = tx.Where(field, con.Arg)
  136. case "gt":
  137. field := fmt.Sprintf("%s > ?", con.Field)
  138. tx = tx.Where(field, con.Arg)
  139. case "ge":
  140. field := fmt.Sprintf("%s >= ?", con.Field)
  141. tx = tx.Where(field, con.Arg)
  142. case "like":
  143. field := fmt.Sprintf("%s LIKE ?", con.Field) // field LIKE '%arg%'
  144. tx = tx.Where(field, fmt.Sprintf("%%%v%%", con.Arg))
  145. case "like2":
  146. field := fmt.Sprintf("%s LIKE ?", con.Field) // field LIKE 'arg', support: 'abc%', '%abc', '_1_'
  147. tx = tx.Where(field, con.Arg)
  148. case "notlike":
  149. field := fmt.Sprintf("%s NOT LIKE ?", con.Field)
  150. tx = tx.Where(field, fmt.Sprintf("%%%v%%", con.Arg))
  151. case "in":
  152. field := fmt.Sprintf("%s IN (?)", con.Field)
  153. tx = tx.Where(field, con.Arg)
  154. case "between":
  155. field := fmt.Sprintf("%s BETWEEN ? AND ?", con.Field)
  156. value1, value2, ok := split(con.Arg)
  157. if ok {
  158. tx = tx.Where(field, value1, value2)
  159. }
  160. case "or":
  161. field := fmt.Sprintf("%s = ?", con.Field)
  162. tx = tx.Or(field, con.Arg)
  163. case "and":
  164. tx = tx.Where(con.Field) // 自定义条件, 如: (length(field) = 4 OR length(field) = 6)
  165. case "group":
  166. tx = tx.Group(con.Field)
  167. case "join":
  168. //args := cast.ToStringSlice(con.Arg) // not work, cast.ToSlice not work too
  169. tx = tx.Joins(con.Field, lxUtil.ToSlice1(con.Arg)...)
  170. case "select":
  171. tx = tx.Select(con.Field, lxUtil.ToSlice1(con.Arg)...)
  172. }
  173. }
  174. return tx
  175. }
  176. // BuildRawWhere 构造原生SQL的查询条件
  177. func (q *PaginationQuery) BuildRawWhere() (where string, args []interface{}) {
  178. var sb strings.Builder
  179. for _, con := range q.Conditions {
  180. switch con.Operator {
  181. case "eq":
  182. sb.WriteString(fmt.Sprintf(" AND %s = ?", con.Field))
  183. args = append(args, con.Arg)
  184. case "ne":
  185. sb.WriteString(fmt.Sprintf(" AND %s <> ?", con.Field))
  186. args = append(args, con.Arg)
  187. case "lt":
  188. sb.WriteString(fmt.Sprintf(" AND %s < ?", con.Field))
  189. args = append(args, con.Arg)
  190. case "le":
  191. sb.WriteString(fmt.Sprintf(" AND %s <= ?", con.Field))
  192. args = append(args, con.Arg)
  193. case "gt":
  194. sb.WriteString(fmt.Sprintf(" AND %s > ?", con.Field))
  195. args = append(args, con.Arg)
  196. case "ge":
  197. sb.WriteString(fmt.Sprintf(" AND %s >= ?", con.Field))
  198. args = append(args, con.Arg)
  199. case "like":
  200. sb.WriteString(fmt.Sprintf(" AND %s LIKE ?", con.Field)) // field LIKE '%arg%'
  201. args = append(args, fmt.Sprintf("%%%v%%", con.Arg))
  202. case "like2":
  203. sb.WriteString(fmt.Sprintf(" AND %s LIKE ?", con.Field)) // field LIKE 'arg', support: 'abc%', '%abc', '_1_'
  204. args = append(args, con.Arg)
  205. case "notlike":
  206. sb.WriteString(fmt.Sprintf(" AND %s NOT LIKE ?", con.Field))
  207. args = append(args, fmt.Sprintf("%%%v%%", con.Arg))
  208. case "in":
  209. sb.WriteString(fmt.Sprintf(" AND %s IN (?)", con.Field))
  210. args = append(args, con.Arg)
  211. case "between":
  212. value1, value2, ok := split(con.Arg)
  213. if ok {
  214. sb.WriteString(fmt.Sprintf(" AND %s BETWEEN ? AND ?", con.Field))
  215. args = append(args, value1, value2)
  216. }
  217. case "or":
  218. sb.WriteString(fmt.Sprintf(" OR %s = ?", con.Field))
  219. args = append(args, con.Arg)
  220. case "and":
  221. sb.WriteString(fmt.Sprintf(" AND %s", con.Field)) // 自定义条件, 如: (length(field) = 4 OR length(field) = 6)
  222. case "group":
  223. sb.WriteString(fmt.Sprintf(" GROUP BY %s", con.Field))
  224. //case "join":
  225. // if con.Arg == nil {
  226. // tx = tx.Joins(con.Field)
  227. // } else {
  228. // tx = tx.Joins(con.Field, con.Arg)
  229. // }
  230. //case "select":
  231. // if con.Arg == nil {
  232. // tx = tx.Select(con.Field)
  233. // } else {
  234. // tx = tx.Select(con.Field, con.Arg)
  235. // }
  236. }
  237. }
  238. where = sb.String()
  239. if args == nil {
  240. args = make([]interface{}, 0)
  241. }
  242. return
  243. }
  244. // 参数拆分 // TODO: 不知道有没有更好的实现方式
  245. // TODO: 加异常处理, 如应该两个值只传了一个值
  246. //func split(value interface{}) (interface{}, interface{}) {
  247. // values := value.([2]interface{})
  248. // return values[0], values[1]
  249. //}
  250. // 参数拆分
  251. func split(value interface{}) (v1 interface{}, v2 interface{}, ok bool) {
  252. rv := reflect.ValueOf(value)
  253. // 取值
  254. for rv.Kind() == reflect.Ptr {
  255. rv = rv.Elem()
  256. }
  257. // 校验是否为长度为 2 的数组或切片
  258. if (rv.Kind() != reflect.Slice && rv.Kind() != reflect.Array) || rv.Len() != 2 {
  259. return
  260. }
  261. return rv.Index(0).Interface(), rv.Index(1).Interface(), true
  262. }