mirror of
https://gitee.com/johng/gf
synced 2026-07-06 21:45:34 +08:00
1
.gitignore
vendored
1
.gitignore
vendored
@ -7,7 +7,6 @@
|
||||
.settings/
|
||||
.vscode/
|
||||
vender/
|
||||
log/
|
||||
composer.lock
|
||||
gitpush.sh
|
||||
pkg/
|
||||
|
||||
@ -26,6 +26,10 @@ before_install:
|
||||
install:
|
||||
- cat /etc/hosts
|
||||
|
||||
before_script:
|
||||
- find . -name "*.go" | xargs gofmt -w
|
||||
- git diff --exit-code
|
||||
|
||||
script:
|
||||
- cd g
|
||||
- GOARCH=386 go test -v ./...
|
||||
|
||||
@ -12,9 +12,11 @@
|
||||
|[zhuhuan12](https://gitee.com/zhuhuan12)|gitee|¥50.00
|
||||
|[zfan_codes](https://gitee.com/zfan_codes)|gitee|¥10.00
|
||||
|[arden](https://github.com/arden)|alipay|¥10.00
|
||||
|x*z|wechat|¥20.00
|
||||
|潘兄|wechat|¥100.00
|
||||
|Fly的狐狸|wechat|¥100.00
|
||||
|土豆相公|alipay|¥66.60
|
||||
|Hades|alipay|¥66.66
|
||||
|蔡蔡|wechat|¥666.00
|
||||
|上海金保证网络科技|bank|¥2000.00
|
||||
|
||||
|
||||
66
README.MD
66
README.MD
@ -11,48 +11,35 @@
|
||||
|
||||
</div>
|
||||
|
||||
`GF(Go Frame)`是一款模块化、高性能、生产级Go应用开发框架。提供了常用的核心开发组件,如:缓存、日志、文件、时间、队列、数组、集合、字符串、定时器、命令行、文件锁、内存锁、对象池、连接池、数据校验、数据编码、文件监控、定时任务、数据库ORM、TCP/UDP组件、进程管理/通信、
|
||||
并发安全容器等等。并提供了Web服务开发的系列核心组件,如:Router、Cookie、Session、服务注册、配置管理、模板引擎等等,支持热重启、热更新、多域名、多端口、多服务、HTTPS、Rewrite等特性。
|
||||
`GF(GoFrame)` is a modular, full-featured and production-ready application development framework of golang. Providing a series of core components and dozens of practical modules, such as: memcache, configure, validator, logging, array/queue/set/map containers, timer/timing tasks, file/memory lock, object pool, database ORM, etc. Supporting web server integrated with router, cookie, session, logger, template, https, hooks, rewrites and many more features.
|
||||
|
||||
|
||||
# 特点
|
||||
* 模块化、松耦合设计;
|
||||
* 模块丰富,开箱即用;
|
||||
* 详尽的开发文档及示例;
|
||||
* 完善的本地中文化支持;
|
||||
* 致力于项目的通用方案;
|
||||
* 更适合企业及团队使用;
|
||||
* 更多请查阅文档及源码;
|
||||
|
||||
# 安装
|
||||
```html
|
||||
# Installation
|
||||
```
|
||||
go get -u github.com/gogf/gf
|
||||
```
|
||||
或者
|
||||
`go.mod`:
|
||||
or use `go.mod`:
|
||||
```
|
||||
require github.com/gogf/gf latest
|
||||
```
|
||||
|
||||
# 限制
|
||||
```shell
|
||||
golang版本 >= 1.10
|
||||
# Limitation
|
||||
```
|
||||
golang version >= 1.10
|
||||
```
|
||||
|
||||
# 架构
|
||||
# Documentation
|
||||
|
||||
* [APIDoc](https://godoc.org/github.com/gogf/gf)
|
||||
* [中文文档](https://goframe.org)
|
||||
|
||||
# Architecture
|
||||
<div align=center>
|
||||
<img src="https://goframe.org/images/arch.png"/>
|
||||
</div>
|
||||
|
||||
# Quick Start
|
||||
|
||||
|
||||
# 文档
|
||||
|
||||
开发文档:[https://goframe.org](https://goframe.org)
|
||||
|
||||
接口文档:[https://godoc.org/github.com/gogf/gf](https://godoc.org/github.com/gogf/gf)
|
||||
|
||||
# 使用
|
||||
```go
|
||||
package main
|
||||
|
||||
@ -70,17 +57,26 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
[更多..](https://goframe.org/start/index)
|
||||
[View More..](https://goframe.org/start/index)
|
||||
|
||||
|
||||
# 协议
|
||||
# License
|
||||
|
||||
`GF` is licensed under the [MIT License](LICENSE), 100% free and open-source, forever.
|
||||
|
||||
# Donators
|
||||
|
||||
We currently accept donation by Alipay/WechatPay, please note your github/gitee account in your payment bill. If you like `GF`, why not [buy developer a cup of coffee](DONATOR.MD)?
|
||||
|
||||
# Thanks
|
||||
<a href="https://www.jetbrains.com/?from=GoFrame"><img src="https://goframe.org/images/jetbrains.png" width="100" alt="JetBrains"/></a>
|
||||
|
||||
|
||||
<!--
|
||||
# Sponsor
|
||||
We appreciate any kind of sponsorship for `GF` development. If you've got some interested, please contact john@goframe.org.
|
||||
-->
|
||||
|
||||
`GF` 使用非常友好的 [MIT](LICENSE) 开源协议进行发布,永久`100%`开源免费。
|
||||
|
||||
# 捐赠
|
||||
|
||||
如果您喜欢`GF`,要不[给开发者来杯咖啡吧](DONATOR.MD)!
|
||||
请在捐赠时备注您的`github`/`gitee`账号名称。
|
||||
|
||||
# 感谢
|
||||
<a href="https://www.jetbrains.com/?from=GoFrame"><img src="https://goframe.org/images/jetbrains.png" width="100" alt="JetBrains"/></a>
|
||||
1
TODO.MD
1
TODO.MD
@ -48,6 +48,7 @@
|
||||
1. 改进gdb对pgsql/mssql/oracle的支持,使用方法覆盖的方式改进操作,而不是完全依靠正则替换的方式;
|
||||
1. gdb的Cache缓存功能增加可自定义缓存接口,以便支持外部缓存功能,缓存接口可以通过io.ReadWriter接口实现;
|
||||
1. grpool增加支持阻塞添加任务接口;
|
||||
1. gdb.Model在链式安全的对象创建中增加sync.Pool的使用;
|
||||
|
||||
|
||||
# DONE
|
||||
|
||||
@ -9,20 +9,21 @@
|
||||
package gaes_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/encoding/gbase64"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/g/encoding/gbase64"
|
||||
|
||||
"github.com/gogf/gf/g/crypto/gaes"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
)
|
||||
|
||||
var (
|
||||
content = []byte("pibigstar")
|
||||
content_16, _ = gbase64.Decode("v1jqsGHId/H8onlVHR8Vaw==")
|
||||
content_24, _ = gbase64.Decode("0TXOaj5KMoLhNWmJ3lxY1A==")
|
||||
content_32, _ = gbase64.Decode("qM/Waw1kkWhrwzek24rCSA==")
|
||||
content_16_iv, _ = gbase64.Decode("DqQUXiHgW/XFb6Qs98+hrA==")
|
||||
content_32_iv, _ = gbase64.Decode("ZuLgAOii+lrD5KJoQ7yQ8Q==")
|
||||
content_16, _ = gbase64.DecodeString("v1jqsGHId/H8onlVHR8Vaw==")
|
||||
content_24, _ = gbase64.DecodeString("0TXOaj5KMoLhNWmJ3lxY1A==")
|
||||
content_32, _ = gbase64.DecodeString("qM/Waw1kkWhrwzek24rCSA==")
|
||||
content_16_iv, _ = gbase64.DecodeString("DqQUXiHgW/XFb6Qs98+hrA==")
|
||||
content_32_iv, _ = gbase64.DecodeString("ZuLgAOii+lrD5KJoQ7yQ8Q==")
|
||||
// iv 长度必须等于blockSize,只能为16
|
||||
iv = []byte("Hello My GoFrame")
|
||||
key_16 = []byte("1234567891234567")
|
||||
@ -35,7 +36,7 @@ var (
|
||||
|
||||
// cfb模式blockSize补位长度, add by zseeker
|
||||
padding_size = 16 - len(content)
|
||||
content_16_cfb, _ = gbase64.Decode("oSmget3aBDT1nJnBp8u6kA==")
|
||||
content_16_cfb, _ = gbase64.DecodeString("oSmget3aBDT1nJnBp8u6kA==")
|
||||
)
|
||||
|
||||
func TestEncrypt(t *testing.T) {
|
||||
|
||||
@ -14,13 +14,14 @@ import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/g/container/gmap"
|
||||
"github.com/gogf/gf/g/container/gring"
|
||||
"github.com/gogf/gf/g/container/gtype"
|
||||
"github.com/gogf/gf/g/container/gvar"
|
||||
"github.com/gogf/gf/g/os/gcache"
|
||||
"github.com/gogf/gf/g/util/grand"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 数据库操作接口
|
||||
|
||||
@ -11,13 +11,14 @@ import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/g/container/gvar"
|
||||
"github.com/gogf/gf/g/os/gcache"
|
||||
"github.com/gogf/gf/g/os/gtime"
|
||||
"github.com/gogf/gf/g/text/gregex"
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -498,7 +499,10 @@ func (bs *dbBase) doBatchInsert(link dbLink, table string, list interface{}, opt
|
||||
// CURD操作:数据更新,统一采用sql预处理。
|
||||
// data参数支持string/map/struct/*struct类型。
|
||||
func (bs *dbBase) Update(table string, data interface{}, condition interface{}, args ...interface{}) (sql.Result, error) {
|
||||
newWhere, newArgs := formatCondition(condition, args)
|
||||
newWhere, newArgs := formatWhere(condition, args)
|
||||
if newWhere != "" {
|
||||
newWhere = " WHERE " + newWhere
|
||||
}
|
||||
return bs.db.doUpdate(nil, table, data, newWhere, newArgs...)
|
||||
}
|
||||
|
||||
@ -537,15 +541,15 @@ func (bs *dbBase) doUpdate(link dbLink, table string, data interface{}, conditio
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if len(condition) == 0 {
|
||||
return bs.db.doExec(link, fmt.Sprintf("UPDATE %s SET %s", table, updates), args...)
|
||||
}
|
||||
return bs.db.doExec(link, fmt.Sprintf("UPDATE %s SET %s WHERE %s", table, updates, condition), args...)
|
||||
return bs.db.doExec(link, fmt.Sprintf("UPDATE %s SET %s%s", table, updates, condition), args...)
|
||||
}
|
||||
|
||||
// CURD操作:删除数据
|
||||
func (bs *dbBase) Delete(table string, condition interface{}, args ...interface{}) (result sql.Result, err error) {
|
||||
newWhere, newArgs := formatCondition(condition, args)
|
||||
newWhere, newArgs := formatWhere(condition, args)
|
||||
if newWhere != "" {
|
||||
newWhere = " WHERE " + newWhere
|
||||
}
|
||||
return bs.db.doDelete(nil, table, newWhere, newArgs...)
|
||||
}
|
||||
|
||||
@ -556,10 +560,7 @@ func (bs *dbBase) doDelete(link dbLink, table string, condition string, args ...
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if len(condition) == 0 {
|
||||
return bs.db.doExec(link, fmt.Sprintf("DELETE FROM %s", table), args...)
|
||||
}
|
||||
return bs.db.doExec(link, fmt.Sprintf("DELETE FROM %s WHERE %s", table, condition), args...)
|
||||
return bs.db.doExec(link, fmt.Sprintf("DELETE FROM %s%s", table, condition), args...)
|
||||
}
|
||||
|
||||
// 获得缓存对象
|
||||
@ -570,12 +571,15 @@ func (bs *dbBase) getCache() *gcache.Cache {
|
||||
// 将数据查询的列表数据*sql.Rows转换为Result类型
|
||||
func (bs *dbBase) rowsToResult(rows *sql.Rows) (Result, error) {
|
||||
// 列信息列表, 名称与类型
|
||||
types := make([]string, 0)
|
||||
columns := make([]string, 0)
|
||||
columnTypes, _ := rows.ColumnTypes()
|
||||
for _, t := range columnTypes {
|
||||
types = append(types, t.DatabaseTypeName())
|
||||
columns = append(columns, t.Name())
|
||||
columnTypes, err := rows.ColumnTypes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
types := make([]string, len(columnTypes))
|
||||
columns := make([]string, len(columnTypes))
|
||||
for k, v := range columnTypes {
|
||||
types[k] = v.DatabaseTypeName()
|
||||
columns[k] = v.Name()
|
||||
}
|
||||
// 返回结构组装
|
||||
values := make([]sql.RawBytes, len(columns))
|
||||
@ -589,14 +593,15 @@ func (bs *dbBase) rowsToResult(rows *sql.Rows) (Result, error) {
|
||||
return records, err
|
||||
}
|
||||
row := make(Record)
|
||||
// 注意col字段是一个[]byte类型(slice类型本身是一个指针),多个记录循环时该变量指向的是同一个内存地址
|
||||
for i, col := range values {
|
||||
if col == nil {
|
||||
// 注意col字段是一个[]byte类型(slice类型本身是一个引用类型),
|
||||
// 多个记录循环时该变量指向的是同一个内存地址
|
||||
for i, column := range values {
|
||||
if column == nil {
|
||||
row[columns[i]] = gvar.New(nil, true)
|
||||
} else {
|
||||
// 由于 sql.RawBytes 是slice类型, 这里必须使用值复制
|
||||
v := make([]byte, len(col))
|
||||
copy(v, col)
|
||||
v := make([]byte, len(column))
|
||||
copy(v, column)
|
||||
row[columns[i]] = gvar.New(bs.db.convertValue(v, types[i]), true)
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,14 +10,15 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/g/os/glog"
|
||||
"github.com/gogf/gf/g/os/gtime"
|
||||
"github.com/gogf/gf/g/text/gregex"
|
||||
"github.com/gogf/gf/g/text/gstr"
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Type assert api for String().
|
||||
@ -25,8 +26,8 @@ type apiString interface {
|
||||
String() string
|
||||
}
|
||||
|
||||
// 格式化SQL查询条件
|
||||
func formatCondition(where interface{}, args []interface{}) (newWhere string, newArgs []interface{}) {
|
||||
// 格式化Where查询条件
|
||||
func formatWhere(where interface{}, args []interface{}) (newWhere string, newArgs []interface{}) {
|
||||
// 条件字符串处理
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
// 使用反射进行类型判断
|
||||
|
||||
@ -12,8 +12,9 @@ import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
"reflect"
|
||||
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
)
|
||||
|
||||
// 数据库链式操作模型对象
|
||||
@ -29,13 +30,13 @@ type Model struct {
|
||||
orderBy string // 排序语句
|
||||
start int // 分页开始
|
||||
limit int // 分页条数
|
||||
data interface{} // 操作记录(支持Map/List/string类型)
|
||||
data interface{} // 操作数据(注意仅支持Map/List/string类型)
|
||||
batch int // 批量操作条数
|
||||
filter bool // 是否按照表字段过滤data参数
|
||||
cacheEnabled bool // 当前SQL操作是否开启查询缓存功能
|
||||
cacheTime int // 查询缓存时间
|
||||
cacheName string // 查询缓存名称
|
||||
safe bool // 当前模型是否运行安全模式(可修改当前模型,否则每一次链式操作都是返回新的模型对象)
|
||||
safe bool // 当前模型是否安全模式(默认非安全表示链式操作直接修改当前模型属性;否则每一次链式操作都是返回新的模型对象)
|
||||
}
|
||||
|
||||
// 链式操作,数据表字段,可支持多个表,以半角逗号连接
|
||||
@ -45,6 +46,7 @@ func (bs *dbBase) Table(tables string) *Model {
|
||||
tablesInit: tables,
|
||||
tables: tables,
|
||||
fields: "*",
|
||||
start: -1,
|
||||
safe: false,
|
||||
}
|
||||
}
|
||||
@ -149,7 +151,7 @@ func (md *Model) Where(where interface{}, args ...interface{}) *Model {
|
||||
if model.where != "" {
|
||||
return md.And(where, args...)
|
||||
}
|
||||
newWhere, newArgs := formatCondition(where, args)
|
||||
newWhere, newArgs := formatWhere(where, args)
|
||||
model.where = newWhere
|
||||
model.whereArgs = newArgs
|
||||
return model
|
||||
@ -158,7 +160,7 @@ func (md *Model) Where(where interface{}, args ...interface{}) *Model {
|
||||
// 链式操作,添加AND条件到Where中
|
||||
func (md *Model) And(where interface{}, args ...interface{}) *Model {
|
||||
model := md.getModel()
|
||||
newWhere, newArgs := formatCondition(where, args)
|
||||
newWhere, newArgs := formatWhere(where, args)
|
||||
if len(model.where) > 0 && model.where[0] == '(' {
|
||||
model.where = fmt.Sprintf(`%s AND (%s)`, model.where, newWhere)
|
||||
} else {
|
||||
@ -171,7 +173,7 @@ func (md *Model) And(where interface{}, args ...interface{}) *Model {
|
||||
// 链式操作,添加OR条件到Where中
|
||||
func (md *Model) Or(where interface{}, args ...interface{}) *Model {
|
||||
model := md.getModel()
|
||||
newWhere, newArgs := formatCondition(where, args)
|
||||
newWhere, newArgs := formatWhere(where, args)
|
||||
if len(model.where) > 0 && model.where[0] == '(' {
|
||||
model.where = fmt.Sprintf(`%s OR (%s)`, model.where, newWhere)
|
||||
} else {
|
||||
@ -195,11 +197,20 @@ func (md *Model) OrderBy(orderBy string) *Model {
|
||||
return model
|
||||
}
|
||||
|
||||
// 链式操作,limit
|
||||
func (md *Model) Limit(start int, limit int) *Model {
|
||||
// 链式操作,limit。
|
||||
//
|
||||
// 如果给定一个参数,那么生成的SQL为:LIMIT limit[0]
|
||||
//
|
||||
// 如果给定两个参数,那么生成的SQL为:LIMIT limit[0], limit[1]
|
||||
func (md *Model) Limit(limit ...int) *Model {
|
||||
model := md.getModel()
|
||||
model.start = start
|
||||
model.limit = limit
|
||||
switch len(limit) {
|
||||
case 1:
|
||||
model.limit = limit[0]
|
||||
case 2:
|
||||
model.start = limit[0]
|
||||
model.limit = limit[1]
|
||||
}
|
||||
return model
|
||||
}
|
||||
|
||||
@ -425,9 +436,9 @@ func (md *Model) Update() (result sql.Result, err error) {
|
||||
}
|
||||
}
|
||||
if md.tx == nil {
|
||||
return md.db.doUpdate(nil, md.tables, md.data, md.where, md.whereArgs...)
|
||||
return md.db.doUpdate(nil, md.tables, md.data, md.getConditionSql(), md.whereArgs...)
|
||||
} else {
|
||||
return md.tx.doUpdate(md.tables, md.data, md.where, md.whereArgs...)
|
||||
return md.tx.doUpdate(md.tables, md.data, md.getConditionSql(), md.whereArgs...)
|
||||
}
|
||||
}
|
||||
|
||||
@ -439,9 +450,9 @@ func (md *Model) Delete() (result sql.Result, err error) {
|
||||
}
|
||||
}()
|
||||
if md.tx == nil {
|
||||
return md.db.doDelete(nil, md.tables, md.where, md.whereArgs...)
|
||||
return md.db.doDelete(nil, md.tables, md.getConditionSql(), md.whereArgs...)
|
||||
} else {
|
||||
return md.tx.doDelete(md.tables, md.where, md.whereArgs...)
|
||||
return md.tx.doDelete(md.tables, md.getConditionSql(), md.whereArgs...)
|
||||
}
|
||||
}
|
||||
|
||||
@ -452,7 +463,7 @@ func (md *Model) Select() (Result, error) {
|
||||
|
||||
// 链式操作,查询所有记录
|
||||
func (md *Model) All() (Result, error) {
|
||||
return md.getAll(md.getFormattedSql(), md.whereArgs...)
|
||||
return md.getAll(fmt.Sprintf("SELECT %s FROM %s %s", md.fields, md.tables, md.getConditionSql()), md.whereArgs...)
|
||||
}
|
||||
|
||||
// 链式操作,查询单条记录
|
||||
@ -530,7 +541,7 @@ func (md *Model) Count() (int, error) {
|
||||
} else {
|
||||
md.fields = fmt.Sprintf(`COUNT(%s)`, md.fields)
|
||||
}
|
||||
s := md.getFormattedSql()
|
||||
s := fmt.Sprintf("SELECT %s FROM %s %s", md.fields, md.tables, md.getConditionSql())
|
||||
if len(md.groupBy) > 0 {
|
||||
s = fmt.Sprintf("SELECT COUNT(1) FROM (%s) count_alias", s)
|
||||
}
|
||||
@ -583,12 +594,9 @@ func (md *Model) checkAndRemoveCache() {
|
||||
}
|
||||
}
|
||||
|
||||
// 格式化当前输入参数,返回可执行的SQL语句(不带参数)
|
||||
func (md *Model) getFormattedSql() string {
|
||||
if md.fields == "" {
|
||||
md.fields = "*"
|
||||
}
|
||||
s := fmt.Sprintf("SELECT %s FROM %s", md.fields, md.tables)
|
||||
// 格式化当前输入参数,返回SQL条件语句(不带参数)
|
||||
func (md *Model) getConditionSql() string {
|
||||
s := ""
|
||||
if md.where != "" {
|
||||
s += " WHERE " + md.where
|
||||
}
|
||||
@ -599,7 +607,12 @@ func (md *Model) getFormattedSql() string {
|
||||
s += " ORDER BY " + md.orderBy
|
||||
}
|
||||
if md.limit != 0 {
|
||||
s += fmt.Sprintf(" LIMIT %d, %d", md.start, md.limit)
|
||||
if md.start >= 0 {
|
||||
s += fmt.Sprintf(" LIMIT %d, %d", md.start, md.limit)
|
||||
} else {
|
||||
s += fmt.Sprintf(" LIMIT %d", md.limit)
|
||||
}
|
||||
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
@ -9,8 +9,9 @@ package gdb
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/g/text/gregex"
|
||||
"reflect"
|
||||
|
||||
"github.com/gogf/gf/g/text/gregex"
|
||||
)
|
||||
|
||||
// 数据库事务对象
|
||||
@ -164,7 +165,10 @@ func (tx *TX) BatchSave(table string, list interface{}, batch ...int) (sql.Resul
|
||||
// CURD操作:数据更新,统一采用sql预处理,
|
||||
// data参数支持字符串或者关联数组类型,内部会自行做判断处理.
|
||||
func (tx *TX) Update(table string, data interface{}, condition interface{}, args ...interface{}) (sql.Result, error) {
|
||||
newWhere, newArgs := formatCondition(condition, args)
|
||||
newWhere, newArgs := formatWhere(condition, args)
|
||||
if newWhere != "" {
|
||||
newWhere = " WHERE " + newWhere
|
||||
}
|
||||
return tx.doUpdate(table, data, newWhere, newArgs...)
|
||||
}
|
||||
|
||||
@ -175,7 +179,10 @@ func (tx *TX) doUpdate(table string, data interface{}, condition string, args ..
|
||||
|
||||
// CURD操作:删除数据
|
||||
func (tx *TX) Delete(table string, condition interface{}, args ...interface{}) (sql.Result, error) {
|
||||
newWhere, newArgs := formatCondition(condition, args)
|
||||
newWhere, newArgs := formatWhere(condition, args)
|
||||
if newWhere != "" {
|
||||
newWhere = " WHERE " + newWhere
|
||||
}
|
||||
return tx.doDelete(table, newWhere, newArgs...)
|
||||
}
|
||||
|
||||
|
||||
@ -8,12 +8,14 @@ package gdb_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/gogf/gf/g"
|
||||
"github.com/gogf/gf/g/container/garray"
|
||||
|
||||
"github.com/gogf/gf/g/database/gdb"
|
||||
"github.com/gogf/gf/g/os/gtime"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"os"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -88,14 +90,6 @@ func createTable(table ...string) (name string) {
|
||||
return
|
||||
}
|
||||
|
||||
// 删除指定表.
|
||||
func dropTable(table string) {
|
||||
if _, err := db.Exec(fmt.Sprintf("DROP TABLE IF EXISTS `%s`", table)); err != nil {
|
||||
gtest.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// See createTable.
|
||||
// 创建测试表,并初始化默认数据。
|
||||
func createInitTable(table ...string) (name string) {
|
||||
name = createTable(table...)
|
||||
@ -117,3 +111,10 @@ func createInitTable(table ...string) (name string) {
|
||||
gtest.Assert(n, INIT_DATA_SIZE)
|
||||
return
|
||||
}
|
||||
|
||||
// 删除指定表.
|
||||
func dropTable(table string) {
|
||||
if _, err := db.Exec(fmt.Sprintf("DROP TABLE IF EXISTS `%s`", table)); err != nil {
|
||||
gtest.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,10 +7,11 @@
|
||||
package gdb_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/g"
|
||||
"github.com/gogf/gf/g/os/gtime"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// 基本测试
|
||||
@ -187,6 +188,25 @@ func TestModel_Save(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestModel_Update(t *testing.T) {
|
||||
table := createInitTable()
|
||||
// UPDATE...LIMIT
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).Data("nickname", "T100").OrderBy("id desc").Limit(2).Update()
|
||||
if err != nil {
|
||||
gtest.Fatal(err)
|
||||
}
|
||||
n, _ := result.RowsAffected()
|
||||
gtest.Assert(n, 2)
|
||||
|
||||
v1, err := db.Table(table).Fields("nickname").Where("id", 10).Value()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(v1.String(), "T100")
|
||||
|
||||
v2, err := db.Table(table).Fields("nickname").Where("id", 8).Value()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(v2.String(), "T8")
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table("user").Data("passport", "t22").Where("passport=?", "t2").Update()
|
||||
if err != nil {
|
||||
@ -644,10 +664,22 @@ func TestModel_Where(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestModel_Delete(t *testing.T) {
|
||||
result, err := db.Table("user").Delete()
|
||||
if err != nil {
|
||||
gtest.Fatal(err)
|
||||
}
|
||||
n, _ := result.RowsAffected()
|
||||
gtest.Assert(n, 3)
|
||||
// DELETE...LIMIT
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table("user").Limit(2).Delete()
|
||||
if err != nil {
|
||||
gtest.Fatal(err)
|
||||
}
|
||||
n, _ := result.RowsAffected()
|
||||
gtest.Assert(n, 2)
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table("user").Delete()
|
||||
if err != nil {
|
||||
gtest.Fatal(err)
|
||||
}
|
||||
n, _ := result.RowsAffected()
|
||||
gtest.Assert(n, 1)
|
||||
})
|
||||
}
|
||||
|
||||
@ -4,20 +4,36 @@
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package gbase64 provides useful API for BASE64 encoding/decoding algorithms.
|
||||
// Package gbase64 provides useful API for BASE64 encoding/decoding algorithm.
|
||||
package gbase64
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
)
|
||||
|
||||
// base64 encode
|
||||
func Encode(str string) string {
|
||||
return base64.StdEncoding.EncodeToString([]byte(str))
|
||||
// Encode encodes bytes with BASE64 algorithm.
|
||||
func Encode(src []byte) []byte {
|
||||
dst := make([]byte, base64.StdEncoding.EncodedLen(len(src)))
|
||||
base64.StdEncoding.Encode(dst, src)
|
||||
return dst
|
||||
}
|
||||
|
||||
// base64 decode
|
||||
func Decode(str string) (string, error) {
|
||||
s, e := base64.StdEncoding.DecodeString(str)
|
||||
return string(s), e
|
||||
// Decode decodes bytes with BASE64 algorithm.
|
||||
func Decode(dst []byte) ([]byte, error) {
|
||||
src := make([]byte, base64.StdEncoding.DecodedLen(len(dst)))
|
||||
n, err := base64.StdEncoding.Decode(src, dst)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return src[:n], nil
|
||||
}
|
||||
|
||||
// EncodeString encodes bytes with BASE64 algorithm.
|
||||
func EncodeString(src []byte) string {
|
||||
return string(Encode(src))
|
||||
}
|
||||
|
||||
// DecodeString decodes string with BASE64 algorithm.
|
||||
func DecodeString(str string) ([]byte, error) {
|
||||
return Decode([]byte(str))
|
||||
}
|
||||
|
||||
@ -6,9 +6,10 @@
|
||||
package gbase64_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/g/encoding/gbase64"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type testpair struct {
|
||||
@ -42,10 +43,17 @@ var pairs = []testpair{
|
||||
}
|
||||
|
||||
func TestBase64(t *testing.T) {
|
||||
for k := range pairs {
|
||||
gtest.Assert(gbase64.Encode(pairs[k].decoded), pairs[k].encoded)
|
||||
gtest.Case(t, func() {
|
||||
for k := range pairs {
|
||||
// []byte
|
||||
gtest.Assert(gbase64.Encode([]byte(pairs[k].decoded)), []byte(pairs[k].encoded))
|
||||
e1, _ := gbase64.Decode([]byte(pairs[k].encoded))
|
||||
gtest.Assert(e1, []byte(pairs[k].decoded))
|
||||
|
||||
e, _ := gbase64.Decode(pairs[k].encoded)
|
||||
gtest.Assert(e, pairs[k].decoded)
|
||||
}
|
||||
// string
|
||||
gtest.Assert(gbase64.EncodeString([]byte(pairs[k].decoded)), pairs[k].encoded)
|
||||
e2, _ := gbase64.DecodeString(pairs[k].encoded)
|
||||
gtest.Assert(e2, []byte(pairs[k].decoded))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -14,13 +14,14 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/g/os/gfile"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/g/os/gfile"
|
||||
)
|
||||
|
||||
// http客户端
|
||||
@ -82,7 +83,7 @@ func (c *Client) Put(url string, data ...interface{}) (*ClientResponse, error) {
|
||||
// POST请求提交数据,默认使用表单方式提交数据(绝大部分场景下也是如此)。
|
||||
// 如果服务端对Content-Type有要求,可使用Client对象进行请求,单独设置相关属性。
|
||||
// 支持文件上传,需要字段格式为:FieldName=@file:
|
||||
func (c *Client) Post(url string, data ...interface{}) (*ClientResponse, error) {
|
||||
func (c *Client) Post(url string, data ...interface{}) (resp *ClientResponse, err error) {
|
||||
if len(c.prefix) > 0 {
|
||||
url = c.prefix + url
|
||||
}
|
||||
@ -119,23 +120,27 @@ func (c *Client) Post(url string, data ...interface{}) (*ClientResponse, error)
|
||||
}
|
||||
}
|
||||
writer.Close()
|
||||
if r, err := http.NewRequest("POST", url, buffer); err != nil {
|
||||
if req, err = http.NewRequest("POST", url, buffer); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
req = r
|
||||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||
}
|
||||
} else {
|
||||
// 识别提交数据格式
|
||||
// 普通请求
|
||||
paramBytes := []byte(param)
|
||||
if r, err := http.NewRequest("POST", url, bytes.NewReader(paramBytes)); err != nil {
|
||||
if req, err = http.NewRequest("POST", url, bytes.NewReader(paramBytes)); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
req = r
|
||||
if json.Valid(paramBytes) {
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
if v, ok := c.header["Content-Type"]; ok {
|
||||
// 自定义请求类型
|
||||
req.Header.Set("Content-Type", v)
|
||||
} else {
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
// 识别提交数据格式
|
||||
if json.Valid(paramBytes) {
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
} else {
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -163,23 +168,22 @@ func (c *Client) Post(url string, data ...interface{}) (*ClientResponse, error)
|
||||
req.SetBasicAuth(c.authUser, c.authPass)
|
||||
}
|
||||
// 执行请求
|
||||
resp := (*http.Response)(nil)
|
||||
r := (*http.Response)(nil)
|
||||
for {
|
||||
if r, err := c.Do(req); err != nil {
|
||||
if r, err = c.Do(req); err != nil {
|
||||
if c.retryCount > 0 {
|
||||
c.retryCount--
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
resp = r
|
||||
break
|
||||
}
|
||||
}
|
||||
r := &ClientResponse{
|
||||
resp = &ClientResponse{
|
||||
cookies: make(map[string]string),
|
||||
}
|
||||
r.Response = resp
|
||||
resp.Response = r
|
||||
// 浏览器模式
|
||||
if c.browserMode {
|
||||
now := time.Now()
|
||||
@ -191,7 +195,7 @@ func (c *Client) Post(url string, data ...interface{}) (*ClientResponse, error)
|
||||
}
|
||||
}
|
||||
}
|
||||
return r, nil
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// DELETE请求
|
||||
|
||||
@ -8,9 +8,10 @@ package ghttp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/g/encoding/gbase64"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/g/encoding/gbase64"
|
||||
)
|
||||
|
||||
// 设置Basic Auth校验提示
|
||||
@ -40,12 +41,12 @@ func (r *Request) BasicAuth(user, pass string, tips ...string) bool {
|
||||
}
|
||||
switch authArray[0] {
|
||||
case "Basic":
|
||||
authStr, err := gbase64.Decode(authArray[1])
|
||||
authBytes, err := gbase64.DecodeString(authArray[1])
|
||||
if err != nil {
|
||||
r.Response.WriteStatus(http.StatusForbidden, err.Error())
|
||||
return false
|
||||
}
|
||||
authArray := strings.SplitN(string(authStr), ":", 2)
|
||||
authArray := strings.SplitN(string(authBytes), ":", 2)
|
||||
if len(authArray) != 2 {
|
||||
r.Response.WriteStatus(http.StatusForbidden)
|
||||
return false
|
||||
|
||||
@ -8,7 +8,6 @@
|
||||
package ghttp
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/text/gstr"
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
)
|
||||
|
||||
@ -26,7 +25,7 @@ type CORSOptions struct {
|
||||
// 默认的CORS配置
|
||||
func (r *Response) DefaultCORSOptions() CORSOptions {
|
||||
return CORSOptions{
|
||||
AllowOrigin: gstr.TrimRight(r.request.Referer(), "/"),
|
||||
AllowOrigin: "*",
|
||||
AllowMethods: HTTP_METHODS,
|
||||
AllowCredentials: "true",
|
||||
MaxAge: 3628800,
|
||||
|
||||
@ -8,10 +8,11 @@
|
||||
package ghttp
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/os/glog"
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/g/os/glog"
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
)
|
||||
|
||||
// 分组路由对象
|
||||
@ -55,10 +56,16 @@ func (g *RouterGroup) Bind(items []GroupItem) {
|
||||
if strings.EqualFold(gconv.String(item[0]), "REST") {
|
||||
g.bind("REST", gconv.String(item[0])+":"+gconv.String(item[1]), item[2])
|
||||
} else {
|
||||
if len(item) > 3 {
|
||||
g.bind("HANDLER", gconv.String(item[0])+":"+gconv.String(item[1]), item[2], item[3])
|
||||
method := gconv.String(item[0])
|
||||
if strings.EqualFold(method, "ALL") {
|
||||
method = ""
|
||||
} else {
|
||||
g.bind("HANDLER", gconv.String(item[0])+":"+gconv.String(item[1]), item[2])
|
||||
method += ":"
|
||||
}
|
||||
if len(item) > 3 {
|
||||
g.bind("HANDLER", method+gconv.String(item[1]), item[2], item[3])
|
||||
} else {
|
||||
g.bind("HANDLER", method+gconv.String(item[1]), item[2])
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -126,10 +133,10 @@ func (g *RouterGroup) bind(bindType string, pattern string, object interface{},
|
||||
if err != nil {
|
||||
glog.Fatalf("invalid pattern: %s", pattern)
|
||||
}
|
||||
if bindType == "HANDLER" {
|
||||
pattern = g.server.serveHandlerKey(method, g.prefix+"/"+strings.TrimLeft(path, "/"), domain)
|
||||
} else {
|
||||
if bindType == "REST" {
|
||||
pattern = g.prefix + "/" + strings.TrimLeft(path, "/")
|
||||
} else {
|
||||
pattern = g.server.serveHandlerKey(method, g.prefix+"/"+strings.TrimLeft(path, "/"), domain)
|
||||
}
|
||||
}
|
||||
methods := gconv.Strings(params)
|
||||
|
||||
@ -9,8 +9,9 @@ package ghttp
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"github.com/gogf/gf/g/text/gregex"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/g/text/gregex"
|
||||
)
|
||||
|
||||
// 查询请求处理方法.
|
||||
@ -117,5 +118,8 @@ func (s *Server) searchServeHandler(method, path, domain string) *handlerParsedI
|
||||
|
||||
// 生成回调方法查询的Key
|
||||
func (s *Server) serveHandlerKey(method, path, domain string) string {
|
||||
if method == "" {
|
||||
return path + "@" + strings.ToLower(domain)
|
||||
}
|
||||
return strings.ToUpper(method) + ":" + path + "@" + strings.ToLower(domain)
|
||||
}
|
||||
|
||||
@ -9,18 +9,29 @@ package ghttp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/g/os/gfile"
|
||||
"github.com/gogf/gf/g/os/glog"
|
||||
"github.com/gogf/gf/g/text/gregex"
|
||||
"github.com/gogf/gf/g/text/gstr"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 绑定控制器,控制器需要实现 gmvc.Controller 接口,
|
||||
// 这种方式绑定的控制器每一次请求都会初始化一个新的控制器对象进行处理,对应不同的请求会话,
|
||||
// 第三个参数methods用以指定需要注册的方法,支持多个方法名称,多个方法以英文“,”号分隔,区分大小写.
|
||||
func (s *Server) BindController(pattern string, c Controller, methods ...string) {
|
||||
// 当pattern中的method为all时,去掉该method,以便于后续方法判断
|
||||
domain, method, path, err := s.parsePattern(pattern)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return
|
||||
}
|
||||
if strings.EqualFold(method, gDEFAULT_METHOD) {
|
||||
pattern = s.serveHandlerKey("", path, domain)
|
||||
}
|
||||
|
||||
methodMap := (map[string]bool)(nil)
|
||||
if len(methods) > 0 {
|
||||
methodMap = make(map[string]bool)
|
||||
|
||||
@ -9,17 +9,28 @@ package ghttp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/g/os/gfile"
|
||||
"github.com/gogf/gf/g/os/glog"
|
||||
"github.com/gogf/gf/g/text/gregex"
|
||||
"github.com/gogf/gf/g/text/gstr"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 绑定对象到URI请求处理中,会自动识别方法名称,并附加到对应的URI地址后面
|
||||
// 第三个参数methods用以指定需要注册的方法,支持多个方法名称,多个方法以英文“,”号分隔,区分大小写
|
||||
func (s *Server) BindObject(pattern string, obj interface{}, methods ...string) {
|
||||
// 当pattern中的method为all时,去掉该method,以便于后续方法判断
|
||||
domain, method, path, err := s.parsePattern(pattern)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return
|
||||
}
|
||||
if strings.EqualFold(method, gDEFAULT_METHOD) {
|
||||
pattern = s.serveHandlerKey("", path, domain)
|
||||
}
|
||||
|
||||
methodMap := (map[string]bool)(nil)
|
||||
if len(methods) > 0 {
|
||||
methodMap = make(map[string]bool)
|
||||
|
||||
@ -7,14 +7,15 @@
|
||||
package gcache
|
||||
|
||||
import (
|
||||
"math"
|
||||
"sync"
|
||||
|
||||
"github.com/gogf/gf/g/container/glist"
|
||||
"github.com/gogf/gf/g/container/gset"
|
||||
"github.com/gogf/gf/g/container/gtype"
|
||||
"github.com/gogf/gf/g/os/gtime"
|
||||
"github.com/gogf/gf/g/os/gtimer"
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
"math"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Internal cache object.
|
||||
@ -121,8 +122,8 @@ func (c *memCache) Set(key interface{}, value interface{}, expire int) {
|
||||
func (c *memCache) doSetWithLockCheck(key interface{}, value interface{}, expire int) interface{} {
|
||||
expireTimestamp := c.getInternalExpire(expire)
|
||||
c.dataMu.Lock()
|
||||
defer c.dataMu.Unlock()
|
||||
if v, ok := c.data[key]; ok && !v.IsExpired() {
|
||||
c.dataMu.Unlock()
|
||||
return v.v
|
||||
}
|
||||
if f, ok := value.(func() interface{}); ok {
|
||||
@ -132,7 +133,6 @@ func (c *memCache) doSetWithLockCheck(key interface{}, value interface{}, expire
|
||||
return nil
|
||||
}
|
||||
c.data[key] = memCacheItem{v: value, e: expireTimestamp}
|
||||
c.dataMu.Unlock()
|
||||
c.eventList.PushBack(&memCacheEvent{k: key, e: expireTimestamp})
|
||||
return value
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
// 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 gflock_test
|
||||
|
||||
import (
|
||||
|
||||
@ -12,6 +12,7 @@ package gfsnotify
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/g/container/glist"
|
||||
"github.com/gogf/gf/g/container/gmap"
|
||||
"github.com/gogf/gf/g/container/gqueue"
|
||||
@ -92,7 +93,7 @@ func New() (*Watcher, error) {
|
||||
return w, nil
|
||||
}
|
||||
|
||||
// 添加对指定文件/目录的监听,并给定回调函数;如果给定的是一个目录,默认非递归监控。
|
||||
// 添加对指定文件/目录的监听,并给定回调函数;如果给定的是一个目录,默认递归监控。
|
||||
func Add(path string, callbackFunc func(event *Event), recursive ...bool) (callback *Callback, err error) {
|
||||
return defaultWatcher.Add(path, callbackFunc, recursive...)
|
||||
}
|
||||
|
||||
@ -9,10 +9,11 @@ package gfsnotify
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/g/container/glist"
|
||||
)
|
||||
|
||||
// 添加监控,path参数支持文件或者目录路径,recursive为非必需参数,默认为非递归监控(当path为目录时)。
|
||||
// 添加监控,path参数支持文件或者目录路径,recursive为非必需参数,默认为递归监控(当path为目录时)。
|
||||
// 如果添加目录,这里只会返回目录的callback,按照callback删除时会递归删除。
|
||||
func (w *Watcher) Add(path string, callbackFunc func(event *Event), recursive ...bool) (callback *Callback, err error) {
|
||||
// 首先添加这个文件/目录
|
||||
|
||||
1368
g/util/gconv/gconv_z_all_test.go
Normal file
1368
g/util/gconv/gconv_z_all_test.go
Normal file
File diff suppressed because it is too large
Load Diff
156
g/util/gutil/gutil_comparator_z_unit_test.go
Executable file
156
g/util/gutil/gutil_comparator_z_unit_test.go
Executable file
@ -0,0 +1,156 @@
|
||||
package gutil_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"github.com/gogf/gf/g/util/gutil"
|
||||
)
|
||||
|
||||
func Test_ComparatorString(t *testing.T) {
|
||||
|
||||
gtest.Case(t, func() {
|
||||
gtest.Assert(gutil.ComparatorString(1, 1), 0)
|
||||
gtest.Assert(gutil.ComparatorString(1, 2), -1)
|
||||
gtest.Assert(gutil.ComparatorString(2, 1), 1)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_ComparatorInt(t *testing.T) {
|
||||
|
||||
gtest.Case(t, func() {
|
||||
gtest.Assert(gutil.ComparatorInt(1, 1), 0)
|
||||
gtest.Assert(gutil.ComparatorInt(1, 2), -1)
|
||||
gtest.Assert(gutil.ComparatorInt(2, 1), 1)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_ComparatorInt8(t *testing.T) {
|
||||
|
||||
gtest.Case(t, func() {
|
||||
gtest.Assert(gutil.ComparatorInt8(1, 1), 0)
|
||||
gtest.Assert(gutil.ComparatorInt8(1, 2), -1)
|
||||
gtest.Assert(gutil.ComparatorInt8(2, 1), 1)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_ComparatorInt16(t *testing.T) {
|
||||
|
||||
gtest.Case(t, func() {
|
||||
gtest.Assert(gutil.ComparatorInt16(1, 1), 0)
|
||||
gtest.Assert(gutil.ComparatorInt16(1, 2), -1)
|
||||
gtest.Assert(gutil.ComparatorInt16(2, 1), 1)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_ComparatorInt32(t *testing.T) {
|
||||
|
||||
gtest.Case(t, func() {
|
||||
gtest.Assert(gutil.ComparatorInt32(1, 1), 0)
|
||||
gtest.Assert(gutil.ComparatorInt32(1, 2), -1)
|
||||
gtest.Assert(gutil.ComparatorInt32(2, 1), 1)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_ComparatorInt64(t *testing.T) {
|
||||
|
||||
gtest.Case(t, func() {
|
||||
gtest.Assert(gutil.ComparatorInt64(1, 1), 0)
|
||||
gtest.Assert(gutil.ComparatorInt64(1, 2), -1)
|
||||
gtest.Assert(gutil.ComparatorInt64(2, 1), 1)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_ComparatorUint(t *testing.T) {
|
||||
|
||||
gtest.Case(t, func() {
|
||||
gtest.Assert(gutil.ComparatorUint(1, 1), 0)
|
||||
gtest.Assert(gutil.ComparatorUint(1, 2), -1)
|
||||
gtest.Assert(gutil.ComparatorUint(2, 1), 1)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_ComparatorUint8(t *testing.T) {
|
||||
|
||||
gtest.Case(t, func() {
|
||||
gtest.Assert(gutil.ComparatorUint8(1, 1), 0)
|
||||
gtest.Assert(gutil.ComparatorUint8(2, 6), 252)
|
||||
gtest.Assert(gutil.ComparatorUint8(2, 1), 1)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_ComparatorUint16(t *testing.T) {
|
||||
|
||||
gtest.Case(t, func() {
|
||||
gtest.Assert(gutil.ComparatorUint16(1, 1), 0)
|
||||
gtest.Assert(gutil.ComparatorUint16(1, 2), 65535)
|
||||
gtest.Assert(gutil.ComparatorUint16(2, 1), 1)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_ComparatorUint32(t *testing.T) {
|
||||
|
||||
gtest.Case(t, func() {
|
||||
gtest.Assert(gutil.ComparatorUint32(1, 1), 0)
|
||||
gtest.Assert(gutil.ComparatorUint32(-1000, 2147483640), 2147482656)
|
||||
gtest.Assert(gutil.ComparatorUint32(2, 1), 1)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_ComparatorUint64(t *testing.T) {
|
||||
|
||||
gtest.Case(t, func() {
|
||||
gtest.Assert(gutil.ComparatorUint64(1, 1), 0)
|
||||
gtest.Assert(gutil.ComparatorUint64(1, 2), -1)
|
||||
gtest.Assert(gutil.ComparatorUint64(2, 1), 1)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_ComparatorFloat32(t *testing.T) {
|
||||
|
||||
gtest.Case(t, func() {
|
||||
gtest.Assert(gutil.ComparatorFloat32(1, 1), 0)
|
||||
gtest.Assert(gutil.ComparatorFloat32(1, 2), -1)
|
||||
gtest.Assert(gutil.ComparatorFloat32(2, 1), 1)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_ComparatorFloat64(t *testing.T) {
|
||||
|
||||
gtest.Case(t, func() {
|
||||
gtest.Assert(gutil.ComparatorFloat64(1, 1), 0)
|
||||
gtest.Assert(gutil.ComparatorFloat64(1, 2), -1)
|
||||
gtest.Assert(gutil.ComparatorFloat64(2, 1), 1)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_ComparatorByte(t *testing.T) {
|
||||
|
||||
gtest.Case(t, func() {
|
||||
gtest.Assert(gutil.ComparatorByte(1, 1), 0)
|
||||
gtest.Assert(gutil.ComparatorByte(1, 2), 255)
|
||||
gtest.Assert(gutil.ComparatorByte(2, 1), 1)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_ComparatorRune(t *testing.T) {
|
||||
|
||||
gtest.Case(t, func() {
|
||||
gtest.Assert(gutil.ComparatorRune(1, 1), 0)
|
||||
gtest.Assert(gutil.ComparatorRune(1, 2), -1)
|
||||
gtest.Assert(gutil.ComparatorRune(2, 1), 1)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_ComparatorTime(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
j := gutil.ComparatorTime("2019-06-14", "2019-06-14")
|
||||
gtest.Assert(j, 0)
|
||||
|
||||
k := gutil.ComparatorTime("2019-06-15", "2019-06-14")
|
||||
gtest.Assert(k, 1)
|
||||
|
||||
l := gutil.ComparatorTime("2019-06-13", "2019-06-14")
|
||||
gtest.Assert(l, -1)
|
||||
})
|
||||
}
|
||||
66
g/util/gutil/gutil_z_unit_test.go
Executable file
66
g/util/gutil/gutil_z_unit_test.go
Executable file
@ -0,0 +1,66 @@
|
||||
package gutil_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"github.com/gogf/gf/g/util/gutil"
|
||||
)
|
||||
|
||||
func Test_Dump(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
gutil.Dump(map[int]int{
|
||||
100: 100,
|
||||
})
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
gutil.Dump(map[string]interface{}{"": func() {}})
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
gutil.Dump([]byte("gutil Dump test"))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_PrintBacktrace(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
gutil.PrintBacktrace()
|
||||
})
|
||||
}
|
||||
|
||||
func Test_TryCatch(t *testing.T) {
|
||||
|
||||
gtest.Case(t, func() {
|
||||
gutil.TryCatch(func() {
|
||||
panic("gutil TryCatch test")
|
||||
})
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
gutil.TryCatch(func() {
|
||||
panic("gutil TryCatch test")
|
||||
|
||||
}, func(err interface{}) {
|
||||
gtest.Assert(err, "gutil TryCatch test")
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_IsEmpty(t *testing.T) {
|
||||
|
||||
gtest.Case(t, func() {
|
||||
gtest.Assert(gutil.IsEmpty(1), false)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Throw(t *testing.T) {
|
||||
|
||||
gtest.Case(t, func() {
|
||||
defer func() {
|
||||
gtest.Assert(recover(), "gutil Throw test")
|
||||
}()
|
||||
|
||||
gutil.Throw("gutil Throw test")
|
||||
})
|
||||
}
|
||||
@ -69,7 +69,12 @@ func CheckStruct(object interface{}, rules interface{}, msgs ...CustomMsg) *Erro
|
||||
continue
|
||||
}
|
||||
params[fieldName] = field.Value()
|
||||
if tag := field.Tag("gvalid"); tag != "" {
|
||||
// 同时支持valid和gvalid标签,优先使用valid
|
||||
tag := field.Tag("valid")
|
||||
if tag == "" {
|
||||
tag = field.Tag("gvalid")
|
||||
}
|
||||
if tag != "" {
|
||||
// sequence tag == struct tag, 这里的name为别名
|
||||
name, rule, msg := parseSequenceTag(tag)
|
||||
if len(name) == 0 {
|
||||
|
||||
@ -7,9 +7,10 @@
|
||||
package gvalid_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"github.com/gogf/gf/g/util/gvalid"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_CheckStruct(t *testing.T) {
|
||||
@ -51,6 +52,7 @@ func Test_CheckStruct(t *testing.T) {
|
||||
gtest.Assert(err.Maps()["password"]["required"], "登录密码不能为空")
|
||||
})
|
||||
|
||||
// gvalid tag
|
||||
gtest.Case(t, func() {
|
||||
type User struct {
|
||||
Id int `gvalid:"uid@required|min:10#|ID不能为空"`
|
||||
@ -69,4 +71,22 @@ func Test_CheckStruct(t *testing.T) {
|
||||
gtest.Assert(err.Maps()["uid"]["min"], "ID不能为空")
|
||||
})
|
||||
|
||||
// valid tag
|
||||
gtest.Case(t, func() {
|
||||
type User struct {
|
||||
Id int `valid:"uid@required|min:10#|ID不能为空"`
|
||||
Age int `valid:"age@required#年龄不能为空"`
|
||||
Username string `json:"username" gvalid:"username@required#用户名不能为空"`
|
||||
Password string `json:"password" gvalid:"password@required#登录密码不能为空"`
|
||||
}
|
||||
user := &User{
|
||||
Id: 1,
|
||||
Username: "john",
|
||||
Password: "123456",
|
||||
}
|
||||
err := gvalid.CheckStruct(user, nil)
|
||||
gtest.AssertNE(err, nil)
|
||||
gtest.Assert(len(err.Maps()), 1)
|
||||
gtest.Assert(err.Maps()["uid"]["min"], "ID不能为空")
|
||||
})
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/g"
|
||||
"github.com/gogf/gf/g/database/gdb"
|
||||
"github.com/gogf/gf/g/os/glog"
|
||||
@ -22,8 +23,11 @@ func main() {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
glog.SetPath("/tmp")
|
||||
db.SetDebug(true)
|
||||
db.Table("user").Limit(2).Delete()
|
||||
return
|
||||
glog.SetPath("/tmp")
|
||||
|
||||
// 执行3条SQL查询
|
||||
for i := 1; i <= 3; i++ {
|
||||
db.Table("user").Where("uid=?", i).One()
|
||||
25
geg/net/ghttp/server/log/log.go
Normal file
25
geg/net/ghttp/server/log/log.go
Normal file
@ -0,0 +1,25 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/net/ghttp"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := ghttp.GetServer()
|
||||
s.BindHandler("/log/handler", func(r *ghttp.Request) {
|
||||
r.Response.WriteStatus(http.StatusNotFound, "文件找不到了")
|
||||
})
|
||||
s.SetAccessLogEnabled(true)
|
||||
s.SetErrorLogEnabled(true)
|
||||
//s.SetLogHandler(func(r *ghttp.Request, error ...interface{}) {
|
||||
// if len(error) > 0 {
|
||||
// // 如果是错误日志
|
||||
// fmt.Println("错误产生了:", error[0])
|
||||
// }
|
||||
// // 这里是请求日志
|
||||
// fmt.Println("请求处理完成,请求地址:", r.URL.String(), "请求结果:", r.Response.Status)
|
||||
//})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
17
geg/net/ghttp/server/log/log_error.go
Normal file
17
geg/net/ghttp/server/log/log_error.go
Normal file
@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := ghttp.GetServer()
|
||||
s.BindHandler("/log/error", func(r *ghttp.Request) {
|
||||
if j := r.GetJson(); j != nil {
|
||||
r.Response.Write(j.Get("test"))
|
||||
}
|
||||
})
|
||||
s.SetErrorLogEnabled(true)
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/g/net/gscanner"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
//gscanner.New().SetTimeout(3*time.Second).ScanIp("192.168.2.1", "192.168.2.255", 80, func(conn net.Conn){
|
||||
// fmt.Println(conn.RemoteAddr())
|
||||
//})
|
||||
|
||||
gscanner.New().SetTimeout(3*time.Second).ScanIp("120.76.249.1", "120.76.249.255", 80, func(conn net.Conn) {
|
||||
fmt.Println(conn.RemoteAddr())
|
||||
})
|
||||
|
||||
//gscanner.New().SetTimeout(6*time.Second).ScanPort("120.76.249.2", func(conn net.Conn){
|
||||
// //fmt.Println("yes")
|
||||
// fmt.Println(conn.RemoteAddr())
|
||||
//})
|
||||
}
|
||||
@ -1,5 +1,28 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
import (
|
||||
"github.com/gogf/gf/g/os/glog"
|
||||
|
||||
"github.com/gogf/gf/g/os/gcache"
|
||||
)
|
||||
|
||||
func localCache() {
|
||||
result := gcache.GetOrSetFunc("test.key.1", func() interface{} {
|
||||
return nil
|
||||
}, 1000*60*2)
|
||||
if result == nil {
|
||||
glog.Error("未获取到值")
|
||||
} else {
|
||||
glog.Infofln("result is $v", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCache() {
|
||||
for i := 0; i < 100; i++ {
|
||||
localCache()
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
TestCache()
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package gf
|
||||
|
||||
const VERSION = "v1.7.0"
|
||||
const VERSION = "v1.7.1"
|
||||
const AUTHORS = "john<john@goframe.org>"
|
||||
|
||||
Reference in New Issue
Block a user