github.com/eden-framework/sqlx@v0.0.2/builder/expr.go (about)

     1  package builder
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"database/sql/driver"
     7  	"fmt"
     8  	"reflect"
     9  
    10  	"github.com/eden-framework/reflectx"
    11  )
    12  
    13  type SqlExpr interface {
    14  	IsNil() bool
    15  	Ex(ctx context.Context) *Ex
    16  }
    17  
    18  func IsNilExpr(e SqlExpr) bool {
    19  	return e == nil || e.IsNil()
    20  }
    21  
    22  func RangeNotNilExpr(exprs []SqlExpr, each func(e SqlExpr, i int)) {
    23  	count := 0
    24  
    25  	for i := range exprs {
    26  		e := exprs[i]
    27  		if IsNilExpr(e) {
    28  			continue
    29  		}
    30  		each(e, count)
    31  		count++
    32  	}
    33  }
    34  
    35  func Expr(query string, args ...interface{}) *Ex {
    36  	return &Ex{Buffer: bytes.NewBufferString(query), args: args}
    37  }
    38  
    39  func ResolveExpr(v interface{}) *Ex {
    40  	return ResolveExprContext(context.Background(), v)
    41  }
    42  
    43  func ResolveExprContext(ctx context.Context, v interface{}) *Ex {
    44  	switch e := v.(type) {
    45  	case nil:
    46  		return nil
    47  	case SqlExpr:
    48  		if IsNilExpr(e) {
    49  			return nil
    50  		}
    51  		return e.Ex(ctx)
    52  	}
    53  	return nil
    54  }
    55  
    56  func Multi(exprs ...SqlExpr) SqlExpr {
    57  	return MultiWith(" ", exprs...)
    58  }
    59  
    60  func MultiWith(connector string, exprs ...SqlExpr) SqlExpr {
    61  	return ExprBy(func(ctx context.Context) *Ex {
    62  		e := Expr("")
    63  		for i := range exprs {
    64  			if i != 0 {
    65  				e.WriteString(connector)
    66  			}
    67  			e.WriteExpr(exprs[i])
    68  		}
    69  		return e.Ex(ctx)
    70  	})
    71  }
    72  
    73  func ExprBy(build func(ctx context.Context) *Ex) SqlExpr {
    74  	return &exBy{build: build}
    75  }
    76  
    77  type exBy struct {
    78  	build func(ctx context.Context) *Ex
    79  }
    80  
    81  func (c *exBy) IsNil() bool {
    82  	return c == nil || c.build == nil
    83  }
    84  
    85  func (c *exBy) Ex(ctx context.Context) *Ex {
    86  	return c.build(ctx)
    87  }
    88  
    89  type Ex struct {
    90  	*bytes.Buffer
    91  	args     []interface{}
    92  	err      error
    93  	rendered bool
    94  	ident    int
    95  }
    96  
    97  func (e *Ex) IsNil() bool {
    98  	return e == nil || e.Len() == 0
    99  }
   100  
   101  func (e *Ex) Query() string {
   102  	if e == nil {
   103  		return ""
   104  	}
   105  	return e.String()
   106  }
   107  
   108  func (e *Ex) Args() []interface{} {
   109  	return e.args
   110  }
   111  
   112  func (e *Ex) Err() error {
   113  	return e.err
   114  }
   115  
   116  func (e *Ex) AppendArgs(args ...interface{}) {
   117  	e.args = append(e.args, args...)
   118  }
   119  
   120  func (e *Ex) ArgsLen() int {
   121  	return len(e.args)
   122  }
   123  
   124  func (e Ex) Ex(ctx context.Context) *Ex {
   125  	if e.rendered {
   126  		return &e
   127  	}
   128  
   129  	if e.IsNil() {
   130  		return nil
   131  	}
   132  
   133  	if e.ArgsLen() == 0 {
   134  		e.rendered = true
   135  		return &e
   136  	}
   137  
   138  	index := 0
   139  	expr := Expr("")
   140  	expr.rendered = true
   141  
   142  	query := e.Bytes()
   143  	n := len(e.args)
   144  
   145  	for i := range query {
   146  		c := query[i]
   147  		switch c {
   148  		case '?':
   149  			if index >= n {
   150  				panic(fmt.Errorf("missing arg %d of %s", index, query))
   151  			}
   152  
   153  			arg := e.args[index]
   154  
   155  			switch a := arg.(type) {
   156  			case ValuerExpr:
   157  				expr.WriteString(a.ValueEx())
   158  				expr.AppendArgs(arg)
   159  			case SqlExpr:
   160  				if !IsNilExpr(a) {
   161  					subEx := a.Ex(ctx)
   162  					if !IsNilExpr(subEx) {
   163  						expr.Write(subEx.Bytes())
   164  						expr.AppendArgs(subEx.Args()...)
   165  					}
   166  				}
   167  
   168  			case driver.Valuer:
   169  				expr.WriteHolder(0)
   170  				expr.AppendArgs(arg)
   171  			default:
   172  				typ := reflect.TypeOf(arg)
   173  
   174  				if !reflectx.IsBytes(typ) && typ.Kind() == reflect.Slice {
   175  					sliceRv := reflect.ValueOf(arg)
   176  					length := sliceRv.Len()
   177  
   178  					for i := 0; i < length; i++ {
   179  						expr.WriteHolder(i)
   180  						expr.AppendArgs(sliceRv.Index(i).Interface())
   181  					}
   182  				} else {
   183  					expr.WriteHolder(0)
   184  					expr.AppendArgs(arg)
   185  				}
   186  			}
   187  			index++
   188  		default:
   189  			expr.WriteByte(c)
   190  		}
   191  	}
   192  
   193  	return expr
   194  }
   195  
   196  func (e *Ex) WriteGroup(fn func(e *Ex)) {
   197  	e.WriteByte('(')
   198  	fn(e)
   199  	e.WriteByte(')')
   200  }
   201  
   202  func (e *Ex) WhiteComments(comments []byte) {
   203  	e.WriteString("/* ")
   204  	e.Write(comments)
   205  	e.WriteString(" */")
   206  }
   207  
   208  func (e *Ex) WriteExpr(expr SqlExpr) {
   209  	if IsNilExpr(expr) {
   210  		return
   211  	}
   212  
   213  	e.WriteHolder(0)
   214  	e.AppendArgs(expr)
   215  }
   216  
   217  func (e *Ex) WriteEnd() {
   218  	e.WriteByte(';')
   219  }
   220  
   221  func (e *Ex) WriteHolder(idx int) {
   222  	if idx > 0 {
   223  		e.WriteByte(',')
   224  	}
   225  	e.WriteByte('?')
   226  }