From 09e6f10b6062bce628ee36a3e13293bd33618b71 Mon Sep 17 00:00:00 2001 From: John Date: Fri, 14 Dec 2018 10:09:45 +0800 Subject: [PATCH] new version of gdb developing --- TODO.MD | 2 ++ g/database/gdb/gdb_model.go | 48 +++++++++++++++++++------- g/g.go | 10 +++--- g/net/ghttp/ghttp_server_admin_unix.go | 3 +- g/util/gstr/gstr.go | 4 +-- g/util/gvalid/gvalid_check_map.go | 11 ++++-- g/util/gvalid/gvalid_error.go | 14 +++++++- geg/other/test2.go | 44 +++++++++-------------- 8 files changed, 84 insertions(+), 52 deletions(-) diff --git a/TODO.MD b/TODO.MD index 2c1f997f6..3d7f9cdb1 100644 --- a/TODO.MD +++ b/TODO.MD @@ -42,6 +42,8 @@ 1. gtcp提供简便的包发送/接收方法(SendPkg/RecvPkg)以解决常见的TCP通信粘包问题,并完善文档(参考:https://www.cnblogs.com/kex1n/p/6502002.html); 1. gfile对于文件的读写强行使用了gfpool,在某些场景下不合适,需要考虑剥离开,并为开发者提供单独的指针池文件操作特性; 1. 路由增加不区分大小写得匹配方式; +1. str_ireplace: http://php.net/manual/en/function.str-ireplace.php +1. strpos/stripos/strrpos/strripos: http://php.net/manual/en/function.stripos.php diff --git a/g/database/gdb/gdb_model.go b/g/database/gdb/gdb_model.go index f9347f2c3..a86f4dbe9 100644 --- a/g/database/gdb/gdb_model.go +++ b/g/database/gdb/gdb_model.go @@ -12,12 +12,14 @@ import ( "database/sql" "gitee.com/johng/gf/g/util/gconv" _ "gitee.com/johng/gf/third/github.com/go-sql-driver/mysql" + "strings" ) // 数据库链式操作模型对象 type Model struct { tx *Tx // 数据库事务对象 db *Db // 数据库操作对象 + tablesInit string // 初始化Model时的表名称(可以是多个) tables string // 数据库操作表 fields string // 操作字段 where string // 操作条件 @@ -36,9 +38,10 @@ type Model struct { // 链式操作,数据表字段,可支持多个表,以半角逗号连接 func (db *Db) Table(tables string) (*Model) { return &Model{ - db: db, - tables: tables, - fields: "*", + db : db, + tablesInit : tables, + tables : tables, + fields : "*", } } @@ -50,9 +53,10 @@ func (db *Db) From(tables string) (*Model) { // (事务)链式操作,数据表字段,可支持多个表,以半角逗号连接 func (tx *Tx) Table(tables string) (*Model) { return &Model{ - db: tx.db, - tx: tx, - tables: tables, + db : tx.db, + tx : tx, + tablesInit : tables, + tables : tables, } } @@ -61,6 +65,15 @@ func (tx *Tx) From(tables string) (*Model) { return tx.Table(tables) } +// 清空链式操作数据,以便改model可以重复使用 +func (md *Model) clear() { + if md.tx != nil { + *md = *md.tx.Table(md.tablesInit) + } else { + *md = *md.db.Table(md.tablesInit) + } +} + // 链式操作,左联表 func (md *Model) LeftJoin(joinTable string, on string) (*Model) { md.tables += fmt.Sprintf(" LEFT JOIN %s ON (%s)", joinTable, on) @@ -87,21 +100,25 @@ func (md *Model) Fields(fields string) (*Model) { // 链式操作,condition,支持string & gdb.Map func (md *Model) Where(where interface{}, args ...interface{}) (*Model) { - md.where = md.db.formatCondition(where) + md.where = md.db.formatCondition(where) md.whereArgs = append(md.whereArgs, args...) + // 支持 Where("uid", 1)这种格式 + if len(args) == 1 && strings.Index(md.where , "?") < 0 { + md.where += "=?" + } return md } // 链式操作,添加AND条件到Where中 func (md *Model) And(where interface{}, args ...interface{}) (*Model) { - md.where += " AND " + md.db.formatCondition(where) + 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.where += " OR " + md.db.formatCondition(where) md.whereArgs = append(md.whereArgs, args...) return md } @@ -153,6 +170,7 @@ func (md *Model) Insert() (result sql.Result, err error) { if err == nil { md.checkAndRemoveCache() } + md.clear() }() if md.data == nil { return nil, errors.New("inserting into table with empty data") @@ -184,6 +202,7 @@ func (md *Model) Replace() (result sql.Result, err error) { if err == nil { md.checkAndRemoveCache() } + md.clear() }() if md.data == nil { return nil, errors.New("replacing into table with empty data") @@ -215,6 +234,7 @@ func (md *Model) Save() (result sql.Result, err error) { if err == nil { md.checkAndRemoveCache() } + md.clear() }() if md.data == nil { return nil, errors.New("replacing into table with empty data") @@ -246,6 +266,7 @@ func (md *Model) Update() (result sql.Result, err error) { if err == nil { md.checkAndRemoveCache() } + md.clear() }() if md.data == nil { return nil, errors.New("updating table with empty data") @@ -263,6 +284,7 @@ func (md *Model) Delete() (result sql.Result, err error) { if err == nil { md.checkAndRemoveCache() } + md.clear() }() if md.where == "" { return nil, errors.New("where is required while deleting") @@ -298,6 +320,7 @@ func (md *Model) Cache(time int, name ... string) *Model { // 链式操作,select func (md *Model) Select() (Result, error) { + defer md.clear() return md.getAll(md.getFormattedSql(), md.whereArgs...) } @@ -342,6 +365,7 @@ func (md *Model) Struct(obj interface{}) error { // 链式操作,查询数量,fields可以为空,也可以自定义查询字段, // 当给定自定义查询字段时,该字段必须为数量结果,否则会引起歧义,使用如:md.Fields("COUNT(id)") func (md *Model) Count() (int, error) { + defer md.clear() if md.fields == "" || md.fields == "*" { md.fields = "COUNT(1)" } else { @@ -424,11 +448,11 @@ func (md *Model) getFormattedSql() string { // @author ymrjqyy // @author 2018-08-15 func (md *Model) Chunk(limit int, callback func(result Result, err error) bool) { - var page = 1 + defer md.clear() + page := 1 for { md.ForPage(page, limit) - sqls := md.getFormattedSql() - data, err := md.getAll(sqls, md.whereArgs...) + data, err := md.getAll(md.getFormattedSql(), md.whereArgs...) if err != nil { callback(nil, err) break diff --git a/g/g.go b/g/g.go index 94a4d5601..c3eb2d107 100644 --- a/g/g.go +++ b/g/g.go @@ -10,14 +10,14 @@ package g import "gitee.com/johng/gf/g/container/gvar" // 框架动态变量,可以用该类型替代interface{}类型 -type Var = gvar.Var +type Var = gvar.Var // 常用map数据结构(使用别名) -type Map = map[string]interface{} +type Map = map[string]interface{} // 常用list数据结构(使用别名) -type List = []Map +type List = []Map // 常用slice数据结构(使用别名) -type Slice = []interface{} -type Array = Slice +type Slice = []interface{} +type Array = Slice diff --git a/g/net/ghttp/ghttp_server_admin_unix.go b/g/net/ghttp/ghttp_server_admin_unix.go index 96fc28049..06b18fd94 100644 --- a/g/net/ghttp/ghttp_server_admin_unix.go +++ b/g/net/ghttp/ghttp_server_admin_unix.go @@ -25,7 +25,6 @@ func handleProcessSignal() { syscall.SIGINT, syscall.SIGQUIT, syscall.SIGKILL, - syscall.SIGHUP, syscall.SIGTERM, syscall.SIGUSR1, syscall.SIGUSR2, @@ -34,7 +33,7 @@ func handleProcessSignal() { sig = <- procSignalChan switch sig { // 进程终止,停止所有子进程运行 - case syscall.SIGINT, syscall.SIGQUIT, syscall.SIGKILL, syscall.SIGHUP, syscall.SIGTERM: + case syscall.SIGINT, syscall.SIGQUIT, syscall.SIGKILL, syscall.SIGTERM: shutdownWebServers(sig.String()) return diff --git a/g/util/gstr/gstr.go b/g/util/gstr/gstr.go index 8decd74ba..1758de12a 100644 --- a/g/util/gstr/gstr.go +++ b/g/util/gstr/gstr.go @@ -13,7 +13,7 @@ import ( "strings" ) -// 字符串替换 +// 字符串替换(大小写敏感) func Replace(origin, search, replace string, count...int) string { n := -1 if len(count) > 0 { @@ -22,7 +22,7 @@ func Replace(origin, search, replace string, count...int) string { return strings.Replace(origin, search, replace, n) } -// 使用map进行字符串替换 +// 使用map进行字符串替换(大小写敏感) func ReplaceByMap(origin string, replaces map[string]string) string { result := origin for k, v := range replaces { diff --git a/g/util/gvalid/gvalid_check_map.go b/g/util/gvalid/gvalid_check_map.go index 3f26bbd4a..1ad486ac7 100644 --- a/g/util/gvalid/gvalid_check_map.go +++ b/g/util/gvalid/gvalid_check_map.go @@ -14,7 +14,12 @@ import ( // 检测键值对参数Map, // rules参数支持 []string / map[string]string 类型,前面一种类型支持返回校验结果顺序(具体格式参考struct tag),后一种不支持; // rules参数中得 map[string]string 是一个2维的关联数组,第一维键名为参数键名,第二维为带有错误的校验规则名称,值为错误信息。 -func CheckMap(params map[string]interface{}, rules interface{}, msgs...CustomMsg) *Error { +func CheckMap(params interface{}, rules interface{}, msgs...CustomMsg) *Error { + // 将参数转换为 map[string]interface{}类型 + data := gconv.Map(params) + if data == nil { + return newErrorStr("invalid_params", "invalid params type: convert to map[string]interface{} failed") + } // 真实校验规则数据结构 checkRules := make(map[string]string) // 真实自定义错误信息数据结构 @@ -74,10 +79,10 @@ func CheckMap(params map[string]interface{}, rules interface{}, msgs...CustomMsg // 这里的rule变量为多条校验规则,不包含名字或者错误信息定义 for key, rule := range checkRules { value = nil - if v, ok := params[key]; ok { + if v, ok := data[key]; ok { value = v } - if e := Check(value, rule, customMsgs[key], params); e != nil { + if e := Check(value, rule, customMsgs[key], data); e != nil { _, item := e.FirstItem() // 如果值为nil|"",并且不需要require*验证时,其他验证失效 if value == nil || gconv.String(value) == "" { diff --git a/g/util/gvalid/gvalid_error.go b/g/util/gvalid/gvalid_error.go index 8db62bba7..0f495bc64 100644 --- a/g/util/gvalid/gvalid_error.go +++ b/g/util/gvalid/gvalid_error.go @@ -22,7 +22,7 @@ type Error struct { type ErrorMap map[string]map[string]string -// 创建一个校验错误对象指针 +// 创建一个校验错误对象指针(校验错误) func newError(rules []string, errors map[string]map[string]string) *Error { return &Error { rules : rules, @@ -30,6 +30,18 @@ func newError(rules []string, errors map[string]map[string]string) *Error { } } +// 创建一个校验错误对象指针(内部错误) +func newErrorStr(key, err string) *Error { + return &Error { + rules : nil, + errors : map[string]map[string]string{ + "__gvalid__" : { + key: err, + }, + }, + } +} + // 获得规则与错误信息的map; 当校验结果为多条数据校验时,返回第一条错误map(此时类似FirstItem) func (e *Error) Map() map[string]string { _, m := e.FirstItem() diff --git a/geg/other/test2.go b/geg/other/test2.go index 153822499..a1aad8c3c 100644 --- a/geg/other/test2.go +++ b/geg/other/test2.go @@ -1,35 +1,25 @@ package main -import ( - "gitee.com/johng/gf/g" - "gitee.com/johng/gf/g/util/gvalid" -) +import "fmt" type User struct { - Uid int `gvalid:"uid @integer|min:1"` - Name string `gvalid:"name @required|length:6,30#请输入用户名称|用户名称长度非法"` - Pass1 string `gvalid:"password1@required|password3"` - Pass2 string `gvalid:"password2@required|password3|same:password1#||两次密码不一致,请重新输入"` + Uid int +} + +func New() *User { + return &User{ + 100, + } +} + +func (user *User) Clear() { + user = New() } func main() { - user := &User{ - Name : "john", - Pass1: "Abc123!@#", - Pass2: "123", - } - - // 使用结构体定义的校验规则和错误提示进行校验 - g.Dump(gvalid.CheckStruct(user, nil).Maps()) - - // 自定义校验规则和错误提示,对定义的特定校验规则和错误提示进行覆盖 - rules := map[string]string { - "Uid" : "required", - } - msgs := map[string]interface{} { - "Pass2" : map[string]string { - "password3" : "名称不能为空", - }, - } - g.Dump(gvalid.CheckStruct(user, rules, msgs).Maps()) + user := New() + user.Uid = 10000 + fmt.Println(user) + user.Clear() + fmt.Println(user) } \ No newline at end of file