mirror of
https://gitee.com/johng/gf
synced 2026-06-06 02:25:47 +08:00
improve model feature
This commit is contained in:
4
.example/frame/main/model/config.toml
Normal file
4
.example/frame/main/model/config.toml
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
# MySQL数据库配置
|
||||
[database]
|
||||
link = "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
|
||||
15
.example/frame/main/model/model1.go
Normal file
15
.example/frame/main/model/model1.go
Normal file
@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/.example/frame/mvc/model/test"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
g.DB().SetDebug(true)
|
||||
user, err := test.ModelUser().One()
|
||||
g.Dump(err)
|
||||
g.Dump(user)
|
||||
user.Password = "1"
|
||||
g.Dump(user.Update())
|
||||
}
|
||||
10
.example/frame/mvc/model/test/init.go
Normal file
10
.example/frame/mvc/model/test/init.go
Normal file
@ -0,0 +1,10 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/database/gdb"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
func DB() gdb.DB {
|
||||
return g.DB()
|
||||
}
|
||||
81
.example/frame/mvc/model/test/user.go
Normal file
81
.example/frame/mvc/model/test/user.go
Normal file
@ -0,0 +1,81 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
"github.com/gogf/gf/debug/gdebug"
|
||||
"github.com/gogf/gf/frame/gins"
|
||||
|
||||
"github.com/gogf/gf/database/gdb"
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
Id int `orm:"id,primary" json:"id"`
|
||||
Passport string `orm:"passport" json:"passport"`
|
||||
Password string `orm:"password" json:"password"`
|
||||
NickName string `orm:"nickname" json:"nick_name"`
|
||||
CreateTime *gtime.Time `orm:"create_time" json:"create_time"`
|
||||
}
|
||||
|
||||
type UserModel struct {
|
||||
*gdb.Model
|
||||
TableName string
|
||||
}
|
||||
|
||||
var (
|
||||
UserTableName = "user"
|
||||
gUserModelCacheKey = gdebug.CallerFilePath()
|
||||
)
|
||||
|
||||
func ModelUser() *UserModel {
|
||||
return gins.GetOrSetFunc(gUserModelCacheKey, func() interface{} {
|
||||
return &UserModel{
|
||||
DB().Table(UserTableName).Safe(),
|
||||
UserTableName,
|
||||
}
|
||||
}).(*UserModel)
|
||||
}
|
||||
|
||||
func (r *User) Insert() (result sql.Result, err error) {
|
||||
return ModelUser().Data(r).Insert()
|
||||
}
|
||||
|
||||
func (r *User) Replace() (result sql.Result, err error) {
|
||||
return ModelUser().Data(r).Replace()
|
||||
}
|
||||
|
||||
func (r *User) Save() (result sql.Result, err error) {
|
||||
return ModelUser().Data(r).Save()
|
||||
}
|
||||
|
||||
func (r *User) Update() (result sql.Result, err error) {
|
||||
return ModelUser().Data(r).Where(gdb.GetWhereConditionOfStruct(r)).Update()
|
||||
}
|
||||
|
||||
func (r *User) Delete() (result sql.Result, err error) {
|
||||
return ModelUser().Where(gdb.GetWhereConditionOfStruct(r)).Delete()
|
||||
}
|
||||
|
||||
func (m *UserModel) Select() ([]*User, error) {
|
||||
return m.All()
|
||||
}
|
||||
|
||||
func (m *UserModel) All() ([]*User, error) {
|
||||
array := ([]*User)(nil)
|
||||
if err := m.Scan(&array); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return array, nil
|
||||
}
|
||||
|
||||
func (m *UserModel) One() (*User, error) {
|
||||
list, err := m.All()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(list) > 0 {
|
||||
return list[0], nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
17
.example/net/ghttp/server/admin/admin.go
Normal file
17
.example/net/ghttp/server/admin/admin.go
Normal file
@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.SetNameToUriType(ghttp.NAME_TO_URI_TYPE_FULLNAME)
|
||||
s.EnableAdmin()
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
r.Response.Write("hello world")
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
@ -13,12 +13,12 @@ func main() {
|
||||
//w := gtimer.New(10, 10*time.Millisecond)
|
||||
fmt.Println("start:", time.Now())
|
||||
for i := 0; i < 1000000; i++ {
|
||||
gtimer.AddTimes(time.Second, 2, func() {
|
||||
gtimer.AddTimes(time.Second, 1, func() {
|
||||
v.Add(1)
|
||||
})
|
||||
}
|
||||
fmt.Println("end :", time.Now())
|
||||
time.Sleep(5000 * time.Millisecond)
|
||||
time.Sleep(1000 * time.Millisecond)
|
||||
fmt.Println(v.Val(), time.Now())
|
||||
|
||||
//gtimer.AddSingleton(time.Second, func() {
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/os/glog"
|
||||
)
|
||||
|
||||
func main() {
|
||||
glog.Error("error")
|
||||
v := g.NewVar(1)
|
||||
glog.Error(v.String())
|
||||
glog.Errorfln("error")
|
||||
}
|
||||
|
||||
@ -14,6 +14,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/internal/structs"
|
||||
|
||||
"github.com/gogf/gf/text/gregex"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
@ -24,6 +26,38 @@ type apiString interface {
|
||||
String() string
|
||||
}
|
||||
|
||||
const (
|
||||
OrmTagForStruct = "orm"
|
||||
OrmTagForUnique = "unique"
|
||||
OrmTagForPrimary = "primary"
|
||||
)
|
||||
|
||||
// 获得struct对象对应的where查询条件
|
||||
func GetWhereConditionOfStruct(pointer interface{}) (where string, args []interface{}) {
|
||||
array := ([]string)(nil)
|
||||
for tag, field := range structs.TagMapField(pointer, []string{OrmTagForStruct}, true) {
|
||||
array = strings.Split(tag, ",")
|
||||
if len(array) > 1 && gstr.InArray([]string{OrmTagForUnique, OrmTagForPrimary}, array[1]) {
|
||||
return array[0], []interface{}{field.Value()}
|
||||
}
|
||||
if len(where) > 0 {
|
||||
where += " "
|
||||
}
|
||||
where += tag + "=?"
|
||||
args = append(args, field.Value())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 获得orm标签与属性的映射关系
|
||||
func GetOrmMappingOfStruct(pointer interface{}) map[string]string {
|
||||
mapping := make(map[string]string)
|
||||
for tag, attr := range structs.TagMapName(pointer, []string{OrmTagForStruct}, true) {
|
||||
mapping[strings.Split(tag, ",")[0]] = attr
|
||||
}
|
||||
return mapping
|
||||
}
|
||||
|
||||
// 格式化SQL语句.
|
||||
func formatQuery(query string, args []interface{}) (newQuery string, newArgs []interface{}) {
|
||||
return handlerSliceArguments(query, args)
|
||||
@ -138,7 +172,7 @@ func getInsertOperationByOption(option int) string {
|
||||
// 将对象转换为map,如果对象带有继承对象,那么执行递归转换。
|
||||
// 该方法用于将变量传递给数据库执行之前。
|
||||
func structToMap(obj interface{}) map[string]interface{} {
|
||||
data := gconv.Map(obj)
|
||||
data := gconv.Map(obj, OrmTagForStruct)
|
||||
for key, value := range data {
|
||||
rv := reflect.ValueOf(value)
|
||||
kind := rv.Kind()
|
||||
@ -183,7 +217,7 @@ func bindArgsToQuery(query string, args []interface{}) string {
|
||||
}
|
||||
switch kind {
|
||||
case reflect.String, reflect.Map, reflect.Slice, reflect.Array:
|
||||
return "'" + gconv.String(args[index]) + "'"
|
||||
return "'" + gstr.QuoteMeta(gconv.String(args[index]), "'") + "'"
|
||||
}
|
||||
return gconv.String(args[index])
|
||||
}
|
||||
@ -194,5 +228,5 @@ func bindArgsToQuery(query string, args []interface{}) string {
|
||||
|
||||
// 使用递归的方式将map键值对映射到struct对象上,注意参数<pointer>是一个指向struct的指针。
|
||||
func mapToStruct(data map[string]interface{}, pointer interface{}) error {
|
||||
return gconv.StructDeep(data, pointer)
|
||||
return gconv.StructDeep(data, pointer, GetOrmMappingOfStruct(pointer))
|
||||
}
|
||||
|
||||
@ -490,21 +490,21 @@ func (md *Model) Value() (Value, error) {
|
||||
}
|
||||
|
||||
// 链式操作,查询单条记录,并自动转换为struct对象, 参数必须为对象的指针,不能为空指针。
|
||||
func (md *Model) Struct(objPointer interface{}) error {
|
||||
func (md *Model) Struct(pointer interface{}) error {
|
||||
one, err := md.One()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return one.ToStruct(objPointer)
|
||||
return one.ToStruct(pointer)
|
||||
}
|
||||
|
||||
// 链式操作,查询多条记录,并自动转换为指定的slice对象, 如: []struct/[]*struct。
|
||||
func (md *Model) Structs(objPointerSlice interface{}) error {
|
||||
func (md *Model) Structs(pointer interface{}) error {
|
||||
r, err := md.All()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return r.ToStructs(objPointerSlice)
|
||||
return r.ToStructs(pointer)
|
||||
}
|
||||
|
||||
// 链式操作,将结果转换为指定的struct/*struct/[]struct/[]*struct,
|
||||
|
||||
@ -12,6 +12,8 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/gogf/gf/encoding/gini"
|
||||
"github.com/gogf/gf/encoding/gtoml"
|
||||
"github.com/gogf/gf/encoding/gxml"
|
||||
@ -21,7 +23,6 @@ import (
|
||||
"github.com/gogf/gf/os/gfile"
|
||||
"github.com/gogf/gf/text/gregex"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// New creates a Json object with any variable type of <data>,
|
||||
@ -186,16 +187,14 @@ func doLoadContent(dataType string, data []byte, safe ...bool) (*Json, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if result == nil {
|
||||
decoder := json.NewDecoder(bytes.NewReader(data))
|
||||
decoder.UseNumber()
|
||||
if err := decoder.Decode(&result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch result.(type) {
|
||||
case string, []byte:
|
||||
return nil, fmt.Errorf(`json decoding failed for content: %s`, string(data))
|
||||
}
|
||||
decoder := json.NewDecoder(bytes.NewReader(data))
|
||||
decoder.UseNumber()
|
||||
if err := decoder.Decode(&result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch result.(type) {
|
||||
case string, []byte:
|
||||
return nil, fmt.Errorf(`json decoding failed for content: %s`, string(data))
|
||||
}
|
||||
return New(result, safe...), nil
|
||||
}
|
||||
|
||||
@ -83,7 +83,7 @@ func (s *Server) BindController(pattern string, c Controller, methods ...string)
|
||||
// 这里处理新增/user路由绑定。
|
||||
// 注意,当pattern带有内置变量时,不会自动加该路由。
|
||||
if strings.EqualFold(mname, "Index") && !gregex.IsMatchString(`\{\.\w+\}`, pattern) {
|
||||
p := gstr.PosR(key, "/index")
|
||||
p := gstr.PosRI(key, "/index")
|
||||
k := key[0:p] + key[p+6:]
|
||||
if len(k) == 0 || k[0] == '@' {
|
||||
k = "/" + k
|
||||
|
||||
@ -87,7 +87,7 @@ func (s *Server) BindObject(pattern string, obj interface{}, methods ...string)
|
||||
// 如果方法中带有Index方法,那么额外自动增加一个路由规则匹配主URI。
|
||||
// 注意,当pattern带有内置变量时,不会自动加该路由。
|
||||
if strings.EqualFold(mname, "Index") && !gregex.IsMatchString(`\{\.\w+\}`, pattern) {
|
||||
p := gstr.PosR(key, "/index")
|
||||
p := gstr.PosRI(key, "/index")
|
||||
k := key[0:p] + key[p+6:]
|
||||
if len(k) == 0 || k[0] == '@' {
|
||||
k = "/" + k
|
||||
|
||||
@ -45,6 +45,7 @@ func MainPkgPath() string {
|
||||
if path != "" {
|
||||
return path
|
||||
}
|
||||
lastFile := ""
|
||||
for i := 1; i < 10000; i++ {
|
||||
if _, file, _, ok := runtime.Caller(i); ok {
|
||||
if goRootForFilter != "" && len(file) >= len(goRootForFilter) && file[0:len(goRootForFilter)] == goRootForFilter {
|
||||
@ -58,21 +59,26 @@ func MainPkgPath() string {
|
||||
if Ext(file) != ".go" {
|
||||
continue
|
||||
}
|
||||
// separator of <file> '/' will be converted to Separator.
|
||||
for path = Dir(file); len(path) > 1 && Exists(path) && path[len(path)-1] != os.PathSeparator; {
|
||||
files, _ := ScanDir(path, "*.go")
|
||||
for _, v := range files {
|
||||
if gregex.IsMatchString(`package\s+main`, GetContents(v)) {
|
||||
mainPkgPath.Set(path)
|
||||
return path
|
||||
}
|
||||
}
|
||||
path = Dir(path)
|
||||
lastFile = file
|
||||
if gregex.IsMatchString(`package\s+main`, GetContents(file)) {
|
||||
mainPkgPath.Set(Dir(file))
|
||||
return Dir(file)
|
||||
}
|
||||
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
if lastFile != "" {
|
||||
for path = Dir(lastFile); len(path) > 1 && Exists(path) && path[len(path)-1] != os.PathSeparator; {
|
||||
files, _ := ScanDir(path, "*.go")
|
||||
for _, v := range files {
|
||||
if gregex.IsMatchString(`package\s+main`, GetContents(v)) {
|
||||
mainPkgPath.Set(path)
|
||||
return path
|
||||
}
|
||||
}
|
||||
path = Dir(path)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
@ -7,19 +7,6 @@
|
||||
// Package gres provides resource management and packing/unpacking feature between files and bytes.
|
||||
package gres
|
||||
|
||||
const (
|
||||
gPACKAGE_TEMPLATE = `package %s
|
||||
|
||||
import "github.com/gogf/gf/os/gres"
|
||||
|
||||
func init() {
|
||||
if err := gres.Add(%s); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
`
|
||||
)
|
||||
|
||||
var (
|
||||
// Default resource object.
|
||||
defaultResource = Instance()
|
||||
|
||||
@ -16,6 +16,19 @@ import (
|
||||
"github.com/gogf/gf/os/gfile"
|
||||
)
|
||||
|
||||
const (
|
||||
gPACKAGE_TEMPLATE = `package %s
|
||||
|
||||
import "github.com/gogf/gf/os/gres"
|
||||
|
||||
func init() {
|
||||
if err := gres.Add(%s); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
`
|
||||
)
|
||||
|
||||
// Pack packs the path specified by <srcPath> into bytes.
|
||||
// The unnecessary parameter <keyPrefix> indicates the prefix for each file
|
||||
// packed into the result bytes.
|
||||
|
||||
@ -569,14 +569,22 @@ func StripSlashes(str string) string {
|
||||
}
|
||||
|
||||
// QuoteMeta returns a version of str with a backslash character (\)
|
||||
// before every character that is among:
|
||||
// .\+*?[^]($)
|
||||
func QuoteMeta(str string) string {
|
||||
// before every character that is among: .\+*?[^]($)
|
||||
func QuoteMeta(str string, chars ...string) string {
|
||||
var buf bytes.Buffer
|
||||
for _, char := range str {
|
||||
switch char {
|
||||
case '.', '+', '\\', '(', '$', ')', '[', '^', ']', '*', '?':
|
||||
buf.WriteRune('\\')
|
||||
if len(chars) > 0 {
|
||||
for _, c := range chars[0] {
|
||||
if c == char {
|
||||
buf.WriteRune('\\')
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch char {
|
||||
case '.', '+', '\\', '(', '$', ')', '[', '^', ']', '*', '?':
|
||||
buf.WriteRune('\\')
|
||||
}
|
||||
}
|
||||
buf.WriteRune(char)
|
||||
}
|
||||
|
||||
@ -315,6 +315,9 @@ func Test_StripSlashes(t *testing.T) {
|
||||
func Test_QuoteMeta(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
gtest.Assert(gstr.QuoteMeta(`.\+*?[^]($)`), `\.\\\+\*\?\[\^\]\(\$\)`)
|
||||
gtest.Assert(gstr.QuoteMeta(`.\+*中国?[^]($)`), `\.\\\+\*中国\?\[\^\]\(\$\)`)
|
||||
gtest.Assert(gstr.QuoteMeta(`.''`, `'`), `.\'\'`)
|
||||
gtest.Assert(gstr.QuoteMeta(`中国.''`, `'`), `中国.\'\'`)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user