1
0
mirror of https://shylinux.com/x/ContextOS synced 2025-04-25 16:58:06 +08:00
2018-11-09 12:17:54 +08:00

326 lines
12 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package mdb
import (
"contexts/ctx"
"database/sql"
"encoding/json"
"fmt"
_ "github.com/go-sql-driver/mysql"
"strings"
)
type MDB struct {
*sql.DB
*ctx.Context
}
func (mdb *MDB) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server {
c.Caches = map[string]*ctx.Cache{
"database": &ctx.Cache{Name: "数据库", Value: m.Confx("database", arg, 0), Help: "数据库"},
"username": &ctx.Cache{Name: "账户", Value: m.Confx("username", arg, 1), Help: "账户"},
"password": &ctx.Cache{Name: "密码", Value: m.Confx("password", arg, 2), Help: "密码"},
"address": &ctx.Cache{Name: "服务地址", Value: m.Confx("address", arg, 3), Help: "服务地址"},
"protocol": &ctx.Cache{Name: "服务协议(tcp)", Value: m.Confx("protocol", arg, 4), Help: "服务协议"},
"driver": &ctx.Cache{Name: "数据库驱动(mysql)", Value: m.Confx("driver", arg, 5), Help: "数据库驱动"},
}
c.Configs = map[string]*ctx.Config{
"dbs": &ctx.Config{Name: "dbs", Value: []string{}, Help: "关系表"},
"tables": &ctx.Config{Name: "dbs", Value: []string{}, Help: "关系表"},
"table": &ctx.Config{Name: "关系表", Value: "0", Help: "关系表"},
"field": &ctx.Config{Name: "字段名", Value: "", Help: "字段名"},
"where": &ctx.Config{Name: "条件", Value: "", Help: "条件"},
"group": &ctx.Config{Name: "聚合", Value: "", Help: "聚合"},
"order": &ctx.Config{Name: "排序", Value: "", Help: "排序"},
"limit": &ctx.Config{Name: "分页", Value: "10", Help: "分页"},
"offset": &ctx.Config{Name: "偏移", Value: "0", Help: "偏移"},
"parse": &ctx.Config{Name: "解析", Value: "", Help: "解析"},
}
s := new(MDB)
s.Context = c
return s
}
func (mdb *MDB) Begin(m *ctx.Message, arg ...string) ctx.Server {
return mdb
}
func (mdb *MDB) Start(m *ctx.Message, arg ...string) bool {
db, e := sql.Open(m.Cap("driver"), fmt.Sprintf("%s:%s@%s(%s)/%s",
m.Cap("username"), m.Cap("password"), m.Cap("protocol"), m.Cap("address"), m.Cap("database")))
m.Assert(e)
mdb.DB = db
m.Log("info", "mdb open %s", m.Cap("database"))
return false
}
func (mdb *MDB) Close(m *ctx.Message, arg ...string) bool {
switch mdb.Context {
case m.Target():
case m.Source():
}
return false
}
var Index = &ctx.Context{Name: "mdb", Help: "数据中心",
Caches: map[string]*ctx.Cache{
"nsource": &ctx.Cache{Name: "数据源数量", Value: "0", Help: "已打开数据库的数量"},
},
Configs: map[string]*ctx.Config{
"database": &ctx.Config{Name: "默认数据库", Value: "demo", Help: "默认数据库"},
"username": &ctx.Config{Name: "默认用户名", Value: "demo", Help: "默认用户名"},
"password": &ctx.Config{Name: "默认密码", Value: "demo", Help: "默认密码"},
"protocol": &ctx.Config{Name: "默认协议", Value: "tcp", Help: "默认协议"},
"address": &ctx.Config{Name: "默认地址", Value: "", Help: "默认地址"},
"driver": &ctx.Config{Name: "数据库驱动(mysql)", Value: "mysql", Help: "数据库驱动"},
"csv_col_sep": &ctx.Config{Name: "字段分隔符", Value: "\t", Help: "字段分隔符"},
"csv_row_sep": &ctx.Config{Name: "记录分隔符", Value: "\n", Help: "记录分隔符"},
},
Commands: map[string]*ctx.Command{
"open": &ctx.Command{Name: "open [database [username [password [address [protocol [driver]]]]]]",
Help: "open打开数据库, database: 数据库名, username: 用户名, password: 密码, address: 服务地址, protocol: 服务协议, driver: 数据库类型",
Form: map[string]int{"dbname": 1, "dbhelp": 1},
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
dbname := fmt.Sprintf("db%d", m.Capi("nsource", 1))
dbhelp := "数据源"
if m.Has("dbname") {
dbname = m.Option("dbname")
}
if m.Has("dbhelp") {
dbname = m.Option("dbhelp")
}
m.Start(dbname, dbhelp, arg...)
}},
"exec": &ctx.Command{Name: "exec sql [arg]", Help: "操作数据库, sql: SQL语句, arg: 操作参数", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if mdb, ok := m.Target().Server.(*MDB); m.Assert(ok) && mdb.DB != nil {
which := make([]interface{}, 0, len(arg))
for _, v := range arg[1:] {
which = append(which, v)
}
ret, e := mdb.Exec(arg[0], which...)
m.Assert(e)
id, e := ret.LastInsertId()
m.Assert(e)
n, e := ret.RowsAffected()
m.Assert(e)
m.Log("info", "last(%s) nrow(%s)", m.Append("last", id), m.Append("nrow", n))
m.Echo("%d", n)
}
}},
"query": &ctx.Command{Name: "query sql [arg]", Help: "查询数据库, sql: SQL语句, arg: 查询参数", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if mdb, ok := m.Target().Server.(*MDB); m.Assert(ok) && mdb.DB != nil {
which := make([]interface{}, 0, len(arg))
for _, v := range arg[1:] {
which = append(which, v)
}
rows, e := mdb.Query(arg[0], which...)
m.Assert(e)
defer rows.Close()
cols, e := rows.Columns()
m.Assert(e)
num := len(cols)
for rows.Next() {
vals := make([]interface{}, num)
ptrs := make([]interface{}, num)
for i := range vals {
ptrs[i] = &vals[i]
}
rows.Scan(ptrs...)
for i, k := range cols {
switch b := vals[i].(type) {
case nil:
m.Add("append", k, "")
case []byte:
m.Add("append", k, string(b))
case int64:
m.Add("append", k, fmt.Sprintf("%d", b))
default:
m.Add("append", k, fmt.Sprintf("%v", b))
}
}
}
if len(m.Meta["append"]) > 0 {
m.Log("info", "rows(%d) cols(%d)", len(m.Meta[m.Meta["append"][0]]), len(m.Meta["append"]))
} else {
m.Log("info", "rows(0) cols(0)")
}
}
}},
"db": &ctx.Command{Name: "db [which]", Help: "查看或选择数据库信息", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if mdb, ok := m.Target().Server.(*MDB); m.Assert(ok) && mdb.DB != nil {
if len(arg) == 0 {
msg := m.Spawn().Cmd("query", "show databases")
dbs := []string{}
for i, v := range msg.Meta[msg.Meta["append"][0]] {
dbs = append(dbs, v)
m.Echo("%d: %s\n", i, v)
}
m.Target().Configs["dbs"].Value = dbs
return
}
db := m.Confv("dbs", arg[0]).(string)
m.Assert(m.Spawn().Cmd("exec", fmt.Sprintf("use %s", db)))
m.Echo(m.Cap("database", db))
}
}},
"tab": &ctx.Command{Name: "tab[which [field]]", Help: "查看关系表信息which: 表名, field: 字段名", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if _, ok := m.Target().Server.(*MDB); m.Assert(ok) {
if len(arg) == 0 {
msg := m.Spawn().Cmd("query", "show tables")
tables := []string{}
for i, v := range msg.Meta[msg.Meta["append"][0]] {
tables = append(tables, v)
m.Echo("%d: %s\n", i, v)
}
m.Target().Configs["tables"].Value = tables
return
}
table := arg[0]
switch v := m.Confv("tables", arg[0]).(type) {
case string:
table = v
}
msg := m.Spawn().Cmd("query", fmt.Sprintf("desc %s", table))
m.Copy(msg, "append")
m.Table()
}
}},
"show": &ctx.Command{Name: "show table fields...",
Help: "查询数据库, table: 表名, fields: 字段, where: 查询条件, group: 聚合字段, order: 排序字段",
Form: map[string]int{"where": 1, "group": 1, "order": 1, "limit": 1, "offset": 1, "other": -1,
"extra_field": 2, "extra_fields": 1, "extra_format": 1, "trans_field": 1, "trans_map": 2},
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if _, ok := m.Target().Server.(*MDB); m.Assert(ok) {
table := m.Confx("table", arg, 0)
if v := m.Confv("tables", table); v != nil {
table = v.(string)
}
fields := []string{"*"}
if len(arg) > 1 {
fields = arg[1:]
} else if m.Confs("field") {
fields = []string{m.Conf("field")}
}
field := strings.Join(fields, ",")
where := m.Confx("where", m.Option("where"), "where %s")
group := m.Confx("group", m.Option("group"), "group by %s")
order := m.Confx("order", m.Option("order"), "order by %s")
limit := m.Confx("limit", m.Option("limit"), "limit %s")
offset := m.Confx("offset", m.Option("offset"), "offset %s")
other := m.Meta["other"]
for i, v := range other {
if len(v) > 1 {
switch v[0] {
case '$':
other[i] = m.Cap(v[1:])
case '@':
other[i] = m.Conf(v[1:])
}
}
}
msg := m.Spawn().Cmd("query", fmt.Sprintf("select %s from %s %s %s %s %s %s", field, table, where, group, order, limit, offset), other)
m.Copy(msg, "append")
m.Target().Configs["template_value"] = &ctx.Config{}
if m.Has("extra_field") && len(m.Meta[m.Option("extra_field")]) > 0 {
format := "%v"
if m.Has("extra_format") {
format = m.Option("extra_format")
}
for i := 0; i < len(m.Meta[m.Option("extra_field")]); i++ {
json.Unmarshal([]byte(m.Meta[m.Option("extra_field")][i]), &m.Target().Configs["template_value"].Value)
if m.Meta["extra_field"][1] != "" {
m.Target().Configs["template_value"].Value = m.Confv("template_value", m.Meta["extra_field"][1])
}
fields = strings.Split(m.Option("extra_fields"), " ")
switch v := m.Confv("template_value").(type) {
case map[string]interface{}:
for _, k := range fields {
if k == "" {
continue
}
if val, ok := v[k]; ok {
m.Add("append", k, fmt.Sprintf(format, val))
} else {
m.Add("append", k, fmt.Sprintf(format, ""))
}
}
m.Meta[m.Option("extra_field")][i] = ""
case float64:
m.Meta[m.Option("extra_field")][i] = fmt.Sprintf(format, int(v))
case nil:
m.Meta[m.Option("extra_field")][i] = ""
default:
m.Meta[m.Option("extra_field")][i] = fmt.Sprintf(format, v)
}
}
}
if m.Has("trans_field") {
trans := map[string]string{}
for i := 0; i < len(m.Meta["trans_map"]); i += 2 {
trans[m.Meta["trans_map"][i]] = m.Meta["trans_map"][i+1]
}
for i := 0; i < len(m.Meta[m.Option("trans_field")]); i++ {
if t, ok := trans[m.Meta[m.Option("trans_field")][i]]; ok {
m.Meta[m.Option("trans_field")][i] = t
}
}
}
m.Color(31, table).Echo(" %s %s %s %s %s %v\n", where, group, order, limit, offset, m.Meta["other"])
m.Table(func(maps map[string]string, lists []string, line int) bool {
for i, v := range lists {
if line == -1 {
m.Color(32, v)
} else {
m.Echo(v)
}
if i < len(lists)-1 {
m.Echo(m.Conf("csv_col_sep"))
}
}
m.Echo(m.Conf("csv_row_sep"))
return true
})
}
}},
"set": &ctx.Command{Name: "set table [field value] where condition", Help: "查看或选择数据库信息", Form: map[string]int{"where": 1}, Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if mdb, ok := m.Target().Server.(*MDB); m.Assert(ok) && mdb.DB != nil {
sql := []string{"update", arg[0], "set"}
fields := []string{}
for i := 1; i < len(arg)-1; i += 2 {
sql = append(sql, fmt.Sprintf("%s='%s'", arg[i], arg[i+1]))
fields = append(fields, arg[i])
if i < len(arg)-2 {
sql = append(sql, ",")
}
}
sql = append(sql, fmt.Sprintf("where %s", m.Option("where")))
m.Spawn().Cmd("exec", strings.Join(sql, " "))
msg := m.Spawn().Cmd("show", arg[0], fields, "where", m.Option("where"))
m.Copy(msg, "result").Copy(msg, "append")
}
}},
},
}
func init() {
mdb := &MDB{}
mdb.Context = Index
ctx.Index.Register(Index, mdb)
}