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 }