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