improve gdb/gtime

This commit is contained in:
John
2019-12-17 21:06:34 +08:00
parent a5a88222a6
commit 5f2be10563
15 changed files with 217 additions and 64 deletions

View File

@ -53,6 +53,12 @@ func FindValue(fieldsAndWhere ...interface{}) (gdb.Value, error) {
return Model.Value(fieldsAndWhere...)
}
// FindCount retrieves and returns the record number by a primary key or where conditions by
// Model.Where. Also see FindOne.
func FindCount(where ...interface{}) (int, error) {
return Model.Count(gdb.GetPrimaryKeyCondition(Primary, where...)...)
}
// Insert is alias of Model.Insert.
func Insert(data ...interface{}) (result sql.Result, err error) {
return Model.Insert(data...)

View File

@ -1,10 +1,10 @@
package main
import (
"github.com/gogf/gf/.example/frame/mvc/app/model/article"
"github.com/gogf/gf/frame/g"
"fmt"
"github.com/gogf/gf/os/gtime"
)
func main() {
g.Dump(article.FindAll(g.Slice{2, 3}))
fmt.Println(gtime.Timestamp())
}

View File

@ -93,9 +93,9 @@ func (bs *dbBase) doExec(link dbLink, query string, args ...interface{}) (result
query, args = formatQuery(query, args)
query = bs.db.handleSqlBeforeExec(query)
if bs.db.getDebug() {
mTime1 := gtime.Millisecond()
mTime1 := gtime.TimestampMilli()
result, err = link.Exec(query, args...)
mTime2 := gtime.Millisecond()
mTime2 := gtime.TimestampMilli()
s := &Sql{
Sql: query,
Args: args,

View File

@ -112,7 +112,14 @@ func (tx *TX) From(tables string) *Model {
return tx.Table(tables)
}
// TX sets the transaction for current operation.
// DB sets/changes the db object for current operation.
func (m *Model) DB(db DB) *Model {
model := m.getModel()
model.db = db
return model
}
// TX sets/changes the transaction for current operation.
func (m *Model) TX(tx *TX) *Model {
model := m.getModel()
model.tx = tx

View File

@ -20,7 +20,8 @@ import (
"github.com/gogf/gf/util/gconv"
)
// convertValue converts field value from database type to golang variable type.
// convertValue automatically checks and converts field value from database type
// to golang variable type.
func (bs *dbBase) convertValue(fieldValue []byte, fieldType string) interface{} {
t, _ := gregex.ReplaceString(`\(.+\)`, "", fieldType)
t = strings.ToLower(t)
@ -97,9 +98,9 @@ func (bs *dbBase) convertValue(fieldValue []byte, fieldType string) interface{}
}
}
// 将map的数据按照fields进行过滤只保留与表字段同名的数据
// filterFields removes all key-value pairs which are not the field of given table.
func (bs *dbBase) filterFields(table string, data map[string]interface{}) map[string]interface{} {
// It must use data copy here to avoid changing the origin data map.
// It must use data copy here to avoid its changing the origin data map.
newDataMap := make(map[string]interface{}, len(data))
if fields, err := bs.db.TableFields(table); err == nil {
for k, v := range data {
@ -111,7 +112,7 @@ func (bs *dbBase) filterFields(table string, data map[string]interface{}) map[st
return newDataMap
}
// 返回当前数据库所有的数据表名称
// Tables returns the table name array of current schema.
func (bs *dbBase) Tables() (tables []string, err error) {
result := (Result)(nil)
result, err = bs.GetAll(`SHOW TABLES`)
@ -126,9 +127,12 @@ func (bs *dbBase) Tables() (tables []string, err error) {
return
}
// 获得指定表表的数据结构构造成map哈希表返回其中键名为表字段名称键值为字段数据结构.
// TableFields retrieves and returns the fields of given table.
// Note that it returns a map containing the field name and its corresponding fields.
// As a map is unsorted, the TableField struct has a "Index" field marks its sequence in the fields.
//
// It's using cache feature to enhance the performance, which is never expired util the process restarts.
func (bs *dbBase) TableFields(table string) (fields map[string]*TableField, err error) {
// 缓存不存在时会查询数据表结构,缓存后不过期,直至程序重启(重新部署)
v := bs.cache.GetOrSetFunc("table_fields_"+table, func() interface{} {
result := (Result)(nil)
result, err = bs.GetAll(fmt.Sprintf(`SHOW FULL COLUMNS FROM %s`, bs.db.quoteWord(table)))

View File

@ -9,23 +9,24 @@ package gdb
import (
"database/sql"
"github.com/gogf/gf/container/gmap"
"github.com/gogf/gf/util/gconv"
"github.com/gogf/gf/encoding/gparser"
)
// 将记录结果转换为JSON字符串
// Json converts <r> to JSON format content.
func (r Record) Json() string {
content, _ := gparser.VarToJson(r.Map())
return string(content)
return gconv.UnsafeBytesToStr(content)
}
// 将记录结果转换为XML字符串
// Xml converts <r> to XML format content.
func (r Record) Xml(rootTag ...string) string {
content, _ := gparser.VarToXml(r.Map(), rootTag...)
return string(content)
return gconv.UnsafeBytesToStr(content)
}
// 将Record转换为Map类型
// Map converts <r> to map[string]interface{}.
func (r Record) Map() Map {
m := make(map[string]interface{})
for k, v := range r {
@ -34,12 +35,13 @@ func (r Record) Map() Map {
return m
}
// 将Record转换为常用的gmap.StrAnyMap类型
// GMap converts <r> to a gmap.
func (r Record) GMap() *gmap.StrAnyMap {
return gmap.NewStrAnyMapFrom(r.Map())
}
// 将Map变量映射到指定的struct对象中注意参数应当是一个对象的指针
// Struct converts <r> to a struct.
// Note that the parameter <pointer> should be type of *struct/**struct.
func (r Record) Struct(pointer interface{}) error {
if r == nil {
return sql.ErrNoRows

View File

@ -14,19 +14,19 @@ import (
"github.com/gogf/gf/encoding/gparser"
)
// 将结果集转换为JSON字符串
// Json converts <r> to JSON format content.
func (r Result) Json() string {
content, _ := gparser.VarToJson(r.List())
return string(content)
}
// 将结果集转换为XML字符串
// Xml converts <r> to XML format content.
func (r Result) Xml(rootTag ...string) string {
content, _ := gparser.VarToXml(r.List(), rootTag...)
return string(content)
}
// 将结果集转换为List类型返回便于json处理
// List converts <r> to a List.
func (r Result) List() List {
l := make(List, len(r))
for k, v := range r {
@ -35,7 +35,7 @@ func (r Result) List() List {
return l
}
// 将结果列表按照指定的字段值做map[string]Map
// MapKeyStr converts <r> to a map[string]Map of which key is specified by <key>.
func (r Result) MapKeyStr(key string) map[string]Map {
m := make(map[string]Map)
for _, item := range r {
@ -46,7 +46,7 @@ func (r Result) MapKeyStr(key string) map[string]Map {
return m
}
// 将结果列表按照指定的字段值做map[int]Map
// MapKeyInt converts <r> to a map[int]Map of which key is specified by <key>.
func (r Result) MapKeyInt(key string) map[int]Map {
m := make(map[int]Map)
for _, item := range r {
@ -57,7 +57,7 @@ func (r Result) MapKeyInt(key string) map[int]Map {
return m
}
// 将结果列表按照指定的字段值做map[uint]Map
// MapKeyUint converts <r> to a map[uint]Map of which key is specified by <key>.
func (r Result) MapKeyUint(key string) map[uint]Map {
m := make(map[uint]Map)
for _, item := range r {
@ -68,7 +68,7 @@ func (r Result) MapKeyUint(key string) map[uint]Map {
return m
}
// 将结果列表按照指定的字段值做map[string]Record
// RecordKeyInt converts <r> to a map[int]Record of which key is specified by <key>.
func (r Result) RecordKeyStr(key string) map[string]Record {
m := make(map[string]Record)
for _, item := range r {
@ -79,7 +79,7 @@ func (r Result) RecordKeyStr(key string) map[string]Record {
return m
}
// 将结果列表按照指定的字段值做map[int]Record
// RecordKeyInt converts <r> to a map[int]Record of which key is specified by <key>.
func (r Result) RecordKeyInt(key string) map[int]Record {
m := make(map[int]Record)
for _, item := range r {
@ -90,7 +90,7 @@ func (r Result) RecordKeyInt(key string) map[int]Record {
return m
}
// 将结果列表按照指定的字段值做map[uint]Record
// RecordKeyUint converts <r> to a map[uint]Record of which key is specified by <key>.
func (r Result) RecordKeyUint(key string) map[uint]Record {
m := make(map[uint]Record)
for _, item := range r {
@ -101,7 +101,8 @@ func (r Result) RecordKeyUint(key string) map[uint]Record {
return m
}
// 将结果列表转换为指定对象的slice
// Structs converts <r> to struct slice.
// Note that the parameter <pointer> should be type of *[]struct/*[]*struct.
func (r Result) Structs(pointer interface{}) (err error) {
l := len(r)
if l == 0 {

View File

@ -168,6 +168,7 @@ func Database(name ...string) gdb.DB {
}
instanceKey := fmt.Sprintf("%s.%s", gFRAME_CORE_COMPONENT_NAME_DATABASE, group)
db := instances.GetOrSetFuncLock(instanceKey, func() interface{} {
// Configuration already exists.
if gdb.GetConfig(group) != nil {
db, err := gdb.Instance(group)
if err != nil {

View File

@ -7,6 +7,7 @@
package gmvc
import (
"github.com/gogf/gf/frame/gins"
"sync"
"github.com/gogf/gf/util/gmode"
@ -26,7 +27,7 @@ type View struct {
// 创建一个MVC请求中使用的视图对象
func NewView(w *ghttp.Response) *View {
return &View{
view: gview.New(),
view: gins.View(),
data: make(gview.Params),
response: w,
}

View File

@ -615,3 +615,58 @@ func Test_Middleware_CORSAndAuth(t *testing.T) {
gtest.Assert(client.GetContent("/api.v2/user/list", "token=123456"), "list")
})
}
func MiddlewareScope1(r *ghttp.Request) {
r.Response.Write("a")
r.Middleware.Next()
r.Response.Write("b")
}
func MiddlewareScope2(r *ghttp.Request) {
r.Response.Write("c")
r.Middleware.Next()
r.Response.Write("d")
}
func MiddlewareScope3(r *ghttp.Request) {
r.Response.Write("e")
r.Middleware.Next()
r.Response.Write("f")
}
func Test_Middleware_Scope(t *testing.T) {
p := ports.PopRand()
s := g.Server(p)
s.Group("/", func(group *ghttp.RouterGroup) {
group.Middleware(MiddlewareScope1)
group.ALL("/scope1", func(r *ghttp.Request) {
r.Response.Write("1")
})
group.Group("/", func(group *ghttp.RouterGroup) {
group.Middleware(MiddlewareScope2)
group.ALL("/scope2", func(r *ghttp.Request) {
r.Response.Write("2")
})
})
group.Group("/", func(group *ghttp.RouterGroup) {
group.Middleware(MiddlewareScope3)
group.ALL("/scope3", func(r *ghttp.Request) {
r.Response.Write("3")
})
})
})
s.SetPort(p)
s.SetDumpRouterMap(false)
s.Start()
defer s.Shutdown()
time.Sleep(100 * time.Millisecond)
gtest.Case(t, func() {
client := ghttp.NewClient()
client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", p))
gtest.Assert(client.GetContent("/"), "Not Found")
gtest.Assert(client.GetContent("/scope1"), "a1b")
gtest.Assert(client.GetContent("/scope2"), "ac2db")
gtest.Assert(client.GetContent("/scope3"), "ae3fb")
})
}

View File

@ -96,24 +96,48 @@ func SetTimeZone(zone string) error {
return err
}
// Nanosecond returns the timestamp in nanoseconds.
func Nanosecond() int64 {
return time.Now().UnixNano()
// Timestamp returns the timestamp in seconds.
func Timestamp() int64 {
return Now().Timestamp()
}
// Microsecond returns the timestamp in microseconds.
func Microsecond() int64 {
return time.Now().UnixNano() / 1e3
// TimestampMilli returns the timestamp in milliseconds.
func TimestampMilli() int64 {
return Now().TimestampMilli()
}
// Millisecond returns the timestamp in milliseconds.
func Millisecond() int64 {
return time.Now().UnixNano() / 1e6
// TimestampMicro returns the timestamp in microseconds.
func TimestampMicro() int64 {
return Now().TimestampMicro()
}
// TimestampNano returns the timestamp in nanoseconds.
func TimestampNano() int64 {
return Now().TimestampNano()
}
// Second returns the timestamp in seconds.
// Deprecated, use Timestamp instead.
func Second() int64 {
return time.Now().Unix()
return Timestamp()
}
// Millisecond returns the timestamp in milliseconds.
// Deprecated, use TimestampMilli instead.
func Millisecond() int64 {
return TimestampMilli()
}
// Microsecond returns the timestamp in microseconds.
// Deprecated, use TimestampMicro instead.
func Microsecond() int64 {
return TimestampMicro()
}
// Nanosecond returns the timestamp in nanoseconds.
// Deprecated, use TimestampNano instead.
func Nanosecond() int64 {
return TimestampNano()
}
// Date returns current date in string like "2006-01-02".

View File

@ -126,7 +126,12 @@ func (t *Time) Format(format string) string {
return buffer.String()
}
// FormatTo formats and returns a new Time object with given custom <format>.
// FormatNew formats and returns a new Time object with given custom <format>.
func (t *Time) FormatNew(format string) *Time {
return NewFromStr(t.Format(format))
}
// FormatTo formats <t> with given custom <format>.
func (t *Time) FormatTo(format string) *Time {
t.Time = NewFromStr(t.Format(format)).Time
return t
@ -137,7 +142,12 @@ func (t *Time) Layout(layout string) string {
return t.Time.Format(layout)
}
// Layout formats the time with stdlib layout and returns the new Time object.
// LayoutNew formats the time with stdlib layout and returns the new Time object.
func (t *Time) LayoutNew(layout string) *Time {
return NewFromStr(t.Layout(layout))
}
// LayoutTo formats <t> with stdlib layout.
func (t *Time) LayoutTo(layout string) *Time {
t.Time = NewFromStr(t.Layout(layout)).Time
return t

View File

@ -78,24 +78,48 @@ func NewFromTimeStamp(timestamp int64) *Time {
}
}
// Second returns the timestamp in seconds.
func (t *Time) Second() int64 {
// Timestamp returns the timestamp in seconds.
func (t *Time) Timestamp() int64 {
return t.UnixNano() / 1e9
}
// Nanosecond returns the timestamp in nanoseconds.
func (t *Time) Nanosecond() int64 {
return t.UnixNano()
// TimestampMilli returns the timestamp in milliseconds.
func (t *Time) TimestampMilli() int64 {
return t.UnixNano() / 1e6
}
// Microsecond returns the timestamp in microseconds.
func (t *Time) Microsecond() int64 {
// TimestampMicro returns the timestamp in microseconds.
func (t *Time) TimestampMicro() int64 {
return t.UnixNano() / 1e3
}
// Millisecond returns the timestamp in milliseconds.
func (t *Time) Millisecond() int64 {
return t.UnixNano() / 1e6
// TimestampNano returns the timestamp in nanoseconds.
func (t *Time) TimestampNano() int64 {
return t.UnixNano()
}
// Second returns the second offset within the minute specified by t,
// in the range [0, 59].
func (t *Time) Second() int {
return t.Time.Second()
}
// Millisecond returns the millisecond offset within the second specified by t,
// in the range [0, 999].
func (t *Time) Millisecond() int {
return t.Time.Nanosecond() / 1e6
}
// Microsecond returns the microsecond offset within the second specified by t,
// in the range [0, 999999].
func (t *Time) Microsecond() int {
return t.Time.Nanosecond() / 1e3
}
// Nanosecond returns the nanosecond offset within the second specified by t,
// in the range [0, 999999999].
func (t *Time) Nanosecond() int {
return t.Time.Nanosecond()
}
// String returns current time object as string.
@ -196,6 +220,25 @@ func (t *Time) Truncate(d time.Duration) *Time {
return t
}
// Equal reports whether t and u represent the same time instant.
// Two times can be equal even if they are in different locations.
// For example, 6:00 +0200 CEST and 4:00 UTC are Equal.
// See the documentation on the Time type for the pitfalls of using == with
// Time values; most code should use Equal instead.
func (t *Time) Equal(u *Time) bool {
return t.Time.Equal(u.Time)
}
// Before reports whether the time instant t is before u.
func (t *Time) Before(u *Time) bool {
return t.Time.Before(u.Time)
}
// After reports whether the time instant t is after u.
func (t *Time) After(u *Time) bool {
return t.Time.After(u.Time)
}
// Sub returns the duration t-u. If the result exceeds the maximum (or minimum)
// value that can be stored in a Duration, the maximum (or minimum) duration
// will be returned.

View File

@ -73,28 +73,28 @@ func Test_NewFromTimeStamp(t *testing.T) {
func Test_Time_Second(t *testing.T) {
gtest.Case(t, func() {
timeTemp := gtime.Now()
gtest.Assert(timeTemp.Second(), timeTemp.Time.Unix())
gtest.Assert(timeTemp.Second(), timeTemp.Time.Second())
})
}
func Test_Time_Nanosecond(t *testing.T) {
gtest.Case(t, func() {
timeTemp := gtime.Now()
gtest.Assert(timeTemp.Nanosecond(), timeTemp.Time.UnixNano())
gtest.Assert(timeTemp.Nanosecond(), timeTemp.Time.Nanosecond())
})
}
func Test_Time_Microsecond(t *testing.T) {
gtest.Case(t, func() {
timeTemp := gtime.Now()
gtest.Assert(timeTemp.Microsecond(), timeTemp.Time.UnixNano()/1e3)
gtest.Assert(timeTemp.Microsecond(), timeTemp.Time.Nanosecond()/1e3)
})
}
func Test_Time_Millisecond(t *testing.T) {
gtest.Case(t, func() {
timeTemp := gtime.Now()
gtest.Assert(timeTemp.Millisecond(), timeTemp.Time.UnixNano()/1e6)
gtest.Assert(timeTemp.Millisecond(), timeTemp.Time.Nanosecond()/1e6)
})
}

View File

@ -15,6 +15,7 @@ import (
"github.com/gogf/gf/os/gfcache"
"github.com/gogf/gf/os/gfsnotify"
"github.com/gogf/gf/os/gmlock"
"github.com/gogf/gf/text/gstr"
"github.com/gogf/gf/util/gconv"
"strconv"
"strings"
@ -135,11 +136,10 @@ func (view *View) Parse(file string, params ...Params) (result string, err error
if err := tpl.Execute(buffer, variables); err != nil {
return "", err
}
return view.i18nTranslate(buffer.String(), variables), nil
// TODO any graceful plan to replace "<no value>"?
//result = gstr.Replace(buffer.String(), "<no value>", "")
//result = view.i18nTranslate(result, variables)
//return result, nil
result = gstr.Replace(buffer.String(), "<no value>", "")
result = view.i18nTranslate(result, variables)
return result, nil
}
// ParseDefault parses the default template file with params.
@ -201,11 +201,10 @@ func (view *View) ParseContent(content string, params ...Params) (string, error)
if err := tpl.Execute(buffer, variables); err != nil {
return "", err
}
return view.i18nTranslate(buffer.String(), variables), nil
// TODO any graceful plan to replace "<no value>"?
//result := gstr.Replace(buffer.String(), "<no value>", "")
//result = view.i18nTranslate(result, variables)
//return result, nil
result := gstr.Replace(buffer.String(), "<no value>", "")
result = view.i18nTranslate(result, variables)
return result, nil
}
// getTemplate returns the template object associated with given template file <path>.