gitee.com/h79/goutils@v1.22.10/dao/wrapper/condition.go (about)

     1  package wrapper
     2  
     3  import (
     4  	commonoption "gitee.com/h79/goutils/common/option"
     5  	"gitee.com/h79/goutils/dao/option"
     6  	"reflect"
     7  	"strings"
     8  )
     9  
    10  var _ IQuery = (*Condition)(nil)
    11  
    12  // Operate
    13  const (
    14  	And       = "AND "
    15  	Or        = "OR "
    16  	Eq        = "= ?"
    17  	Neq       = "<> ?"
    18  	Lt        = "< ?"
    19  	Lte       = "<= ?"
    20  	Gt        = "> ?"
    21  	Gte       = ">= ?"
    22  	NotIn     = "NOT IN ?"
    23  	In        = "IN ?"
    24  	Between   = "BETWEEN ? AND ?"
    25  	Like      = "LIKE ?"
    26  	Exists    = "EXISTS ?"
    27  	NotExists = "NOT EXISTS ?"
    28  )
    29  
    30  func Compose[T ComposeType](op []string, cond *Condition, column string, size int, values []T) {
    31  	if len(values) <= 0 {
    32  		return
    33  	}
    34  	if len(values) == 1 {
    35  		cond.And(column, op[0], values[0])
    36  	} else if len(values) >= size {
    37  		cond.Compose(column, op[1], values)
    38  	} else {
    39  		for i := range values {
    40  			cond.Or(column, op[0], values[i])
    41  		}
    42  	}
    43  }
    44  
    45  func OrCompose[T ComposeType](op []string, cond *Condition, column string, size int, values []T) {
    46  	if len(values) <= 0 {
    47  		return
    48  	}
    49  	if len(values) == 1 {
    50  		cond.Or(column, op[0], values[0])
    51  	} else if len(values) >= size {
    52  		cond.Or(column, op[1], values)
    53  	} else {
    54  		for i := range values {
    55  			cond.Or(column, op[0], values[i])
    56  		}
    57  	}
    58  }
    59  
    60  func AndCompose[T ComposeType](op []string, cond *Condition, column string, size int, values []T) {
    61  	if len(values) <= 0 {
    62  		return
    63  	}
    64  	if len(values) == 1 {
    65  		cond.And(column, op[0], values[0])
    66  	} else {
    67  		cs := Condition{}
    68  		if len(values) >= size {
    69  			cs.Compose(column, op[1], values)
    70  		} else {
    71  			for i := range values {
    72  				cs.Or(column, op[0], values[i])
    73  			}
    74  		}
    75  		cond.From(&cs, true, And)
    76  	}
    77  }
    78  
    79  var InOp = []string{Eq, In}
    80  
    81  func IN[T ComposeType](cond *Condition, column string, size int, values []T) {
    82  	Compose(InOp, cond, column, size, values)
    83  }
    84  
    85  var NotInOp = []string{Neq, NotIn}
    86  
    87  func NIN[T ComposeType](cond *Condition, column string, size int, values []T) {
    88  	Compose(NotInOp, cond, column, size, values)
    89  }
    90  
    91  func OR[T ComposeType](cond *Condition, column string, size int, values []T) {
    92  	OrCompose(InOp, cond, column, size, values)
    93  }
    94  
    95  func AND[T ComposeType](cond *Condition, column string, size int, values []T) {
    96  	AndCompose(InOp, cond, column, size, values)
    97  }
    98  
    99  type ComposeType interface {
   100  	~string | bool | ~int8 | ~int16 | ~int | ~int32 | ~int64 | ~uint8 | ~uint16 | ~uint | ~uint32 | ~uint64 | ~float32 | ~float64
   101  }
   102  
   103  type Condition struct {
   104  	sql   strings.Builder
   105  	vars  []any
   106  	hasOp bool
   107  }
   108  
   109  // And
   110  /*  @param column
   111   *  @param operator "=、<小于、>大于、>=大于等于、<=小于等于、<>以及不等于"
   112   */
   113  func (sq *Condition) And(column, operator string, value any) *Condition {
   114  	if sq.hasOp {
   115  		sq.Operate(And)
   116  	}
   117  	return sq.Compose(column, operator, value)
   118  }
   119  
   120  func (sq *Condition) AndEq(column string, value any) *Condition {
   121  	return sq.And(column, Eq, value)
   122  }
   123  
   124  func (sq *Condition) AndNEq(column string, value any) *Condition {
   125  	return sq.And(column, Neq, value)
   126  }
   127  
   128  func (sq *Condition) AndLt(column string, value any) *Condition {
   129  	return sq.And(column, Lt, value)
   130  }
   131  
   132  func (sq *Condition) AndLte(column string, value any) *Condition {
   133  	return sq.And(column, Lte, value)
   134  }
   135  
   136  func (sq *Condition) AndGt(column string, value any) *Condition {
   137  	return sq.And(column, Gt, value)
   138  }
   139  
   140  func (sq *Condition) AndGte(column string, value any) *Condition {
   141  	return sq.And(column, Gte, value)
   142  }
   143  
   144  func (sq *Condition) Or(column, operator string, value any) *Condition {
   145  	if sq.hasOp {
   146  		sq.Operate(Or)
   147  	}
   148  	return sq.Compose(column, operator, value)
   149  }
   150  
   151  func (sq *Condition) OrEq(column string, value any) *Condition {
   152  	return sq.Or(column, Eq, value)
   153  }
   154  
   155  func (sq *Condition) OrNEq(column string, value any) *Condition {
   156  	return sq.Or(column, Neq, value)
   157  }
   158  
   159  func (sq *Condition) OrLt(column string, value any) *Condition {
   160  	return sq.Or(column, Lt, value)
   161  }
   162  
   163  func (sq *Condition) OrLte(column string, value any) *Condition {
   164  	return sq.Or(column, Lte, value)
   165  }
   166  
   167  func (sq *Condition) OrGt(column string, value any) *Condition {
   168  	return sq.Or(column, Gt, value)
   169  }
   170  
   171  func (sq *Condition) OrGte(column string, value any) *Condition {
   172  	return sq.Or(column, Gte, value)
   173  }
   174  
   175  func (sq *Condition) In(column string, value any) *Condition {
   176  	return sq.Compose(column, In, value)
   177  }
   178  
   179  func (sq *Condition) NotIn(column string, value any) *Condition {
   180  	return sq.Compose(column, NotIn, value)
   181  }
   182  
   183  // Like
   184  /* @example db.Where("name LIKE ?", "%jin%").Find(&users)
   185   * Condition.Like("name","jin")
   186   */
   187  func (sq *Condition) Like(column string, value any) *Condition {
   188  	return sq.Compose(column, Like, value)
   189  }
   190  
   191  // PLike %?
   192  func PLike(value string) string {
   193  	return "%" + value
   194  }
   195  func (sq *Condition) PLike(column string, value string) *Condition {
   196  	return sq.Compose(column, Like, "%"+value)
   197  }
   198  
   199  // SLike ?%
   200  func SLike(value string) string {
   201  	return value + "%"
   202  }
   203  func (sq *Condition) SLike(column string, value string) *Condition {
   204  	return sq.Compose(column, Like, value+"%")
   205  }
   206  
   207  // MLike %?%
   208  func MLike(value string) string {
   209  	return "%" + value + "%"
   210  }
   211  func (sq *Condition) MLike(column string, value string) *Condition {
   212  	return sq.Compose(column, Like, "%"+value+"%")
   213  }
   214  
   215  func (sq *Condition) Between(column string, value1, value2 any) *Condition {
   216  	return sq.AndBetween(column, value1, value2)
   217  }
   218  
   219  func (sq *Condition) AndBetween(column string, value1, value2 any) *Condition {
   220  	if sq.hasOp {
   221  		sq.Operate(And)
   222  	}
   223  	return sq.Compose(column, Between, value1, value2)
   224  }
   225  
   226  func (sq *Condition) OrBetween(column string, value1, value2 any) *Condition {
   227  	if sq.hasOp {
   228  		sq.Operate(Or)
   229  	}
   230  	return sq.Compose(column, Between, value1, value2)
   231  }
   232  
   233  func (sq *Condition) Eq(column string, value any) *Condition {
   234  	return sq.Compose(column, Eq, value)
   235  }
   236  
   237  func (sq *Condition) NEq(column string, value any) *Condition {
   238  	return sq.Compose(column, Neq, value)
   239  }
   240  func (sq *Condition) Neq(column string, value any) *Condition {
   241  	return sq.Compose(column, Neq, value)
   242  }
   243  
   244  func (sq *Condition) Lt(column string, value any) *Condition {
   245  	return sq.Compose(column, Lt, value)
   246  }
   247  
   248  func (sq *Condition) LtEq(column string, value any) *Condition {
   249  	return sq.Compose(column, Lte, value)
   250  }
   251  func (sq *Condition) Lte(column string, value any) *Condition {
   252  	return sq.Compose(column, Lte, value)
   253  }
   254  
   255  func (sq *Condition) Gt(column string, value any) *Condition {
   256  	return sq.Compose(column, Gt, value)
   257  }
   258  
   259  func (sq *Condition) GtEq(column string, value any) *Condition {
   260  	return sq.Compose(column, Gte, value)
   261  }
   262  func (sq *Condition) Gte(column string, value any) *Condition {
   263  	return sq.Compose(column, Gte, value)
   264  }
   265  
   266  // Column
   267  /*
   268   * example db.Where("created_at BETWEEN ? AND ?", lastWeek, today).Find(&users)
   269   */
   270  func (sq *Condition) Column(column string) *Condition {
   271  	SqlColumn(&sq.sql, column)
   272  	return sq
   273  }
   274  
   275  // Operate
   276  /* @param operator
   277   * @example created_at BETWEEN ? AND ?
   278   * Condition.Column("created_at").Operate("BETWEEN").Operate("AND").Values(11333,34444)
   279   */
   280  func (sq *Condition) Operate(operator string) *Condition {
   281  	if !sq.hasOp {
   282  		sq.hasOp = true
   283  	}
   284  	sq.sql.WriteByte(' ')
   285  	sq.sql.WriteString(operator)
   286  	return sq
   287  }
   288  
   289  func (sq *Condition) Values(value ...interface{}) *Condition {
   290  	sq.vars = append(sq.vars, value...)
   291  	return sq
   292  }
   293  
   294  func (sq *Condition) Compose(column string, operator string, value ...any) *Condition {
   295  	sq.Column(column)
   296  	sq.Operate(operator)
   297  	sq.vars = append(sq.vars, value...)
   298  	return sq
   299  }
   300  
   301  // Modifier 修饰符,比如 ()
   302  func (sq *Condition) Modifier(m string) *Condition {
   303  	sq.sql.WriteString(m)
   304  	return sq
   305  }
   306  
   307  // ComposeFrom 组合
   308  // Deprecated: please use Condition.From
   309  func (sq *Condition) ComposeFrom(src *Condition, operator string) *Condition {
   310  	return sq.From(src, true, operator)
   311  }
   312  
   313  // From 组合 组合
   314  // brackets 是否需要用 () 把语句
   315  func (sq *Condition) From(src *Condition, brackets bool, operator string) *Condition {
   316  	if !sq.hasOp {
   317  		sq.hasOp = src.hasOp
   318  	} else {
   319  		sq.Operate(operator)
   320  	}
   321  	if brackets {
   322  		sq.sql.WriteByte('(')
   323  		sq.sql.WriteString(strings.Trim(src.Query(), " "))
   324  		sq.sql.WriteByte(')')
   325  	} else {
   326  		sq.sql.WriteString(src.Query())
   327  	}
   328  	sq.Values(src.Value()...)
   329  	return sq
   330  }
   331  
   332  func (sq *Condition) IsFirst() bool {
   333  	return sq.hasOp
   334  }
   335  
   336  func (sq *Condition) Is() bool {
   337  	if sq == nil {
   338  		return false
   339  	}
   340  	return sq.sql.Len() > 0 && len(sq.vars) > 0
   341  }
   342  
   343  func (sq *Condition) Cond() string {
   344  	return sq.sql.String()
   345  }
   346  
   347  func (sq *Condition) Query() string {
   348  	return sq.sql.String()
   349  }
   350  
   351  func (sq *Condition) Value() []interface{} {
   352  	return sq.vars
   353  }
   354  
   355  func (sq *Condition) Reset() *Condition {
   356  	sq.hasOp = false
   357  	sq.sql.Reset()
   358  	sq.vars = nil
   359  	return sq
   360  }
   361  
   362  func (sq *Condition) Build(opts ...commonoption.Option) string {
   363  	return sq.build(option.FullSqlExist(opts...))
   364  }
   365  
   366  func (sq *Condition) build(full bool) string {
   367  	var (
   368  		idx int
   369  	)
   370  	var sql = sq.Query()
   371  	builder := strings.Builder{}
   372  	for i, v := range []byte(sql) {
   373  		if i == 0 && full {
   374  			builder.WriteString(" WHERE ")
   375  		}
   376  		if v == '?' && len(sq.vars) > idx {
   377  			switch rv := reflect.ValueOf(sq.vars[idx]); rv.Kind() {
   378  			case reflect.Slice, reflect.Array:
   379  				if rv.Len() == 0 {
   380  					builder.WriteString("(NULL)")
   381  					AddVar(&builder, nil)
   382  				} else {
   383  					builder.WriteByte('(')
   384  					for j := 0; j < rv.Len(); j++ {
   385  						if j > 0 {
   386  							builder.WriteByte(',')
   387  						}
   388  						AddVar(&builder, rv.Index(j).Interface())
   389  					}
   390  					builder.WriteByte(')')
   391  				}
   392  			default:
   393  				AddVar(&builder, sq.vars[idx])
   394  			}
   395  			idx++
   396  		} else {
   397  			builder.WriteByte(v)
   398  		}
   399  	}
   400  	return builder.String()
   401  }