mirror of
https://gitee.com/johng/gf
synced 2026-06-10 11:27:17 +08:00
Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a9f332fdd6 | |||
| c6f1ae9426 | |||
| b12c909fd6 | |||
| 1a62f22a5b | |||
| 5c2574da7c | |||
| 9fbdb9712b | |||
| 7bc42e6eaa | |||
| b6b1bc8813 | |||
| a62d2589bc | |||
| e4069bdb93 | |||
| 1e100ac0ec | |||
| 9d865e4ac6 | |||
| b3b1418e11 | |||
| 3ab32faccc | |||
| 2eb09efc81 | |||
| dd2dfbf58d | |||
| d549311210 | |||
| 8a91592839 | |||
| 4d962c5aa5 | |||
| d9bd3153ea | |||
| 4991e14dff | |||
| 5629020538 | |||
| 361742c4a0 | |||
| 4272ac16c7 | |||
| 6c08d5fd81 | |||
| 2a9c20bfa2 | |||
| 8dab319a7f |
@ -14,7 +14,7 @@ branches:
|
||||
- staging
|
||||
|
||||
env:
|
||||
- GF_DEBUG=1 GO111MODULE=on
|
||||
- TZ=Asia/Shanghai GF_DEBUG=1 GO111MODULE=on
|
||||
|
||||
services:
|
||||
- mysql
|
||||
|
||||
@ -33,7 +33,7 @@ golang version >= 1.11
|
||||
|
||||
# Architecture
|
||||
<div align=center>
|
||||
<img src="https://itician.org/download/attachments/1114119/arch.png?version=1&modificationDate=1608537397031&api=v2"/>
|
||||
<img src="https://itician.org/download/attachments/1114119/arch.png"/>
|
||||
</div>
|
||||
|
||||
# Packages
|
||||
@ -80,7 +80,7 @@ The `Web` component performance of `GoFrame`, please refer to third-party projec
|
||||
- [XiMaLaYa](https://www.ximalaya.com)
|
||||
- [ZYBang](https://www.zybang.com/)
|
||||
|
||||
> We list part of the users here, if your company or products are using `GoFrame`, please let us know [here](https://github.com/gogf/gf/issues/168).
|
||||
> We list part of the users here, if your company or products are using `GoFrame`, please let us know [here](https://itician.org/pages/viewpage.action?pageId=1114415).
|
||||
|
||||
|
||||
# Contributors
|
||||
|
||||
@ -49,7 +49,7 @@ golang版本 >= 1.11
|
||||
|
||||
# 架构
|
||||
<div align=center>
|
||||
<img src="https://itician.org/download/attachments/1114119/arch.png?version=1&modificationDate=1608537397031&api=v2"/>
|
||||
<img src="https://itician.org/download/attachments/1114119/arch.png"/>
|
||||
</div>
|
||||
|
||||
# 模块
|
||||
@ -95,7 +95,7 @@ golang版本 >= 1.11
|
||||
- [喜马拉雅](https://www.ximalaya.com)
|
||||
- [作业帮](https://www.zybang.com/)
|
||||
|
||||
> 在这里只列举了部分知名的用户,如果您的企业或者产品正在使用`GoFrame`,欢迎到 [这里](https://github.com/gogf/gf/issues/168) 留言。
|
||||
> 在这里只列举了部分知名的用户,如果您的企业或者产品正在使用`GoFrame`,欢迎到 [这里](https://itician.org/pages/viewpage.action?pageId=1114415) 留言。
|
||||
|
||||
# 贡献
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright GoFrame Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
@ -7,7 +7,6 @@
|
||||
package gdb
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/errors/gerror"
|
||||
"github.com/gogf/gf/util/gutil"
|
||||
"strings"
|
||||
"time"
|
||||
@ -56,6 +55,7 @@ func (c *Core) convertFieldValueToLocalValue(fieldValue interface{}, fieldType s
|
||||
return gconv.Int(gconv.String(fieldValue))
|
||||
|
||||
case
|
||||
"int8", // For pgsql, int8 = bigint.
|
||||
"big_int",
|
||||
"bigint",
|
||||
"bigserial":
|
||||
@ -162,15 +162,11 @@ func (c *Core) mappingAndFilterData(schema, table string, data map[string]interf
|
||||
if foundKey != "" {
|
||||
data[foundKey] = dataValue
|
||||
delete(data, dataKey)
|
||||
} else if !filter {
|
||||
if schema != "" {
|
||||
return nil, gerror.Newf(`no column of name "%s" found for table "%s" in schema "%s"`, dataKey, table, schema)
|
||||
}
|
||||
return nil, gerror.Newf(`no column of name "%s" found for table "%s"`, dataKey, table)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Data filtering.
|
||||
// It deletes all key-value pairs that has incorrect field name.
|
||||
if filter {
|
||||
for dataKey, _ := range data {
|
||||
if _, ok := fieldsMap[dataKey]; !ok {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright GoFrame Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
@ -16,13 +16,13 @@ import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/errors/gerror"
|
||||
"github.com/gogf/gf/internal/intlog"
|
||||
"github.com/gogf/gf/text/gregex"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/text/gregex"
|
||||
"time"
|
||||
)
|
||||
|
||||
// DriverOracle is the driver for oracle database.
|
||||
@ -65,24 +65,27 @@ func (d *DriverOracle) GetChars() (charLeft string, charRight string) {
|
||||
}
|
||||
|
||||
// HandleSqlBeforeCommit deals with the sql string before commits it to underlying sql driver.
|
||||
func (d *DriverOracle) HandleSqlBeforeCommit(link Link, sql string, args []interface{}) (string, []interface{}) {
|
||||
func (d *DriverOracle) HandleSqlBeforeCommit(link Link, sql string, args []interface{}) (newSql string, newArgs []interface{}) {
|
||||
var index int
|
||||
// Convert place holder char '?' to string ":vx".
|
||||
str, _ := gregex.ReplaceStringFunc("\\?", sql, func(s string) string {
|
||||
newSql, _ = gregex.ReplaceStringFunc("\\?", sql, func(s string) string {
|
||||
index++
|
||||
return fmt.Sprintf(":v%d", index)
|
||||
})
|
||||
str, _ = gregex.ReplaceString("\"", "", str)
|
||||
// Change time string argument wrapping with TO_DATE function.
|
||||
newSql, _ = gregex.ReplaceString("\"", "", newSql)
|
||||
// Handle string datetime argument.
|
||||
for i, v := range args {
|
||||
if reflect.TypeOf(v).Kind() == reflect.String {
|
||||
valueStr := gconv.String(v)
|
||||
if gregex.IsMatchString(`^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$`, valueStr) {
|
||||
args[i] = fmt.Sprintf(`TO_DATE('%s','yyyy-MM-dd HH:MI:SS')`, valueStr)
|
||||
//args[i] = fmt.Sprintf(`TO_DATE('%s','yyyy-MM-dd HH:MI:SS')`, valueStr)
|
||||
args[i], _ = time.ParseInLocation("2006-01-02 15:04:05", valueStr, time.Local)
|
||||
}
|
||||
}
|
||||
}
|
||||
return d.parseSql(str), args
|
||||
newSql = d.parseSql(newSql)
|
||||
newArgs = args
|
||||
return
|
||||
}
|
||||
|
||||
// parseSql does some replacement of the sql before commits it to underlying driver,
|
||||
@ -232,20 +235,20 @@ func (d *DriverOracle) getTableUniqueIndex(table string) (fields map[string]map[
|
||||
}
|
||||
|
||||
func (d *DriverOracle) DoInsert(link Link, table string, data interface{}, option int, batch ...int) (result sql.Result, err error) {
|
||||
var fields []string
|
||||
var values []string
|
||||
var params []interface{}
|
||||
var dataMap Map
|
||||
rv := reflect.ValueOf(data)
|
||||
kind := rv.Kind()
|
||||
var (
|
||||
fields []string
|
||||
values []string
|
||||
params []interface{}
|
||||
dataMap Map
|
||||
rv = reflect.ValueOf(data)
|
||||
kind = rv.Kind()
|
||||
)
|
||||
if kind == reflect.Ptr {
|
||||
rv = rv.Elem()
|
||||
kind = rv.Kind()
|
||||
}
|
||||
switch kind {
|
||||
case reflect.Slice:
|
||||
fallthrough
|
||||
case reflect.Array:
|
||||
case reflect.Slice, reflect.Array:
|
||||
return d.DB.DoBatchInsert(link, table, data, option, batch...)
|
||||
case reflect.Map:
|
||||
fallthrough
|
||||
@ -254,10 +257,11 @@ func (d *DriverOracle) DoInsert(link Link, table string, data interface{}, optio
|
||||
default:
|
||||
return result, gerror.New(fmt.Sprint("unsupported data type:", kind))
|
||||
}
|
||||
|
||||
indexs := make([]string, 0)
|
||||
indexMap := make(map[string]string)
|
||||
indexExists := false
|
||||
var (
|
||||
indexes = make([]string, 0)
|
||||
indexMap = make(map[string]string)
|
||||
indexExists = false
|
||||
)
|
||||
if option != insertOptionDefault {
|
||||
index, err := d.getTableUniqueIndex(table)
|
||||
if err != nil {
|
||||
@ -267,20 +271,19 @@ func (d *DriverOracle) DoInsert(link Link, table string, data interface{}, optio
|
||||
if len(index) > 0 {
|
||||
for _, v := range index {
|
||||
for k, _ := range v {
|
||||
indexs = append(indexs, k)
|
||||
indexes = append(indexes, k)
|
||||
}
|
||||
indexMap = v
|
||||
indexExists = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
subSqlStr := make([]string, 0)
|
||||
onStr := make([]string, 0)
|
||||
updateStr := make([]string, 0)
|
||||
|
||||
var (
|
||||
subSqlStr = make([]string, 0)
|
||||
onStr = make([]string, 0)
|
||||
updateStr = make([]string, 0)
|
||||
)
|
||||
charL, charR := d.DB.GetChars()
|
||||
for k, v := range dataMap {
|
||||
k = strings.ToUpper(k)
|
||||
@ -290,10 +293,8 @@ func (d *DriverOracle) DoInsert(link Link, table string, data interface{}, optio
|
||||
fields = append(fields, tableAlias1+"."+charL+k+charR)
|
||||
values = append(values, tableAlias2+"."+charL+k+charR)
|
||||
params = append(params, v)
|
||||
|
||||
subSqlStr = append(subSqlStr, fmt.Sprintf("%s?%s %s", charL, charR, k))
|
||||
|
||||
//merge中的on子句中由唯一索引组成,update子句中不含唯一索引
|
||||
//m erge中的on子句中由唯一索引组成, update子句中不含唯一索引
|
||||
if _, ok := indexMap[k]; ok {
|
||||
onStr = append(onStr, fmt.Sprintf("%s.%s = %s.%s ", tableAlias1, k, tableAlias2, k))
|
||||
} else {
|
||||
@ -314,20 +315,21 @@ func (d *DriverOracle) DoInsert(link Link, table string, data interface{}, optio
|
||||
|
||||
if indexExists && option != insertOptionDefault {
|
||||
switch option {
|
||||
case insertOptionReplace:
|
||||
fallthrough
|
||||
case insertOptionSave:
|
||||
case
|
||||
insertOptionReplace,
|
||||
insertOptionSave:
|
||||
tmp := fmt.Sprintf(
|
||||
"MERGE INTO %s %s USING(SELECT %s FROM DUAL) %s ON(%s) WHEN MATCHED THEN UPDATE SET %s WHEN NOT MATCHED THEN INSERT (%s) VALUES(%s)",
|
||||
table, tableAlias1, strings.Join(subSqlStr, ","), tableAlias2,
|
||||
strings.Join(onStr, "AND"), strings.Join(updateStr, ","), strings.Join(fields, ","), strings.Join(values, ","),
|
||||
)
|
||||
return d.DB.DoExec(link, tmp, params...)
|
||||
|
||||
case insertOptionIgnore:
|
||||
return d.DB.DoExec(link,
|
||||
fmt.Sprintf(
|
||||
"INSERT /*+ IGNORE_ROW_ON_DUPKEY_INDEX(%s(%s)) */ INTO %s(%s) VALUES(%s)",
|
||||
table, strings.Join(indexs, ","), table, strings.Join(fields, ","), strings.Join(values, ","),
|
||||
table, strings.Join(indexes, ","), table, strings.Join(fields, ","), strings.Join(values, ","),
|
||||
),
|
||||
params...)
|
||||
}
|
||||
@ -343,9 +345,11 @@ func (d *DriverOracle) DoInsert(link Link, table string, data interface{}, optio
|
||||
}
|
||||
|
||||
func (d *DriverOracle) DoBatchInsert(link Link, table string, list interface{}, option int, batch ...int) (result sql.Result, err error) {
|
||||
var keys []string
|
||||
var values []string
|
||||
var params []interface{}
|
||||
var (
|
||||
keys []string
|
||||
values []string
|
||||
params []interface{}
|
||||
)
|
||||
listMap := (List)(nil)
|
||||
switch v := list.(type) {
|
||||
case Result:
|
||||
@ -357,17 +361,16 @@ func (d *DriverOracle) DoBatchInsert(link Link, table string, list interface{},
|
||||
case Map:
|
||||
listMap = List{v}
|
||||
default:
|
||||
rv := reflect.ValueOf(list)
|
||||
kind := rv.Kind()
|
||||
var (
|
||||
rv = reflect.ValueOf(list)
|
||||
kind = rv.Kind()
|
||||
)
|
||||
if kind == reflect.Ptr {
|
||||
rv = rv.Elem()
|
||||
kind = rv.Kind()
|
||||
}
|
||||
switch kind {
|
||||
// 如果是slice,那么转换为List类型
|
||||
case reflect.Slice:
|
||||
fallthrough
|
||||
case reflect.Array:
|
||||
case reflect.Slice, reflect.Array:
|
||||
listMap = make(List, rv.Len())
|
||||
for i := 0; i < rv.Len(); i++ {
|
||||
listMap[i] = ConvertDataForTableRecord(rv.Index(i).Interface())
|
||||
@ -375,12 +378,11 @@ func (d *DriverOracle) DoBatchInsert(link Link, table string, list interface{},
|
||||
case reflect.Map:
|
||||
fallthrough
|
||||
case reflect.Struct:
|
||||
listMap = List{Map(ConvertDataForTableRecord(list))}
|
||||
listMap = List{ConvertDataForTableRecord(list)}
|
||||
default:
|
||||
return result, gerror.New(fmt.Sprint("unsupported list type:", kind))
|
||||
}
|
||||
}
|
||||
// 判断长度
|
||||
if len(listMap) < 1 {
|
||||
return result, gerror.New("empty data list")
|
||||
}
|
||||
@ -389,18 +391,18 @@ func (d *DriverOracle) DoBatchInsert(link Link, table string, list interface{},
|
||||
return
|
||||
}
|
||||
}
|
||||
// 首先获取字段名称及记录长度
|
||||
// Retrieve the table fields and length.
|
||||
holders := []string(nil)
|
||||
for k, _ := range listMap[0] {
|
||||
keys = append(keys, k)
|
||||
holders = append(holders, "?")
|
||||
}
|
||||
batchResult := new(SqlResult)
|
||||
charL, charR := d.DB.GetChars()
|
||||
keyStr := charL + strings.Join(keys, charL+","+charR) + charR
|
||||
valueHolderStr := strings.Join(holders, ",")
|
||||
|
||||
// 当操作类型非insert时调用单笔的insert功能
|
||||
var (
|
||||
batchResult = new(SqlResult)
|
||||
charL, charR = d.DB.GetChars()
|
||||
keyStr = charL + strings.Join(keys, charL+","+charR) + charR
|
||||
valueHolderStr = strings.Join(holders, ",")
|
||||
)
|
||||
if option != insertOptionDefault {
|
||||
for _, v := range listMap {
|
||||
r, err := d.DB.DoInsert(link, table, v, option, 1)
|
||||
@ -418,13 +420,12 @@ func (d *DriverOracle) DoBatchInsert(link Link, table string, list interface{},
|
||||
return batchResult, nil
|
||||
}
|
||||
|
||||
// 构造批量写入数据格式(注意map的遍历是无序的)
|
||||
batchNum := defaultBatchNumber
|
||||
if len(batch) > 0 {
|
||||
batchNum = batch[0]
|
||||
}
|
||||
|
||||
intoStr := make([]string, 0) //组装into语句
|
||||
// Format "INSERT...INTO..." statement.
|
||||
intoStr := make([]string, 0)
|
||||
for i := 0; i < len(listMap); i++ {
|
||||
for _, k := range keys {
|
||||
params = append(params, listMap[i][k])
|
||||
@ -446,7 +447,7 @@ func (d *DriverOracle) DoBatchInsert(link Link, table string, list interface{},
|
||||
intoStr = intoStr[:0]
|
||||
}
|
||||
}
|
||||
// 处理最后不构成指定批量的数据
|
||||
// The leftover data.
|
||||
if len(intoStr) > 0 {
|
||||
r, err := d.DB.DoExec(link, fmt.Sprintf("INSERT ALL %s SELECT * FROM DUAL", strings.Join(intoStr, " ")), params...)
|
||||
if err != nil {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright GoFrame Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
@ -496,6 +496,16 @@ func Test_Model_Update(t *testing.T) {
|
||||
n, _ := result.RowsAffected()
|
||||
t.Assert(n, 1)
|
||||
})
|
||||
// Update + Fields(string)
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
result, err := db.Table(table).Fields("passport").Data(g.Map{
|
||||
"passport": "user_44",
|
||||
"none": "none",
|
||||
}).Where("passport='user_4'").Update()
|
||||
t.Assert(err, nil)
|
||||
n, _ := result.RowsAffected()
|
||||
t.Assert(n, 1)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Model_Clone(t *testing.T) {
|
||||
|
||||
@ -8,6 +8,7 @@ package gdb_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/frame/g"
|
||||
@ -15,6 +16,7 @@ import (
|
||||
"github.com/gogf/gf/test/gtest"
|
||||
)
|
||||
|
||||
// All types testing.
|
||||
func Test_Types(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
if _, err := db.Exec(fmt.Sprintf(`
|
||||
@ -67,11 +69,34 @@ func Test_Types(t *testing.T) {
|
||||
t.Assert(one["blob"].String(), data["blob"])
|
||||
t.Assert(one["binary"].String(), data["binary"])
|
||||
t.Assert(one["date"].String(), data["date"])
|
||||
t.Assert(one["time"].String(), data["time"])
|
||||
t.Assert(one["time"].String(), `0000-01-01 10:00:01`)
|
||||
t.Assert(one["decimal"].String(), -123.46)
|
||||
t.Assert(one["double"].String(), data["double"])
|
||||
t.Assert(one["bit"].Int(), data["bit"])
|
||||
t.Assert(one["tinyint"].Bool(), data["tinyint"])
|
||||
t.Assert(one["tinyint"].Bool(), data["tinyint"])
|
||||
|
||||
type T struct {
|
||||
Id int
|
||||
Blob []byte
|
||||
Binary []byte
|
||||
Date *gtime.Time
|
||||
Time *gtime.Time
|
||||
Decimal float64
|
||||
Double float64
|
||||
Bit int8
|
||||
TinyInt bool
|
||||
}
|
||||
var obj *T
|
||||
err = db.Table("types").Struct(&obj)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(obj.Id, 1)
|
||||
t.Assert(obj.Blob, data["blob"])
|
||||
t.Assert(obj.Binary, data["binary"])
|
||||
t.Assert(obj.Date.Format("Y-m-d"), data["date"])
|
||||
t.Assert(obj.Time.String(), `0000-01-01 10:00:01`)
|
||||
t.Assert(obj.Decimal, -123.46)
|
||||
t.Assert(obj.Double, data["double"])
|
||||
t.Assert(obj.Bit, data["bit"])
|
||||
t.Assert(obj.TinyInt, data["tinyint"])
|
||||
})
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright GoFrame Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
|
||||
@ -8,6 +8,7 @@ package gins
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/errors/gerror"
|
||||
"github.com/gogf/gf/internal/intlog"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"github.com/gogf/gf/util/gutil"
|
||||
@ -47,7 +48,25 @@ func Database(name ...string) gdb.DB {
|
||||
configMap = Config().GetMap(configNodeKey)
|
||||
}
|
||||
if len(configMap) == 0 && !gdb.IsConfigured() {
|
||||
panic(fmt.Sprintf(`database init failed: "%s" node not found, is config file or configuration missing?`, configNodeNameDatabase))
|
||||
if !Config().Available() {
|
||||
exampleFileName := "config.example.toml"
|
||||
if Config().Available(exampleFileName) {
|
||||
panic(gerror.Newf(
|
||||
`configuration file "%s" not found, but found "%s", did you miss renaming the configuration example file?`,
|
||||
Config().GetFileName(),
|
||||
exampleFileName,
|
||||
))
|
||||
} else {
|
||||
panic(gerror.Newf(
|
||||
`configuration file "%s" not found, did you miss the configuration file or the file name setting?`,
|
||||
Config().GetFileName(),
|
||||
))
|
||||
}
|
||||
}
|
||||
panic(gerror.Newf(
|
||||
`database initialization failed: "%s" node not found, is configuration file or configuration node missing?`,
|
||||
configNodeNameDatabase,
|
||||
))
|
||||
}
|
||||
if len(configMap) == 0 {
|
||||
configMap = make(map[string]interface{})
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
@ -13,8 +13,6 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/gogf/gf/os/glog"
|
||||
|
||||
"github.com/gogf/gf/os/gfsnotify"
|
||||
|
||||
"github.com/gogf/gf/text/gregex"
|
||||
@ -235,11 +233,11 @@ func (m *Manager) init() {
|
||||
m.data[lang] = make(map[string]string)
|
||||
}
|
||||
if j, err := gjson.LoadContent(file.Content()); err == nil {
|
||||
for k, v := range j.ToMap() {
|
||||
for k, v := range j.Map() {
|
||||
m.data[lang][k] = gconv.String(v)
|
||||
}
|
||||
} else {
|
||||
glog.Errorf("load i18n file '%s' failed: %v", name, err)
|
||||
intlog.Errorf("load i18n file '%s' failed: %v", name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -270,11 +268,11 @@ func (m *Manager) init() {
|
||||
m.data[lang] = make(map[string]string)
|
||||
}
|
||||
if j, err := gjson.LoadContent(gfile.GetBytes(file)); err == nil {
|
||||
for k, v := range j.ToMap() {
|
||||
for k, v := range j.Map() {
|
||||
m.data[lang][k] = gconv.String(v)
|
||||
}
|
||||
} else {
|
||||
glog.Errorf("load i18n file '%s' failed: %v", file, err)
|
||||
intlog.Errorf("load i18n file '%s' failed: %v", file, err)
|
||||
}
|
||||
}
|
||||
// Monitor changes of i18n files for hot reload feature.
|
||||
|
||||
@ -84,6 +84,7 @@ func (r *Response) buildInVars(params ...map[string]interface{}) map[string]inte
|
||||
gutil.MapMerge(m, map[string]interface{}{
|
||||
"Form": r.Request.GetFormMap(),
|
||||
"Query": r.Request.GetQueryMap(),
|
||||
"Request": r.Request.GetMap(),
|
||||
"Cookie": r.Request.Cookie.Map(),
|
||||
"Session": r.Request.Session.Map(),
|
||||
})
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright GoFrame Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
@ -8,9 +8,8 @@ package ghttp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/debug/gdebug"
|
||||
"github.com/gogf/gf/errors/gerror"
|
||||
"github.com/gogf/gf/internal/intlog"
|
||||
"net/http"
|
||||
"os"
|
||||
@ -125,13 +124,13 @@ func (s *Server) Start() error {
|
||||
|
||||
// Server can only be run once.
|
||||
if s.Status() == ServerStatusRunning {
|
||||
return errors.New("[ghttp] server is already running")
|
||||
return gerror.New("server is already running")
|
||||
}
|
||||
|
||||
// Logging path setting check.
|
||||
if s.config.LogPath != "" {
|
||||
if s.config.LogPath != "" && s.config.LogPath != s.config.Logger.GetPath() {
|
||||
if err := s.config.Logger.SetPath(s.config.LogPath); err != nil {
|
||||
return errors.New(fmt.Sprintf("[ghttp] set log path '%s' error: %v", s.config.LogPath, err))
|
||||
return err
|
||||
}
|
||||
}
|
||||
// Default session storage.
|
||||
@ -141,7 +140,7 @@ func (s *Server) Start() error {
|
||||
path = gfile.Join(s.config.SessionPath, s.name)
|
||||
if !gfile.Exists(path) {
|
||||
if err := gfile.Mkdir(path); err != nil {
|
||||
return errors.New(fmt.Sprintf("[ghttp] mkdir failed for '%s': %v", path, err))
|
||||
return gerror.Wrapf(err, `mkdir failed for "%s"`, path)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -175,7 +174,7 @@ func (s *Server) Start() error {
|
||||
// If there's no route registered and no static service enabled,
|
||||
// it then returns an error of invalid usage of server.
|
||||
if len(s.routesMap) == 0 && !s.config.FileServerEnabled {
|
||||
return errors.New(`[ghttp] there's no route set or static feature enabled, did you forget import the router?`)
|
||||
return gerror.New(`there's no route set or static feature enabled, did you forget import the router?`)
|
||||
}
|
||||
|
||||
// Start the HTTP server.
|
||||
@ -196,7 +195,7 @@ func (s *Server) Start() error {
|
||||
if gproc.IsChild() {
|
||||
gtimer.SetTimeout(2*time.Second, func() {
|
||||
if err := gproc.Send(gproc.PPid(), []byte("exit"), adminGProcCommGroup); err != nil {
|
||||
//glog.Error("[ghttp] server error in process communication:", err)
|
||||
//glog.Error("server error in process communication:", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -320,7 +319,7 @@ func (s *Server) Run() {
|
||||
p.Remove()
|
||||
}
|
||||
}
|
||||
s.Logger().Printf("[ghttp] %d: all servers shutdown", gproc.Pid())
|
||||
s.Logger().Printf("%d: all servers shutdown", gproc.Pid())
|
||||
}
|
||||
|
||||
// Wait blocks to wait for all servers done.
|
||||
@ -338,7 +337,7 @@ func Wait() {
|
||||
}
|
||||
return true
|
||||
})
|
||||
glog.Printf("[ghttp] %d: all servers shutdown", gproc.Pid())
|
||||
glog.Printf("%d: all servers shutdown", gproc.Pid())
|
||||
}
|
||||
|
||||
// startServer starts the underlying server listening.
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
@ -171,40 +171,21 @@ type ServerConfig struct {
|
||||
// ==================================
|
||||
// Logging.
|
||||
// ==================================
|
||||
|
||||
// Logger specifies the logger for server.
|
||||
Logger *glog.Logger
|
||||
|
||||
// LogPath specifies the directory for storing logging files.
|
||||
LogPath string
|
||||
|
||||
// LogStdout specifies whether printing logging content to stdout.
|
||||
LogStdout bool
|
||||
|
||||
// ErrorStack specifies whether logging stack information when error.
|
||||
ErrorStack bool
|
||||
|
||||
// ErrorLogEnabled enables error logging content to files.
|
||||
ErrorLogEnabled bool
|
||||
|
||||
// ErrorLogPattern specifies the error log file pattern like: error-{Ymd}.log
|
||||
ErrorLogPattern string
|
||||
|
||||
// AccessLogEnabled enables access logging content to files.
|
||||
AccessLogEnabled bool
|
||||
|
||||
// AccessLogPattern specifies the error log file pattern like: access-{Ymd}.log
|
||||
AccessLogPattern string
|
||||
Logger *glog.Logger // Logger specifies the logger for server.
|
||||
LogPath string // LogPath specifies the directory for storing logging files.
|
||||
LogLevel string // LogLevel specifies the logging level for logger.
|
||||
LogStdout bool // LogStdout specifies whether printing logging content to stdout.
|
||||
ErrorStack bool // ErrorStack specifies whether logging stack information when error.
|
||||
ErrorLogEnabled bool // ErrorLogEnabled enables error logging content to files.
|
||||
ErrorLogPattern string // ErrorLogPattern specifies the error log file pattern like: error-{Ymd}.log
|
||||
AccessLogEnabled bool // AccessLogEnabled enables access logging content to files.
|
||||
AccessLogPattern string // AccessLogPattern specifies the error log file pattern like: access-{Ymd}.log
|
||||
|
||||
// ==================================
|
||||
// PProf.
|
||||
// ==================================
|
||||
|
||||
// PProfEnabled enables PProf feature.
|
||||
PProfEnabled bool
|
||||
|
||||
// PProfPattern specifies the PProf service pattern for router.
|
||||
PProfPattern string
|
||||
PProfEnabled bool // PProfEnabled enables PProf feature.
|
||||
PProfPattern string // PProfPattern specifies the PProf service pattern for router.
|
||||
|
||||
// ==================================
|
||||
// Other.
|
||||
@ -267,6 +248,7 @@ func NewConfig() ServerConfig {
|
||||
SessionPath: gsession.DefaultStorageFilePath,
|
||||
SessionCookieOutput: true,
|
||||
Logger: glog.New(),
|
||||
LogLevel: "all",
|
||||
LogStdout: true,
|
||||
ErrorStack: true,
|
||||
ErrorLogEnabled: true,
|
||||
@ -334,6 +316,14 @@ func (s *Server) SetConfig(c ServerConfig) error {
|
||||
if c.TLSConfig == nil && c.HTTPSCertPath != "" {
|
||||
s.EnableHTTPS(c.HTTPSCertPath, c.HTTPSKeyPath)
|
||||
}
|
||||
// Logging.
|
||||
if s.config.LogPath != "" && s.config.LogPath != s.config.Logger.GetPath() {
|
||||
if err := s.config.Logger.SetPath(s.config.LogPath); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
s.config.Logger.SetLevelStr(s.config.LogLevel)
|
||||
|
||||
SetGraceful(c.Graceful)
|
||||
intlog.Printf("SetConfig: %+v", s.config)
|
||||
return nil
|
||||
@ -393,7 +383,7 @@ func (s *Server) EnableHTTPS(certFile, keyFile string, tlsConfig ...*tls.Config)
|
||||
certFileRealPath = certFile
|
||||
}
|
||||
if certFileRealPath == "" {
|
||||
s.Logger().Fatal(fmt.Sprintf(`[ghttp] EnableHTTPS failed: certFile "%s" does not exist`, certFile))
|
||||
s.Logger().Fatal(fmt.Sprintf(`EnableHTTPS failed: certFile "%s" does not exist`, certFile))
|
||||
}
|
||||
keyFileRealPath := gfile.RealPath(keyFile)
|
||||
if keyFileRealPath == "" {
|
||||
@ -407,7 +397,7 @@ func (s *Server) EnableHTTPS(certFile, keyFile string, tlsConfig ...*tls.Config)
|
||||
keyFileRealPath = keyFile
|
||||
}
|
||||
if keyFileRealPath == "" {
|
||||
s.Logger().Fatal(fmt.Sprintf(`[ghttp] EnableHTTPS failed: keyFile "%s" does not exist`, keyFile))
|
||||
s.Logger().Fatal(fmt.Sprintf(`EnableHTTPS failed: keyFile "%s" does not exist`, keyFile))
|
||||
}
|
||||
s.config.HTTPSCertPath = certFileRealPath
|
||||
s.config.HTTPSKeyPath = keyFileRealPath
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
@ -6,18 +6,26 @@
|
||||
|
||||
package ghttp
|
||||
|
||||
import "github.com/gogf/gf/internal/intlog"
|
||||
|
||||
// SetLogPath sets the log path for server.
|
||||
// It logs content to file only if the log path is set.
|
||||
func (s *Server) SetLogPath(path string) {
|
||||
func (s *Server) SetLogPath(path string) error {
|
||||
if len(path) == 0 {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
intlog.Print("SetLogPath:", path)
|
||||
s.config.LogPath = path
|
||||
s.config.ErrorLogEnabled = true
|
||||
s.config.AccessLogEnabled = true
|
||||
if s.config.LogPath != "" && s.config.LogPath != s.config.Logger.GetPath() {
|
||||
if err := s.config.Logger.SetPath(s.config.LogPath); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetLogLevel sets logging level by level string.
|
||||
func (s *Server) SetLogLevel(level string) {
|
||||
s.config.LogLevel = level
|
||||
}
|
||||
|
||||
// SetLogStdout sets whether output the logging content to stdout.
|
||||
|
||||
@ -53,12 +53,12 @@ func (s *Server) SetServerRoot(root string) {
|
||||
realPath := root
|
||||
if !gres.Contains(realPath) {
|
||||
if p, err := gfile.Search(root); err != nil {
|
||||
s.Logger().Fatal(fmt.Sprintf(`[ghttp] SetServerRoot failed: %v`, err))
|
||||
s.Logger().Fatal(fmt.Sprintf(`SetServerRoot failed: %v`, err))
|
||||
} else {
|
||||
realPath = p
|
||||
}
|
||||
}
|
||||
s.Logger().Debug("[ghttp] SetServerRoot path:", realPath)
|
||||
s.Logger().Debug("SetServerRoot path:", realPath)
|
||||
s.config.SearchPaths = []string{strings.TrimRight(realPath, gfile.Separator)}
|
||||
s.config.FileServerEnabled = true
|
||||
}
|
||||
@ -68,7 +68,7 @@ func (s *Server) AddSearchPath(path string) {
|
||||
realPath := path
|
||||
if !gres.Contains(realPath) {
|
||||
if p, err := gfile.Search(path); err != nil {
|
||||
s.Logger().Fatal(fmt.Sprintf(`[ghttp] AddSearchPath failed: %v`, err))
|
||||
s.Logger().Fatal(fmt.Sprintf(`AddSearchPath failed: %v`, err))
|
||||
} else {
|
||||
realPath = p
|
||||
}
|
||||
@ -82,7 +82,7 @@ func (s *Server) AddStaticPath(prefix string, path string) {
|
||||
realPath := path
|
||||
if !gres.Contains(realPath) {
|
||||
if p, err := gfile.Search(path); err != nil {
|
||||
s.Logger().Fatal(fmt.Sprintf(`[ghttp] AddStaticPath failed: %v`, err))
|
||||
s.Logger().Fatal(fmt.Sprintf(`AddStaticPath failed: %v`, err))
|
||||
} else {
|
||||
realPath = p
|
||||
}
|
||||
|
||||
@ -52,7 +52,7 @@ func Test_SetConfigWithMap(t *testing.T) {
|
||||
"AccessLogEnabled": true,
|
||||
"ErrorLogEnabled": true,
|
||||
"PProfEnabled": true,
|
||||
"LogPath": "/var/log/MyServerLog",
|
||||
"LogPath": "/tmp/log/MyServerLog",
|
||||
"SessionIdName": "MySessionId",
|
||||
"SessionPath": "/tmp/MySessionStoragePath",
|
||||
"SessionMaxAge": 24 * time.Hour,
|
||||
|
||||
@ -139,6 +139,27 @@ func Test_Template_Layout2(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Template_BuildInVarRequest(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
p, _ := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/:table/test", func(r *ghttp.Request) {
|
||||
err := r.Response.WriteTplContent("{{.Request.table}}")
|
||||
t.Assert(err, nil)
|
||||
})
|
||||
s.SetDumpRouterMap(false)
|
||||
s.SetPort(p)
|
||||
s.Start()
|
||||
defer s.Shutdown()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
client := g.Client()
|
||||
client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", p))
|
||||
|
||||
t.Assert(client.GetContent("/user/test"), "user")
|
||||
t.Assert(client.GetContent("/order/test"), "order")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Template_XSS(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
v := gview.New()
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright GoFrame Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
@ -49,6 +49,11 @@ func New(file ...string) *Config {
|
||||
name := DefaultConfigFile
|
||||
if len(file) > 0 {
|
||||
name = file[0]
|
||||
} else {
|
||||
// Custom default configuration file name from command line or environment.
|
||||
if customFile := gcmd.GetWithEnv(fmt.Sprintf("%s.file", cmdEnvKey)).String(); customFile != "" {
|
||||
name = customFile
|
||||
}
|
||||
}
|
||||
c := &Config{
|
||||
name: name,
|
||||
@ -56,12 +61,12 @@ func New(file ...string) *Config {
|
||||
jsons: gmap.NewStrAnyMap(true),
|
||||
}
|
||||
// Customized dir path from env/cmd.
|
||||
if envPath := gcmd.GetWithEnv(fmt.Sprintf("%s.path", cmdEnvKey)).String(); envPath != "" {
|
||||
if gfile.Exists(envPath) {
|
||||
_ = c.SetPath(envPath)
|
||||
if customPath := gcmd.GetWithEnv(fmt.Sprintf("%s.path", cmdEnvKey)).String(); customPath != "" {
|
||||
if gfile.Exists(customPath) {
|
||||
_ = c.SetPath(customPath)
|
||||
} else {
|
||||
if errorPrint() {
|
||||
glog.Errorf("Configuration directory path does not exist: %s", envPath)
|
||||
glog.Errorf("Configuration directory path does not exist: %s", customPath)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright GoFrame Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
@ -13,7 +13,7 @@ import (
|
||||
|
||||
const (
|
||||
// Default group name for instance usage.
|
||||
DefaultName = "default"
|
||||
DefaultName = "config"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@ -12,7 +12,6 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/debug/gdebug"
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
|
||||
"github.com/gogf/gf/encoding/gjson"
|
||||
@ -229,71 +228,6 @@ func Test_SetFileName(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Instance(t *testing.T) {
|
||||
config := `
|
||||
array = [1.0, 2.0, 3.0]
|
||||
v1 = 1.0
|
||||
v2 = "true"
|
||||
v3 = "off"
|
||||
v4 = "1.234"
|
||||
|
||||
[redis]
|
||||
cache = "127.0.0.1:6379,1"
|
||||
disk = "127.0.0.1:6379,0"
|
||||
|
||||
`
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
path := gcfg.DefaultConfigFile
|
||||
err := gfile.PutContents(path, config)
|
||||
t.Assert(err, nil)
|
||||
defer func() {
|
||||
t.Assert(gfile.Remove(path), nil)
|
||||
}()
|
||||
|
||||
c := gcfg.Instance()
|
||||
t.Assert(c.Get("v1"), 1)
|
||||
t.AssertEQ(c.GetInt("v1"), 1)
|
||||
t.AssertEQ(c.GetInt8("v1"), int8(1))
|
||||
t.AssertEQ(c.GetInt16("v1"), int16(1))
|
||||
t.AssertEQ(c.GetInt32("v1"), int32(1))
|
||||
t.AssertEQ(c.GetInt64("v1"), int64(1))
|
||||
t.AssertEQ(c.GetUint("v1"), uint(1))
|
||||
t.AssertEQ(c.GetUint8("v1"), uint8(1))
|
||||
t.AssertEQ(c.GetUint16("v1"), uint16(1))
|
||||
t.AssertEQ(c.GetUint32("v1"), uint32(1))
|
||||
t.AssertEQ(c.GetUint64("v1"), uint64(1))
|
||||
|
||||
t.AssertEQ(c.GetVar("v1").String(), "1")
|
||||
t.AssertEQ(c.GetVar("v1").Bool(), true)
|
||||
t.AssertEQ(c.GetVar("v2").String(), "true")
|
||||
t.AssertEQ(c.GetVar("v2").Bool(), true)
|
||||
|
||||
t.AssertEQ(c.GetString("v1"), "1")
|
||||
t.AssertEQ(c.GetFloat32("v4"), float32(1.234))
|
||||
t.AssertEQ(c.GetFloat64("v4"), float64(1.234))
|
||||
t.AssertEQ(c.GetString("v2"), "true")
|
||||
t.AssertEQ(c.GetBool("v2"), true)
|
||||
t.AssertEQ(c.GetBool("v3"), false)
|
||||
|
||||
t.AssertEQ(c.Contains("v1"), true)
|
||||
t.AssertEQ(c.Contains("v2"), true)
|
||||
t.AssertEQ(c.Contains("v3"), true)
|
||||
t.AssertEQ(c.Contains("v4"), true)
|
||||
t.AssertEQ(c.Contains("v5"), false)
|
||||
|
||||
t.AssertEQ(c.GetInts("array"), []int{1, 2, 3})
|
||||
t.AssertEQ(c.GetStrings("array"), []string{"1", "2", "3"})
|
||||
t.AssertEQ(c.GetArray("array"), []interface{}{1, 2, 3})
|
||||
t.AssertEQ(c.GetInterfaces("array"), []interface{}{1, 2, 3})
|
||||
t.AssertEQ(c.GetMap("redis"), map[string]interface{}{
|
||||
"disk": "127.0.0.1:6379,0",
|
||||
"cache": "127.0.0.1:6379,1",
|
||||
})
|
||||
t.AssertEQ(c.FilePath(), gfile.Pwd()+gfile.Separator+path)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestCfg_New(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
os.Setenv("GF_GCFG_PATH", "config")
|
||||
@ -446,26 +380,6 @@ func TestCfg_Get(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestCfg_Instance(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
t.Assert(gcfg.Instance("gf") != nil, true)
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
pwd := gfile.Pwd()
|
||||
gfile.Chdir(gdebug.TestDataPath())
|
||||
defer gfile.Chdir(pwd)
|
||||
t.Assert(gcfg.Instance("c1") != nil, true)
|
||||
t.Assert(gcfg.Instance("c1").Get("my-config"), "1")
|
||||
t.Assert(gcfg.Instance("folder1/c1").Get("my-config"), "2")
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
pwd := gfile.Pwd()
|
||||
gfile.Chdir(gdebug.TestDataPath("folder1"))
|
||||
defer gfile.Chdir(pwd)
|
||||
t.Assert(gcfg.Instance("c2").Get("my-config"), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func TestCfg_Config(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
gcfg.SetContent("gf", "config.yml")
|
||||
127
os/gcfg/gcfg_z_unit_instance_test.go
Normal file
127
os/gcfg/gcfg_z_unit_instance_test.go
Normal file
@ -0,0 +1,127 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// go test *.go -bench=".*" -benchmem
|
||||
|
||||
package gcfg
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/container/gmap"
|
||||
"github.com/gogf/gf/debug/gdebug"
|
||||
"github.com/gogf/gf/os/genv"
|
||||
"github.com/gogf/gf/os/gfile"
|
||||
"github.com/gogf/gf/test/gtest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_Instance_Basic(t *testing.T) {
|
||||
config := `
|
||||
array = [1.0, 2.0, 3.0]
|
||||
v1 = 1.0
|
||||
v2 = "true"
|
||||
v3 = "off"
|
||||
v4 = "1.234"
|
||||
|
||||
[redis]
|
||||
cache = "127.0.0.1:6379,1"
|
||||
disk = "127.0.0.1:6379,0"
|
||||
|
||||
`
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
path := DefaultConfigFile
|
||||
err := gfile.PutContents(path, config)
|
||||
t.Assert(err, nil)
|
||||
defer func() {
|
||||
t.Assert(gfile.Remove(path), nil)
|
||||
}()
|
||||
|
||||
c := Instance()
|
||||
t.Assert(c.Get("v1"), 1)
|
||||
t.AssertEQ(c.GetInt("v1"), 1)
|
||||
t.AssertEQ(c.GetInt8("v1"), int8(1))
|
||||
t.AssertEQ(c.GetInt16("v1"), int16(1))
|
||||
t.AssertEQ(c.GetInt32("v1"), int32(1))
|
||||
t.AssertEQ(c.GetInt64("v1"), int64(1))
|
||||
t.AssertEQ(c.GetUint("v1"), uint(1))
|
||||
t.AssertEQ(c.GetUint8("v1"), uint8(1))
|
||||
t.AssertEQ(c.GetUint16("v1"), uint16(1))
|
||||
t.AssertEQ(c.GetUint32("v1"), uint32(1))
|
||||
t.AssertEQ(c.GetUint64("v1"), uint64(1))
|
||||
|
||||
t.AssertEQ(c.GetVar("v1").String(), "1")
|
||||
t.AssertEQ(c.GetVar("v1").Bool(), true)
|
||||
t.AssertEQ(c.GetVar("v2").String(), "true")
|
||||
t.AssertEQ(c.GetVar("v2").Bool(), true)
|
||||
|
||||
t.AssertEQ(c.GetString("v1"), "1")
|
||||
t.AssertEQ(c.GetFloat32("v4"), float32(1.234))
|
||||
t.AssertEQ(c.GetFloat64("v4"), float64(1.234))
|
||||
t.AssertEQ(c.GetString("v2"), "true")
|
||||
t.AssertEQ(c.GetBool("v2"), true)
|
||||
t.AssertEQ(c.GetBool("v3"), false)
|
||||
|
||||
t.AssertEQ(c.Contains("v1"), true)
|
||||
t.AssertEQ(c.Contains("v2"), true)
|
||||
t.AssertEQ(c.Contains("v3"), true)
|
||||
t.AssertEQ(c.Contains("v4"), true)
|
||||
t.AssertEQ(c.Contains("v5"), false)
|
||||
|
||||
t.AssertEQ(c.GetInts("array"), []int{1, 2, 3})
|
||||
t.AssertEQ(c.GetStrings("array"), []string{"1", "2", "3"})
|
||||
t.AssertEQ(c.GetArray("array"), []interface{}{1, 2, 3})
|
||||
t.AssertEQ(c.GetInterfaces("array"), []interface{}{1, 2, 3})
|
||||
t.AssertEQ(c.GetMap("redis"), map[string]interface{}{
|
||||
"disk": "127.0.0.1:6379,0",
|
||||
"cache": "127.0.0.1:6379,1",
|
||||
})
|
||||
t.AssertEQ(c.FilePath(), gfile.Pwd()+gfile.Separator+path)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Instance_AutoLocateConfigFile(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
t.Assert(Instance("gf") != nil, true)
|
||||
})
|
||||
// Automatically locate the configuration file with supported file extensions.
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
pwd := gfile.Pwd()
|
||||
gfile.Chdir(gdebug.TestDataPath())
|
||||
defer gfile.Chdir(pwd)
|
||||
t.Assert(Instance("c1") != nil, true)
|
||||
t.Assert(Instance("c1").Get("my-config"), "1")
|
||||
t.Assert(Instance("folder1/c1").Get("my-config"), "2")
|
||||
})
|
||||
// Automatically locate the configuration file with supported file extensions.
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
pwd := gfile.Pwd()
|
||||
gfile.Chdir(gdebug.TestDataPath("folder1"))
|
||||
defer gfile.Chdir(pwd)
|
||||
t.Assert(Instance("c2").Get("my-config"), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Instance_EnvPath(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
genv.Set("GF_GCFG_PATH", gdebug.TestDataPath("envpath"))
|
||||
defer genv.Set("GF_GCFG_PATH", "")
|
||||
t.Assert(Instance("c3") != nil, true)
|
||||
t.Assert(Instance("c3").Get("my-config"), "3")
|
||||
t.Assert(Instance("c4").Get("my-config"), "4")
|
||||
instances = gmap.NewStrAnyMap(true)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Instance_EnvFile(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
genv.Set("GF_GCFG_PATH", gdebug.TestDataPath("envfile"))
|
||||
defer genv.Set("GF_GCFG_PATH", "")
|
||||
genv.Set("GF_GCFG_FILE", "c6.json")
|
||||
defer genv.Set("GF_GCFG_FILE", "")
|
||||
t.Assert(Instance().Get("my-config"), "6")
|
||||
instances = gmap.NewStrAnyMap(true)
|
||||
})
|
||||
}
|
||||
2
os/gcfg/testdata/envfile/c6.json
vendored
Normal file
2
os/gcfg/testdata/envfile/c6.json
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
{"my-config": 6}
|
||||
2
os/gcfg/testdata/envpath/c3.toml
vendored
Normal file
2
os/gcfg/testdata/envpath/c3.toml
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
my-config = "3"
|
||||
2
os/gcfg/testdata/envpath/c4.json
vendored
Normal file
2
os/gcfg/testdata/envpath/c4.json
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
{"my-config": 4}
|
||||
@ -59,10 +59,9 @@ func init() {
|
||||
}
|
||||
|
||||
// Mkdir creates directories recursively with given <path>.
|
||||
// The parameter <path> is suggested to be absolute path.
|
||||
// The parameter <path> is suggested to be an absolute path instead of relative one.
|
||||
func Mkdir(path string) error {
|
||||
err := os.MkdirAll(path, os.ModePerm)
|
||||
if err != nil {
|
||||
if err := os.MkdirAll(path, os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
||||
@ -9,6 +9,7 @@ package glog
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/errors/gerror"
|
||||
"github.com/gogf/gf/internal/intlog"
|
||||
"github.com/gogf/gf/os/gfile"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
@ -191,7 +192,7 @@ func (l *Logger) SetPath(path string) error {
|
||||
if !gfile.Exists(path) {
|
||||
if err := gfile.Mkdir(path); err != nil {
|
||||
//fmt.Fprintln(os.Stderr, fmt.Sprintf(`[glog] mkdir "%s" failed: %s`, path, err.Error()))
|
||||
return err
|
||||
return gerror.Wrapf(err, `Mkdir "%s" failed in PWD "%s"`, path, gfile.Pwd())
|
||||
}
|
||||
}
|
||||
l.config.Path = strings.TrimRight(path, gfile.Separator)
|
||||
|
||||
@ -9,6 +9,7 @@ package gsession
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/container/gmap"
|
||||
"github.com/gogf/gf/errors/gerror"
|
||||
"github.com/gogf/gf/internal/intlog"
|
||||
"github.com/gogf/gf/internal/json"
|
||||
"os"
|
||||
@ -55,7 +56,7 @@ func NewStorageFile(path ...string) *StorageFile {
|
||||
}
|
||||
if storagePath != "" {
|
||||
if err := gfile.Mkdir(storagePath); err != nil {
|
||||
panic(fmt.Sprintf("mkdir '%s' failed: %v", path[0], err))
|
||||
panic(gerror.Wrapf(err, `Mkdir "%s" failed in PWD "%s"`, path, gfile.Pwd()))
|
||||
}
|
||||
}
|
||||
s := &StorageFile{
|
||||
|
||||
@ -10,10 +10,10 @@
|
||||
package gtime
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/errors/gerror"
|
||||
"github.com/gogf/gf/internal/utils"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -45,7 +45,7 @@ const (
|
||||
// "2018/10/31 - 16:38:46"
|
||||
// "2018-02-09",
|
||||
// "2018.02.09",
|
||||
TIME_REAGEX_PATTERN1 = `(\d{4}[-/\.]\d{2}[-/\.]\d{2})[:\sT-]*(\d{0,2}:{0,1}\d{0,2}:{0,1}\d{0,2}){0,1}\.{0,1}(\d{0,9})([\sZ]{0,1})([\+-]{0,1})([:\d]*)`
|
||||
timeRegexPattern1 = `(\d{4}[-/\.]\d{2}[-/\.]\d{2})[:\sT-]*(\d{0,2}:{0,1}\d{0,2}:{0,1}\d{0,2}){0,1}\.{0,1}(\d{0,9})([\sZ]{0,1})([\+-]{0,1})([:\d]*)`
|
||||
|
||||
// Regular expression2(datetime separator supports '-', '/', '.').
|
||||
// Eg:
|
||||
@ -53,14 +53,21 @@ const (
|
||||
// 01/Nov/2018 11:50:28
|
||||
// 01.Nov.2018 11:50:28
|
||||
// 01.Nov.2018:11:50:28
|
||||
TIME_REAGEX_PATTERN2 = `(\d{1,2}[-/\.][A-Za-z]{3,}[-/\.]\d{4})[:\sT-]*(\d{0,2}:{0,1}\d{0,2}:{0,1}\d{0,2}){0,1}\.{0,1}(\d{0,9})([\sZ]{0,1})([\+-]{0,1})([:\d]*)`
|
||||
timeRegexPattern2 = `(\d{1,2}[-/\.][A-Za-z]{3,}[-/\.]\d{4})[:\sT-]*(\d{0,2}:{0,1}\d{0,2}:{0,1}\d{0,2}){0,1}\.{0,1}(\d{0,9})([\sZ]{0,1})([\+-]{0,1})([:\d]*)`
|
||||
|
||||
// Regular expression3(time).
|
||||
// Eg:
|
||||
// 11:50:28
|
||||
// 11:50:28.897
|
||||
timeRegexPattern3 = `(\d{2}):(\d{2}):(\d{2})\.{0,1}(\d{0,9})`
|
||||
)
|
||||
|
||||
var (
|
||||
// It's more high performance using regular expression
|
||||
// than time.ParseInLocation to parse the datetime string.
|
||||
timeRegex1, _ = regexp.Compile(TIME_REAGEX_PATTERN1)
|
||||
timeRegex2, _ = regexp.Compile(TIME_REAGEX_PATTERN2)
|
||||
timeRegex1, _ = regexp.Compile(timeRegexPattern1)
|
||||
timeRegex2, _ = regexp.Compile(timeRegexPattern2)
|
||||
timeRegex3, _ = regexp.Compile(timeRegexPattern3)
|
||||
|
||||
// Month words to arabic numerals mapping.
|
||||
monthMap = map[string]int{
|
||||
@ -95,18 +102,14 @@ var (
|
||||
// The parameter <zone> is an area string specifying corresponding time zone,
|
||||
// eg: Asia/Shanghai.
|
||||
//
|
||||
// Note that the time zone database needed by LoadLocation may not be
|
||||
// present on all systems, especially non-Unix systems.
|
||||
// LoadLocation looks in the directory or uncompressed zip file
|
||||
// named by the ZONEINFO environment variable, if any, then looks in
|
||||
// known installation locations on Unix systems,
|
||||
// and finally looks in $GOROOT/lib/time/zoneinfo.zip.
|
||||
// This should be called before package "time" import.
|
||||
// Please refer to issue: https://github.com/golang/go/issues/34814
|
||||
func SetTimeZone(zone string) error {
|
||||
location, err := time.LoadLocation(zone)
|
||||
if err == nil {
|
||||
time.Local = location
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return err
|
||||
return os.Setenv("TZ", location.String())
|
||||
}
|
||||
|
||||
// Timestamp retrieves and returns the timestamp in seconds.
|
||||
@ -247,17 +250,33 @@ func StrToTime(str string, format ...string) (*Time, error) {
|
||||
local = time.Local
|
||||
)
|
||||
if match = timeRegex1.FindStringSubmatch(str); len(match) > 0 && match[1] != "" {
|
||||
for k, v := range match {
|
||||
match[k] = strings.TrimSpace(v)
|
||||
}
|
||||
//for k, v := range match {
|
||||
// match[k] = strings.TrimSpace(v)
|
||||
//}
|
||||
year, month, day = parseDateStr(match[1])
|
||||
} else if match = timeRegex2.FindStringSubmatch(str); len(match) > 0 && match[1] != "" {
|
||||
for k, v := range match {
|
||||
match[k] = strings.TrimSpace(v)
|
||||
}
|
||||
//for k, v := range match {
|
||||
// match[k] = strings.TrimSpace(v)
|
||||
//}
|
||||
year, month, day = parseDateStr(match[1])
|
||||
} else if match = timeRegex3.FindStringSubmatch(str); len(match) > 0 && match[1] != "" {
|
||||
//for k, v := range match {
|
||||
// match[k] = strings.TrimSpace(v)
|
||||
//}
|
||||
s := strings.Replace(match[2], ":", "", -1)
|
||||
if len(s) < 6 {
|
||||
s += strings.Repeat("0", 6-len(s))
|
||||
}
|
||||
hour, _ = strconv.Atoi(match[1])
|
||||
min, _ = strconv.Atoi(match[2])
|
||||
sec, _ = strconv.Atoi(match[3])
|
||||
nsec, _ = strconv.Atoi(match[4])
|
||||
for i := 0; i < 9-len(match[4]); i++ {
|
||||
nsec *= 10
|
||||
}
|
||||
return NewFromTime(time.Date(0, time.Month(1), 1, hour, min, sec, nsec, local)), nil
|
||||
} else {
|
||||
return nil, errors.New("unsupported time format")
|
||||
return nil, gerror.New("unsupported time format")
|
||||
}
|
||||
|
||||
// Time
|
||||
@ -330,8 +349,8 @@ func StrToTime(str string, format ...string) (*Time, error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if year <= 0 {
|
||||
return nil, errors.New("invalid time string:" + str)
|
||||
if month <= 0 || day <= 0 {
|
||||
return nil, gerror.New("invalid time string:" + str)
|
||||
}
|
||||
return NewFromTime(time.Date(year, time.Month(month), day, hour, min, sec, nsec, local)), nil
|
||||
}
|
||||
@ -347,7 +366,7 @@ func ConvertZone(strTime string, toZone string, fromZone ...string) (*Time, erro
|
||||
if l, err := time.LoadLocation(fromZone[0]); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
t.Time = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Time.Second(), t.Time.Nanosecond(), l)
|
||||
t.Time = time.Date(t.Year(), time.Month(t.Month()), t.Day(), t.Hour(), t.Minute(), t.Time.Second(), t.Time.Nanosecond(), l)
|
||||
}
|
||||
}
|
||||
if l, err := time.LoadLocation(toZone); err != nil {
|
||||
@ -387,6 +406,8 @@ func ParseTimeFromContent(content string, format ...string) *Time {
|
||||
return NewFromStr(strings.Trim(match[0], "./_- \n\r"))
|
||||
} else if match := timeRegex2.FindStringSubmatch(content); len(match) >= 1 {
|
||||
return NewFromStr(strings.Trim(match[0], "./_- \n\r"))
|
||||
} else if match := timeRegex3.FindStringSubmatch(content); len(match) >= 1 {
|
||||
return NewFromStr(strings.Trim(match[0], "./_- \n\r"))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
@ -36,8 +36,24 @@ func New(param ...interface{}) *Time {
|
||||
case *Time:
|
||||
return r
|
||||
case string:
|
||||
if len(param) > 1 {
|
||||
switch t := param[1].(type) {
|
||||
case string:
|
||||
return NewFromStrFormat(r, t)
|
||||
case []byte:
|
||||
return NewFromStrFormat(r, string(t))
|
||||
}
|
||||
}
|
||||
return NewFromStr(r)
|
||||
case []byte:
|
||||
if len(param) > 1 {
|
||||
switch t := param[1].(type) {
|
||||
case string:
|
||||
return NewFromStrFormat(string(r), t)
|
||||
case []byte:
|
||||
return NewFromStrFormat(string(r), string(t))
|
||||
}
|
||||
}
|
||||
return NewFromStr(string(r))
|
||||
case int:
|
||||
return NewFromTimeStamp(int64(r))
|
||||
@ -163,6 +179,11 @@ func (t *Time) TimestampNanoStr() string {
|
||||
return strconv.FormatInt(t.TimestampNano(), 10)
|
||||
}
|
||||
|
||||
// Month returns the month of the year specified by t.
|
||||
func (t *Time) Month() int {
|
||||
return int(t.Time.Month())
|
||||
}
|
||||
|
||||
// Second returns the second offset within the minute specified by t,
|
||||
// in the range [0, 59].
|
||||
func (t *Time) Second() int {
|
||||
@ -219,22 +240,6 @@ func (t *Time) AddStr(duration string) (*Time, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// ToLocation converts current time to specified location.
|
||||
func (t *Time) ToLocation(location *time.Location) *Time {
|
||||
newTime := t.Clone()
|
||||
newTime.Time = newTime.Time.In(location)
|
||||
return newTime
|
||||
}
|
||||
|
||||
// ToZone converts current time to specified zone like: Asia/Shanghai.
|
||||
func (t *Time) ToZone(zone string) (*Time, error) {
|
||||
if l, err := time.LoadLocation(zone); err == nil {
|
||||
return t.ToLocation(l), nil
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// UTC converts current time to UTC timezone.
|
||||
func (t *Time) UTC() *Time {
|
||||
newTime := t.Clone()
|
||||
@ -252,13 +257,6 @@ func (t *Time) RFC822() string {
|
||||
return t.Layout("Mon, 02 Jan 06 15:04 MST")
|
||||
}
|
||||
|
||||
// Local converts the time to local timezone.
|
||||
func (t *Time) Local() *Time {
|
||||
newTime := t.Clone()
|
||||
newTime.Time = newTime.Time.Local()
|
||||
return newTime
|
||||
}
|
||||
|
||||
// AddDate adds year, month and day to the time.
|
||||
func (t *Time) AddDate(years int, months int, days int) *Time {
|
||||
newTime := t.Clone()
|
||||
|
||||
58
os/gtime/gtime_time_zone.go
Normal file
58
os/gtime/gtime_time_zone.go
Normal file
@ -0,0 +1,58 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gtime
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
// locationMap is time zone name to its location object.
|
||||
// Time zone name is like: Asia/Shanghai.
|
||||
locationMap = make(map[string]*time.Location)
|
||||
// locationMu is used for concurrent safety for `locationMap`.
|
||||
locationMu = sync.RWMutex{}
|
||||
)
|
||||
|
||||
// ToLocation converts current time to specified location.
|
||||
func (t *Time) ToLocation(location *time.Location) *Time {
|
||||
newTime := t.Clone()
|
||||
newTime.Time = newTime.Time.In(location)
|
||||
return newTime
|
||||
}
|
||||
|
||||
// ToZone converts current time to specified zone like: Asia/Shanghai.
|
||||
func (t *Time) ToZone(zone string) (*Time, error) {
|
||||
if location, err := t.getLocationByZoneName(zone); err == nil {
|
||||
return t.ToLocation(location), nil
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Time) getLocationByZoneName(name string) (location *time.Location, err error) {
|
||||
locationMu.RLock()
|
||||
location = locationMap[name]
|
||||
locationMu.RUnlock()
|
||||
if location == nil {
|
||||
location, err = time.LoadLocation(name)
|
||||
if err == nil && location != nil {
|
||||
locationMu.Lock()
|
||||
locationMap[name] = location
|
||||
locationMu.Unlock()
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Local converts the time to local timezone.
|
||||
func (t *Time) Local() *Time {
|
||||
newTime := t.Clone()
|
||||
newTime.Time = newTime.Time.Local()
|
||||
return newTime
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
@ -8,6 +8,7 @@ package gtime_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
)
|
||||
@ -42,6 +43,18 @@ func Benchmark_StrToTime(b *testing.B) {
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_StrToTime_Format(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
gtime.StrToTime("2018-02-09 20:46:17.897", "Y-m-d H:i:su")
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_StrToTime_Layout(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
gtime.StrToTimeLayout("2018-02-09T20:46:17.897Z", time.RFC3339)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_ParseTimeFromContent(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
gtime.ParseTimeFromContent("2018-02-09T20:46:17.897Z")
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
@ -7,6 +7,7 @@
|
||||
package gtime_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -16,8 +17,8 @@ import (
|
||||
|
||||
func Test_SetTimeZone(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
gtime.SetTimeZone("Asia/Shanghai")
|
||||
t.Assert(time.Local.String(), "Asia/Shanghai")
|
||||
t.Assert(gtime.SetTimeZone("Asia/Shanghai"), nil)
|
||||
//t.Assert(time.Local.String(), "Asia/Shanghai")
|
||||
})
|
||||
}
|
||||
|
||||
@ -86,6 +87,7 @@ func Test_RFC822(t *testing.T) {
|
||||
|
||||
func Test_StrToTime(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
// Correct datetime string.
|
||||
var testDateTimes = []string{
|
||||
"2006-01-02 15:04:05",
|
||||
"2006/01/02 15:04:05",
|
||||
@ -103,13 +105,11 @@ func Test_StrToTime(t *testing.T) {
|
||||
|
||||
for _, item := range testDateTimes {
|
||||
timeTemp, err := gtime.StrToTime(item)
|
||||
if err != nil {
|
||||
t.Error("test fail")
|
||||
}
|
||||
t.Assert(err, nil)
|
||||
t.Assert(timeTemp.Time.Format("2006-01-02 15:04:05"), "2006-01-02 15:04:05")
|
||||
}
|
||||
|
||||
//正常日期列表,时间00:00:00
|
||||
// Correct date string,.
|
||||
var testDates = []string{
|
||||
"2006.01.02",
|
||||
"2006.01.02 00:00",
|
||||
@ -118,13 +118,25 @@ func Test_StrToTime(t *testing.T) {
|
||||
|
||||
for _, item := range testDates {
|
||||
timeTemp, err := gtime.StrToTime(item)
|
||||
if err != nil {
|
||||
t.Error("test fail")
|
||||
}
|
||||
t.Assert(err, nil)
|
||||
t.Assert(timeTemp.Time.Format("2006-01-02 15:04:05"), "2006-01-02 00:00:00")
|
||||
}
|
||||
|
||||
//测试格式化formatToStdLayout
|
||||
// Correct time string.
|
||||
var testTimes = g.MapStrStr{
|
||||
"16:12:01": "15:04:05",
|
||||
"16:12:01.789": "15:04:05.000",
|
||||
}
|
||||
|
||||
for k, v := range testTimes {
|
||||
time1, err := gtime.StrToTime(k)
|
||||
t.Assert(err, nil)
|
||||
time2, err := time.ParseInLocation(v, k, time.Local)
|
||||
t.Assert(err, nil)
|
||||
t.Assert(time1.Time, time2)
|
||||
}
|
||||
|
||||
// formatToStdLayout
|
||||
var testDateFormats = []string{
|
||||
"Y-m-d H:i:s",
|
||||
"\\T\\i\\m\\e Y-m-d H:i:s",
|
||||
@ -149,7 +161,7 @@ func Test_StrToTime(t *testing.T) {
|
||||
t.Assert(timeTemp.Time.Format("2006-01-02 15:04:05.000"), "2007-01-02 15:04:05.000")
|
||||
}
|
||||
|
||||
//异常日期列表
|
||||
// 异常日期列表
|
||||
var testDatesFail = []string{
|
||||
"2006.01",
|
||||
"06..02",
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
@ -51,11 +51,11 @@ func (view *View) buildInFuncMaps(value ...interface{}) []map[string]interface{}
|
||||
func (view *View) buildInFuncEq(value interface{}, others ...interface{}) bool {
|
||||
s := gconv.String(value)
|
||||
for _, v := range others {
|
||||
if strings.Compare(s, gconv.String(v)) != 0 {
|
||||
return false
|
||||
if strings.Compare(s, gconv.String(v)) == 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return true
|
||||
return false
|
||||
}
|
||||
|
||||
// buildInFuncNe implements build-in template function: ne
|
||||
|
||||
@ -175,6 +175,19 @@ func Test_Func(t *testing.T) {
|
||||
t.Assert(err, nil)
|
||||
t.Assert(result, `ILoveGoFrame`)
|
||||
})
|
||||
// eq: multiple values.
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
str := `{{eq 1 2 1 3 4 5}}`
|
||||
result, err := gview.ParseContent(str, nil)
|
||||
t.Assert(err != nil, false)
|
||||
t.Assert(result, `true`)
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
str := `{{eq 6 2 1 3 4 5}}`
|
||||
result, err := gview.ParseContent(str, nil)
|
||||
t.Assert(err != nil, false)
|
||||
t.Assert(result, `false`)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_FuncNl2Br(t *testing.T) {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
@ -17,9 +17,28 @@ import (
|
||||
|
||||
func Test_Time(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
t1 := "2011-10-10 01:02:03.456"
|
||||
t.AssertEQ(gconv.GTime(t1), gtime.NewFromStr(t1))
|
||||
t.AssertEQ(gconv.Time(t1), gtime.NewFromStr(t1).Time)
|
||||
s := "2011-10-10 01:02:03.456"
|
||||
t.AssertEQ(gconv.GTime(s), gtime.NewFromStr(s))
|
||||
t.AssertEQ(gconv.Time(s), gtime.NewFromStr(s).Time)
|
||||
t.AssertEQ(gconv.Duration(100), 100*time.Nanosecond)
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
s := "01:02:03.456"
|
||||
t.AssertEQ(gconv.GTime(s).Hour(), 1)
|
||||
t.AssertEQ(gconv.GTime(s).Minute(), 2)
|
||||
t.AssertEQ(gconv.GTime(s).Second(), 3)
|
||||
t.AssertEQ(gconv.GTime(s), gtime.NewFromStr(s))
|
||||
t.AssertEQ(gconv.Time(s), gtime.NewFromStr(s).Time)
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
s := "0000-01-01 01:02:03"
|
||||
t.AssertEQ(gconv.GTime(s).Year(), 0)
|
||||
t.AssertEQ(gconv.GTime(s).Month(), 1)
|
||||
t.AssertEQ(gconv.GTime(s).Day(), 1)
|
||||
t.AssertEQ(gconv.GTime(s).Hour(), 1)
|
||||
t.AssertEQ(gconv.GTime(s).Minute(), 2)
|
||||
t.AssertEQ(gconv.GTime(s).Second(), 3)
|
||||
t.AssertEQ(gconv.GTime(s), gtime.NewFromStr(s))
|
||||
t.AssertEQ(gconv.Time(s), gtime.NewFromStr(s).Time)
|
||||
})
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package gf
|
||||
|
||||
const VERSION = "v1.15.0"
|
||||
const VERSION = "v1.15.1"
|
||||
const AUTHORS = "john<john@goframe.org>"
|
||||
|
||||
Reference in New Issue
Block a user