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  }