github.com/unionj-cloud/go-doudou@v1.3.8-0.20221011095552-0088008e5b31/toolkit/sqlext/query/query.go (about) 1 package query 2 3 import ( 4 "fmt" 5 "github.com/unionj-cloud/go-doudou/toolkit/sqlext/arithsymbol" 6 "github.com/unionj-cloud/go-doudou/toolkit/sqlext/logicsymbol" 7 "github.com/unionj-cloud/go-doudou/toolkit/sqlext/sortenum" 8 "github.com/unionj-cloud/go-doudou/toolkit/stringutils" 9 "reflect" 10 "strings" 11 ) 12 13 // Base sql expression 14 type Base interface { 15 Sql() (string, []interface{}) 16 //NamedSql() (string, []interface{}) 17 } 18 19 // Q used for building sql expression 20 type Q interface { 21 Base 22 And(q Base) Where 23 Or(q Base) Where 24 Append(q Base) Where 25 End(q Base) Where 26 } 27 28 // Criteria wrap a group of column, value and operator such as name = 20 29 type Criteria struct { 30 // table alias 31 talias string 32 col string 33 val interface{} 34 asym arithsymbol.ArithSymbol 35 } 36 37 // Sql implement Base interface, return sql expression 38 func (c Criteria) Sql() (string, []interface{}) { 39 if c.asym == arithsymbol.In || c.asym == arithsymbol.NotIn { 40 var args []interface{} 41 var sb strings.Builder 42 sb.WriteString(fmt.Sprintf("`%s` %s (", c.col, c.asym)) 43 44 var vals []string 45 switch reflect.TypeOf(c.val).Kind() { 46 case reflect.Slice: 47 data := reflect.ValueOf(c.val) 48 for i := 0; i < data.Len(); i++ { 49 vals = append(vals, "?") 50 args = append(args, data.Index(i).Interface()) 51 } 52 default: 53 vals = append(vals, "?") 54 args = append(args, c.val) 55 } 56 57 sb.WriteString(strings.Join(vals, ",")) 58 sb.WriteString(")") 59 60 return sb.String(), args 61 } 62 if stringutils.IsNotEmpty(c.talias) { 63 if c.asym == arithsymbol.Is || c.asym == arithsymbol.Not { 64 return fmt.Sprintf("%s.`%s` %s null", c.talias, c.col, c.asym), nil 65 } 66 return fmt.Sprintf("%s.`%s` %s ?", c.talias, c.col, c.asym), []interface{}{c.val} 67 } 68 if c.asym == arithsymbol.Is || c.asym == arithsymbol.Not { 69 return fmt.Sprintf("`%s` %s null", c.col, c.asym), nil 70 } 71 return fmt.Sprintf("`%s` %s ?", c.col, c.asym), []interface{}{c.val} 72 } 73 74 // C new a Criteria 75 func C() Criteria { 76 return Criteria{} 77 } 78 79 func (c Criteria) ToWhere() Where { 80 w := Where{ 81 children: make([]Base, 0), 82 } 83 w.children = append(w.children, c, String("")) 84 w.lsym = logicsymbol.End 85 return w 86 } 87 88 // Col set column name 89 func (c Criteria) Col(col string) Criteria { 90 if strings.Contains(col, ".") { 91 i := strings.Index(col, ".") 92 c.talias = col[:i] 93 c.col = col[i+1:] 94 } else { 95 c.col = col 96 } 97 return c 98 } 99 100 // Eq set = operator and column value 101 func (c Criteria) Eq(val interface{}) Criteria { 102 c.val = val 103 c.asym = arithsymbol.Eq 104 return c 105 } 106 107 // Ne set != operator and column value 108 func (c Criteria) Ne(val interface{}) Criteria { 109 c.val = val 110 c.asym = arithsymbol.Ne 111 return c 112 } 113 114 // Gt set > operator and column value 115 func (c Criteria) Gt(val interface{}) Criteria { 116 c.val = val 117 c.asym = arithsymbol.Gt 118 return c 119 } 120 121 // Lt set < operator and column value 122 func (c Criteria) Lt(val interface{}) Criteria { 123 c.val = val 124 c.asym = arithsymbol.Lt 125 return c 126 } 127 128 // Gte set >= operator and column value 129 func (c Criteria) Gte(val interface{}) Criteria { 130 c.val = val 131 c.asym = arithsymbol.Gte 132 return c 133 } 134 135 // Lte set <= operator and column value 136 func (c Criteria) Lte(val interface{}) Criteria { 137 c.val = val 138 c.asym = arithsymbol.Lte 139 return c 140 } 141 142 // IsNull set is null 143 func (c Criteria) IsNull() Criteria { 144 c.asym = arithsymbol.Is 145 return c 146 } 147 148 // IsNotNull set is not null 149 func (c Criteria) IsNotNull() Criteria { 150 c.asym = arithsymbol.Not 151 return c 152 } 153 154 // In set in operator and column value, val should be a slice type value 155 func (c Criteria) In(val interface{}) Criteria { 156 c.val = val 157 c.asym = arithsymbol.In 158 return c 159 } 160 161 // NotIn set not in operator and column value, val should be a slice type value 162 func (c Criteria) NotIn(val interface{}) Criteria { 163 c.val = val 164 c.asym = arithsymbol.NotIn 165 return c 166 } 167 168 // Like set like operator and column value, val should be a slice type value 169 func (c Criteria) Like(val interface{}) Criteria { 170 c.val = val 171 c.asym = arithsymbol.Like 172 return c 173 } 174 175 // And concat another sql expression builder with And 176 func (c Criteria) And(cri Base) Where { 177 w := Where{ 178 children: make([]Base, 0), 179 } 180 w.children = append(w.children, c, cri) 181 w.lsym = logicsymbol.And 182 return w 183 } 184 185 // Or concat another sql expression builder with Or 186 func (c Criteria) Or(cri Base) Where { 187 w := Where{ 188 children: make([]Base, 0), 189 } 190 w.children = append(w.children, c, cri) 191 w.lsym = logicsymbol.Or 192 return w 193 } 194 195 // Append concat another sql expression builder with Append 196 func (c Criteria) Append(cri Base) Where { 197 w := Where{ 198 children: make([]Base, 0), 199 } 200 w.children = append(w.children, c, cri) 201 w.lsym = logicsymbol.Append 202 return w 203 } 204 205 // End does nothing for Criteria same as Append empty 206 func (c Criteria) End(q Base) Where { 207 w := Where{ 208 children: make([]Base, 0), 209 } 210 w.children = append(w.children, c, q) 211 w.lsym = logicsymbol.End 212 return w 213 } 214 215 // Where concat children clauses with one of logic operators And, Or, Append 216 type Where struct { 217 lsym logicsymbol.LogicSymbol 218 children []Base 219 } 220 221 // Sql implement Base interface, return string sql expression 222 func (w Where) Sql() (string, []interface{}) { 223 if len(w.children) == 0 { 224 return "", nil 225 } 226 var args []interface{} 227 w0, args0 := w.children[0].Sql() 228 args = append(args, args0...) 229 w1, args1 := w.children[1].Sql() 230 args = append(args, args1...) 231 switch w.lsym { 232 case logicsymbol.And, logicsymbol.Or: 233 if stringutils.IsNotEmpty(w0) && stringutils.IsNotEmpty(w1) { 234 return fmt.Sprintf("(%s %s %s)", w0, w.lsym, w1), args 235 } else { 236 if stringutils.IsNotEmpty(w0) { 237 return w0, args 238 } else if stringutils.IsNotEmpty(w1) { 239 return w1, args 240 } else { 241 return "", nil 242 } 243 } 244 case logicsymbol.Append: 245 if stringutils.IsNotEmpty(w0) && stringutils.IsNotEmpty(w1) { 246 return fmt.Sprintf("(%s%s%s)", w0, w.lsym, w1), args 247 } else { 248 if stringutils.IsNotEmpty(w0) { 249 return w0, args 250 } else if stringutils.IsNotEmpty(w1) { 251 return w1, args 252 } else { 253 return "", nil 254 } 255 } 256 case logicsymbol.End: 257 fallthrough 258 default: 259 if stringutils.IsEmpty(w1) { 260 return w0, args 261 } 262 return fmt.Sprintf("%s %s", w0, w1), args 263 } 264 } 265 266 // And concat another sql expression builder with And 267 func (w Where) And(whe Base) Where { 268 parentW := Where{ 269 children: make([]Base, 0), 270 } 271 parentW.children = append(parentW.children, w, whe) 272 parentW.lsym = logicsymbol.And 273 return parentW 274 } 275 276 // Or concat another sql expression builder with Or 277 func (w Where) Or(whe Base) Where { 278 parentW := Where{ 279 children: make([]Base, 0), 280 } 281 parentW.children = append(parentW.children, w, whe) 282 parentW.lsym = logicsymbol.Or 283 return parentW 284 } 285 286 // Append concat another sql expression builder with Append 287 func (w Where) Append(whe Base) Where { 288 parentW := Where{ 289 children: make([]Base, 0), 290 } 291 parentW.children = append(parentW.children, w, whe) 292 if _, ok := whe.(Page); ok { 293 parentW.lsym = logicsymbol.End 294 } else { 295 parentW.lsym = logicsymbol.Append 296 } 297 return parentW 298 } 299 300 func (w Where) End(q Base) Where { 301 parentW := Where{ 302 children: make([]Base, 0), 303 } 304 parentW.children = append(parentW.children, w, q) 305 parentW.lsym = logicsymbol.End 306 return parentW 307 } 308 309 // Order by Col Sort 310 type Order struct { 311 Col string 312 Sort sortenum.Sort 313 } 314 315 // Page a sql expression builder for order by clause 316 type Page struct { 317 Orders []Order 318 Offset int 319 Size int 320 } 321 322 // P new a Page 323 func P() Page { 324 return Page{ 325 Orders: make([]Order, 0), 326 } 327 } 328 329 func NewPage(pageNo, pageSize int, orders ...Order) Page { 330 if pageNo <= 0 { 331 pageNo = 1 332 } 333 offset := 0 334 if pageSize > 0 { 335 offset = (pageNo - 1) * pageSize 336 } 337 return Page{ 338 Offset: offset, 339 Size: pageSize, 340 Orders: orders, 341 } 342 } 343 344 // Order append an Order 345 func (p Page) Order(o Order) Page { 346 p.Orders = append(p.Orders, o) 347 return p 348 } 349 350 // Limit set Offset and Size 351 func (p Page) Limit(offset, size int) Page { 352 p.Offset = offset 353 p.Size = size 354 return p 355 } 356 357 // Sql implement Base interface, order by age desc limit 2,1 358 func (p Page) Sql() (string, []interface{}) { 359 var sb strings.Builder 360 var args []interface{} 361 if len(p.Orders) > 0 { 362 sb.WriteString("order by ") 363 364 for i, order := range p.Orders { 365 if i > 0 { 366 sb.WriteString(",") 367 } 368 var ( 369 alias string 370 col string 371 ) 372 if strings.Contains(order.Col, ".") { 373 idx := strings.Index(order.Col, ".") 374 alias = order.Col[:idx] 375 col = order.Col[idx+1:] 376 } else { 377 col = order.Col 378 } 379 if stringutils.IsNotEmpty(alias) { 380 sb.WriteString(fmt.Sprintf("%s.`%s` %s", alias, col, order.Sort)) 381 } else { 382 sb.WriteString(fmt.Sprintf("`%s` %s", col, order.Sort)) 383 } 384 } 385 } 386 387 sb.WriteString(" ") 388 389 if p.Size > 0 { 390 sb.WriteString("limit ?,?") 391 args = append(args, p.Offset, p.Size) 392 } 393 394 return strings.TrimSpace(sb.String()), args 395 } 396 397 // PageRet wrap page query result 398 type PageRet struct { 399 Items interface{} 400 PageNo int 401 PageSize int 402 Total int 403 HasNext bool 404 } 405 406 // NewPageRet new a PageRet 407 func NewPageRet(page Page) PageRet { 408 pageNo := 1 409 if page.Size > 0 { 410 pageNo = page.Offset/page.Size + 1 411 } 412 return PageRet{ 413 PageNo: pageNo, 414 PageSize: page.Size, 415 } 416 } 417 418 // String is an alias of string 419 type String string 420 421 // Sql implements Base 422 func (s String) Sql() (string, []interface{}) { 423 return string(s), nil 424 }