package mdb // {{{ // }}} import ( // {{{ "context" "database/sql" _ "github.com/go-sql-driver/mysql" "errors" "fmt" ) // }}} type MDB struct { db *sql.DB *ctx.Context } func (mdb *MDB) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{ return mdb } // }}} func (mdb *MDB) Start(m *ctx.Message, arg ...string) bool { // {{{ if m.Conf("source") == "" || m.Conf("driver") == "" { return true } db, e := sql.Open(m.Conf("driver"), m.Conf("source")) m.Assert(e) mdb.db = db m.Log("info", "%s: open %s %s", mdb.Name, m.Conf("driver"), m.Conf("source")) m.Capi("nsource", 1) return true } // }}} func (mdb *MDB) Spawn(c *ctx.Context, m *ctx.Message, arg ...string) ctx.Server { // {{{ c.Caches = map[string]*ctx.Cache{} c.Configs = map[string]*ctx.Config{ "source": &ctx.Config{Name: "source", Value: "", Help: "数据库参数"}, "driver": &ctx.Config{Name: "driver", Value: "", Help: "数据库驱动"}, } if len(arg) > 0 { m.Conf("source", arg[0]) if len(arg) > 1 { m.Conf("driver", arg[1]) } } s := new(MDB) s.Context = c return s } // }}} func (mdb *MDB) Exit(m *ctx.Message, arg ...string) bool { // {{{ if mdb.db != nil && m.Target == mdb.Context { m.Log("info", "%s: close %s %s", mdb.Name, m.Conf("driver"), m.Conf("source")) m.Capi("nsource", -1) mdb.db.Close() mdb.db = nil } return true } // }}} var Index = &ctx.Context{Name: "mdb", Help: "内存数据库", Caches: map[string]*ctx.Cache{ "nsource": &ctx.Cache{Name: "数据源数量", Value: "0", Help: "数据库连接的数量"}, }, Configs: map[string]*ctx.Config{}, Commands: map[string]*ctx.Command{ "open": &ctx.Command{Name: "open name [source [driver]]", Help: "打开数据库", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string { m.Start(arg[0], arg[1:]...) // {{{ return "" // }}} }}, "exec": &ctx.Command{Name: "exec sql [arg]", Help: "执行SQL语句", Appends: map[string]string{ "LastInsertId": "最后插入元组的标识", "RowsAffected": "修改元组的数量", }, Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string { mdb, ok := m.Target.Server.(*MDB) // {{{ if !ok { m.Assert(errors.New("目标模块类型错误")) } if len(arg) == 0 { m.Assert(errors.New("缺少参数")) } which := make([]interface{}, 0, len(arg)) for _, v := range arg[1:] { which = append(which, v) } ret, e := mdb.db.Exec(arg[0], which...) m.Assert(e) id, e := ret.LastInsertId() m.Assert(e) n, e := ret.RowsAffected() m.Assert(e) m.Add("append", "LastInsertId", fmt.Sprintf("%d", id)) m.Add("append", "RowsAffected", fmt.Sprintf("%d", n)) return "" // }}} }}, "query": &ctx.Command{Name: "query sql [arg]", Help: "执行SQL语句", Hand: func(c *ctx.Context, m *ctx.Message, key string, arg ...string) string { mdb, ok := m.Target.Server.(*MDB) // {{{ if !ok { m.Assert(errors.New("目标模块类型错误")) } if len(arg) == 0 { m.Assert(errors.New("缺少参数")) } which := make([]interface{}, 0, len(arg)) for _, v := range arg[1:] { which = append(which, v) } rows, e := mdb.db.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 []byte: m.Add("append", k, string(b)) case int64: m.Add("append", k, fmt.Sprintf("%d", b)) } } } return "" // }}} }}, }, } func init() { mdb := &MDB{} mdb.Context = Index ctx.Index.Register(Index, mdb) }