diff --git a/g/database/gdb/gdb.go b/g/database/gdb/gdb.go index 8d5322248..9125c2383 100644 --- a/g/database/gdb/gdb.go +++ b/g/database/gdb/gdb.go @@ -15,6 +15,7 @@ import ( "gitee.com/johng/gf/g/util/grand" _ "github.com/lib/pq" _ "github.com/go-sql-driver/mysql" + "gitee.com/johng/gf/g/util/gconv" ) const ( @@ -65,8 +66,8 @@ type Link interface { Delete(table string, condition interface{}, args ...interface{}) (sql.Result, error) // 创建链式操作对象(Table为From的别名) - Table(tables string) (*DbOp) - From(tables string) (*DbOp) + Table(tables string) (*Model) + From(tables string) (*Model) // 关闭数据库操作对象 Close() error @@ -193,12 +194,8 @@ func getConfigNodeByPriority (cg *ConfigGroup) *ConfigNode { func newDb (masterNode *ConfigNode, slaveNode *ConfigNode) (*Db, error) { var link Link switch masterNode.Type { - case "mysql": - link = Link(&dbmysql{}) - - case "pgsql": - link = Link(&dbpgsql{}) - + case "mysql": link = Link(&dbmysql{}) + case "pgsql": link = Link(&dbpgsql{}) default: return nil, errors.New(fmt.Sprintf("unsupported db type '%s'", masterNode.Type)) } @@ -226,3 +223,35 @@ func newDb (masterNode *ConfigNode, slaveNode *ConfigNode) (*Db, error) { }, nil } +// 将结果列表按照指定的字段值做map[string]Map +func (list List) ToStringMap(key string) map[string]Map { + m := make(map[string]Map) + for _, item := range list { + if v, ok := item[key]; ok { + m[gconv.String(v)] = item + } + } + return m +} + +// 将结果列表按照指定的字段值做map[int]Map +func (list List) ToIntMap(key string) map[int]Map { + m := make(map[int]Map) + for _, item := range list { + if v, ok := item[key]; ok { + m[gconv.Int(v)] = item + } + } + return m +} + +// 将结果列表按照指定的字段值做map[uint]Map +func (list List) ToUintMap(key string) map[uint]Map { + m := make(map[uint]Map) + for _, item := range list { + if v, ok := item[key]; ok { + m[gconv.Uint(v)] = item + } + } + return m +} diff --git a/g/database/gdb/gdb_base.go b/g/database/gdb/gdb_base.go index ec1167152..a74e20627 100644 --- a/g/database/gdb/gdb_base.go +++ b/g/database/gdb/gdb_base.go @@ -128,6 +128,24 @@ func (db *Db) GetValue(query string, args ...interface{}) (interface{}, error) { return nil, nil } +// 数据表查询,其中tables可以是多个联表查询语句,这种查询方式较复杂,建议使用链式操作 +func (db *Db) Select(tables, fields string, condition interface{}, groupBy, orderBy string, first, limit int, args ... interface{}) (List, error) { + s := fmt.Sprintf("SELECT %s FROM %s ", fields, tables) + if condition != nil { + s += fmt.Sprintf("WHERE %s ", db.formatCondition(condition)) + } + if len(groupBy) > 0 { + s += fmt.Sprintf("GROUP BY %s ", groupBy) + } + if len(orderBy) > 0 { + s += fmt.Sprintf("ORDER BY %s ", orderBy) + } + if limit > 0 { + s += fmt.Sprintf("LIMIT %d,%d ", first, limit) + } + return db.GetAll(s, args ... ) +} + // sql预处理,执行完成后调用返回值sql.Stmt.Exec完成sql操作 // 记得调用sql.Stmt.Close关闭操作对象 func (db *Db) Prepare(query string) (*sql.Stmt, error) { diff --git a/g/database/gdb/gdb_linkop.go b/g/database/gdb/gdb_linkop.go deleted file mode 100644 index 7fd75313b..000000000 --- a/g/database/gdb/gdb_linkop.go +++ /dev/null @@ -1,281 +0,0 @@ -// Copyright 2017 gf Author(https://gitee.com/johng/gf). All Rights Reserved. -// -// This Source Code Form is subject to the terms of the MIT License. -// If a copy of the MIT was not distributed with this file, -// You can obtain one at https://gitee.com/johng/gf. - -package gdb - -import ( - "fmt" - "errors" - "database/sql" - _ "github.com/go-sql-driver/mysql" -) - -// 数据库链式操作对象 -type DbOp struct { - tx *Tx // 数据库事务对象 - db *Db // 数据库操作对象 - tables string // 数据库操作表 - fields string // 操作字段 - where string // 操作条件 - whereArgs []interface{} // 操作条件参数 - groupBy string // 分组语句 - orderBy string // 排序语句 - start int // 分页开始 - limit int // 分页条数 - data interface{} // 操作记录(支持Map/List/string类型) - batch int // 批量操作条数 -} - -// 链式操作,数据表字段,可支持多个表,以半角逗号连接 -func (db *Db) Table(tables string) (*DbOp) { - return &DbOp { - db : db, - tables : tables, - } -} - -// 链式操作,数据表字段,可支持多个表,以半角逗号连接 -func (db *Db) From(tables string) (*DbOp) { - return db.Table(tables) -} - -// (事务)链式操作,数据表字段,可支持多个表,以半角逗号连接 -func (tx *Tx) Table(tables string) (*DbOp) { - return &DbOp { - tx : tx, - tables : tables, - } -} - -// (事务)链式操作,数据表字段,可支持多个表,以半角逗号连接 -func (tx *Tx) From(tables string) (*DbOp) { - return tx.Table(tables) -} - -// 链式操作,左联表 -func (op *DbOp) LeftJoin(joinTable string, on string) (*DbOp) { - op.tables += fmt.Sprintf(" LEFT JOIN %s ON (%s)", joinTable, on) - return op -} - -// 链式操作,右联表 -func (op *DbOp) RightJoin(joinTable string, on string) (*DbOp) { - op.tables += fmt.Sprintf(" RIGHT JOIN %s ON (%s)", joinTable, on) - return op -} - -// 链式操作,内联表 -func (op *DbOp) InnerJoin(joinTable string, on string) (*DbOp) { - op.tables += fmt.Sprintf(" INNER JOIN %s ON (%s)", joinTable, on) - return op -} - -// 链式操作,查询字段 -func (op *DbOp) Fields(fields string) (*DbOp) { - op.fields = fields - return op -} - -// 链式操作,condition,支持string & gdb.Map -func (op *DbOp) Where(where interface{}, args...interface{}) (*DbOp) { - op.where = op.db.formatCondition(where) - op.whereArgs = args - return op -} - -// 链式操作,group by -func (op *DbOp) GroupBy(groupBy string) (*DbOp) { - op.groupBy = groupBy - return op -} - -// 链式操作,order by -func (op *DbOp) OrderBy(orderBy string) (*DbOp) { - op.orderBy = orderBy - return op -} - -// 链式操作,limit -func (op *DbOp) Limit(start int, limit int) (*DbOp) { - op.start = start - op.limit = limit - return op -} - -// 链式操作,操作数据记录项 -func (op *DbOp) Data(data interface{}) (*DbOp) { - op.data = data - return op -} - -// 链式操作, CURD - Insert/BatchInsert -func (op *DbOp) Insert() (sql.Result, error) { - // 批量操作 - if list, ok := op.data.(List); ok { - batch := 10 - if op.batch > 0 { - batch = op.batch - } - if op.tx == nil { - return op.db.BatchInsert(op.tables, list, batch) - } else { - return op.tx.BatchInsert(op.tables, list, batch) - } - } - // 记录操作 - if op.data == nil { - return nil, errors.New("inserting into table with empty data") - } - if dataMap, ok := op.data.(Map); ok { - if op.tx == nil { - return op.db.Insert(op.tables, dataMap) - } else { - return op.tx.Insert(op.tables, dataMap) - } - } - return nil, errors.New("inserting into table with invalid data type") -} - -// 链式操作, CURD - Replace/BatchReplace -func (op *DbOp) Replace() (sql.Result, error) { - // 批量操作 - if list, ok := op.data.(List); ok { - batch := 10 - if op.batch > 0 { - batch = op.batch - } - if op.tx == nil { - return op.db.BatchReplace(op.tables, list, batch) - } else { - return op.tx.BatchReplace(op.tables, list, batch) - } - } - // 记录操作 - if op.data == nil { - return nil, errors.New("replacing into table with empty data") - } - if dataMap, ok := op.data.(Map); ok { - if op.tx == nil { - return op.db.Insert(op.tables, dataMap) - } else { - return op.tx.Insert(op.tables, dataMap) - } - } - return nil, errors.New("replacing into table with invalid data type") -} - -// 链式操作, CURD - Save/BatchSave -func (op *DbOp) Save() (sql.Result, error) { - // 批量操作 - if list, ok := op.data.(List); ok { - batch := 10 - if op.batch > 0 { - batch = op.batch - } - if op.tx == nil { - return op.db.BatchSave(op.tables, list, batch) - } else { - return op.tx.BatchSave(op.tables, list, batch) - } - } - // 记录操作 - if op.data == nil { - return nil, errors.New("saving into table with empty data") - } - if dataMap, ok := op.data.(Map); ok { - if op.tx == nil { - return op.db.Save(op.tables, dataMap) - } else { - return op.tx.Save(op.tables, dataMap) - } - } - return nil, errors.New("saving into table with invalid data type") -} - -// 链式操作, CURD - Update -func (op *DbOp) Update() (sql.Result, error) { - if op.data == nil { - return nil, errors.New("updating table with empty data") - } - if op.tx == nil { - return op.db.Update(op.tables, op.data, op.where, op.whereArgs ...) - } else { - return op.tx.Update(op.tables, op.data, op.where, op.whereArgs ...) - } -} - -// 链式操作, CURD - Delete -func (op *DbOp) Delete() (sql.Result, error) { - if op.where == "" { - return nil, errors.New("where is required while deleting") - } - if op.tx == nil { - return op.db.Delete(op.tables, op.where, op.whereArgs...) - } else { - return op.tx.Delete(op.tables, op.where, op.whereArgs...) - } -} - -// 设置批处理的大小 -func (op *DbOp) Batch(batch int) *DbOp { - op.batch = batch - return op -} - -// 链式操作,select -func (op *DbOp) Select() (List, error) { - if op.fields == "" { - op.fields = "*" - } - s := fmt.Sprintf("SELECT %s FROM %s", op.fields, op.tables) - if op.where != "" { - s += " WHERE " + op.where - } - if op.groupBy != "" { - s += " GROUP BY " + op.groupBy - } - if op.orderBy != "" { - s += " ORDER BY " + op.orderBy - } - if op.limit != 0 { - s += fmt.Sprintf(" LIMIT %d, %d", op.start, op.limit) - } - if op.tx == nil { - return op.db.GetAll(s, op.whereArgs...) - } else { - return op.tx.GetAll(s, op.whereArgs...) - } -} - -// 链式操作,查询所有记录 -func (op *DbOp) All() (List, error) { - return op.Select() -} - -// 链式操作,查询单条记录 -func (op *DbOp) One() (Map, error) { - list, err := op.All() - if err != nil { - return nil, err - } - if len(list) > 0 { - return list[0], nil - } - return nil, nil -} - -// 链式操作,查询字段值 -func (op *DbOp) Value() (interface{}, error) { - one, err := op.One() - if err != nil { - return "", err - } - for _, v := range one { - return v, nil - } - return "", nil -} - diff --git a/g/database/gdb/gdb_model.go b/g/database/gdb/gdb_model.go new file mode 100644 index 000000000..d6857fce8 --- /dev/null +++ b/g/database/gdb/gdb_model.go @@ -0,0 +1,304 @@ +// Copyright 2017 gf Author(https://gitee.com/johng/gf). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://gitee.com/johng/gf. + +package gdb + +import ( + "fmt" + "errors" + "database/sql" + "gitee.com/johng/gf/g/util/gconv" + _ "github.com/go-sql-driver/mysql" +) + +// 数据库链式操作模型对象 +type Model struct { + tx *Tx // 数据库事务对象 + db *Db // 数据库操作对象 + tables string // 数据库操作表 + fields string // 操作字段 + where string // 操作条件 + whereArgs []interface{} // 操作条件参数 + groupBy string // 分组语句 + orderBy string // 排序语句 + start int // 分页开始 + limit int // 分页条数 + data interface{} // 操作记录(支持Map/List/string类型) + batch int // 批量操作条数 +} + +// 链式操作,数据表字段,可支持多个表,以半角逗号连接 +func (db *Db) Table(tables string) (*Model) { + return &Model { + db : db, + tables : tables, + } +} + +// 链式操作,数据表字段,可支持多个表,以半角逗号连接 +func (db *Db) From(tables string) (*Model) { + return db.Table(tables) +} + +// (事务)链式操作,数据表字段,可支持多个表,以半角逗号连接 +func (tx *Tx) Table(tables string) (*Model) { + return &Model { + tx : tx, + tables : tables, + } +} + +// (事务)链式操作,数据表字段,可支持多个表,以半角逗号连接 +func (tx *Tx) From(tables string) (*Model) { + return tx.Table(tables) +} + +// 链式操作,左联表 +func (md *Model) LeftJoin(joinTable string, on string) (*Model) { + md.tables += fmt.Sprintf(" LEFT JOIN %s ON (%s)", joinTable, on) + return md +} + +// 链式操作,右联表 +func (md *Model) RightJoin(joinTable string, on string) (*Model) { + md.tables += fmt.Sprintf(" RIGHT JOIN %s ON (%s)", joinTable, on) + return md +} + +// 链式操作,内联表 +func (md *Model) InnerJoin(joinTable string, on string) (*Model) { + md.tables += fmt.Sprintf(" INNER JOIN %s ON (%s)", joinTable, on) + return md +} + +// 链式操作,查询字段 +func (md *Model) Fields(fields string) (*Model) { + md.fields = fields + return md +} + +// 链式操作,condition,支持string & gdb.Map +func (md *Model) Where(where interface{}, args...interface{}) (*Model) { + md.where = md.db.formatCondition(where) + md.whereArgs = args + return md +} + +// 链式操作,添加AND条件到Where中 +func (md *Model) And(where interface{}, args...interface{}) (*Model) { + md.where += " AND " + md.db.formatCondition(where) + md.whereArgs = append(md.whereArgs, args) + return md +} + +// 链式操作,添加OR条件到Where中 +func (md *Model) Or(where interface{}, args...interface{}) (*Model) { + md.where += " OR " + md.db.formatCondition(where) + md.whereArgs = append(md.whereArgs, args) + return md +} + +// 链式操作,group by +func (md *Model) GroupBy(groupBy string) (*Model) { + md.groupBy = groupBy + return md +} + +// 链式操作,order by +func (md *Model) OrderBy(orderBy string) (*Model) { + md.orderBy = orderBy + return md +} + +// 链式操作,limit +func (md *Model) Limit(start int, limit int) (*Model) { + md.start = start + md.limit = limit + return md +} + +// 链式操作,操作数据记录项,可以是string/Map, 也可以是:key,value,key,value,... +func (md *Model) Data(data...interface{}) (*Model) { + if len(data) > 1 { + m := make(map[string]interface{}) + for i := 0; i < len(data); i += 2 { + m[gconv.String(data[i])] = data[i + 1] + } + md.data = m + } else { + md.data = data[0] + } + return md +} + +// 链式操作, CURD - Insert/BatchInsert +func (md *Model) Insert() (sql.Result, error) { + // 批量操作 + if list, ok := md.data.(List); ok { + batch := 10 + if md.batch > 0 { + batch = md.batch + } + if md.tx == nil { + return md.db.BatchInsert(md.tables, list, batch) + } else { + return md.tx.BatchInsert(md.tables, list, batch) + } + } + // 记录操作 + if md.data == nil { + return nil, errors.New("inserting into table with empty data") + } + if dataMap, ok := md.data.(Map); ok { + if md.tx == nil { + return md.db.Insert(md.tables, dataMap) + } else { + return md.tx.Insert(md.tables, dataMap) + } + } + return nil, errors.New("inserting into table with invalid data type") +} + +// 链式操作, CURD - Replace/BatchReplace +func (md *Model) Replace() (sql.Result, error) { + // 批量操作 + if list, ok := md.data.(List); ok { + batch := 10 + if md.batch > 0 { + batch = md.batch + } + if md.tx == nil { + return md.db.BatchReplace(md.tables, list, batch) + } else { + return md.tx.BatchReplace(md.tables, list, batch) + } + } + // 记录操作 + if md.data == nil { + return nil, errors.New("replacing into table with empty data") + } + if dataMap, ok := md.data.(Map); ok { + if md.tx == nil { + return md.db.Insert(md.tables, dataMap) + } else { + return md.tx.Insert(md.tables, dataMap) + } + } + return nil, errors.New("replacing into table with invalid data type") +} + +// 链式操作, CURD - Save/BatchSave +func (md *Model) Save() (sql.Result, error) { + // 批量操作 + if list, ok := md.data.(List); ok { + batch := 10 + if md.batch > 0 { + batch = md.batch + } + if md.tx == nil { + return md.db.BatchSave(md.tables, list, batch) + } else { + return md.tx.BatchSave(md.tables, list, batch) + } + } + // 记录操作 + if md.data == nil { + return nil, errors.New("saving into table with empty data") + } + if dataMap, ok := md.data.(Map); ok { + if md.tx == nil { + return md.db.Save(md.tables, dataMap) + } else { + return md.tx.Save(md.tables, dataMap) + } + } + return nil, errors.New("saving into table with invalid data type") +} + +// 链式操作, CURD - Update +func (md *Model) Update() (sql.Result, error) { + if md.data == nil { + return nil, errors.New("updating table with empty data") + } + if md.tx == nil { + return md.db.Update(md.tables, md.data, md.where, md.whereArgs ...) + } else { + return md.tx.Update(md.tables, md.data, md.where, md.whereArgs ...) + } +} + +// 链式操作, CURD - Delete +func (md *Model) Delete() (sql.Result, error) { + if md.where == "" { + return nil, errors.New("where is required while deleting") + } + if md.tx == nil { + return md.db.Delete(md.tables, md.where, md.whereArgs...) + } else { + return md.tx.Delete(md.tables, md.where, md.whereArgs...) + } +} + +// 设置批处理的大小 +func (md *Model) Batch(batch int) *Model { + md.batch = batch + return md +} + +// 链式操作,select +func (md *Model) Select() (List, error) { + if md.fields == "" { + md.fields = "*" + } + s := fmt.Sprintf("SELECT %s FROM %s", md.fields, md.tables) + if md.where != "" { + s += " WHERE " + md.where + } + if md.groupBy != "" { + s += " GROUP BY " + md.groupBy + } + if md.orderBy != "" { + s += " ORDER BY " + md.orderBy + } + if md.limit != 0 { + s += fmt.Sprintf(" LIMIT %d, %d", md.start, md.limit) + } + if md.tx == nil { + return md.db.GetAll(s, md.whereArgs...) + } else { + return md.tx.GetAll(s, md.whereArgs...) + } +} + +// 链式操作,查询所有记录 +func (md *Model) All() (List, error) { + return md.Select() +} + +// 链式操作,查询单条记录 +func (md *Model) One() (Map, error) { + list, err := md.All() + if err != nil { + return nil, err + } + if len(list) > 0 { + return list[0], nil + } + return nil, nil +} + +// 链式操作,查询字段值 +func (md *Model) Value() (interface{}, error) { + one, err := md.One() + if err != nil { + return "", err + } + for _, v := range one { + return v, nil + } + return "", nil +} + diff --git a/g/g.go b/g/g.go index 1bfbfd3e0..e3a659f2f 100644 --- a/g/g.go +++ b/g/g.go @@ -4,8 +4,10 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://gitee.com/johng/gf. - package g // 常用map数据结构 type Map map[string]interface{} + +// 常用list数据结构 +type List []Map diff --git a/g/net/ghttp/http_server.go b/g/net/ghttp/http_server.go index d159ef96c..043081c05 100644 --- a/g/net/ghttp/http_server.go +++ b/g/net/ghttp/http_server.go @@ -14,6 +14,7 @@ import ( "net/http" "gitee.com/johng/gf/g/os/glog" "gitee.com/johng/gf/g/os/gcache" + "gitee.com/johng/gf/g/util/gconv" "gitee.com/johng/gf/g/container/gmap" "gitee.com/johng/gf/g/container/gtype" "gitee.com/johng/gf/g/container/gqueue" @@ -83,16 +84,16 @@ var serverMapping = gmap.NewStringInterfaceMap() // 获取/创建一个默认配置的HTTP Server(默认监听端口是80) // 单例模式,请保证name的唯一性 -func GetServer(names...string) (*Server) { - name := gDEFAULT_SERVER - if len(names) > 0 { - name = names[0] +func GetServer(name...interface{}) (*Server) { + sname := gDEFAULT_SERVER + if len(name) > 0 { + sname = gconv.String(name[0]) } - if s := serverMapping.Get(name); s != nil { + if s := serverMapping.Get(sname); s != nil { return s.(*Server) } s := &Server { - name : name, + name : sname, methodsMap : make(map[string]bool), handlerMap : make(HandlerMap), handlerTree : make(map[string]interface{}), @@ -122,7 +123,7 @@ func GetServer(names...string) (*Server) { s.methodsMap[v] = true } s.SetConfig(defaultServerConfig) - serverMapping.Set(name, s) + serverMapping.Set(sname, s) return s }