diff options
Diffstat (limited to 'vendor/github.com/uptrace/bun/schema/formatter.go')
-rw-r--r-- | vendor/github.com/uptrace/bun/schema/formatter.go | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/vendor/github.com/uptrace/bun/schema/formatter.go b/vendor/github.com/uptrace/bun/schema/formatter.go new file mode 100644 index 000000000..7b26fbaca --- /dev/null +++ b/vendor/github.com/uptrace/bun/schema/formatter.go @@ -0,0 +1,248 @@ +package schema + +import ( + "reflect" + "strconv" + "strings" + + "github.com/uptrace/bun/dialect" + "github.com/uptrace/bun/dialect/feature" + "github.com/uptrace/bun/internal" + "github.com/uptrace/bun/internal/parser" +) + +var nopFormatter = Formatter{ + dialect: newNopDialect(), +} + +type Formatter struct { + dialect Dialect + args *namedArgList +} + +func NewFormatter(dialect Dialect) Formatter { + return Formatter{ + dialect: dialect, + } +} + +func NewNopFormatter() Formatter { + return nopFormatter +} + +func (f Formatter) IsNop() bool { + return f.dialect.Name() == dialect.Invalid +} + +func (f Formatter) Dialect() Dialect { + return f.dialect +} + +func (f Formatter) IdentQuote() byte { + return f.dialect.IdentQuote() +} + +func (f Formatter) AppendIdent(b []byte, ident string) []byte { + return dialect.AppendIdent(b, ident, f.IdentQuote()) +} + +func (f Formatter) AppendValue(b []byte, v reflect.Value) []byte { + if v.Kind() == reflect.Ptr && v.IsNil() { + return dialect.AppendNull(b) + } + appender := f.dialect.Appender(v.Type()) + return appender(f, b, v) +} + +func (f Formatter) HasFeature(feature feature.Feature) bool { + return f.dialect.Features().Has(feature) +} + +func (f Formatter) WithArg(arg NamedArgAppender) Formatter { + return Formatter{ + dialect: f.dialect, + args: f.args.WithArg(arg), + } +} + +func (f Formatter) WithNamedArg(name string, value interface{}) Formatter { + return Formatter{ + dialect: f.dialect, + args: f.args.WithArg(&namedArg{name: name, value: value}), + } +} + +func (f Formatter) FormatQuery(query string, args ...interface{}) string { + if f.IsNop() || (args == nil && f.args == nil) || strings.IndexByte(query, '?') == -1 { + return query + } + return internal.String(f.AppendQuery(nil, query, args...)) +} + +func (f Formatter) AppendQuery(dst []byte, query string, args ...interface{}) []byte { + if f.IsNop() || (args == nil && f.args == nil) || strings.IndexByte(query, '?') == -1 { + return append(dst, query...) + } + return f.append(dst, parser.NewString(query), args) +} + +func (f Formatter) append(dst []byte, p *parser.Parser, args []interface{}) []byte { + var namedArgs NamedArgAppender + if len(args) == 1 { + var ok bool + namedArgs, ok = args[0].(NamedArgAppender) + if !ok { + namedArgs, _ = newStructArgs(f, args[0]) + } + } + + var argIndex int + for p.Valid() { + b, ok := p.ReadSep('?') + if !ok { + dst = append(dst, b...) + continue + } + if len(b) > 0 && b[len(b)-1] == '\\' { + dst = append(dst, b[:len(b)-1]...) + dst = append(dst, '?') + continue + } + dst = append(dst, b...) + + name, numeric := p.ReadIdentifier() + if name != "" { + if numeric { + idx, err := strconv.Atoi(name) + if err != nil { + goto restore_arg + } + + if idx >= len(args) { + goto restore_arg + } + + dst = f.appendArg(dst, args[idx]) + continue + } + + if namedArgs != nil { + dst, ok = namedArgs.AppendNamedArg(f, dst, name) + if ok { + continue + } + } + + dst, ok = f.args.AppendNamedArg(f, dst, name) + if ok { + continue + } + + restore_arg: + dst = append(dst, '?') + dst = append(dst, name...) + continue + } + + if argIndex >= len(args) { + dst = append(dst, '?') + continue + } + + arg := args[argIndex] + argIndex++ + + dst = f.appendArg(dst, arg) + } + + return dst +} + +func (f Formatter) appendArg(b []byte, arg interface{}) []byte { + switch arg := arg.(type) { + case QueryAppender: + bb, err := arg.AppendQuery(f, b) + if err != nil { + return dialect.AppendError(b, err) + } + return bb + default: + return f.dialect.Append(f, b, arg) + } +} + +//------------------------------------------------------------------------------ + +type NamedArgAppender interface { + AppendNamedArg(fmter Formatter, b []byte, name string) ([]byte, bool) +} + +//------------------------------------------------------------------------------ + +type namedArgList struct { + arg NamedArgAppender + next *namedArgList +} + +func (l *namedArgList) WithArg(arg NamedArgAppender) *namedArgList { + return &namedArgList{ + arg: arg, + next: l, + } +} + +func (l *namedArgList) AppendNamedArg(fmter Formatter, b []byte, name string) ([]byte, bool) { + for l != nil && l.arg != nil { + if b, ok := l.arg.AppendNamedArg(fmter, b, name); ok { + return b, true + } + l = l.next + } + return b, false +} + +//------------------------------------------------------------------------------ + +type namedArg struct { + name string + value interface{} +} + +var _ NamedArgAppender = (*namedArg)(nil) + +func (a *namedArg) AppendNamedArg(fmter Formatter, b []byte, name string) ([]byte, bool) { + if a.name == name { + return fmter.appendArg(b, a.value), true + } + return b, false +} + +//------------------------------------------------------------------------------ + +var _ NamedArgAppender = (*structArgs)(nil) + +type structArgs struct { + table *Table + strct reflect.Value +} + +func newStructArgs(fmter Formatter, strct interface{}) (*structArgs, bool) { + v := reflect.ValueOf(strct) + if !v.IsValid() { + return nil, false + } + + v = reflect.Indirect(v) + if v.Kind() != reflect.Struct { + return nil, false + } + + return &structArgs{ + table: fmter.Dialect().Tables().Get(v.Type()), + strct: v, + }, true +} + +func (m *structArgs) AppendNamedArg(fmter Formatter, b []byte, name string) ([]byte, bool) { + return m.table.AppendNamedArg(fmter, b, name, m.strct) +} |