mirror of
https://gitee.com/johng/gf
synced 2026-06-06 16:21:40 +08:00
done refacting gdb package
This commit is contained in:
@ -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...)
|
||||
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
|
||||
// 执行底层数据库操作的核心接口
|
||||
|
||||
@ -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
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
23
g/g.go
@ -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
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)) {
|
||||
|
||||
@ -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()
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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 (
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user