You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
go-library/vendor/github.com/daodao97/fly/sql.go

587 lines
12 KiB

package fly
import (
"encoding/json"
"fmt"
"strings"
"github.com/pkg/errors"
"github.com/daodao97/fly/interval/util"
)
var ErrRowBindingType = errors.New("binding dest type must be *struct **struct")
var ErrRowsBindingType = errors.New("binding dest type must be *[]struct, *[]*struct")
const selectMod = "select %s from `%s`"
const insertMod = "insert into %s (%s) values (%s)"
const updateMod = "update %s set %s"
const deleteMod = "delete from %s"
type Row struct {
Data map[string]interface{}
Err error
}
func (r *Row) MarshalJSON() ([]byte, error) {
return json.Marshal(r.Data)
}
func (r *Row) Binding(dest interface{}) error {
if !util.AllowType(dest, []string{"*struct", "**struct"}) {
return ErrRowBindingType
}
return util.Decoder(r.Data, dest)
}
func (r Row) Get(key string) (interface{}, bool) {
v, ok := r.Data[key]
return v, ok
}
type Rows struct {
List []Row
Err error
}
func (r *Rows) Binding(dest interface{}) error {
if !util.AllowType(dest, []string{"*[]struct", "*[]*struct"}) {
return ErrRowsBindingType
}
var source []map[string]interface{}
for _, v := range r.List {
source = append(source, v.Data)
}
return util.Decoder(source, dest)
}
type Option = func(opts *Options)
type Options struct {
database string
table string
field []string
where []where
orderBy string
groupBy string
limit int
offset int
value []interface{}
}
func table(table string) Option {
return func(opts *Options) {
opts.table = table
}
}
func database(database string) Option {
return func(opts *Options) {
opts.database = database
}
}
func Offset(offset int) Option {
return func(opts *Options) {
opts.offset = offset
}
}
func Limit(offset int) Option {
return func(opts *Options) {
opts.limit = offset
}
}
func Pagination(pageNumber, pageSize int) []Option {
return []Option{
Limit(pageSize),
Offset((pageNumber - 1) * pageSize),
}
}
func Field(name ...string) Option {
var _name []string
for _, v := range name {
if strings.Contains(v, " as ") {
tmp := strings.Split(v, " as ")
_name = append(_name, "`"+strings.Trim(tmp[0], " ")+"` as `"+strings.Trim(tmp[1], " ")+"`")
} else if strings.Contains(v, " AS ") {
tmp := strings.Split(v, " AS ")
_name = append(_name, "`"+strings.Trim(tmp[0], " ")+"` as `"+strings.Trim(tmp[1], " ")+"`")
_name = append(_name, "`"+v+"`")
} else {
_name = append(_name, "`"+v+"`")
}
}
return func(opts *Options) {
opts.field = _name
}
}
func FieldRaw(name string) Option {
return func(opts *Options) {
opts.field = append(opts.field, name)
}
}
func AggregateSum(name string) Option {
return Field("sum(" + name + ") as aggregate")
}
func AggregateCount(name string) Option {
return FieldRaw("count(" + name + ") as count")
}
func AggregateMax(name string) Option {
return Field("max(" + name + ") as aggregate")
}
func Value(val ...interface{}) Option {
return func(opts *Options) {
opts.value = val
}
}
type where struct {
field string
operator string
value interface{}
logic string
sub []where
}
func Where(field, operator string, value interface{}) Option {
return func(opts *Options) {
opts.where = append(opts.where, where{
field: field,
operator: operator,
value: value,
logic: "and",
})
}
}
func WhereEq(field string, value interface{}) Option {
return func(opts *Options) {
opts.where = append(opts.where, where{
field: field,
operator: "=",
value: value,
})
}
}
func WhereNotEq(field string, value interface{}) Option {
return func(opts *Options) {
opts.where = append(opts.where, where{
field: field,
operator: "!=",
value: value,
})
}
}
func WhereGt(field string, value interface{}) Option {
return func(opts *Options) {
opts.where = append(opts.where, where{
field: field,
operator: ">",
value: value,
})
}
}
func WhereGe(field string, value interface{}) Option {
return func(opts *Options) {
opts.where = append(opts.where, where{
field: field,
operator: ">=",
value: value,
})
}
}
func WhereLt(field string, value interface{}) Option {
return func(opts *Options) {
opts.where = append(opts.where, where{
field: field,
operator: "<",
value: value,
})
}
}
func WhereLe(field string, value interface{}) Option {
return func(opts *Options) {
opts.where = append(opts.where, where{
field: field,
operator: "<=",
value: value,
})
}
}
func WhereIn(field string, value []interface{}) Option {
return func(opts *Options) {
opts.where = append(opts.where, where{
field: field,
operator: "in",
value: value,
})
}
}
func WhereNotIn(field string, value []interface{}) Option {
return func(opts *Options) {
opts.where = append(opts.where, where{
field: field,
operator: "not in",
value: value,
})
}
}
func WhereOr(field, operator string, value interface{}) Option {
return func(opts *Options) {
opts.where = append(opts.where, where{
field: field,
operator: operator,
value: value,
logic: "or",
})
}
}
func WhereOrEq(field string, value interface{}) Option {
return func(opts *Options) {
opts.where = append(opts.where, where{
field: field,
operator: "=",
value: value,
logic: "or",
})
}
}
func WhereOrNotEq(field string, value interface{}) Option {
return func(opts *Options) {
opts.where = append(opts.where, where{
field: field,
operator: "!=",
value: value,
logic: "or",
})
}
}
func WhereOrGt(field string, value interface{}) Option {
return func(opts *Options) {
opts.where = append(opts.where, where{
field: field,
operator: ">",
value: value,
logic: "or",
})
}
}
func WhereOrGe(field string, value interface{}) Option {
return func(opts *Options) {
opts.where = append(opts.where, where{
field: field,
operator: ">=",
value: value,
logic: "or",
})
}
}
func WhereOrLt(field string, value interface{}) Option {
return func(opts *Options) {
opts.where = append(opts.where, where{
field: field,
operator: "<",
value: value,
logic: "or",
})
}
}
func WhereOrLe(field string, value interface{}) Option {
return func(opts *Options) {
opts.where = append(opts.where, where{
field: field,
operator: "<=",
value: value,
logic: "or",
})
}
}
func WhereOrIn(field string, value []interface{}) Option {
return func(opts *Options) {
opts.where = append(opts.where, where{
field: field,
operator: "in",
value: value,
logic: "or",
})
}
}
func WhereOrNotIn(field string, value []interface{}) Option {
return func(opts *Options) {
opts.where = append(opts.where, where{
field: field,
operator: "not in",
value: value,
logic: "or",
})
}
}
func WhereGroup(opts ...Option) Option {
opt := &Options{}
for _, v := range opts {
v(opt)
}
return func(opts *Options) {
opts.where = append(opts.where, where{
logic: "and",
sub: opt.where,
})
}
}
func WhereOrGroup(opts ...Option) Option {
opt := &Options{}
for _, v := range opts {
v(opt)
}
return func(opts *Options) {
opts.where = append(opts.where, where{
logic: "or",
sub: opt.where,
})
}
}
func WhereLike(field string, value interface{}) Option {
return func(opts *Options) {
opts.where = append(opts.where, where{
field: field,
operator: "like",
value: value,
})
}
}
func WhereOrLike(field string, value interface{}) Option {
return func(opts *Options) {
opts.where = append(opts.where, where{
field: field,
operator: "like",
value: value,
logic: "or",
})
}
}
func WhereOrNotLike(field string, value interface{}) Option {
return func(opts *Options) {
opts.where = append(opts.where, where{
field: field,
operator: "not like",
value: value,
})
}
}
func WhereBetween(field string, value interface{}) Option {
return func(opts *Options) {
opts.where = append(opts.where, where{
field: field,
operator: "between",
value: value,
})
}
}
func WhereFindInSet(field string, value interface{}) Option {
return func(opts *Options) {
opts.where = append(opts.where, where{
field: field,
operator: "find_in_set",
value: value,
})
}
}
func WhereOrFindInSet(field string, value interface{}) Option {
return func(opts *Options) {
opts.where = append(opts.where, where{
field: field,
operator: "find_in_set",
value: value,
logic: "or",
})
}
}
func OrderByDesc(field string) Option {
return func(opts *Options) {
opts.orderBy = "`" + field + "` " + "desc"
}
}
func OrderByAsc(field string) Option {
return func(opts *Options) {
opts.orderBy = "`" + field + "` " + "asc"
}
}
func GroupBy(field string) Option {
return func(opts *Options) {
opts.groupBy = field
}
}
func whereBuilder(condition []where) (sql string, args []interface{}) {
if len(condition) == 0 {
return "", nil
}
var tokens []string
for i, v := range condition {
if i != 0 {
if v.logic != "" {
tokens = append(tokens, v.logic)
} else {
tokens = append(tokens, "and")
}
}
if v.field != "" {
switch v.operator {
case "in", "not in":
val := v.value.([]interface{})
var placeholder []string
for range val {
placeholder = append(placeholder, "?")
}
tokens = append(tokens, fmt.Sprintf("`%s` %s (%s)", v.field, v.operator, strings.Join(placeholder, ",")))
args = append(args, val...)
case "between":
val := v.value.([]interface{})
tokens = append(tokens, fmt.Sprintf("`%s` %s ? and ?", v.field, v.operator))
args = append(args, val...)
case "find_in_set":
tokens = append(tokens, fmt.Sprintf("find_in_set(?, %s)", v.field))
args = append(args, v.value)
default:
tokens = append(tokens, fmt.Sprintf("`%s` %s ?", v.field, v.operator))
args = append(args, v.value)
}
}
if v.sub != nil {
_sql, _args := whereBuilder(v.sub)
tokens = append(tokens, "("+_sql+")")
args = append(args, _args...)
}
}
return strings.Join(tokens, " "), args
}
func SelectBuilder(opts ...Option) (sql string, args []interface{}) {
_opts := &Options{}
for _, v := range opts {
v(_opts)
}
_where, args := whereBuilder(_opts.where)
_field := "*"
if len(_opts.field) > 0 {
_field = strings.Join(_opts.field, ", ")
}
sql = fmt.Sprintf(selectMod, _field, _opts.table)
if _where != "" {
sql = sql + " where " + _where
}
if _opts.orderBy != "" {
sql = sql + " order by " + _opts.orderBy
}
if _opts.groupBy != "" {
sql = sql + " group by " + _opts.groupBy
}
if _opts.limit != 0 {
sql = sql + " limit ? offset ? "
args = append(args, _opts.limit, _opts.offset)
}
return sql, args
}
func getTable(opt *Options) string {
if opt.database == "" {
return opt.table
}
return opt.database + "." + opt.table
}
func InsertBuilder(opts ...Option) (sql string, args []interface{}) {
_opts := &Options{}
for _, v := range opts {
v(_opts)
}
var _val []string
for range _opts.field {
_val = append(_val, "?")
}
sql = fmt.Sprintf(insertMod, getTable(_opts), strings.Join(_opts.field, ", "), strings.Join(_val, ","))
args = _opts.value
return sql, args
}
func UpdateBuilder(opts ...Option) (sql string, args []interface{}) {
_opts := &Options{}
for _, v := range opts {
v(_opts)
}
var _val []string
for _, v := range _opts.field {
_val = append(_val, v+" = ?")
}
sql = fmt.Sprintf(updateMod, getTable(_opts), strings.Join(_val, ","))
args = _opts.value
if len(_opts.where) > 0 {
_where, _args := whereBuilder(_opts.where)
sql = sql + " where " + _where
args = append(args, _args...)
}
return sql, args
}
func DeleteBuilder(opts ...Option) (sql string, args []interface{}) {
_opts := &Options{}
for _, v := range opts {
v(_opts)
}
sql = fmt.Sprintf(deleteMod, _opts.table)
if len(_opts.where) > 0 {
_where, _args := whereBuilder(_opts.where)
sql = sql + " where " + _where
args = append(args, _args...)
}
return sql, args
}