github.com/unionj-cloud/go-doudou/v2@v2.3.5/toolkit/sqlext/query/query.go (about) 1 package query 2 3 import ( 4 "fmt" 5 "github.com/unionj-cloud/go-doudou/v2/toolkit/sqlext/arithsymbol" 6 "github.com/unionj-cloud/go-doudou/v2/toolkit/sqlext/logicsymbol" 7 "github.com/unionj-cloud/go-doudou/v2/toolkit/sqlext/sortenum" 8 "github.com/unionj-cloud/go-doudou/v2/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 func (w Where) IsEmpty() bool { 222 return len(w.children) == 0 223 } 224 225 // Sql implement Base interface, return string sql expression 226 func (w Where) Sql() (string, []interface{}) { 227 if len(w.children) == 0 { 228 return "", nil 229 } 230 var args []interface{} 231 w0, args0 := w.children[0].Sql() 232 args = append(args, args0...) 233 w1, args1 := w.children[1].Sql() 234 args = append(args, args1...) 235 switch w.lsym { 236 case logicsymbol.And, logicsymbol.Or: 237 if stringutils.IsNotEmpty(w0) && stringutils.IsNotEmpty(w1) { 238 return fmt.Sprintf("(%s %s %s)", w0, w.lsym, w1), args 239 } else { 240 if stringutils.IsNotEmpty(w0) { 241 return w0, args 242 } else if stringutils.IsNotEmpty(w1) { 243 return w1, args 244 } else { 245 return "", nil 246 } 247 } 248 case logicsymbol.Append: 249 if stringutils.IsNotEmpty(w0) && stringutils.IsNotEmpty(w1) { 250 return fmt.Sprintf("(%s%s%s)", w0, w.lsym, w1), args 251 } else { 252 if stringutils.IsNotEmpty(w0) { 253 return w0, args 254 } else if stringutils.IsNotEmpty(w1) { 255 return w1, args 256 } else { 257 return "", nil 258 } 259 } 260 case logicsymbol.End: 261 fallthrough 262 default: 263 if stringutils.IsEmpty(w1) { 264 return w0, args 265 } 266 return fmt.Sprintf("%s %s", w0, w1), args 267 } 268 } 269 270 // And concat another sql expression builder with And 271 func (w Where) And(whe Base) Where { 272 parentW := Where{ 273 children: make([]Base, 0), 274 } 275 parentW.children = append(parentW.children, w, whe) 276 parentW.lsym = logicsymbol.And 277 return parentW 278 } 279 280 // Or concat another sql expression builder with Or 281 func (w Where) Or(whe Base) Where { 282 parentW := Where{ 283 children: make([]Base, 0), 284 } 285 parentW.children = append(parentW.children, w, whe) 286 parentW.lsym = logicsymbol.Or 287 return parentW 288 } 289 290 // Append concat another sql expression builder with Append 291 func (w Where) Append(whe Base) Where { 292 parentW := Where{ 293 children: make([]Base, 0), 294 } 295 parentW.children = append(parentW.children, w, whe) 296 if _, ok := whe.(Page); ok { 297 parentW.lsym = logicsymbol.End 298 } else { 299 parentW.lsym = logicsymbol.Append 300 } 301 return parentW 302 } 303 304 func (w Where) End(q Base) Where { 305 parentW := Where{ 306 children: make([]Base, 0), 307 } 308 parentW.children = append(parentW.children, w, q) 309 parentW.lsym = logicsymbol.End 310 return parentW 311 } 312 313 // Order by Col Sort 314 type Order struct { 315 Col string 316 Sort sortenum.Sort 317 } 318 319 // Page a sql expression builder for order by clause 320 type Page struct { 321 Orders []Order 322 Offset int 323 Size int 324 } 325 326 // P new a Page 327 func P() Page { 328 return Page{ 329 Orders: make([]Order, 0), 330 } 331 } 332 333 func NewPage(pageNo, pageSize int, orders ...Order) Page { 334 if pageNo <= 0 { 335 pageNo = 1 336 } 337 offset := 0 338 if pageSize > 0 { 339 offset = (pageNo - 1) * pageSize 340 } 341 return Page{ 342 Offset: offset, 343 Size: pageSize, 344 Orders: orders, 345 } 346 } 347 348 // Order append an Order 349 func (p Page) Order(o Order) Page { 350 p.Orders = append(p.Orders, o) 351 return p 352 } 353 354 // Limit set Offset and Size 355 func (p Page) Limit(offset, size int) Page { 356 p.Offset = offset 357 p.Size = size 358 return p 359 } 360 361 // Sql implement Base interface, order by age desc limit 2,1 362 func (p Page) Sql() (string, []interface{}) { 363 var sb strings.Builder 364 var args []interface{} 365 if len(p.Orders) > 0 { 366 sb.WriteString("order by ") 367 368 for i, order := range p.Orders { 369 if i > 0 { 370 sb.WriteString(",") 371 } 372 var ( 373 alias string 374 col string 375 ) 376 if strings.Contains(order.Col, ".") { 377 idx := strings.Index(order.Col, ".") 378 alias = order.Col[:idx] 379 col = order.Col[idx+1:] 380 } else { 381 col = order.Col 382 } 383 if stringutils.IsNotEmpty(alias) { 384 sb.WriteString(fmt.Sprintf("%s.`%s` %s", alias, col, order.Sort)) 385 } else { 386 sb.WriteString(fmt.Sprintf("`%s` %s", col, order.Sort)) 387 } 388 } 389 } 390 391 sb.WriteString(" ") 392 393 if p.Size > 0 { 394 sb.WriteString("limit ?,?") 395 args = append(args, p.Offset, p.Size) 396 } 397 398 return strings.TrimSpace(sb.String()), args 399 } 400 401 // PageRet wrap page query result 402 type PageRet struct { 403 Items interface{} 404 PageNo int 405 PageSize int 406 Total int 407 HasNext bool 408 } 409 410 // NewPageRet new a PageRet 411 func NewPageRet(page Page) PageRet { 412 pageNo := 1 413 if page.Size > 0 { 414 pageNo = page.Offset/page.Size + 1 415 } 416 return PageRet{ 417 PageNo: pageNo, 418 PageSize: page.Size, 419 } 420 } 421 422 // String is an alias of string 423 type String string 424 425 // Sql implements Base 426 func (s String) Sql() (string, []interface{}) { 427 return string(s), nil 428 }