formatter.go (5161B)
1 package schema 2 3 import ( 4 "reflect" 5 "strconv" 6 "strings" 7 8 "github.com/uptrace/bun/dialect" 9 "github.com/uptrace/bun/dialect/feature" 10 "github.com/uptrace/bun/internal" 11 "github.com/uptrace/bun/internal/parser" 12 ) 13 14 var nopFormatter = Formatter{ 15 dialect: newNopDialect(), 16 } 17 18 type Formatter struct { 19 dialect Dialect 20 args *namedArgList 21 } 22 23 func NewFormatter(dialect Dialect) Formatter { 24 return Formatter{ 25 dialect: dialect, 26 } 27 } 28 29 func NewNopFormatter() Formatter { 30 return nopFormatter 31 } 32 33 func (f Formatter) IsNop() bool { 34 return f.dialect.Name() == dialect.Invalid 35 } 36 37 func (f Formatter) Dialect() Dialect { 38 return f.dialect 39 } 40 41 func (f Formatter) IdentQuote() byte { 42 return f.dialect.IdentQuote() 43 } 44 45 func (f Formatter) AppendIdent(b []byte, ident string) []byte { 46 return dialect.AppendIdent(b, ident, f.IdentQuote()) 47 } 48 49 func (f Formatter) AppendValue(b []byte, v reflect.Value) []byte { 50 if v.Kind() == reflect.Ptr && v.IsNil() { 51 return dialect.AppendNull(b) 52 } 53 appender := Appender(f.dialect, v.Type()) 54 return appender(f, b, v) 55 } 56 57 func (f Formatter) HasFeature(feature feature.Feature) bool { 58 return f.dialect.Features().Has(feature) 59 } 60 61 func (f Formatter) WithArg(arg NamedArgAppender) Formatter { 62 return Formatter{ 63 dialect: f.dialect, 64 args: f.args.WithArg(arg), 65 } 66 } 67 68 func (f Formatter) WithNamedArg(name string, value interface{}) Formatter { 69 return Formatter{ 70 dialect: f.dialect, 71 args: f.args.WithArg(&namedArg{name: name, value: value}), 72 } 73 } 74 75 func (f Formatter) FormatQuery(query string, args ...interface{}) string { 76 if f.IsNop() || (args == nil && f.args == nil) || strings.IndexByte(query, '?') == -1 { 77 return query 78 } 79 return internal.String(f.AppendQuery(nil, query, args...)) 80 } 81 82 func (f Formatter) AppendQuery(dst []byte, query string, args ...interface{}) []byte { 83 if f.IsNop() || (args == nil && f.args == nil) || strings.IndexByte(query, '?') == -1 { 84 return append(dst, query...) 85 } 86 return f.append(dst, parser.NewString(query), args) 87 } 88 89 func (f Formatter) append(dst []byte, p *parser.Parser, args []interface{}) []byte { 90 var namedArgs NamedArgAppender 91 if len(args) == 1 { 92 if v, ok := args[0].(NamedArgAppender); ok { 93 namedArgs = v 94 } else if v, ok := newStructArgs(f, args[0]); ok { 95 namedArgs = v 96 } 97 } 98 99 var argIndex int 100 for p.Valid() { 101 b, ok := p.ReadSep('?') 102 if !ok { 103 dst = append(dst, b...) 104 continue 105 } 106 if len(b) > 0 && b[len(b)-1] == '\\' { 107 dst = append(dst, b[:len(b)-1]...) 108 dst = append(dst, '?') 109 continue 110 } 111 dst = append(dst, b...) 112 113 name, numeric := p.ReadIdentifier() 114 if name != "" { 115 if numeric { 116 idx, err := strconv.Atoi(name) 117 if err != nil { 118 goto restore_arg 119 } 120 121 if idx >= len(args) { 122 goto restore_arg 123 } 124 125 dst = f.appendArg(dst, args[idx]) 126 continue 127 } 128 129 if namedArgs != nil { 130 dst, ok = namedArgs.AppendNamedArg(f, dst, name) 131 if ok { 132 continue 133 } 134 } 135 136 dst, ok = f.args.AppendNamedArg(f, dst, name) 137 if ok { 138 continue 139 } 140 141 restore_arg: 142 dst = append(dst, '?') 143 dst = append(dst, name...) 144 continue 145 } 146 147 if argIndex >= len(args) { 148 dst = append(dst, '?') 149 continue 150 } 151 152 arg := args[argIndex] 153 argIndex++ 154 155 dst = f.appendArg(dst, arg) 156 } 157 158 return dst 159 } 160 161 func (f Formatter) appendArg(b []byte, arg interface{}) []byte { 162 switch arg := arg.(type) { 163 case QueryAppender: 164 bb, err := arg.AppendQuery(f, b) 165 if err != nil { 166 return dialect.AppendError(b, err) 167 } 168 return bb 169 default: 170 return Append(f, b, arg) 171 } 172 } 173 174 //------------------------------------------------------------------------------ 175 176 type NamedArgAppender interface { 177 AppendNamedArg(fmter Formatter, b []byte, name string) ([]byte, bool) 178 } 179 180 type namedArgList struct { 181 arg NamedArgAppender 182 next *namedArgList 183 } 184 185 func (l *namedArgList) WithArg(arg NamedArgAppender) *namedArgList { 186 return &namedArgList{ 187 arg: arg, 188 next: l, 189 } 190 } 191 192 func (l *namedArgList) AppendNamedArg(fmter Formatter, b []byte, name string) ([]byte, bool) { 193 for l != nil && l.arg != nil { 194 if b, ok := l.arg.AppendNamedArg(fmter, b, name); ok { 195 return b, true 196 } 197 l = l.next 198 } 199 return b, false 200 } 201 202 //------------------------------------------------------------------------------ 203 204 type namedArg struct { 205 name string 206 value interface{} 207 } 208 209 var _ NamedArgAppender = (*namedArg)(nil) 210 211 func (a *namedArg) AppendNamedArg(fmter Formatter, b []byte, name string) ([]byte, bool) { 212 if a.name == name { 213 return fmter.appendArg(b, a.value), true 214 } 215 return b, false 216 } 217 218 //------------------------------------------------------------------------------ 219 220 type structArgs struct { 221 table *Table 222 strct reflect.Value 223 } 224 225 var _ NamedArgAppender = (*structArgs)(nil) 226 227 func newStructArgs(fmter Formatter, strct interface{}) (*structArgs, bool) { 228 v := reflect.ValueOf(strct) 229 if !v.IsValid() { 230 return nil, false 231 } 232 233 v = reflect.Indirect(v) 234 if v.Kind() != reflect.Struct { 235 return nil, false 236 } 237 238 return &structArgs{ 239 table: fmter.Dialect().Tables().Get(v.Type()), 240 strct: v, 241 }, true 242 } 243 244 func (m *structArgs) AppendNamedArg(fmter Formatter, b []byte, name string) ([]byte, bool) { 245 return m.table.AppendNamedArg(fmter, b, name, m.strct) 246 }