You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

322 lines
6.4 KiB

2 years ago
  1. // Copyright 2016 The Xorm Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package builder
  5. import (
  6. sql2 "database/sql"
  7. "fmt"
  8. )
  9. type optype byte
  10. const (
  11. condType optype = iota // only conditions
  12. selectType // select
  13. insertType // insert
  14. updateType // update
  15. deleteType // delete
  16. setOpType // set operation
  17. )
  18. // all databasees
  19. const (
  20. POSTGRES = "postgres"
  21. SQLITE = "sqlite3"
  22. MYSQL = "mysql"
  23. MSSQL = "mssql"
  24. ORACLE = "oracle"
  25. UNION = "union"
  26. INTERSECT = "intersect"
  27. EXCEPT = "except"
  28. )
  29. type join struct {
  30. joinType string
  31. joinTable interface{}
  32. joinCond Cond
  33. joinAlias string
  34. }
  35. type setOp struct {
  36. opType string
  37. distinctType string
  38. builder *Builder
  39. }
  40. type limit struct {
  41. limitN int
  42. offset int
  43. }
  44. // Builder describes a SQL statement
  45. type Builder struct {
  46. optype
  47. dialect string
  48. isNested bool
  49. into string
  50. from string
  51. subQuery *Builder
  52. cond Cond
  53. selects []string
  54. joins []join
  55. setOps []setOp
  56. limitation *limit
  57. insertCols []string
  58. insertVals []interface{}
  59. updates []UpdateCond
  60. orderBy string
  61. groupBy string
  62. having string
  63. }
  64. // Dialect sets the db dialect of Builder.
  65. func Dialect(dialect string) *Builder {
  66. builder := &Builder{cond: NewCond(), dialect: dialect}
  67. return builder
  68. }
  69. // MySQL is shortcut of Dialect(MySQL)
  70. func MySQL() *Builder {
  71. return Dialect(MYSQL)
  72. }
  73. // MsSQL is shortcut of Dialect(MsSQL)
  74. func MsSQL() *Builder {
  75. return Dialect(MSSQL)
  76. }
  77. // Oracle is shortcut of Dialect(Oracle)
  78. func Oracle() *Builder {
  79. return Dialect(ORACLE)
  80. }
  81. // Postgres is shortcut of Dialect(Postgres)
  82. func Postgres() *Builder {
  83. return Dialect(POSTGRES)
  84. }
  85. // SQLite is shortcut of Dialect(SQLITE)
  86. func SQLite() *Builder {
  87. return Dialect(SQLITE)
  88. }
  89. // Where sets where SQL
  90. func (b *Builder) Where(cond Cond) *Builder {
  91. if b.cond.IsValid() {
  92. b.cond = b.cond.And(cond)
  93. } else {
  94. b.cond = cond
  95. }
  96. return b
  97. }
  98. // From sets from subject(can be a table name in string or a builder pointer) and its alias
  99. func (b *Builder) From(subject interface{}, alias ...string) *Builder {
  100. switch subject.(type) {
  101. case *Builder:
  102. b.subQuery = subject.(*Builder)
  103. if len(alias) > 0 {
  104. b.from = alias[0]
  105. } else {
  106. b.isNested = true
  107. }
  108. case string:
  109. b.from = subject.(string)
  110. if len(alias) > 0 {
  111. b.from = b.from + " " + alias[0]
  112. }
  113. }
  114. return b
  115. }
  116. // TableName returns the table name
  117. func (b *Builder) TableName() string {
  118. if b.optype == insertType {
  119. return b.into
  120. }
  121. return b.from
  122. }
  123. // Into sets insert table name
  124. func (b *Builder) Into(tableName string) *Builder {
  125. b.into = tableName
  126. return b
  127. }
  128. // Union sets union conditions
  129. func (b *Builder) Union(distinctType string, cond *Builder) *Builder {
  130. return b.setOperation(UNION, distinctType, cond)
  131. }
  132. // Intersect sets intersect conditions
  133. func (b *Builder) Intersect(distinctType string, cond *Builder) *Builder {
  134. return b.setOperation(INTERSECT, distinctType, cond)
  135. }
  136. // Except sets except conditions
  137. func (b *Builder) Except(distinctType string, cond *Builder) *Builder {
  138. return b.setOperation(EXCEPT, distinctType, cond)
  139. }
  140. func (b *Builder) setOperation(opType, distinctType string, cond *Builder) *Builder {
  141. var builder *Builder
  142. if b.optype != setOpType {
  143. builder = &Builder{cond: NewCond()}
  144. builder.optype = setOpType
  145. builder.dialect = b.dialect
  146. builder.selects = b.selects
  147. currentSetOps := b.setOps
  148. // erase sub setOps (actually append to new Builder.unions)
  149. b.setOps = nil
  150. for e := range currentSetOps {
  151. currentSetOps[e].builder.dialect = b.dialect
  152. }
  153. builder.setOps = append(append(builder.setOps, setOp{opType, "", b}), currentSetOps...)
  154. } else {
  155. builder = b
  156. }
  157. if cond != nil {
  158. if cond.dialect == "" && builder.dialect != "" {
  159. cond.dialect = builder.dialect
  160. }
  161. builder.setOps = append(builder.setOps, setOp{opType, distinctType, cond})
  162. }
  163. return builder
  164. }
  165. // Limit sets limitN condition
  166. func (b *Builder) Limit(limitN int, offset ...int) *Builder {
  167. b.limitation = &limit{limitN: limitN}
  168. if len(offset) > 0 {
  169. b.limitation.offset = offset[0]
  170. }
  171. return b
  172. }
  173. // Select sets select SQL
  174. func (b *Builder) Select(cols ...string) *Builder {
  175. b.selects = cols
  176. if b.optype == condType {
  177. b.optype = selectType
  178. }
  179. return b
  180. }
  181. // And sets AND condition
  182. func (b *Builder) And(cond Cond) *Builder {
  183. b.cond = And(b.cond, cond)
  184. return b
  185. }
  186. // Or sets OR condition
  187. func (b *Builder) Or(cond Cond) *Builder {
  188. b.cond = Or(b.cond, cond)
  189. return b
  190. }
  191. // Update sets update SQL
  192. func (b *Builder) Update(updates ...Cond) *Builder {
  193. b.updates = make([]UpdateCond, 0, len(updates))
  194. for _, update := range updates {
  195. if u, ok := update.(UpdateCond); ok && u.IsValid() {
  196. b.updates = append(b.updates, u)
  197. }
  198. }
  199. b.optype = updateType
  200. return b
  201. }
  202. // Delete sets delete SQL
  203. func (b *Builder) Delete(conds ...Cond) *Builder {
  204. b.cond = b.cond.And(conds...)
  205. b.optype = deleteType
  206. return b
  207. }
  208. // WriteTo implements Writer interface
  209. func (b *Builder) WriteTo(w Writer) error {
  210. switch b.optype {
  211. /*case condType:
  212. return b.cond.WriteTo(w)*/
  213. case selectType:
  214. return b.selectWriteTo(w)
  215. case insertType:
  216. return b.insertWriteTo(w)
  217. case updateType:
  218. return b.updateWriteTo(w)
  219. case deleteType:
  220. return b.deleteWriteTo(w)
  221. case setOpType:
  222. return b.setOpWriteTo(w)
  223. }
  224. return ErrNotSupportType
  225. }
  226. // ToSQL convert a builder to SQL and args
  227. func (b *Builder) ToSQL() (string, []interface{}, error) {
  228. w := NewWriter()
  229. if err := b.WriteTo(w); err != nil {
  230. return "", nil, err
  231. }
  232. // in case of sql.NamedArg in args
  233. for e := range w.args {
  234. if namedArg, ok := w.args[e].(sql2.NamedArg); ok {
  235. w.args[e] = namedArg.Value
  236. }
  237. }
  238. var sql = w.String()
  239. var err error
  240. switch b.dialect {
  241. case ORACLE, MSSQL:
  242. // This is for compatibility with different sql drivers
  243. for e := range w.args {
  244. w.args[e] = sql2.Named(fmt.Sprintf("p%d", e+1), w.args[e])
  245. }
  246. var prefix string
  247. if b.dialect == ORACLE {
  248. prefix = ":p"
  249. } else {
  250. prefix = "@p"
  251. }
  252. if sql, err = ConvertPlaceholder(sql, prefix); err != nil {
  253. return "", nil, err
  254. }
  255. case POSTGRES:
  256. if sql, err = ConvertPlaceholder(sql, "$"); err != nil {
  257. return "", nil, err
  258. }
  259. }
  260. return sql, w.args, nil
  261. }
  262. // ToBoundSQL generated a bound SQL string
  263. func (b *Builder) ToBoundSQL() (string, error) {
  264. w := NewWriter()
  265. if err := b.WriteTo(w); err != nil {
  266. return "", err
  267. }
  268. return ConvertToBoundSQL(w.String(), w.args)
  269. }