本站源代码
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.

302 lines
5.9KB

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