gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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 }