package apijson import ( "bytes" "encoding/json" "strconv" "strings" ) const DefaultLimit = 1000 type MysqlExecutor struct { table string columns []string where []string params []interface{} order string group string limit int page int } func (e *MysqlExecutor) Table() string { return e.table } func (e *MysqlExecutor) ParseTable(t string) error { if strings.HasSuffix(t, "[]") { t = t[0 : len(t)-2] } e.table = t return nil } func (e *MysqlExecutor) ToSQL() string { var buf bytes.Buffer buf.WriteString("SELECT ") if e.columns == nil { buf.WriteString("*") } else { buf.WriteString(strings.Join(e.columns, ",")) } buf.WriteString(" FROM ") buf.WriteString(e.table) if len(e.where) > 0 { buf.WriteString(" WHERE ") buf.WriteString(strings.Join(e.where, " and ")) } if e.order != "" { buf.WriteString(" ORDER BY ") buf.WriteString(e.order) } buf.WriteString(" LIMIT ") buf.WriteString(strconv.Itoa(e.limit)) if e.limit > 1 { buf.WriteString(" OFFSET ") buf.WriteString(strconv.Itoa(e.limit * e.page)) } return buf.String() } func jsonEncode(v interface{}) string { raw, _ := json.Marshal(v) return string(raw) } func (e *MysqlExecutor) ParseCondition(field string, value interface{}) { if values, ok := value.([]interface{}); ok { // 数组使用 IN 条件 condition := field + " in (" for i, v := range values { if i == 0 { // condition += "?" condition += jsonEncode(v) } else { // condition += ",?" condition += "," + jsonEncode(v) } // e.params = append(e.params, v) } e.where = append(e.where, condition+")") } else if valueStr, ok := value.(string); ok { if strings.HasPrefix(field, "@") { switch field[1:] { case "order": e.order = valueStr case "column": e.columns = strings.Split(valueStr, ",") } } else { // e.where = append(e.where, field+"=?") e.where = append(e.where, field+"="+jsonEncode(valueStr)) // e.params = append(e.params, valueStr) } } else { // e.where = append(e.where, field+"=?") e.where = append(e.where, field+"="+jsonEncode(value)) // e.params = append(e.params, value) } } func (e *MysqlExecutor) Exec(c *QueryContext) ([]map[string]interface{}, error) { sql := e.ToSQL() return QueryAll(c, sql, e.params...) } var QueryAll = func(c *QueryContext, sql string, args ...interface{}) ([]map[string]interface{}, error) { return nil, nil } func SetQueryAll(f func(c *QueryContext, sql string, args ...interface{}) ([]map[string]interface{}, error)) { QueryAll = f } func (e *MysqlExecutor) PageSize(page interface{}, count interface{}) { e.page = parseNum(page, 0) e.limit = parseNum(count, 10) } func parseNum(value interface{}, defaultVal int) int { if n, ok := value.(float64); ok { return int(n) } if n, ok := value.(int); ok { return n } return defaultVal }