done refacting gdb package

This commit is contained in:
John
2018-12-16 22:22:07 +08:00
parent e67aa63a50
commit 7434dfe6fa
16 changed files with 190 additions and 40 deletions

View File

@ -10,6 +10,7 @@ package gvar
import (
"gitee.com/johng/gf/g/container/gtype"
"gitee.com/johng/gf/g/os/gtime"
"gitee.com/johng/gf/g/util/gconv"
"time"
)
@ -92,6 +93,8 @@ func (v *Var) Interfaces() []interface{} { return gconv.Interfaces(v.Val()
func (v *Var) Time(format...string) time.Time { return gconv.Time(v.Val(), format...) }
func (v *Var) TimeDuration() time.Duration { return gconv.TimeDuration(v.Val()) }
func (v *Var) GTime(format...string) *gtime.Time { return gconv.GTime(v.Val(), format...) }
// 将变量转换为对象,注意 objPointer 参数必须为struct指针
func (v *Var) Struct(objPointer interface{}, attrMapping...map[string]string) error {
return gconv.Struct(v.Val(), objPointer, attrMapping...)

View File

@ -6,7 +6,10 @@
package gvar
import "time"
import (
"gitee.com/johng/gf/g/os/gtime"
"time"
)
// 只读变量接口
type VarRead interface {
@ -34,5 +37,6 @@ type VarRead interface {
Interfaces() []interface{}
Time(format ...string) time.Time
TimeDuration() time.Duration
GTime(format...string) *gtime.Time
Struct(objPointer interface{}, attrMapping ...map[string]string) error
}

View File

@ -4,6 +4,7 @@
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://gitee.com/johng/gf.
// Package gdb provides ORM features for popular relationship databases.
// 数据库ORM.
// 默认内置支持MySQL, 其他数据库需要手动import对应的数据库引擎第三方包.
package gdb
@ -94,7 +95,9 @@ type DB interface {
getCache() (*gcache.Cache)
getChars() (charLeft string, charRight string)
getDebug() bool
handleSqlBeforeExec(sql string) string
filterFields(table string, data map[string]interface{}) map[string]interface{}
getTableFields(table string) (map[string]string, error)
handleSqlBeforeExec(sql string) string
}
// 执行底层数据库操作的核心接口

View File

@ -431,3 +431,36 @@ func (bs *dbBase) doDelete(link dbLink, table string, condition interface{}, arg
func (bs *dbBase) getCache() *gcache.Cache {
return bs.cache
}
// 将map的数据按照fields进行过滤只保留与表字段同名的数据
func (bs *dbBase) filterFields(table string, data map[string]interface{}) map[string]interface{} {
if fields, err := bs.db.getTableFields(table); err == nil {
for k, _ := range data {
if _, ok := fields[k]; !ok {
delete(data, k)
}
}
}
return data
}
// 获得指定表表的数据结构map
func (bs *dbBase) getTableFields(table string) (fields map[string]string, err error) {
v := bs.cache.GetOrSetFunc("table_fields_" + table, func() interface{} {
result := (Result)(nil)
charl, charr := bs.db.getChars()
result, err = bs.GetAll(fmt.Sprintf(`SHOW COLUMNS FROM %s%s%s`, charl, table, charr))
if err != nil {
return nil
}
fields = make(map[string]string)
for _, m := range result {
fields[m["Field"].String()] = m["Type"].String()
}
return fields
}, 0)
if err == nil {
fields = v.(map[string]string)
}
return
}

View File

@ -41,9 +41,13 @@ func rowsToResult(rows *sql.Rows) (Result, error) {
row := make(Record)
// 注意col字段是一个[]byte类型(slice类型本身是一个指针),多个记录循环时该变量指向的是同一个内存地址
for i, col := range values {
v := make([]byte, len(col))
copy(v, col)
row[columns[i]] = gvar.New(v, false)
if col == nil {
row[columns[i]] = gvar.New(nil, false)
} else {
v := make([]byte, len(col))
copy(v, col)
row[columns[i]] = gvar.New(v, false)
}
}
records = append(records, row)
}

View File

@ -12,6 +12,7 @@ import (
"database/sql"
"gitee.com/johng/gf/g/util/gconv"
_ "gitee.com/johng/gf/third/github.com/go-sql-driver/mysql"
"reflect"
"strings"
)
@ -30,6 +31,7 @@ type Model struct {
limit int // 分页条数
data interface{} // 操作记录(支持Map/List/string类型)
batch int // 批量操作条数
filter bool // 是否按照表字段过滤data参数
cacheEnabled bool // 当前SQL操作是否开启查询缓存功能
cacheTime int // 查询缓存时间
cacheName string // 查询缓存名称
@ -98,6 +100,12 @@ func (md *Model) Fields(fields string) (*Model) {
return md
}
// 链式操作,过滤字段
func (md *Model) Filter() (*Model) {
md.filter = true
return md
}
// 链式操作condition支持string & gdb.Map
func (md *Model) Where(where interface{}, args ...interface{}) (*Model) {
md.where = formatCondition(where)
@ -159,7 +167,32 @@ func (md *Model) Data(data ...interface{}) (*Model) {
}
md.data = m
} else {
md.data = data[0]
switch data[0].(type) {
case List:
md.data = data[0]
case Map:
md.data = data[0]
default:
rv := reflect.ValueOf(data[0])
kind := rv.Kind()
if kind == reflect.Ptr {
rv = rv.Elem()
kind = rv.Kind()
}
switch kind {
case reflect.Slice: fallthrough
case reflect.Array:
list := make(List, rv.Len())
for i := 0; i < rv.Len(); i++ {
list[i] = gconv.Map(rv.Index(i).Interface())
}
md.data = list
case reflect.Map:
md.data = gconv.Map(data[0])
default:
md.data = data[0]
}
}
}
return md
}
@ -181,16 +214,24 @@ func (md *Model) Insert() (result sql.Result, err error) {
if md.batch > 0 {
batch = md.batch
}
if md.filter {
for k, m := range list {
list[k] = md.db.filterFields(md.tables, m)
}
}
if md.tx == nil {
return md.db.BatchInsert(md.tables, list, batch)
} else {
return md.tx.BatchInsert(md.tables, list, batch)
}
} else if dataMap, ok := md.data.(Map); ok {
} else if data, ok := md.data.(Map); ok {
if md.filter {
data = md.db.filterFields(md.tables, data)
}
if md.tx == nil {
return md.db.Insert(md.tables, dataMap)
return md.db.Insert(md.tables, data)
} else {
return md.tx.Insert(md.tables, dataMap)
return md.tx.Insert(md.tables, data)
}
}
return nil, errors.New("inserting into table with invalid data type")
@ -213,16 +254,24 @@ func (md *Model) Replace() (result sql.Result, err error) {
if md.batch > 0 {
batch = md.batch
}
if md.filter {
for k, m := range list {
list[k] = md.db.filterFields(md.tables, m)
}
}
if md.tx == nil {
return md.db.BatchReplace(md.tables, list, batch)
} else {
return md.tx.BatchReplace(md.tables, list, batch)
}
} else if dataMap, ok := md.data.(Map); ok {
} else if data, ok := md.data.(Map); ok {
if md.filter {
data = md.db.filterFields(md.tables, data)
}
if md.tx == nil {
return md.db.Replace(md.tables, dataMap)
return md.db.Replace(md.tables, data)
} else {
return md.tx.Replace(md.tables, dataMap)
return md.tx.Replace(md.tables, data)
}
}
return nil, errors.New("replacing into table with invalid data type")
@ -245,16 +294,24 @@ func (md *Model) Save() (result sql.Result, err error) {
if md.batch > 0 {
batch = md.batch
}
if md.filter {
for k, m := range list {
list[k] = md.db.filterFields(md.tables, m)
}
}
if md.tx == nil {
return md.db.BatchSave(md.tables, list, batch)
} else {
return md.tx.BatchSave(md.tables, list, batch)
}
} else if dataMap, ok := md.data.(Map); ok {
} else if data, ok := md.data.(Map); ok {
if md.filter {
data = md.db.filterFields(md.tables, data)
}
if md.tx == nil {
return md.db.Save(md.tables, dataMap)
return md.db.Save(md.tables, data)
} else {
return md.tx.Save(md.tables, dataMap)
return md.tx.Save(md.tables, data)
}
}
return nil, errors.New("saving into table with invalid data type")
@ -271,6 +328,13 @@ func (md *Model) Update() (result sql.Result, err error) {
if md.data == nil {
return nil, errors.New("updating table with empty data")
}
if md.filter {
if data, ok := md.data.(Map); ok {
if md.filter {
md.data = md.db.filterFields(md.tables, data)
}
}
}
if md.tx == nil {
return md.db.Update(md.tables, md.data, md.where, md.whereArgs ...)
} else {

View File

@ -8,8 +8,9 @@ import (
)
func TestModel_Insert(t *testing.T) {
result, err := db.Table("user").Data(g.Map{
result, err := db.Table("user").Filter().Data(g.Map{
"id" : 1,
"uid" : 1,
"passport" : "t1",
"password" : "25d55ad283aa400af464c76d713c07ad",
"nickname" : "T1",
@ -23,9 +24,10 @@ func TestModel_Insert(t *testing.T) {
}
func TestModel_Batch(t *testing.T) {
result, err := db.Table("user").Data(g.List{
result, err := db.Table("user").Filter().Data(g.List{
{
"id" : 2,
"uid" : 2,
"passport" : "t2",
"password" : "25d55ad283aa400af464c76d713c07ad",
"nickname" : "T2",
@ -33,6 +35,7 @@ func TestModel_Batch(t *testing.T) {
},
{
"id" : 3,
"uid" : 3,
"passport" : "t3",
"password" : "25d55ad283aa400af464c76d713c07ad",
"nickname" : "T3",

23
g/g.go
View File

@ -10,14 +10,27 @@ 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{}
type MapStrStr = map[string]string
type MapStrInt = map[string]int
type MapIntStr = map[int]string
type MapIntInt = map[int]int
// 常用list数据结构(使用别名)
type List = []Map
type List = []Map
type ListStrStr = []map[string]string
type ListStrInt = []map[string]int
type ListIntStr = []map[int]string
type ListIntInt = []map[int]int
// 常用slice数据结构(使用别名)
type Slice = []interface{}
type Array = Slice
type Slice = []interface{}
type SliceStr = []string
type SliceInt = []int
type Array = Slice
type ArrayStr = SliceStr
type ArrayInt = SliceInt

View File

@ -15,6 +15,7 @@ import (
"gitee.com/johng/gf/g/container/gtype"
"gitee.com/johng/gf/g/os/gcache"
"gitee.com/johng/gf/g/os/genv"
"gitee.com/johng/gf/g/os/gfile"
"gitee.com/johng/gf/g/os/glog"
"gitee.com/johng/gf/g/os/gproc"
"gitee.com/johng/gf/g/os/gtime"
@ -254,6 +255,10 @@ func (s *Server) Start() error {
}
})
}
// 是否处于开发环境
if gfile.MainPkgPath() != "" {
glog.Backtrace(false, 0).Notice("GF notices that you're in develop environment, so error logs are auto enabled to stdout.")
}
// 打印展示路由表
s.DumpRoutesMap()

View File

@ -9,6 +9,7 @@ package ghttp
import (
"fmt"
"gitee.com/johng/gf/g/os/gfile"
"net/http"
)
@ -36,7 +37,7 @@ func (s *Server) handleErrorLog(error interface{}, r *Request) {
r.Response.WriteStatus(http.StatusInternalServerError)
// 错误输出默认是开启的
if !s.IsErrorLogEnabled() {
if !s.IsErrorLogEnabled() && gfile.MainPkgPath() == "" {
return
}
@ -56,5 +57,9 @@ func (s *Server) handleErrorLog(error interface{}, r *Request) {
s.logger.Cat("error").Backtrace(true, 2).StdPrint(true).Error(content)
} else {
s.logger.Cat("error").Backtrace(true, 2).Error(content)
// 开发环境下(MainPkgPath)自动输出错误信息到标准输出
if gfile.MainPkgPath() != "" {
s.logger.Cat("error").Backtrace(true, 2).StdPrint(true).Error(content)
}
}
}

View File

@ -370,7 +370,7 @@ func homeWindows() (string, error) {
return home, nil
}
// 获取入口函数文件所在目录(main包文件目录)
// 获取入口函数文件所在目录(main包文件目录),
// **仅对源码开发环境有效(即仅对生成该可执行文件的系统下有效)**
func MainPkgPath() string {
path := mainPkgPath.Val()
@ -401,6 +401,7 @@ func MainPkgPath() string {
if p == f {
break
}
// 会自动扫描源码寻找main包
if paths, err := ScanDir(p, "*.go"); err == nil && len(paths) > 0 {
for _, path := range paths {
if gregex.IsMatchString(`package\s+main`, GetContents(path)) {

View File

@ -99,8 +99,11 @@ func Map(i interface{}, noTagCheck...bool) map[string]interface{} {
rt := rv.Type()
name := ""
for i := 0; i < rv.NumField(); i++ {
if name = rt.Field(i).Tag.Get("json"); name == "" {
name = rt.Field(i).Name
// 检查json tag
if len(noTagCheck) == 0 || !noTagCheck[0] {
if name = rt.Field(i).Tag.Get("json"); name == "" {
name = rt.Field(i).Name
}
}
m[name] = rv.Field(i).Interface()
}

View File

@ -14,21 +14,26 @@ import (
// 将变量i转换为time.Time类型
func Time(i interface{}, format...string) time.Time {
s := String(i)
// 优先使用用户输入日期格式进行转换
if len(format) > 0 {
t, _ := gtime.StrToTimeFormat(s, format[0])
return t.Time
}
if gstr.IsNumeric(s) {
return gtime.NewFromTimeStamp(Int64(s)).Time
} else {
t, _ := gtime.StrToTime(s)
return t.Time
}
return GTime(i, format...).Time
}
// 将变量i转换为time.Time类型
func TimeDuration(i interface{}) time.Duration {
return time.Duration(Int64(i))
}
// 将变量i转换为time.Time类型
func GTime(i interface{}, format...string) *gtime.Time {
s := String(i)
// 优先使用用户输入日期格式进行转换
if len(format) > 0 {
t, _ := gtime.StrToTimeFormat(s, format[0])
return t
}
if gstr.IsNumeric(s) {
return gtime.NewFromTimeStamp(Int64(s))
} else {
t, _ := gtime.StrToTime(s)
return t
}
}

View File

@ -4,7 +4,7 @@
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://gitee.com/johng/gf.
// 其他工具包
// 工具包
package gutil
import (

View File

@ -78,6 +78,10 @@ func CheckMap(params interface{}, rules interface{}, msgs...CustomMsg) *Error {
value := (interface{})(nil)
// 这里的rule变量为多条校验规则不包含名字或者错误信息定义
for key, rule := range checkRules {
// 如果规则为空,那么不执行校验
if len(rule) == 0 {
continue
}
value = nil
if v, ok := data[key]; ok {
value = v

View File

@ -10,7 +10,7 @@ func main() {
// 开启调试模式以便于记录所有执行的SQL
db.SetDebug(true)
r, _ := db.Table("user").All()
r, _ := db.Table("test").Where("id IN (?,?)", 1,2).All()
if r != nil {
fmt.Println(r.ToList())
}