mirror of
https://gitee.com/johng/gf
synced 2026-06-11 03:41:44 +08:00
Compare commits
51 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 506552c3a9 | |||
| 2bacc77224 | |||
| bc53f265af | |||
| 344f232c36 | |||
| 27b677b0c0 | |||
| a5a0e381bd | |||
| d528d7f5ab | |||
| 821c71bd8d | |||
| 604a10400d | |||
| 9219471f67 | |||
| fe5d2e5685 | |||
| 0a89daa513 | |||
| 5dbda8aedc | |||
| 134e4cf28f | |||
| 56a85abef7 | |||
| 80c6ceaf26 | |||
| a10f428715 | |||
| 597f7468e9 | |||
| 5db8851213 | |||
| 1d53d760d8 | |||
| 922e720d63 | |||
| 50018773b7 | |||
| df99036d41 | |||
| ae0fa888f0 | |||
| 18892fb66d | |||
| 5f2be10563 | |||
| a5a88222a6 | |||
| 4facdd5c9e | |||
| 76bc9bd385 | |||
| 364452f3bb | |||
| 4996755f11 | |||
| e33230a88f | |||
| 951ce46932 | |||
| 795c7395e6 | |||
| 27cf47bcd3 | |||
| 58a25c6f61 | |||
| 2d754f80b1 | |||
| f4e8fbe767 | |||
| 458318d374 | |||
| e3f54e1353 | |||
| 4374996073 | |||
| 87295ef1fe | |||
| 81d4082b6a | |||
| d7e19bc3f3 | |||
| 34ef0ea792 | |||
| 2804834540 | |||
| add7dd5a45 | |||
| e40894ca45 | |||
| 28825f5395 | |||
| 6ca5141020 | |||
| fe4f8e1810 |
@ -10,10 +10,10 @@ func main() {
|
||||
// Push
|
||||
l.PushBack(1)
|
||||
l.PushBack(2)
|
||||
e0 := l.PushFront(0)
|
||||
e := l.PushFront(0)
|
||||
// Insert
|
||||
l.InsertBefore(e0, -1)
|
||||
l.InsertAfter(e0, "a")
|
||||
l.InsertBefore(e, -1)
|
||||
l.InsertAfter(e, "a")
|
||||
fmt.Println(l)
|
||||
// Pop
|
||||
fmt.Println(l.PopFront())
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
|
||||
# MySQL数据库配置
|
||||
[database]
|
||||
debug = true
|
||||
# debug = true
|
||||
link = "mysql:root:12345678@tcp(127.0.0.1:3306)/test?parseTime=true&loc=Local"
|
||||
|
||||
#[database]
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/database/gdb"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/os/glog"
|
||||
@ -23,7 +21,7 @@ func main() {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
db.SetDebug(true)
|
||||
//db.SetDebug(false)
|
||||
|
||||
glog.SetPath("/tmp")
|
||||
|
||||
@ -36,7 +34,4 @@ func main() {
|
||||
|
||||
db.Table("user").Data(g.Map{"name": "smith"}).Where("uid=?", 1).Save()
|
||||
|
||||
db.PrintQueriedSqls()
|
||||
|
||||
fmt.Println(db.GetLastSql())
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ import (
|
||||
|
||||
func main() {
|
||||
db := g.DB()
|
||||
|
||||
// 执行3条SQL查询
|
||||
for i := 1; i <= 3; i++ {
|
||||
db.Table("user").Where("id=?", i).One()
|
||||
|
||||
10
.example/debug/gdebug/gdebug_info.go
Normal file
10
.example/debug/gdebug/gdebug_info.go
Normal file
@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/debug/gdebug"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(gdebug.BuildInfo())
|
||||
}
|
||||
3
.example/frame/mvc/app/model/article/article.go
Normal file
3
.example/frame/mvc/app/model/article/article.go
Normal file
@ -0,0 +1,3 @@
|
||||
package article
|
||||
|
||||
// Fill with you ideas below.
|
||||
68
.example/frame/mvc/app/model/article/article_entity.go
Normal file
68
.example/frame/mvc/app/model/article/article_entity.go
Normal file
@ -0,0 +1,68 @@
|
||||
// ==========================================================================
|
||||
// This is auto-generated by gf cli tool. You may not really want to edit it.
|
||||
// ==========================================================================
|
||||
|
||||
package article
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"github.com/gogf/gf/database/gdb"
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
)
|
||||
|
||||
// Entity is the golang structure for table gf_article.
|
||||
type Entity struct {
|
||||
Id int `orm:"id,primary" json:"id"` //
|
||||
CatId int `orm:"cat_id" json:"cat_id"` // 分类ID
|
||||
Uid int `orm:"uid" json:"uid"` // 用户ID
|
||||
Title string `orm:"title" json:"title"` // 标题
|
||||
Content string `orm:"content" json:"content"` // 内容
|
||||
Order int `orm:"order" json:"order"` // 排序
|
||||
Brief string `orm:"brief" json:"brief"` // 摘要
|
||||
Thumb string `orm:"thumb" json:"thumb"` // 缩略图
|
||||
Tags string `orm:"tags" json:"tags"` // 标签
|
||||
Referer string `orm:"referer" json:"referer"` // 内容来源
|
||||
Status int `orm:"status" json:"status"` // 状态\n0: 禁用\n1: 正常
|
||||
CreateTime *gtime.Time `orm:"create_time" json:"create_time"` // 创建时间
|
||||
UpdateTime *gtime.Time `orm:"update_time" json:"update_time"` // 修改时间
|
||||
}
|
||||
|
||||
// Article is alias of Entity, which some developers say they just want.
|
||||
type Article = Entity
|
||||
|
||||
// OmitEmpty sets OPTION_OMITEMPTY option for the model, which automatically filers
|
||||
// the data and where attributes for empty values.
|
||||
func (r *Entity) OmitEmpty() *arModel {
|
||||
return Model.Data(r).OmitEmpty()
|
||||
}
|
||||
|
||||
// Inserts does "INSERT...INTO..." statement for inserting current object into table.
|
||||
func (r *Entity) Insert() (result sql.Result, err error) {
|
||||
return Model.Data(r).Insert()
|
||||
}
|
||||
|
||||
// Replace does "REPLACE...INTO..." statement for inserting current object into table.
|
||||
// If there's already another same record in the table (it checks using primary key or unique index),
|
||||
// it deletes it and insert this one.
|
||||
func (r *Entity) Replace() (result sql.Result, err error) {
|
||||
return Model.Data(r).Replace()
|
||||
}
|
||||
|
||||
// Save does "INSERT...INTO..." statement for inserting/updating current object into table.
|
||||
// It updates the record if there's already another same record in the table
|
||||
// (it checks using primary key or unique index).
|
||||
func (r *Entity) Save() (result sql.Result, err error) {
|
||||
return Model.Data(r).Save()
|
||||
}
|
||||
|
||||
// Update does "UPDATE...WHERE..." statement for updating current object from table.
|
||||
// It updates the record if there's already another same record in the table
|
||||
// (it checks using primary key or unique index).
|
||||
func (r *Entity) Update() (result sql.Result, err error) {
|
||||
return Model.Data(r).Where(gdb.GetWhereConditionOfStruct(r)).Update()
|
||||
}
|
||||
|
||||
// Delete does "DELETE FROM...WHERE..." statement for deleting current object from table.
|
||||
func (r *Entity) Delete() (result sql.Result, err error) {
|
||||
return Model.Where(gdb.GetWhereConditionOfStruct(r)).Delete()
|
||||
}
|
||||
362
.example/frame/mvc/app/model/article/article_model.go
Normal file
362
.example/frame/mvc/app/model/article/article_model.go
Normal file
@ -0,0 +1,362 @@
|
||||
// ==========================================================================
|
||||
// This is auto-generated by gf cli tool. You may not really want to edit it.
|
||||
// ==========================================================================
|
||||
|
||||
package article
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"github.com/gogf/gf/database/gdb"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"time"
|
||||
)
|
||||
|
||||
// arModel is a active record design model for table gf_article operations.
|
||||
type arModel struct {
|
||||
M *gdb.Model
|
||||
}
|
||||
|
||||
var (
|
||||
// Table is the table name of gf_article.
|
||||
Table = "gf_article"
|
||||
// Model is the model object of gf_article.
|
||||
Model = &arModel{g.DB("default").Table(Table).Safe()}
|
||||
)
|
||||
|
||||
// FindOne is a convenience method for Model.FindOne.
|
||||
// See Model.FindOne.
|
||||
func FindOne(where ...interface{}) (*Entity, error) {
|
||||
return Model.FindOne(where...)
|
||||
}
|
||||
|
||||
// FindAll is a convenience method for Model.FindAll.
|
||||
// See Model.FindAll.
|
||||
func FindAll(where ...interface{}) ([]*Entity, error) {
|
||||
return Model.FindAll(where...)
|
||||
}
|
||||
|
||||
// FindValue is a convenience method for Model.FindValue.
|
||||
// See Model.FindValue.
|
||||
func FindValue(fieldsAndWhere ...interface{}) (gdb.Value, error) {
|
||||
return Model.FindValue(fieldsAndWhere...)
|
||||
}
|
||||
|
||||
// FindCount is a convenience method for Model.FindCount.
|
||||
// See Model.FindCount.
|
||||
func FindCount(where ...interface{}) (int, error) {
|
||||
return Model.FindCount(where...)
|
||||
}
|
||||
|
||||
// Insert is a convenience method for Model.Insert.
|
||||
func Insert(data ...interface{}) (result sql.Result, err error) {
|
||||
return Model.Insert(data...)
|
||||
}
|
||||
|
||||
// Replace is a convenience method for Model.Replace.
|
||||
func Replace(data ...interface{}) (result sql.Result, err error) {
|
||||
return Model.Replace(data...)
|
||||
}
|
||||
|
||||
// Save is a convenience method for Model.Save.
|
||||
func Save(data ...interface{}) (result sql.Result, err error) {
|
||||
return Model.Save(data...)
|
||||
}
|
||||
|
||||
// Update is a convenience method for Model.Update.
|
||||
func Update(dataAndWhere ...interface{}) (result sql.Result, err error) {
|
||||
return Model.Update(dataAndWhere...)
|
||||
}
|
||||
|
||||
// Delete is a convenience method for Model.Delete.
|
||||
func Delete(where ...interface{}) (result sql.Result, err error) {
|
||||
return Model.Delete(where...)
|
||||
}
|
||||
|
||||
// TX sets the transaction for current operation.
|
||||
func (m *arModel) TX(tx *gdb.TX) *arModel {
|
||||
return &arModel{m.M.TX(tx)}
|
||||
}
|
||||
|
||||
// Master marks the following operation on master node.
|
||||
func (m *arModel) Master() *arModel {
|
||||
return &arModel{m.M.Master()}
|
||||
}
|
||||
|
||||
// Slave marks the following operation on slave node.
|
||||
// Note that it makes sense only if there's any slave node configured.
|
||||
func (m *arModel) Slave() *arModel {
|
||||
return &arModel{m.M.Slave()}
|
||||
}
|
||||
|
||||
// LeftJoin does "LEFT JOIN ... ON ..." statement on the model.
|
||||
func (m *arModel) LeftJoin(joinTable string, on string) *arModel {
|
||||
return &arModel{m.M.LeftJoin(joinTable, on)}
|
||||
}
|
||||
|
||||
// RightJoin does "RIGHT JOIN ... ON ..." statement on the model.
|
||||
func (m *arModel) RightJoin(joinTable string, on string) *arModel {
|
||||
return &arModel{m.M.RightJoin(joinTable, on)}
|
||||
}
|
||||
|
||||
// InnerJoin does "INNER JOIN ... ON ..." statement on the model.
|
||||
func (m *arModel) InnerJoin(joinTable string, on string) *arModel {
|
||||
return &arModel{m.M.InnerJoin(joinTable, on)}
|
||||
}
|
||||
|
||||
// Fields sets the operation fields of the model, multiple fields joined using char ','.
|
||||
func (m *arModel) Fields(fields string) *arModel {
|
||||
return &arModel{m.M.Fields(fields)}
|
||||
}
|
||||
|
||||
// FieldsEx sets the excluded operation fields of the model, multiple fields joined using char ','.
|
||||
func (m *arModel) FieldsEx(fields string) *arModel {
|
||||
return &arModel{m.M.FieldsEx(fields)}
|
||||
}
|
||||
|
||||
// Option sets the extra operation option for the model.
|
||||
func (m *arModel) Option(option int) *arModel {
|
||||
return &arModel{m.M.Option(option)}
|
||||
}
|
||||
|
||||
// OmitEmpty sets OPTION_OMITEMPTY option for the model, which automatically filers
|
||||
// the data and where attributes for empty values.
|
||||
func (m *arModel) OmitEmpty() *arModel {
|
||||
return &arModel{m.M.OmitEmpty()}
|
||||
}
|
||||
|
||||
// Filter marks filtering the fields which does not exist in the fields of the operated table.
|
||||
func (m *arModel) Filter() *arModel {
|
||||
return &arModel{m.M.Filter()}
|
||||
}
|
||||
|
||||
// Where sets the condition statement for the model. The parameter <where> can be type of
|
||||
// string/map/gmap/slice/struct/*struct, etc. Note that, if it's called more than one times,
|
||||
// multiple conditions will be joined into where statement using "AND".
|
||||
// Eg:
|
||||
// Where("uid=10000")
|
||||
// Where("uid", 10000)
|
||||
// Where("money>? AND name like ?", 99999, "vip_%")
|
||||
// Where("uid", 1).Where("name", "john")
|
||||
// Where("status IN (?)", g.Slice{1,2,3})
|
||||
// Where("age IN(?,?)", 18, 50)
|
||||
// Where(User{ Id : 1, UserName : "john"})
|
||||
func (m *arModel) Where(where interface{}, args ...interface{}) *arModel {
|
||||
return &arModel{m.M.Where(where, args...)}
|
||||
}
|
||||
|
||||
// And adds "AND" condition to the where statement.
|
||||
func (m *arModel) And(where interface{}, args ...interface{}) *arModel {
|
||||
return &arModel{m.M.And(where, args...)}
|
||||
}
|
||||
|
||||
// Or adds "OR" condition to the where statement.
|
||||
func (m *arModel) Or(where interface{}, args ...interface{}) *arModel {
|
||||
return &arModel{m.M.Or(where, args...)}
|
||||
}
|
||||
|
||||
// Group sets the "GROUP BY" statement for the model.
|
||||
func (m *arModel) Group(groupBy string) *arModel {
|
||||
return &arModel{m.M.Group(groupBy)}
|
||||
}
|
||||
|
||||
// Order sets the "ORDER BY" statement for the model.
|
||||
func (m *arModel) Order(orderBy string) *arModel {
|
||||
return &arModel{m.M.Order(orderBy)}
|
||||
}
|
||||
|
||||
// Limit sets the "LIMIT" statement for the model.
|
||||
// The parameter <limit> can be either one or two number, if passed two number is passed,
|
||||
// it then sets "LIMIT limit[0],limit[1]" statement for the model, or else it sets "LIMIT limit[0]"
|
||||
// statement.
|
||||
func (m *arModel) Limit(limit ...int) *arModel {
|
||||
return &arModel{m.M.Limit(limit...)}
|
||||
}
|
||||
|
||||
// Offset sets the "OFFSET" statement for the model.
|
||||
// It only makes sense for some databases like SQLServer, PostgreSQL, etc.
|
||||
func (m *arModel) Offset(offset int) *arModel {
|
||||
return &arModel{m.M.Offset(offset)}
|
||||
}
|
||||
|
||||
// Page sets the paging number for the model.
|
||||
// The parameter <page> is started from 1 for paging.
|
||||
// Note that, it differs that the Limit function start from 0 for "LIMIT" statement.
|
||||
func (m *arModel) Page(page, limit int) *arModel {
|
||||
return &arModel{m.M.Page(page, limit)}
|
||||
}
|
||||
|
||||
// Batch sets the batch operation number for the model.
|
||||
func (m *arModel) Batch(batch int) *arModel {
|
||||
return &arModel{m.M.Batch(batch)}
|
||||
}
|
||||
|
||||
// Cache sets the cache feature for the model. It caches the result of the sql, which means
|
||||
// if there's another same sql request, it just reads and returns the result from cache, it
|
||||
// but not committed and executed into the database.
|
||||
//
|
||||
// If the parameter <duration> < 0, which means it clear the cache with given <name>.
|
||||
// If the parameter <duration> = 0, which means it never expires.
|
||||
// If the parameter <duration> > 0, which means it expires after <duration>.
|
||||
//
|
||||
// The optional parameter <name> is used to bind a name to the cache, which means you can later
|
||||
// control the cache like changing the <duration> or clearing the cache with specified <name>.
|
||||
//
|
||||
// Note that, the cache feature is disabled if the model is operating on a transaction.
|
||||
func (m *arModel) Cache(expire time.Duration, name ...string) *arModel {
|
||||
return &arModel{m.M.Cache(expire, name...)}
|
||||
}
|
||||
|
||||
// Data sets the operation data for the model.
|
||||
// The parameter <data> can be type of string/map/gmap/slice/struct/*struct, etc.
|
||||
// Eg:
|
||||
// Data("uid=10000")
|
||||
// Data("uid", 10000)
|
||||
// Data(g.Map{"uid": 10000, "name":"john"})
|
||||
// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"})
|
||||
func (m *arModel) Data(data ...interface{}) *arModel {
|
||||
return &arModel{m.M.Data(data...)}
|
||||
}
|
||||
|
||||
// Insert does "INSERT INTO ..." statement for the model.
|
||||
// The optional parameter <data> is the same as the parameter of Model.Data function,
|
||||
// see Model.Data.
|
||||
func (m *arModel) Insert(data ...interface{}) (result sql.Result, err error) {
|
||||
return m.M.Insert(data...)
|
||||
}
|
||||
|
||||
// Replace does "REPLACE INTO ..." statement for the model.
|
||||
// The optional parameter <data> is the same as the parameter of Model.Data function,
|
||||
// see Model.Data.
|
||||
func (m *arModel) Replace(data ...interface{}) (result sql.Result, err error) {
|
||||
return m.M.Replace(data...)
|
||||
}
|
||||
|
||||
// Save does "INSERT INTO ... ON DUPLICATE KEY UPDATE..." statement for the model.
|
||||
// It updates the record if there's primary or unique index in the saving data,
|
||||
// or else it inserts a new record into the table.
|
||||
//
|
||||
// The optional parameter <data> is the same as the parameter of Model.Data function,
|
||||
// see Model.Data.
|
||||
func (m *arModel) Save(data ...interface{}) (result sql.Result, err error) {
|
||||
return m.M.Save(data...)
|
||||
}
|
||||
|
||||
// Update does "UPDATE ... " statement for the model.
|
||||
//
|
||||
// If the optional parameter <dataAndWhere> is given, the dataAndWhere[0] is the updated
|
||||
// data field, and dataAndWhere[1:] is treated as where condition fields.
|
||||
// Also see Model.Data and Model.Where functions.
|
||||
func (m *arModel) Update(dataAndWhere ...interface{}) (result sql.Result, err error) {
|
||||
return m.M.Update(dataAndWhere...)
|
||||
}
|
||||
|
||||
// Delete does "DELETE FROM ... " statement for the model.
|
||||
// The optional parameter <where> is the same as the parameter of Model.Where function,
|
||||
// see Model.Where.
|
||||
func (m *arModel) Delete(where ...interface{}) (result sql.Result, err error) {
|
||||
return m.M.Delete(where...)
|
||||
}
|
||||
|
||||
// Count does "SELECT COUNT(x) FROM ..." statement for the model.
|
||||
// The optional parameter <where> is the same as the parameter of Model.Where function,
|
||||
// see Model.Where.
|
||||
func (m *arModel) Count(where ...interface{}) (int, error) {
|
||||
return m.M.Count(where...)
|
||||
}
|
||||
|
||||
// All does "SELECT FROM ..." statement for the model.
|
||||
// It retrieves the records from table and returns the result as []*Entity.
|
||||
// It returns nil if there's no record retrieved with the given conditions from table.
|
||||
//
|
||||
// The optional parameter <where> is the same as the parameter of Model.Where function,
|
||||
// see Model.Where.
|
||||
func (m *arModel) All(where ...interface{}) ([]*Entity, error) {
|
||||
all, err := m.M.All(where...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var entities []*Entity
|
||||
if err = all.Structs(&entities); err != nil && err != sql.ErrNoRows {
|
||||
return nil, err
|
||||
}
|
||||
return entities, nil
|
||||
}
|
||||
|
||||
// One retrieves one record from table and returns the result as *Entity.
|
||||
// It returns nil if there's no record retrieved with the given conditions from table.
|
||||
//
|
||||
// The optional parameter <where> is the same as the parameter of Model.Where function,
|
||||
// see Model.Where.
|
||||
func (m *arModel) One(where ...interface{}) (*Entity, error) {
|
||||
one, err := m.M.One(where...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var entity *Entity
|
||||
if err = one.Struct(&entity); err != nil && err != sql.ErrNoRows {
|
||||
return nil, err
|
||||
}
|
||||
return entity, nil
|
||||
}
|
||||
|
||||
// Value retrieves a specified record value from table and returns the result as interface type.
|
||||
// It returns nil if there's no record found with the given conditions from table.
|
||||
//
|
||||
// If the optional parameter <fieldsAndWhere> is given, the fieldsAndWhere[0] is the selected fields
|
||||
// and fieldsAndWhere[1:] is treated as where condition fields.
|
||||
// Also see Model.Fields and Model.Where functions.
|
||||
func (m *arModel) Value(fieldsAndWhere ...interface{}) (gdb.Value, error) {
|
||||
return m.M.Value(fieldsAndWhere...)
|
||||
}
|
||||
|
||||
// FindOne retrieves and returns a single Record by Model.WherePri and Model.One.
|
||||
// Also see Model.WherePri and Model.One.
|
||||
func (m *arModel) FindOne(where ...interface{}) (*Entity, error) {
|
||||
one, err := m.M.FindOne(where...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var entity *Entity
|
||||
if err = one.Struct(&entity); err != nil && err != sql.ErrNoRows {
|
||||
return nil, err
|
||||
}
|
||||
return entity, nil
|
||||
}
|
||||
|
||||
// FindAll retrieves and returns Result by by Model.WherePri and Model.All.
|
||||
// Also see Model.WherePri and Model.All.
|
||||
func (m *arModel) FindAll(where ...interface{}) ([]*Entity, error) {
|
||||
all, err := m.M.FindAll(where...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var entities []*Entity
|
||||
if err = all.Structs(&entities); err != nil && err != sql.ErrNoRows {
|
||||
return nil, err
|
||||
}
|
||||
return entities, nil
|
||||
}
|
||||
|
||||
// FindValue retrieves and returns single field value by Model.WherePri and Model.Value.
|
||||
// Also see Model.WherePri and Model.Value.
|
||||
func (m *arModel) FindValue(fieldsAndWhere ...interface{}) (gdb.Value, error) {
|
||||
return m.M.FindValue(fieldsAndWhere...)
|
||||
}
|
||||
|
||||
// FindCount retrieves and returns the record number by Model.WherePri and Model.Count.
|
||||
// Also see Model.WherePri and Model.Count.
|
||||
func (m *arModel) FindCount(where ...interface{}) (int, error) {
|
||||
return m.M.FindCount(where...)
|
||||
}
|
||||
|
||||
// Chunk iterates the table with given size and callback function.
|
||||
func (m *arModel) Chunk(limit int, callback func(entities []*Entity, err error) bool) {
|
||||
m.M.Chunk(limit, func(result gdb.Result, err error) bool {
|
||||
var entities []*Entity
|
||||
err = result.Structs(&entities)
|
||||
if err == sql.ErrNoRows {
|
||||
return false
|
||||
}
|
||||
return callback(entities, err)
|
||||
})
|
||||
}
|
||||
@ -1,60 +0,0 @@
|
||||
// This is auto-generated by gf cli tool. You may not really want to edit it.
|
||||
|
||||
package defaults
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"github.com/gogf/gf/database/gdb"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
)
|
||||
|
||||
// User is the golang structure for table user.
|
||||
type User struct {
|
||||
Id int `orm:"id,primary" json:"id"`
|
||||
Passport string `orm:"passport" json:"passport"`
|
||||
Password string `orm:"password" json:"password"`
|
||||
Nickname string `orm:"nickname,unique" json:"nickname"`
|
||||
CreateTime *gtime.Time `orm:"create_time" json:"create_time"`
|
||||
}
|
||||
|
||||
var (
|
||||
// TableUser is the table name of user.
|
||||
TableUser = "user"
|
||||
// ModelUser is the model object of user.
|
||||
ModelUser = g.DB("default").Table(TableUser).Safe()
|
||||
)
|
||||
|
||||
// Inserts does "INSERT...INTO..." statement for inserting current object into table.
|
||||
func (r *User) Insert() (result sql.Result, err error) {
|
||||
return ModelUser.Data(r).Insert()
|
||||
}
|
||||
|
||||
// Replace does "REPLACE...INTO..." statement for inserting current object into table.
|
||||
// If there's already another same record in the table (it checks using primary key or unique index),
|
||||
// it deletes it and insert this one.
|
||||
func (r *User) Replace() (result sql.Result, err error) {
|
||||
return ModelUser.Data(r).Replace()
|
||||
}
|
||||
|
||||
// Save does "INSERT...INTO..." statement for inserting/updating current object into table.
|
||||
// It updates the record if there's already another same record in the table
|
||||
// (it checks using primary key or unique index).
|
||||
func (r *User) Save() (result sql.Result, err error) {
|
||||
return ModelUser.Data(r).Save()
|
||||
}
|
||||
|
||||
// Update does "UPDATE...WHERE..." statement for updating current object from table.
|
||||
// It updates the record if there's already another same record in the table
|
||||
// (it checks using primary key or unique index).
|
||||
func (r *User) Update() (result sql.Result, err error) {
|
||||
return ModelUser.Data(r).Where(gdb.GetWhereConditionOfStruct(r)).Update()
|
||||
}
|
||||
|
||||
// Delete does "DELETE FROM...WHERE..." statement for deleting current object from table.
|
||||
func (r *User) Delete() (result sql.Result, err error) {
|
||||
return ModelUser.Where(gdb.GetWhereConditionOfStruct(r)).Delete()
|
||||
}
|
||||
@ -3,7 +3,7 @@ viewpath = "/home/www/templates"
|
||||
# MySQL数据库配置
|
||||
[database]
|
||||
debug = true
|
||||
link = "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
|
||||
link = "mysql:root:12345678@tcp(127.0.0.1:3306)/gf"
|
||||
|
||||
|
||||
[redis]
|
||||
|
||||
@ -1,13 +1,10 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/.example/frame/mvc/app/model/defaults"
|
||||
"github.com/gogf/gf/database/gdb"
|
||||
"github.com/gogf/gf/.example/frame/mvc/app/model/article"
|
||||
)
|
||||
|
||||
func main() {
|
||||
u := defaults.User{Id: 1, Nickname: "test"}
|
||||
fmt.Println(gdb.GetWhereConditionOfStruct(&u))
|
||||
fmt.Println(u.Replace())
|
||||
m := article.Model
|
||||
m.All()
|
||||
}
|
||||
|
||||
@ -7,9 +7,7 @@ import (
|
||||
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"))
|
||||
}
|
||||
panic("OMG")
|
||||
})
|
||||
s.SetErrorLogEnabled(true)
|
||||
s.SetPort(8199)
|
||||
|
||||
17
.example/net/ghttp/server/request/basic.go
Normal file
17
.example/net/ghttp/server/request/basic.go
Normal file
@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
r.Response.Writeln(r.Get("amount"))
|
||||
r.Response.Writeln(r.GetInt("amount"))
|
||||
r.Response.Writeln(r.GetFloat32("amount"))
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
18
.example/net/ghttp/server/request/exit/exit.go
Normal file
18
.example/net/ghttp/server/request/exit/exit.go
Normal file
@ -0,0 +1,18 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
if r.GetInt("type") == 1 {
|
||||
r.Response.Writeln("john")
|
||||
}
|
||||
r.Response.Writeln("smith")
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
15
.example/net/ghttp/server/request/json-xml/test1.go
Normal file
15
.example/net/ghttp/server/request/json-xml/test1.go
Normal file
@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
r.Response.Writef("name: %v, pass: %v", r.Get("name"), r.Get("pass"))
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
47
.example/net/ghttp/server/request/json-xml/test2.go
Normal file
47
.example/net/ghttp/server/request/json-xml/test2.go
Normal file
@ -0,0 +1,47 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
"github.com/gogf/gf/util/gvalid"
|
||||
)
|
||||
|
||||
type RegisterReq struct {
|
||||
Name string `p:"username" v:"required|length:6,30#请输入账号|账号长度为:min到:max位"`
|
||||
Pass string `p:"password1" v:"required|length:6,30#请输入密码|密码长度不够"`
|
||||
Pass2 string `p:"password2" v:"required|length:6,30|same:password1#请确认密码|两次密码不一致"`
|
||||
}
|
||||
|
||||
type RegisterRes struct {
|
||||
Code int `json:"code"`
|
||||
Error string `json:"error"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/register", func(r *ghttp.Request) {
|
||||
var req *RegisterReq
|
||||
//fmt.Println(r.GetBody())
|
||||
if err := r.Parse(&req); err != nil {
|
||||
// Validation error.
|
||||
if v, ok := err.(*gvalid.Error); ok {
|
||||
r.Response.WriteJsonExit(RegisterRes{
|
||||
Code: 1,
|
||||
Error: v.FirstString(),
|
||||
})
|
||||
}
|
||||
// Other error.
|
||||
r.Response.WriteJsonExit(RegisterRes{
|
||||
Code: 1,
|
||||
Error: err.Error(),
|
||||
})
|
||||
}
|
||||
// ...
|
||||
r.Response.WriteJsonExit(RegisterRes{
|
||||
Data: req,
|
||||
})
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
15
.example/net/ghttp/server/request/params/array.go
Normal file
15
.example/net/ghttp/server/request/params/array.go
Normal file
@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
r.Response.Write(r.Get("array"))
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
15
.example/net/ghttp/server/request/params/map.go
Normal file
15
.example/net/ghttp/server/request/params/map.go
Normal file
@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
r.Response.Write(r.Get("map"))
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
15
.example/net/ghttp/server/request/params/repeat.go
Normal file
15
.example/net/ghttp/server/request/params/repeat.go
Normal file
@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
r.Response.Write(r.Get("name"))
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
18
.example/net/ghttp/server/request/priority.go
Normal file
18
.example/net/ghttp/server/request/priority.go
Normal file
@ -0,0 +1,18 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/input", func(r *ghttp.Request) {
|
||||
r.Response.Writeln(r.Get("amount"))
|
||||
})
|
||||
s.BindHandler("/query", func(r *ghttp.Request) {
|
||||
r.Response.Writeln(r.GetQuery("amount"))
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
@ -5,20 +5,20 @@ import (
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
Uid int `json:"uid"`
|
||||
Name string `json:"name" params:"username"`
|
||||
Pass1 string `json:"pass1" params:"password1,userpass1"`
|
||||
Pass2 string `json:"pass2" params:"password3,userpass2"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
type User struct {
|
||||
Uid int `json:"uid"`
|
||||
Name string `json:"name" p:"username"`
|
||||
Pass1 string `json:"pass1" p:"password1"`
|
||||
Pass2 string `json:"pass2" p:"password2"`
|
||||
}
|
||||
|
||||
s := g.Server()
|
||||
s.BindHandler("/user", func(r *ghttp.Request) {
|
||||
user := new(User)
|
||||
r.GetToStruct(user)
|
||||
//r.GetPostToStruct(user)
|
||||
//r.GetQueryToStruct(user)
|
||||
var user *User
|
||||
if err := r.Parse(&user); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
r.Response.WriteJson(user)
|
||||
})
|
||||
s.SetPort(8199)
|
||||
|
||||
25
.example/net/ghttp/server/request/struct/parse1.go
Normal file
25
.example/net/ghttp/server/request/struct/parse1.go
Normal file
@ -0,0 +1,25 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type User struct {
|
||||
Id int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Pass1 string `json:"password1" p:"password1"`
|
||||
Pass2 string `json:"password2" p:"password2"`
|
||||
}
|
||||
s := g.Server()
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
var user *User
|
||||
if err := r.Parse(&user); err != nil {
|
||||
r.Response.WriteExit(err)
|
||||
}
|
||||
r.Response.WriteExit(user)
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
37
.example/net/ghttp/server/request/struct/parse2.go
Normal file
37
.example/net/ghttp/server/request/struct/parse2.go
Normal file
@ -0,0 +1,37 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
type RegisterReq struct {
|
||||
Name string
|
||||
Pass string `p:"password1"`
|
||||
Pass2 string `p:"password2"`
|
||||
}
|
||||
|
||||
type RegisterRes struct {
|
||||
Code int `json:"code"`
|
||||
Error string `json:"error"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/register", func(r *ghttp.Request) {
|
||||
var req *RegisterReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
r.Response.WriteJsonExit(RegisterRes{
|
||||
Code: 1,
|
||||
Error: err.Error(),
|
||||
})
|
||||
}
|
||||
// ...
|
||||
r.Response.WriteJsonExit(RegisterRes{
|
||||
Data: req,
|
||||
})
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
37
.example/net/ghttp/server/request/validation/validation1.go
Normal file
37
.example/net/ghttp/server/request/validation/validation1.go
Normal file
@ -0,0 +1,37 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
type RegisterReq struct {
|
||||
Name string `p:"username" v:"required|length:6,30#请输入账号|账号长度为:min到:max位"`
|
||||
Pass string `p:"password1" v:"required|length:6,30#请输入密码|密码长度不够"`
|
||||
Pass2 string `p:"password2" v:"required|length:6,30|same:password1#请确认密码|两次密码不一致"`
|
||||
}
|
||||
|
||||
type RegisterRes struct {
|
||||
Code int `json:"code"`
|
||||
Error string `json:"error"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/register", func(r *ghttp.Request) {
|
||||
var req *RegisterReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
r.Response.WriteJsonExit(RegisterRes{
|
||||
Code: 1,
|
||||
Error: err.Error(),
|
||||
})
|
||||
}
|
||||
// ...
|
||||
r.Response.WriteJsonExit(RegisterRes{
|
||||
Data: req,
|
||||
})
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
46
.example/net/ghttp/server/request/validation/validation2.go
Normal file
46
.example/net/ghttp/server/request/validation/validation2.go
Normal file
@ -0,0 +1,46 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
"github.com/gogf/gf/util/gvalid"
|
||||
)
|
||||
|
||||
type RegisterReq struct {
|
||||
Name string `p:"username" v:"required|length:6,30#请输入账号|账号长度为:min到:max位"`
|
||||
Pass string `p:"password1" v:"required|length:6,30#请输入密码|密码长度不够"`
|
||||
Pass2 string `p:"password2" v:"required|length:6,30|same:password1#请确认密码|两次密码不一致"`
|
||||
}
|
||||
|
||||
type RegisterRes struct {
|
||||
Code int `json:"code"`
|
||||
Error string `json:"error"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/register", func(r *ghttp.Request) {
|
||||
var req *RegisterReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
// Validation error.
|
||||
if v, ok := err.(*gvalid.Error); ok {
|
||||
r.Response.WriteJsonExit(RegisterRes{
|
||||
Code: 1,
|
||||
Error: v.FirstString(),
|
||||
})
|
||||
}
|
||||
// Other error.
|
||||
r.Response.WriteJsonExit(RegisterRes{
|
||||
Code: 1,
|
||||
Error: err.Error(),
|
||||
})
|
||||
}
|
||||
// ...
|
||||
r.Response.WriteJsonExit(RegisterRes{
|
||||
Data: req,
|
||||
})
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
22
.example/net/ghttp/server/router/group/basic.go
Normal file
22
.example/net/ghttp/server/router/group/basic.go
Normal file
@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
group := s.Group("/api")
|
||||
group.ALL("/all", func(r *ghttp.Request) {
|
||||
r.Response.Write("all")
|
||||
})
|
||||
group.GET("/get", func(r *ghttp.Request) {
|
||||
r.Response.Write("get")
|
||||
})
|
||||
group.POST("/post", func(r *ghttp.Request) {
|
||||
r.Response.Write("post")
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
38
.example/net/ghttp/server/router/group/batch.go
Normal file
38
.example/net/ghttp/server/router/group/batch.go
Normal file
@ -0,0 +1,38 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
type Object struct{}
|
||||
|
||||
func (o *Object) Show(r *ghttp.Request) {
|
||||
r.Response.Writeln("Show")
|
||||
}
|
||||
|
||||
func (o *Object) Delete(r *ghttp.Request) {
|
||||
r.Response.Writeln("REST Delete")
|
||||
}
|
||||
|
||||
func Handler(r *ghttp.Request) {
|
||||
r.Response.Writeln("Handler")
|
||||
}
|
||||
|
||||
func HookHandler(r *ghttp.Request) {
|
||||
r.Response.Writeln("HOOK Handler")
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
obj := new(Object)
|
||||
s.Group("/api").Bind([]ghttp.GroupItem{
|
||||
{"ALL", "*", HookHandler, ghttp.HOOK_BEFORE_SERVE},
|
||||
{"ALL", "/handler", Handler},
|
||||
{"ALL", "/obj", obj},
|
||||
{"GET", "/obj/show", obj, "Show"},
|
||||
{"REST", "/obj/rest", obj},
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
@ -5,7 +5,6 @@ import (
|
||||
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
"github.com/gogf/gf/os/glog"
|
||||
)
|
||||
|
||||
func MiddlewareAuth(r *ghttp.Request) {
|
||||
@ -24,39 +23,37 @@ func MiddlewareCORS(r *ghttp.Request) {
|
||||
|
||||
func MiddlewareLog(r *ghttp.Request) {
|
||||
r.Middleware.Next()
|
||||
glog.Println(r.Response.Status, r.URL.Path)
|
||||
g.Log().Println(r.Response.Status, r.URL.Path)
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.Group("/", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(MiddlewareLog)
|
||||
})
|
||||
s.Use(MiddlewareLog)
|
||||
s.Group("/api.v2", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(MiddlewareAuth, MiddlewareCORS)
|
||||
g.GET("/test", func(r *ghttp.Request) {
|
||||
group.GET("/test", func(r *ghttp.Request) {
|
||||
r.Response.Write("test")
|
||||
})
|
||||
g.Group("/order", func(group *ghttp.RouterGroup) {
|
||||
g.GET("/list", func(r *ghttp.Request) {
|
||||
group.Group("/order", func(group *ghttp.RouterGroup) {
|
||||
group.GET("/list", func(r *ghttp.Request) {
|
||||
r.Response.Write("list")
|
||||
})
|
||||
g.PUT("/update", func(r *ghttp.Request) {
|
||||
group.PUT("/update", func(r *ghttp.Request) {
|
||||
r.Response.Write("update")
|
||||
})
|
||||
})
|
||||
g.Group("/user", func(group *ghttp.RouterGroup) {
|
||||
g.GET("/info", func(r *ghttp.Request) {
|
||||
group.Group("/user", func(group *ghttp.RouterGroup) {
|
||||
group.GET("/info", func(r *ghttp.Request) {
|
||||
r.Response.Write("info")
|
||||
})
|
||||
g.POST("/edit", func(r *ghttp.Request) {
|
||||
group.POST("/edit", func(r *ghttp.Request) {
|
||||
r.Response.Write("edit")
|
||||
})
|
||||
g.DELETE("/drop", func(r *ghttp.Request) {
|
||||
group.DELETE("/drop", func(r *ghttp.Request) {
|
||||
r.Response.Write("drop")
|
||||
})
|
||||
})
|
||||
g.Group("/hook", func(group *ghttp.RouterGroup) {
|
||||
group.Group("/hook", func(group *ghttp.RouterGroup) {
|
||||
group.Hook("/*", ghttp.HOOK_BEFORE_SERVE, func(r *ghttp.Request) {
|
||||
r.Response.Write("hook any")
|
||||
})
|
||||
|
||||
@ -1,9 +1,12 @@
|
||||
package main
|
||||
|
||||
import "github.com/gogf/gf/net/ghttp"
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := ghttp.GetServer()
|
||||
s := g.Server()
|
||||
s.BindHandler("/user/:name", func(r *ghttp.Request) {
|
||||
r.Response.Writeln(r.Router.Uri)
|
||||
})
|
||||
|
||||
16
.example/net/ghttp/server/template/conflicts-name/client.go
Normal file
16
.example/net/ghttp/server/template/conflicts-name/client.go
Normal file
@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
// https://github.com/gogf/gf/issues/437
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
r.Response.WriteTpl("client/layout.html")
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
1
|
||||
9
.example/os/gbuild/config.toml
Normal file
9
.example/os/gbuild/config.toml
Normal file
@ -0,0 +1,9 @@
|
||||
|
||||
|
||||
# custom gf build setting.
|
||||
[compiler]
|
||||
name = "app"
|
||||
[compiler.varmap]
|
||||
name = "GoFrame"
|
||||
version = "1.10.1"
|
||||
home-site = "https://goframe.org"
|
||||
11
.example/os/gbuild/gbuild.go
Normal file
11
.example/os/gbuild/gbuild.go
Normal file
@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/os/gbuild"
|
||||
)
|
||||
|
||||
func main() {
|
||||
g.Dump(gbuild.Info())
|
||||
g.Dump(gbuild.Map())
|
||||
}
|
||||
@ -1,6 +1,3 @@
|
||||
// 多进程通信示例,
|
||||
// 子进程每个1秒向父进程发送当前时间,
|
||||
// 父进程监听进程消息,收到后打印到终端。
|
||||
package main
|
||||
|
||||
import (
|
||||
|
||||
@ -2,16 +2,15 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/os/gproc"
|
||||
)
|
||||
|
||||
// 使用gproc kill指定其他进程(清确保运行该程序的用户有足够权限)
|
||||
func main() {
|
||||
pid := 28536
|
||||
pid := 32556
|
||||
m := gproc.NewManager()
|
||||
m.AddProcess(pid)
|
||||
m.KillAll()
|
||||
err := m.KillAll()
|
||||
fmt.Println(err)
|
||||
m.WaitAll()
|
||||
fmt.Printf("%d was killed\n", pid)
|
||||
}
|
||||
12
.example/os/gproc/gproc_sleep.go
Normal file
12
.example/os/gproc/gproc_sleep.go
Normal file
@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/os/gproc"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(gproc.Pid())
|
||||
err := gproc.ShellRun("sleep 99999s")
|
||||
fmt.Println(err)
|
||||
}
|
||||
@ -12,16 +12,18 @@ func main() {
|
||||
s.SetConfigWithMap(g.Map{
|
||||
"SessionMaxAge": time.Minute,
|
||||
})
|
||||
s.BindHandler("/set", func(r *ghttp.Request) {
|
||||
r.Session.Set("time", gtime.Second())
|
||||
r.Response.Write("ok")
|
||||
})
|
||||
s.BindHandler("/get", func(r *ghttp.Request) {
|
||||
r.Response.Write(r.Session.Map())
|
||||
})
|
||||
s.BindHandler("/del", func(r *ghttp.Request) {
|
||||
r.Session.Clear()
|
||||
r.Response.Write("ok")
|
||||
s.Group("/", func(group *ghttp.RouterGroup) {
|
||||
group.ALL("/set", func(r *ghttp.Request) {
|
||||
r.Session.Set("time", gtime.Timestamp())
|
||||
r.Response.Write("ok")
|
||||
})
|
||||
group.ALL("/get", func(r *ghttp.Request) {
|
||||
r.Response.Write(r.Session.Map())
|
||||
})
|
||||
group.ALL("/del", func(r *ghttp.Request) {
|
||||
r.Session.Clear()
|
||||
r.Response.Write("ok")
|
||||
})
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
|
||||
@ -14,16 +14,18 @@ func main() {
|
||||
"SessionMaxAge": time.Minute,
|
||||
"SessionStorage": gsession.NewStorageMemory(),
|
||||
})
|
||||
s.BindHandler("/set", func(r *ghttp.Request) {
|
||||
r.Session.Set("time", gtime.Second())
|
||||
r.Response.Write("ok")
|
||||
})
|
||||
s.BindHandler("/get", func(r *ghttp.Request) {
|
||||
r.Response.Write(r.Session.Map())
|
||||
})
|
||||
s.BindHandler("/del", func(r *ghttp.Request) {
|
||||
r.Session.Clear()
|
||||
r.Response.Write("ok")
|
||||
s.Group("/", func(group *ghttp.RouterGroup) {
|
||||
group.ALL("/set", func(r *ghttp.Request) {
|
||||
r.Session.Set("time", gtime.Timestamp())
|
||||
r.Response.Write("ok")
|
||||
})
|
||||
group.ALL("/get", func(r *ghttp.Request) {
|
||||
r.Response.Write(r.Session.Map())
|
||||
})
|
||||
group.ALL("/del", func(r *ghttp.Request) {
|
||||
r.Session.Clear()
|
||||
r.Response.Write("ok")
|
||||
})
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
|
||||
@ -14,16 +14,18 @@ func main() {
|
||||
"SessionMaxAge": time.Minute,
|
||||
"SessionStorage": gsession.NewStorageRedisHashTable(g.Redis()),
|
||||
})
|
||||
s.BindHandler("/set", func(r *ghttp.Request) {
|
||||
r.Session.Set("time", gtime.Second())
|
||||
r.Response.Write("ok")
|
||||
})
|
||||
s.BindHandler("/get", func(r *ghttp.Request) {
|
||||
r.Response.Write(r.Session.Map())
|
||||
})
|
||||
s.BindHandler("/del", func(r *ghttp.Request) {
|
||||
r.Session.Clear()
|
||||
r.Response.Write("ok")
|
||||
s.Group("/", func(group *ghttp.RouterGroup) {
|
||||
group.ALL("/set", func(r *ghttp.Request) {
|
||||
r.Session.Set("time", gtime.Timestamp())
|
||||
r.Response.Write("ok")
|
||||
})
|
||||
group.ALL("/get", func(r *ghttp.Request) {
|
||||
r.Response.Write(r.Session.Map())
|
||||
})
|
||||
group.ALL("/del", func(r *ghttp.Request) {
|
||||
r.Session.Clear()
|
||||
r.Response.Write("ok")
|
||||
})
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
|
||||
@ -14,16 +14,18 @@ func main() {
|
||||
"SessionMaxAge": time.Minute,
|
||||
"SessionStorage": gsession.NewStorageRedis(g.Redis()),
|
||||
})
|
||||
s.BindHandler("/set", func(r *ghttp.Request) {
|
||||
r.Session.Set("time", gtime.Second())
|
||||
r.Response.Write("ok")
|
||||
})
|
||||
s.BindHandler("/get", func(r *ghttp.Request) {
|
||||
r.Response.Write(r.Session.Map())
|
||||
})
|
||||
s.BindHandler("/del", func(r *ghttp.Request) {
|
||||
r.Session.Clear()
|
||||
r.Response.Write("ok")
|
||||
s.Group("/", func(group *ghttp.RouterGroup) {
|
||||
group.ALL("/set", func(r *ghttp.Request) {
|
||||
r.Session.Set("time", gtime.Timestamp())
|
||||
r.Response.Write("ok")
|
||||
})
|
||||
group.ALL("/get", func(r *ghttp.Request) {
|
||||
r.Response.Write(r.Session.Map())
|
||||
})
|
||||
group.ALL("/del", func(r *ghttp.Request) {
|
||||
r.Session.Clear()
|
||||
r.Response.Write("ok")
|
||||
})
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
|
||||
@ -1,3 +1,8 @@
|
||||
|
||||
[database]
|
||||
debug = true
|
||||
link = "mysql:root:12345678@tcp(127.0.0.1:3306)/test?parseTime=true&loc=Local"
|
||||
link = "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
|
||||
|
||||
[redis]
|
||||
default = "127.0.0.1:6379,0"
|
||||
cache = "127.0.0.1:6379,1"
|
||||
@ -1,42 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("")
|
||||
|
||||
// 前景 背景 颜色
|
||||
// ---------------------------------------
|
||||
// 30 40 黑色
|
||||
// 31 41 红色
|
||||
// 32 42 绿色
|
||||
// 33 43 黄色
|
||||
// 34 44 蓝色
|
||||
// 35 45 紫红色
|
||||
// 36 46 青蓝色
|
||||
// 37 47 白色
|
||||
//
|
||||
// 代码 意义
|
||||
// -------------------------
|
||||
// 0 终端默认设置
|
||||
// 1 高亮显示
|
||||
// 4 使用下划线
|
||||
// 5 闪烁
|
||||
// 7 反白显示
|
||||
// 8 不可见
|
||||
|
||||
// 背景色彩 = 40-47
|
||||
for b := 40; b <= 47; b++ {
|
||||
// 前景色彩 = 30-37
|
||||
for f := 30; f <= 37; f++ {
|
||||
// 显示方式 = 0,1,4,5,7,8
|
||||
for _, d := range []int{0, 1, 4, 5, 7, 8} {
|
||||
fmt.Printf(" %c[%d;%d;%dm%s(f=%d,b=%d,d=%d)%c[0m ", 0x1B, d, b, f, "", f, b, d, 0x1B)
|
||||
}
|
||||
fmt.Println("")
|
||||
}
|
||||
fmt.Println("")
|
||||
}
|
||||
}
|
||||
@ -1,17 +1,27 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.Group("/api.v2", func(group *ghttp.RouterGroup) {
|
||||
group.ALL("/test", func(r *ghttp.Request) {
|
||||
r.Response.Write(r.GetRequest("nickname"))
|
||||
})
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
type Base struct {
|
||||
Id int `c:"id"`
|
||||
CreateTime string `c:"create_time"`
|
||||
}
|
||||
type User struct {
|
||||
Base `c:"base"`
|
||||
Passport string `c:"passport"`
|
||||
Password string `c:"password"`
|
||||
Nickname string `c:"nickname"`
|
||||
}
|
||||
user := new(User)
|
||||
user.Id = 1
|
||||
user.Nickname = "John"
|
||||
user.Passport = "johng"
|
||||
user.Password = "123456"
|
||||
user.CreateTime = "2019"
|
||||
fmt.Println(gconv.Map(user))
|
||||
fmt.Println(gconv.MapDeep(user))
|
||||
}
|
||||
|
||||
@ -1,13 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/text/gregex"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := `-abc`
|
||||
m, err := gregex.MatchString(`^\-{1,2}a={0,1}(.*)`, s)
|
||||
g.Dump(err)
|
||||
g.Dump(m)
|
||||
r := ghttp.PostContent("http://127.0.0.1:8199/test", `<doc><id>1</id><name>john</name><password1>123Abc!@#</password1><password2>123Abc!@#</password2></doc>`)
|
||||
fmt.Println(r)
|
||||
}
|
||||
|
||||
@ -1,22 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/os/glog"
|
||||
)
|
||||
|
||||
func main() {
|
||||
g.TryCatch(func() {
|
||||
glog.Println("hello")
|
||||
g.Throw("exception")
|
||||
glog.Println("world")
|
||||
})
|
||||
|
||||
g.TryCatch(func() {
|
||||
glog.Println("hello")
|
||||
g.Throw("exception")
|
||||
glog.Println("world")
|
||||
}, func(exception interface{}) {
|
||||
glog.Error(exception)
|
||||
})
|
||||
}
|
||||
@ -7,18 +7,18 @@ import (
|
||||
|
||||
func main() {
|
||||
type Ids struct {
|
||||
Id int `json:"id"`
|
||||
Uid int `json:"uid"`
|
||||
Id int `c:"id"`
|
||||
Uid int `c:"uid"`
|
||||
}
|
||||
type Base struct {
|
||||
Ids
|
||||
CreateTime string `json:"create_time"`
|
||||
CreateTime string `c:"create_time"`
|
||||
}
|
||||
type User struct {
|
||||
Base
|
||||
Passport string `json:"passport"`
|
||||
Password string `json:"password"`
|
||||
Nickname string `json:"nickname"`
|
||||
Passport string `c:"passport"`
|
||||
Password string `c:"password"`
|
||||
Nickname string `c:"nickname"`
|
||||
}
|
||||
user := new(User)
|
||||
user.Id = 1
|
||||
@ -27,5 +27,6 @@ func main() {
|
||||
user.Passport = "johng"
|
||||
user.Password = "123456"
|
||||
user.CreateTime = "2019"
|
||||
g.Dump(gconv.Map(user))
|
||||
g.Dump(gconv.MapDeep(user))
|
||||
}
|
||||
|
||||
68
DONATOR.MD
68
DONATOR.MD
@ -1,35 +1,47 @@
|
||||
# Donators
|
||||
|
||||
We currently accept donation by Alipay/WechatPay, please note your github/gitee account in your payment bill.
|
||||
|
||||
| Name | Channel | Amount
|
||||
|---|---|---
|
||||
|[hailaz](https://gitee.com/hailaz)|gitee|¥20.00
|
||||
|[ireadx](https://github.com/ireadx)|alipay|¥301.00
|
||||
|[mg91](https://gitee.com/mg91)|gitee|¥10.00
|
||||
|[pibigstar](https://github.com/pibigstar)|alipay|¥10.00
|
||||
|[tiangenglan](https://gitee.com/tiangenglan)|gitee|¥30.00
|
||||
|[wxkj](https://gitee.com/wxkj)|wechat|¥10.00
|
||||
|[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
|
||||
|[macnie](https://www.macnie.com)|wechat|¥100.00
|
||||
|lah|wechat|¥100.00
|
||||
|x*z|wechat|¥20.00
|
||||
|潘兄|wechat|¥100.00
|
||||
|Fly的狐狸|wechat|¥100.00
|
||||
|全|alipay|¥100.00
|
||||
|东东|wechat|¥100.00
|
||||
|严宇轩|alipay|¥99.99
|
||||
|土豆相公|alipay|¥66.60
|
||||
|Hades|alipay|¥66.66
|
||||
|蔡蔡|wechat|¥666.00
|
||||
|上海金保证网络科技|bank|¥2000.00
|
||||
|[foxhack](https://github.com/foxhack)|wechat|¥20.00
|
||||
|*栈|wechat|¥5.00
|
||||
|*络|wechat|¥10.00
|
||||
|R*s|wechat|¥18.88
|
||||
|粟*e|wechat|¥50.00
|
||||
|
||||
| Name | Channel | Amount | Comment
|
||||
|---|---|--- | ---
|
||||
|[hailaz](https://gitee.com/hailaz)|gitee|¥20.00 |
|
||||
|[ireadx](https://github.com/ireadx)|alipay|¥301.00 |
|
||||
|[mg91](https://gitee.com/mg91)|gitee|¥10.00 |
|
||||
|[pibigstar](https://github.com/pibigstar)|alipay|¥10.00 |
|
||||
|[tiangenglan](https://gitee.com/tiangenglan)|gitee|¥30.00 |
|
||||
|[wxkj](https://gitee.com/wxkj)|wechat|¥10.00 |
|
||||
|[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 |
|
||||
|[macnie](https://www.macnie.com)|wechat|¥100.00 |
|
||||
|lah|wechat|¥100.00 |
|
||||
|x*z|wechat|¥20.00 |
|
||||
|潘兄|wechat|¥100.00 |
|
||||
|Fly的狐狸|wechat|¥100.00 |
|
||||
|全|alipay|¥100.00 |
|
||||
|东东|wechat|¥100.00 |
|
||||
|严宇轩|alipay|¥99.99 |
|
||||
|土豆相公|alipay|¥66.60 |
|
||||
|Hades|alipay|¥66.66 |
|
||||
|蔡蔡|wechat|¥666.00 | gf越来越强
|
||||
|上海金保证网络科技|bank|¥2000.00 |
|
||||
|[foxhack](https://github.com/foxhack)|wechat|¥20.00 |
|
||||
|*栈|wechat|¥5.00 |
|
||||
|*络|wechat|¥10.00|
|
||||
|M*e|wechat|¥20.00|
|
||||
|*G|wechat|¥10.00|
|
||||
|E*_|wechat|¥10.00|
|
||||
|A*y|wechat|¥1.00| 感谢大佬goframe
|
||||
|K*e|wechat|¥168.00| 感谢老大
|
||||
|*雨|wechat|¥100.00|
|
||||
|*洁|wechat|¥10.00|赞助你肥宅快乐水
|
||||
|R*s|wechat|¥18.88| 谢谢GF!辛苦了!
|
||||
|粟*e|wechat|¥50.00|
|
||||
|[李超](https://github.com/effortlee)|wechat|¥124.00|
|
||||
|张炳贤|wechat+qq|¥600.00|
|
||||
|[王哈哈](https://gitee.com/develop1024)|wechat|¥6.66| 希望gf越来越好
|
||||
|夕景|alipay+qq|¥9.96+3.57|
|
||||
|
||||
|
||||
<img src="https://goframe.org/images/donate.png"/>
|
||||
|
||||
@ -9,7 +9,12 @@
|
||||
|
||||
English | [简体中文](README_ZH.MD)
|
||||
|
||||
`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, middleware, logger, template, https, hooks, rewrites and many more features.
|
||||
`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, middleware, logger,
|
||||
template, https, hooks, rewrites and many more features.
|
||||
|
||||
|
||||
# Installation
|
||||
@ -23,7 +28,7 @@ require github.com/gogf/gf latest
|
||||
|
||||
# Limitation
|
||||
```
|
||||
golang version >= 1.11
|
||||
golang version >= 1.10
|
||||
```
|
||||
|
||||
# Documentation
|
||||
|
||||
@ -8,8 +8,11 @@
|
||||
|
||||
[English](README.MD) | 简体中文
|
||||
|
||||
`GF(Go Frame)`是一款模块化、高性能、生产级Go应用开发框架。提供了常用的核心开发组件,如:缓存、日志、文件、时间、队列、数组、集合、字符串、定时器、命令行、文件锁、内存锁、对象池、连接池、资源管理、数据校验、数据编码、文件监控、定时任务、数据库ORM、TCP/UDP组件、进程管理/通信、
|
||||
并发安全容器等等。并提供了Web服务开发的系列核心组件,如:Router、Cookie、Session、Middleware、服务注册、配置管理、模板引擎等等,支持热重启、热更新、多域名、多端口、多服务、HTTPS、Rewrite等特性。
|
||||
`GF(Go Frame)`是一款模块化、高性能、生产级的Go基础开发框架。实现了比较完善的基础设施建设,包括常用的核心开发组件,
|
||||
如:缓存、日志、文件、时间、队列、数组、集合、字符串、定时器、命令行、文件锁、内存锁、对象池、连接池、资源管理、数据校验、数据编码、文件监控、
|
||||
定时任务、数据库ORM、TCP/UDP组件、进程管理/通信、并发安全容器等等。
|
||||
并提供了Web服务开发的系列核心组件,如:Router、Cookie、Session、Middleware、服务注册、配置管理、模板引擎等等,
|
||||
支持热重启、热更新、多域名、多端口、多服务、HTTPS、Rewrite等特性。
|
||||
|
||||
|
||||
# 特点
|
||||
@ -18,7 +21,6 @@
|
||||
* 简便及可维护性为宗旨;
|
||||
* 详尽的开发文档及示例;
|
||||
* 完善的本地中文化支持;
|
||||
* 致力于项目的通用方案;
|
||||
* 更适合企业及团队使用;
|
||||
* 更多请查阅文档及源码;
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@ package garray
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"math"
|
||||
"sort"
|
||||
@ -45,6 +46,21 @@ func NewArraySize(size int, cap int, safe ...bool) *Array {
|
||||
}
|
||||
}
|
||||
|
||||
// NewArrayRange creates and returns a array by a range from <start> to <end>
|
||||
// with step value <step>.
|
||||
func NewArrayRange(start, end, step int, safe ...bool) *Array {
|
||||
if step == 0 {
|
||||
panic(fmt.Sprintf(`invalid step value: %d`, step))
|
||||
}
|
||||
slice := make([]interface{}, (end-start+1)/step)
|
||||
index := 0
|
||||
for i := start; i <= end; i += step {
|
||||
slice[index] = i
|
||||
index++
|
||||
}
|
||||
return NewArrayFrom(slice, safe...)
|
||||
}
|
||||
|
||||
// See NewArrayFrom.
|
||||
func NewFrom(array []interface{}, safe ...bool) *Array {
|
||||
return NewArrayFrom(array, safe...)
|
||||
@ -609,6 +625,35 @@ func (a *Array) CountValues() map[interface{}]int {
|
||||
return m
|
||||
}
|
||||
|
||||
// Iterator is alias of IteratorAsc.
|
||||
func (a *Array) Iterator(f func(k int, v interface{}) bool) {
|
||||
a.IteratorAsc(f)
|
||||
}
|
||||
|
||||
// IteratorAsc iterates the array in ascending order with given callback function <f>.
|
||||
// If <f> returns true, then it continues iterating; or false to stop.
|
||||
func (a *Array) IteratorAsc(f func(k int, v interface{}) bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
for k, v := range a.array {
|
||||
if !f(k, v) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IteratorDesc iterates the array in descending order with given callback function <f>.
|
||||
// If <f> returns true, then it continues iterating; or false to stop.
|
||||
func (a *Array) IteratorDesc(f func(k int, v interface{}) bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
for i := len(a.array) - 1; i >= 0; i-- {
|
||||
if !f(i, a.array[i]) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// String returns current array as a string, which implements like json.Marshal does.
|
||||
func (a *Array) String() string {
|
||||
a.mu.RLock()
|
||||
|
||||
@ -9,6 +9,7 @@ package garray
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"sort"
|
||||
|
||||
@ -39,6 +40,21 @@ func NewIntArraySize(size int, cap int, safe ...bool) *IntArray {
|
||||
}
|
||||
}
|
||||
|
||||
// NewIntArrayRange creates and returns a array by a range from <start> to <end>
|
||||
// with step value <step>.
|
||||
func NewIntArrayRange(start, end, step int, safe ...bool) *IntArray {
|
||||
if step == 0 {
|
||||
panic(fmt.Sprintf(`invalid step value: %d`, step))
|
||||
}
|
||||
slice := make([]int, (end-start+1)/step)
|
||||
index := 0
|
||||
for i := start; i <= end; i += step {
|
||||
slice[index] = i
|
||||
index++
|
||||
}
|
||||
return NewIntArrayFrom(slice, safe...)
|
||||
}
|
||||
|
||||
// NewIntArrayFrom creates and returns an array with given slice <array>.
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// which is false in default.
|
||||
@ -621,6 +637,35 @@ func (a *IntArray) CountValues() map[int]int {
|
||||
return m
|
||||
}
|
||||
|
||||
// Iterator is alias of IteratorAsc.
|
||||
func (a *IntArray) Iterator(f func(k int, v int) bool) {
|
||||
a.IteratorAsc(f)
|
||||
}
|
||||
|
||||
// IteratorAsc iterates the array in ascending order with given callback function <f>.
|
||||
// If <f> returns true, then it continues iterating; or false to stop.
|
||||
func (a *IntArray) IteratorAsc(f func(k int, v int) bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
for k, v := range a.array {
|
||||
if !f(k, v) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IteratorDesc iterates the array in descending order with given callback function <f>.
|
||||
// If <f> returns true, then it continues iterating; or false to stop.
|
||||
func (a *IntArray) IteratorDesc(f func(k int, v int) bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
for i := len(a.array) - 1; i >= 0; i-- {
|
||||
if !f(i, a.array[i]) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// String returns current array as a string, which implements like json.Marshal does.
|
||||
func (a *IntArray) String() string {
|
||||
return "[" + a.Join(",") + "]"
|
||||
|
||||
@ -622,6 +622,35 @@ func (a *StrArray) CountValues() map[string]int {
|
||||
return m
|
||||
}
|
||||
|
||||
// Iterator is alias of IteratorAsc.
|
||||
func (a *StrArray) Iterator(f func(k int, v string) bool) {
|
||||
a.IteratorAsc(f)
|
||||
}
|
||||
|
||||
// IteratorAsc iterates the array in ascending order with given callback function <f>.
|
||||
// If <f> returns true, then it continues iterating; or false to stop.
|
||||
func (a *StrArray) IteratorAsc(f func(k int, v string) bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
for k, v := range a.array {
|
||||
if !f(k, v) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IteratorDesc iterates the array in descending order with given callback function <f>.
|
||||
// If <f> returns true, then it continues iterating; or false to stop.
|
||||
func (a *StrArray) IteratorDesc(f func(k int, v string) bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
for i := len(a.array) - 1; i >= 0; i-- {
|
||||
if !f(i, a.array[i]) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// String returns current array as a string, which implements like json.Marshal does.
|
||||
func (a *StrArray) String() string {
|
||||
a.mu.RLock()
|
||||
|
||||
@ -9,6 +9,7 @@ package garray
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"github.com/gogf/gf/util/gutil"
|
||||
"math"
|
||||
@ -50,6 +51,21 @@ func NewSortedArraySize(cap int, comparator func(a, b interface{}) int, safe ...
|
||||
}
|
||||
}
|
||||
|
||||
// NewSortedArrayRange creates and returns a array by a range from <start> to <end>
|
||||
// with step value <step>.
|
||||
func NewSortedArrayRange(start, end, step int, comparator func(a, b interface{}) int, safe ...bool) *SortedArray {
|
||||
if step == 0 {
|
||||
panic(fmt.Sprintf(`invalid step value: %d`, step))
|
||||
}
|
||||
slice := make([]interface{}, (end-start+1)/step)
|
||||
index := 0
|
||||
for i := start; i <= end; i += step {
|
||||
slice[index] = i
|
||||
index++
|
||||
}
|
||||
return NewSortedArrayFrom(slice, comparator, safe...)
|
||||
}
|
||||
|
||||
// NewSortedArrayFrom creates and returns an sorted array with given slice <array>.
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// which is false in default.
|
||||
@ -554,6 +570,35 @@ func (a *SortedArray) CountValues() map[interface{}]int {
|
||||
return m
|
||||
}
|
||||
|
||||
// Iterator is alias of IteratorAsc.
|
||||
func (a *SortedArray) Iterator(f func(k int, v interface{}) bool) {
|
||||
a.IteratorAsc(f)
|
||||
}
|
||||
|
||||
// IteratorAsc iterates the array in ascending order with given callback function <f>.
|
||||
// If <f> returns true, then it continues iterating; or false to stop.
|
||||
func (a *SortedArray) IteratorAsc(f func(k int, v interface{}) bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
for k, v := range a.array {
|
||||
if !f(k, v) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IteratorDesc iterates the array in descending order with given callback function <f>.
|
||||
// If <f> returns true, then it continues iterating; or false to stop.
|
||||
func (a *SortedArray) IteratorDesc(f func(k int, v interface{}) bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
for i := len(a.array) - 1; i >= 0; i-- {
|
||||
if !f(i, a.array[i]) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// String returns current array as a string, which implements like json.Marshal does.
|
||||
func (a *SortedArray) String() string {
|
||||
a.mu.RLock()
|
||||
|
||||
@ -9,6 +9,7 @@ package garray
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"sort"
|
||||
|
||||
@ -53,6 +54,21 @@ func NewSortedIntArraySize(cap int, safe ...bool) *SortedIntArray {
|
||||
}
|
||||
}
|
||||
|
||||
// NewSortedIntArrayRange creates and returns a array by a range from <start> to <end>
|
||||
// with step value <step>.
|
||||
func NewSortedIntArrayRange(start, end, step int, safe ...bool) *SortedIntArray {
|
||||
if step == 0 {
|
||||
panic(fmt.Sprintf(`invalid step value: %d`, step))
|
||||
}
|
||||
slice := make([]int, (end-start+1)/step)
|
||||
index := 0
|
||||
for i := start; i <= end; i += step {
|
||||
slice[index] = i
|
||||
index++
|
||||
}
|
||||
return NewSortedIntArrayFrom(slice, safe...)
|
||||
}
|
||||
|
||||
// NewIntArrayFrom creates and returns an sorted array with given slice <array>.
|
||||
// The parameter <safe> is used to specify whether using array in concurrent-safety,
|
||||
// which is false in default.
|
||||
@ -546,6 +562,35 @@ func (a *SortedIntArray) CountValues() map[int]int {
|
||||
return m
|
||||
}
|
||||
|
||||
// Iterator is alias of IteratorAsc.
|
||||
func (a *SortedIntArray) Iterator(f func(k int, v int) bool) {
|
||||
a.IteratorAsc(f)
|
||||
}
|
||||
|
||||
// IteratorAsc iterates the array in ascending order with given callback function <f>.
|
||||
// If <f> returns true, then it continues iterating; or false to stop.
|
||||
func (a *SortedIntArray) IteratorAsc(f func(k int, v int) bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
for k, v := range a.array {
|
||||
if !f(k, v) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IteratorDesc iterates the array in descending order with given callback function <f>.
|
||||
// If <f> returns true, then it continues iterating; or false to stop.
|
||||
func (a *SortedIntArray) IteratorDesc(f func(k int, v int) bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
for i := len(a.array) - 1; i >= 0; i-- {
|
||||
if !f(i, a.array[i]) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// String returns current array as a string, which implements like json.Marshal does.
|
||||
func (a *SortedIntArray) String() string {
|
||||
return "[" + a.Join(",") + "]"
|
||||
|
||||
@ -547,6 +547,35 @@ func (a *SortedStrArray) CountValues() map[string]int {
|
||||
return m
|
||||
}
|
||||
|
||||
// Iterator is alias of IteratorAsc.
|
||||
func (a *SortedStrArray) Iterator(f func(k int, v string) bool) {
|
||||
a.IteratorAsc(f)
|
||||
}
|
||||
|
||||
// IteratorAsc iterates the array in ascending order with given callback function <f>.
|
||||
// If <f> returns true, then it continues iterating; or false to stop.
|
||||
func (a *SortedStrArray) IteratorAsc(f func(k int, v string) bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
for k, v := range a.array {
|
||||
if !f(k, v) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IteratorDesc iterates the array in descending order with given callback function <f>.
|
||||
// If <f> returns true, then it continues iterating; or false to stop.
|
||||
func (a *SortedStrArray) IteratorDesc(f func(k int, v string) bool) {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
for i := len(a.array) - 1; i >= 0; i-- {
|
||||
if !f(i, a.array[i]) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// String returns current array as a string, which implements like json.Marshal does.
|
||||
func (a *SortedStrArray) String() string {
|
||||
a.mu.RLock()
|
||||
|
||||
@ -450,3 +450,50 @@ func TestArray_Json(t *testing.T) {
|
||||
gtest.Assert(user.Scores, data["Scores"])
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Iterator(t *testing.T) {
|
||||
slice := g.Slice{"a", "b", "d", "c"}
|
||||
array := garray.NewArrayFrom(slice)
|
||||
gtest.Case(t, func() {
|
||||
array.Iterator(func(k int, v interface{}) bool {
|
||||
gtest.Assert(v, slice[k])
|
||||
return true
|
||||
})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
array.IteratorAsc(func(k int, v interface{}) bool {
|
||||
gtest.Assert(v, slice[k])
|
||||
return true
|
||||
})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
array.IteratorDesc(func(k int, v interface{}) bool {
|
||||
gtest.Assert(v, slice[k])
|
||||
return true
|
||||
})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
index := 0
|
||||
array.Iterator(func(k int, v interface{}) bool {
|
||||
index++
|
||||
return false
|
||||
})
|
||||
gtest.Assert(index, 1)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
index := 0
|
||||
array.IteratorAsc(func(k int, v interface{}) bool {
|
||||
index++
|
||||
return false
|
||||
})
|
||||
gtest.Assert(index, 1)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
index := 0
|
||||
array.IteratorDesc(func(k int, v interface{}) bool {
|
||||
index++
|
||||
return false
|
||||
})
|
||||
gtest.Assert(index, 1)
|
||||
})
|
||||
}
|
||||
|
||||
@ -484,3 +484,50 @@ func TestIntArray_Json(t *testing.T) {
|
||||
gtest.Assert(user.Scores, data["Scores"])
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntArray_Iterator(t *testing.T) {
|
||||
slice := g.SliceInt{10, 20, 30, 40}
|
||||
array := garray.NewIntArrayFrom(slice)
|
||||
gtest.Case(t, func() {
|
||||
array.Iterator(func(k int, v int) bool {
|
||||
gtest.Assert(v, slice[k])
|
||||
return true
|
||||
})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
array.IteratorAsc(func(k int, v int) bool {
|
||||
gtest.Assert(v, slice[k])
|
||||
return true
|
||||
})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
array.IteratorDesc(func(k int, v int) bool {
|
||||
gtest.Assert(v, slice[k])
|
||||
return true
|
||||
})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
index := 0
|
||||
array.Iterator(func(k int, v int) bool {
|
||||
index++
|
||||
return false
|
||||
})
|
||||
gtest.Assert(index, 1)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
index := 0
|
||||
array.IteratorAsc(func(k int, v int) bool {
|
||||
index++
|
||||
return false
|
||||
})
|
||||
gtest.Assert(index, 1)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
index := 0
|
||||
array.IteratorDesc(func(k int, v int) bool {
|
||||
index++
|
||||
return false
|
||||
})
|
||||
gtest.Assert(index, 1)
|
||||
})
|
||||
}
|
||||
|
||||
@ -488,3 +488,50 @@ func TestStrArray_Json(t *testing.T) {
|
||||
gtest.Assert(user.Scores, data["Scores"])
|
||||
})
|
||||
}
|
||||
|
||||
func TestStrArray_Iterator(t *testing.T) {
|
||||
slice := g.SliceStr{"a", "b", "d", "c"}
|
||||
array := garray.NewStrArrayFrom(slice)
|
||||
gtest.Case(t, func() {
|
||||
array.Iterator(func(k int, v string) bool {
|
||||
gtest.Assert(v, slice[k])
|
||||
return true
|
||||
})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
array.IteratorAsc(func(k int, v string) bool {
|
||||
gtest.Assert(v, slice[k])
|
||||
return true
|
||||
})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
array.IteratorDesc(func(k int, v string) bool {
|
||||
gtest.Assert(v, slice[k])
|
||||
return true
|
||||
})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
index := 0
|
||||
array.Iterator(func(k int, v string) bool {
|
||||
index++
|
||||
return false
|
||||
})
|
||||
gtest.Assert(index, 1)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
index := 0
|
||||
array.IteratorAsc(func(k int, v string) bool {
|
||||
index++
|
||||
return false
|
||||
})
|
||||
gtest.Assert(index, 1)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
index := 0
|
||||
array.IteratorDesc(func(k int, v string) bool {
|
||||
index++
|
||||
return false
|
||||
})
|
||||
gtest.Assert(index, 1)
|
||||
})
|
||||
}
|
||||
|
||||
@ -587,3 +587,50 @@ func TestSortedArray_Json(t *testing.T) {
|
||||
gtest.AssertIN(user.Scores.PopLeft(), data["Scores"])
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedArray_Iterator(t *testing.T) {
|
||||
slice := g.Slice{"a", "b", "d", "c"}
|
||||
array := garray.NewSortedArrayFrom(slice, gutil.ComparatorString)
|
||||
gtest.Case(t, func() {
|
||||
array.Iterator(func(k int, v interface{}) bool {
|
||||
gtest.Assert(v, slice[k])
|
||||
return true
|
||||
})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
array.IteratorAsc(func(k int, v interface{}) bool {
|
||||
gtest.Assert(v, slice[k])
|
||||
return true
|
||||
})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
array.IteratorDesc(func(k int, v interface{}) bool {
|
||||
gtest.Assert(v, slice[k])
|
||||
return true
|
||||
})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
index := 0
|
||||
array.Iterator(func(k int, v interface{}) bool {
|
||||
index++
|
||||
return false
|
||||
})
|
||||
gtest.Assert(index, 1)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
index := 0
|
||||
array.IteratorAsc(func(k int, v interface{}) bool {
|
||||
index++
|
||||
return false
|
||||
})
|
||||
gtest.Assert(index, 1)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
index := 0
|
||||
array.IteratorDesc(func(k int, v interface{}) bool {
|
||||
index++
|
||||
return false
|
||||
})
|
||||
gtest.Assert(index, 1)
|
||||
})
|
||||
}
|
||||
|
||||
@ -466,3 +466,50 @@ func TestSortedIntArray_Json(t *testing.T) {
|
||||
gtest.Assert(user.Scores, []int{98, 99, 100})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Iterator(t *testing.T) {
|
||||
slice := g.SliceInt{10, 20, 30, 40}
|
||||
array := garray.NewSortedIntArrayFrom(slice)
|
||||
gtest.Case(t, func() {
|
||||
array.Iterator(func(k int, v int) bool {
|
||||
gtest.Assert(v, slice[k])
|
||||
return true
|
||||
})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
array.IteratorAsc(func(k int, v int) bool {
|
||||
gtest.Assert(v, slice[k])
|
||||
return true
|
||||
})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
array.IteratorDesc(func(k int, v int) bool {
|
||||
gtest.Assert(v, slice[k])
|
||||
return true
|
||||
})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
index := 0
|
||||
array.Iterator(func(k int, v int) bool {
|
||||
index++
|
||||
return false
|
||||
})
|
||||
gtest.Assert(index, 1)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
index := 0
|
||||
array.IteratorAsc(func(k int, v int) bool {
|
||||
index++
|
||||
return false
|
||||
})
|
||||
gtest.Assert(index, 1)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
index := 0
|
||||
array.IteratorDesc(func(k int, v int) bool {
|
||||
index++
|
||||
return false
|
||||
})
|
||||
gtest.Assert(index, 1)
|
||||
})
|
||||
}
|
||||
|
||||
@ -476,3 +476,50 @@ func TestSortedStrArray_Json(t *testing.T) {
|
||||
gtest.Assert(user.Scores, []string{"A", "A", "A+"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_Iterator(t *testing.T) {
|
||||
slice := g.SliceStr{"a", "b", "d", "c"}
|
||||
array := garray.NewSortedStrArrayFrom(slice)
|
||||
gtest.Case(t, func() {
|
||||
array.Iterator(func(k int, v string) bool {
|
||||
gtest.Assert(v, slice[k])
|
||||
return true
|
||||
})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
array.IteratorAsc(func(k int, v string) bool {
|
||||
gtest.Assert(v, slice[k])
|
||||
return true
|
||||
})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
array.IteratorDesc(func(k int, v string) bool {
|
||||
gtest.Assert(v, slice[k])
|
||||
return true
|
||||
})
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
index := 0
|
||||
array.Iterator(func(k int, v string) bool {
|
||||
index++
|
||||
return false
|
||||
})
|
||||
gtest.Assert(index, 1)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
index := 0
|
||||
array.IteratorAsc(func(k int, v string) bool {
|
||||
index++
|
||||
return false
|
||||
})
|
||||
gtest.Assert(index, 1)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
index := 0
|
||||
array.IteratorDesc(func(k int, v string) bool {
|
||||
index++
|
||||
return false
|
||||
})
|
||||
gtest.Assert(index, 1)
|
||||
})
|
||||
}
|
||||
|
||||
@ -364,6 +364,7 @@ func (l *List) Iterator(f func(e *Element) bool) {
|
||||
// If <f> returns true, then it continues iterating; or false to stop.
|
||||
func (l *List) IteratorAsc(f func(e *Element) bool) {
|
||||
l.mu.RLock()
|
||||
defer l.mu.RUnlock()
|
||||
length := l.list.Len()
|
||||
if length > 0 {
|
||||
for i, e := 0, l.list.Front(); i < length; i, e = i+1, e.Next() {
|
||||
@ -372,13 +373,13 @@ func (l *List) IteratorAsc(f func(e *Element) bool) {
|
||||
}
|
||||
}
|
||||
}
|
||||
l.mu.RUnlock()
|
||||
}
|
||||
|
||||
// IteratorDesc iterates the list in descending order with given callback function <f>.
|
||||
// If <f> returns true, then it continues iterating; or false to stop.
|
||||
func (l *List) IteratorDesc(f func(e *Element) bool) {
|
||||
l.mu.RLock()
|
||||
defer l.mu.RUnlock()
|
||||
length := l.list.Len()
|
||||
if length > 0 {
|
||||
for i, e := 0, l.list.Back(); i < length; i, e = i+1, e.Prev() {
|
||||
@ -387,7 +388,6 @@ func (l *List) IteratorDesc(f func(e *Element) bool) {
|
||||
}
|
||||
}
|
||||
}
|
||||
l.mu.RUnlock()
|
||||
}
|
||||
|
||||
// Join joins list elements with a string <glue>.
|
||||
|
||||
@ -7,7 +7,9 @@
|
||||
package glist_test
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/container/garray"
|
||||
|
||||
"github.com/gogf/gf/container/glist"
|
||||
)
|
||||
@ -35,3 +37,64 @@ func Example_basic() {
|
||||
//0123456789
|
||||
//0
|
||||
}
|
||||
|
||||
func Example_iterate() {
|
||||
// concurrent-safe list.
|
||||
l := glist.NewFrom(garray.NewArrayRange(1, 10, 1).Slice(), true)
|
||||
// iterate reading from head.
|
||||
l.RLockFunc(func(list *list.List) {
|
||||
length := list.Len()
|
||||
if length > 0 {
|
||||
for i, e := 0, list.Front(); i < length; i, e = i+1, e.Next() {
|
||||
fmt.Print(e.Value)
|
||||
}
|
||||
}
|
||||
})
|
||||
fmt.Println()
|
||||
// iterate reading from tail.
|
||||
l.RLockFunc(func(list *list.List) {
|
||||
length := list.Len()
|
||||
if length > 0 {
|
||||
for i, e := 0, list.Back(); i < length; i, e = i+1, e.Prev() {
|
||||
fmt.Print(e.Value)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
fmt.Println()
|
||||
|
||||
// iterate reading from head using IteratorAsc.
|
||||
l.IteratorAsc(func(e *glist.Element) bool {
|
||||
fmt.Print(e.Value)
|
||||
return true
|
||||
})
|
||||
fmt.Println()
|
||||
// iterate reading from tail using IteratorDesc.
|
||||
l.IteratorDesc(func(e *glist.Element) bool {
|
||||
fmt.Print(e.Value)
|
||||
return true
|
||||
})
|
||||
|
||||
fmt.Println()
|
||||
|
||||
// iterate writing from head.
|
||||
l.LockFunc(func(list *list.List) {
|
||||
length := list.Len()
|
||||
if length > 0 {
|
||||
for i, e := 0, list.Front(); i < length; i, e = i+1, e.Next() {
|
||||
if e.Value == 6 {
|
||||
e.Value = "M"
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
fmt.Println(l)
|
||||
|
||||
//output:
|
||||
//12345678910
|
||||
//10987654321
|
||||
//12345678910
|
||||
//10987654321
|
||||
//[1,2,3,4,5,"M",7,8,9,10]
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@ import (
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// Bool is a struct for concurrent-safe operation for type bool.
|
||||
type Bool struct {
|
||||
value int32
|
||||
}
|
||||
@ -21,7 +22,7 @@ var (
|
||||
bytesFalse = []byte("false")
|
||||
)
|
||||
|
||||
// NewBool returns a concurrent-safe object for bool type,
|
||||
// NewBool creates and returns a concurrent-safe object for bool type,
|
||||
// with given initial value <value>.
|
||||
func NewBool(value ...bool) *Bool {
|
||||
t := &Bool{}
|
||||
@ -50,7 +51,7 @@ func (v *Bool) Set(value bool) (old bool) {
|
||||
return
|
||||
}
|
||||
|
||||
// Val atomically loads t.valueue.
|
||||
// Val atomically loads and returns t.valueue.
|
||||
func (v *Bool) Val() bool {
|
||||
return atomic.LoadInt32(&v.value) > 0
|
||||
}
|
||||
|
||||
@ -12,11 +12,12 @@ import (
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// Byte is a struct for concurrent-safe operation for type byte.
|
||||
type Byte struct {
|
||||
value int32
|
||||
}
|
||||
|
||||
// NewByte returns a concurrent-safe object for byte type,
|
||||
// NewByte creates and returns a concurrent-safe object for byte type,
|
||||
// with given initial value <value>.
|
||||
func NewByte(value ...byte) *Byte {
|
||||
if len(value) > 0 {
|
||||
@ -37,7 +38,7 @@ func (v *Byte) Set(value byte) (old byte) {
|
||||
return byte(atomic.SwapInt32(&v.value, int32(value)))
|
||||
}
|
||||
|
||||
// Val atomically loads t.value.
|
||||
// Val atomically loads and returns t.value.
|
||||
func (v *Byte) Val() byte {
|
||||
return byte(atomic.LoadInt32(&v.value))
|
||||
}
|
||||
|
||||
@ -13,11 +13,12 @@ import (
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// Bytes is a struct for concurrent-safe operation for type []byte.
|
||||
type Bytes struct {
|
||||
value atomic.Value
|
||||
}
|
||||
|
||||
// NewBytes returns a concurrent-safe object for []byte type,
|
||||
// NewBytes creates and returns a concurrent-safe object for []byte type,
|
||||
// with given initial value <value>.
|
||||
func NewBytes(value ...[]byte) *Bytes {
|
||||
t := &Bytes{}
|
||||
@ -40,7 +41,7 @@ func (v *Bytes) Set(value []byte) (old []byte) {
|
||||
return
|
||||
}
|
||||
|
||||
// Val atomically loads t.value.
|
||||
// Val atomically loads and returns t.value.
|
||||
func (v *Bytes) Val() []byte {
|
||||
if s := v.value.Load(); s != nil {
|
||||
return s.([]byte)
|
||||
|
||||
@ -14,11 +14,12 @@ import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Float32 is a struct for concurrent-safe operation for type float32.
|
||||
type Float32 struct {
|
||||
value uint32
|
||||
}
|
||||
|
||||
// NewFloat32 returns a concurrent-safe object for float32 type,
|
||||
// NewFloat32 creates and returns a concurrent-safe object for float32 type,
|
||||
// with given initial value <value>.
|
||||
func NewFloat32(value ...float32) *Float32 {
|
||||
if len(value) > 0 {
|
||||
@ -39,7 +40,7 @@ func (v *Float32) Set(value float32) (old float32) {
|
||||
return math.Float32frombits(atomic.SwapUint32(&v.value, math.Float32bits(value)))
|
||||
}
|
||||
|
||||
// Val atomically loads t.value.
|
||||
// Val atomically loads and returns t.value.
|
||||
func (v *Float32) Val() float32 {
|
||||
return math.Float32frombits(atomic.LoadUint32(&v.value))
|
||||
}
|
||||
|
||||
@ -14,11 +14,12 @@ import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Float64 is a struct for concurrent-safe operation for type float64.
|
||||
type Float64 struct {
|
||||
value uint64
|
||||
}
|
||||
|
||||
// NewFloat64 returns a concurrent-safe object for float64 type,
|
||||
// NewFloat64 creates and returns a concurrent-safe object for float64 type,
|
||||
// with given initial value <value>.
|
||||
func NewFloat64(value ...float64) *Float64 {
|
||||
if len(value) > 0 {
|
||||
@ -39,7 +40,7 @@ func (v *Float64) Set(value float64) (old float64) {
|
||||
return math.Float64frombits(atomic.SwapUint64(&v.value, math.Float64bits(value)))
|
||||
}
|
||||
|
||||
// Val atomically loads t.value.
|
||||
// Val atomically loads and returns t.value.
|
||||
func (v *Float64) Val() float64 {
|
||||
return math.Float64frombits(atomic.LoadUint64(&v.value))
|
||||
}
|
||||
|
||||
@ -12,11 +12,12 @@ import (
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// Int is a struct for concurrent-safe operation for type int.
|
||||
type Int struct {
|
||||
value int64
|
||||
}
|
||||
|
||||
// NewInt returns a concurrent-safe object for int type,
|
||||
// NewInt creates and returns a concurrent-safe object for int type,
|
||||
// with given initial value <value>.
|
||||
func NewInt(value ...int) *Int {
|
||||
if len(value) > 0 {
|
||||
@ -37,7 +38,7 @@ func (v *Int) Set(value int) (old int) {
|
||||
return int(atomic.SwapInt64(&v.value, int64(value)))
|
||||
}
|
||||
|
||||
// Val atomically loads t.value.
|
||||
// Val atomically loads and returns t.value.
|
||||
func (v *Int) Val() int {
|
||||
return int(atomic.LoadInt64(&v.value))
|
||||
}
|
||||
|
||||
@ -12,11 +12,12 @@ import (
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// Int32 is a struct for concurrent-safe operation for type int32.
|
||||
type Int32 struct {
|
||||
value int32
|
||||
}
|
||||
|
||||
// NewInt32 returns a concurrent-safe object for int32 type,
|
||||
// NewInt32 creates and returns a concurrent-safe object for int32 type,
|
||||
// with given initial value <value>.
|
||||
func NewInt32(value ...int32) *Int32 {
|
||||
if len(value) > 0 {
|
||||
@ -37,7 +38,7 @@ func (v *Int32) Set(value int32) (old int32) {
|
||||
return atomic.SwapInt32(&v.value, value)
|
||||
}
|
||||
|
||||
// Val atomically loads t.value.
|
||||
// Val atomically loads and returns t.value.
|
||||
func (v *Int32) Val() int32 {
|
||||
return atomic.LoadInt32(&v.value)
|
||||
}
|
||||
|
||||
@ -12,11 +12,12 @@ import (
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// Int64 is a struct for concurrent-safe operation for type int64.
|
||||
type Int64 struct {
|
||||
value int64
|
||||
}
|
||||
|
||||
// NewInt64 returns a concurrent-safe object for int64 type,
|
||||
// NewInt64 creates and returns a concurrent-safe object for int64 type,
|
||||
// with given initial value <value>.
|
||||
func NewInt64(value ...int64) *Int64 {
|
||||
if len(value) > 0 {
|
||||
@ -37,7 +38,7 @@ func (v *Int64) Set(value int64) (old int64) {
|
||||
return atomic.SwapInt64(&v.value, value)
|
||||
}
|
||||
|
||||
// Val atomically loads t.value.
|
||||
// Val atomically loads and returns t.value.
|
||||
func (v *Int64) Val() int64 {
|
||||
return atomic.LoadInt64(&v.value)
|
||||
}
|
||||
|
||||
@ -12,11 +12,12 @@ import (
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// Interface is a struct for concurrent-safe operation for type interface{}.
|
||||
type Interface struct {
|
||||
value atomic.Value
|
||||
}
|
||||
|
||||
// NewInterface returns a concurrent-safe object for interface{} type,
|
||||
// NewInterface creates and returns a concurrent-safe object for interface{} type,
|
||||
// with given initial value <value>.
|
||||
func NewInterface(value ...interface{}) *Interface {
|
||||
t := &Interface{}
|
||||
@ -39,7 +40,7 @@ func (v *Interface) Set(value interface{}) (old interface{}) {
|
||||
return
|
||||
}
|
||||
|
||||
// Val atomically loads t.value.
|
||||
// Val atomically loads and returns t.value.
|
||||
func (v *Interface) Val() interface{} {
|
||||
return v.value.Load()
|
||||
}
|
||||
|
||||
@ -12,11 +12,12 @@ import (
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// String is a struct for concurrent-safe operation for type string.
|
||||
type String struct {
|
||||
value atomic.Value
|
||||
}
|
||||
|
||||
// NewString returns a concurrent-safe object for string type,
|
||||
// NewString creates and returns a concurrent-safe object for string type,
|
||||
// with given initial value <value>.
|
||||
func NewString(value ...string) *String {
|
||||
t := &String{}
|
||||
@ -38,7 +39,7 @@ func (v *String) Set(value string) (old string) {
|
||||
return
|
||||
}
|
||||
|
||||
// Val atomically loads t.value.
|
||||
// Val atomically loads and returns t.value.
|
||||
func (v *String) Val() string {
|
||||
s := v.value.Load()
|
||||
if s != nil {
|
||||
|
||||
@ -12,11 +12,12 @@ import (
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// Uint is a struct for concurrent-safe operation for type uint.
|
||||
type Uint struct {
|
||||
value uint64
|
||||
}
|
||||
|
||||
// NewUint returns a concurrent-safe object for uint type,
|
||||
// NewUint creates and returns a concurrent-safe object for uint type,
|
||||
// with given initial value <value>.
|
||||
func NewUint(value ...uint) *Uint {
|
||||
if len(value) > 0 {
|
||||
@ -37,7 +38,7 @@ func (v *Uint) Set(value uint) (old uint) {
|
||||
return uint(atomic.SwapUint64(&v.value, uint64(value)))
|
||||
}
|
||||
|
||||
// Val atomically loads t.value.
|
||||
// Val atomically loads and returns t.value.
|
||||
func (v *Uint) Val() uint {
|
||||
return uint(atomic.LoadUint64(&v.value))
|
||||
}
|
||||
|
||||
@ -12,11 +12,12 @@ import (
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// Uint32 is a struct for concurrent-safe operation for type uint32.
|
||||
type Uint32 struct {
|
||||
value uint32
|
||||
}
|
||||
|
||||
// NewUint32 returns a concurrent-safe object for uint32 type,
|
||||
// NewUint32 creates and returns a concurrent-safe object for uint32 type,
|
||||
// with given initial value <value>.
|
||||
func NewUint32(value ...uint32) *Uint32 {
|
||||
if len(value) > 0 {
|
||||
@ -37,7 +38,7 @@ func (v *Uint32) Set(value uint32) (old uint32) {
|
||||
return atomic.SwapUint32(&v.value, value)
|
||||
}
|
||||
|
||||
// Val atomically loads t.value.
|
||||
// Val atomically loads and returns t.value.
|
||||
func (v *Uint32) Val() uint32 {
|
||||
return atomic.LoadUint32(&v.value)
|
||||
}
|
||||
|
||||
@ -12,11 +12,12 @@ import (
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// Uint64 is a struct for concurrent-safe operation for type uint64.
|
||||
type Uint64 struct {
|
||||
value uint64
|
||||
}
|
||||
|
||||
// NewUint64 returns a concurrent-safe object for uint64 type,
|
||||
// NewUint64 creates and returns a concurrent-safe object for uint64 type,
|
||||
// with given initial value <value>.
|
||||
func NewUint64(value ...uint64) *Uint64 {
|
||||
if len(value) > 0 {
|
||||
@ -37,7 +38,7 @@ func (v *Uint64) Set(value uint64) (old uint64) {
|
||||
return atomic.SwapUint64(&v.value, value)
|
||||
}
|
||||
|
||||
// Val atomically loads t.value.
|
||||
// Val atomically loads and returns t.value.
|
||||
func (v *Uint64) Val() uint64 {
|
||||
return atomic.LoadUint64(&v.value)
|
||||
}
|
||||
|
||||
@ -233,15 +233,7 @@ func (v *Var) Map(tags ...string) map[string]interface{} {
|
||||
|
||||
// MapStrStr converts <v> to map[string]string.
|
||||
func (v *Var) MapStrStr(tags ...string) map[string]string {
|
||||
m := v.Map(tags...)
|
||||
if len(m) > 0 {
|
||||
vMap := make(map[string]string)
|
||||
for k, v := range m {
|
||||
vMap[k] = gconv.String(v)
|
||||
}
|
||||
return vMap
|
||||
}
|
||||
return nil
|
||||
return gconv.MapStrStr(v.Val(), tags...)
|
||||
}
|
||||
|
||||
// MapStrVar converts <v> to map[string]*Var.
|
||||
@ -264,15 +256,7 @@ func (v *Var) MapDeep(tags ...string) map[string]interface{} {
|
||||
|
||||
// MapDeep converts <v> to map[string]string recursively.
|
||||
func (v *Var) MapStrStrDeep(tags ...string) map[string]string {
|
||||
m := v.MapDeep(tags...)
|
||||
if len(m) > 0 {
|
||||
vMap := make(map[string]string)
|
||||
for k, v := range m {
|
||||
vMap[k] = gconv.String(v)
|
||||
}
|
||||
return vMap
|
||||
}
|
||||
return nil
|
||||
return gconv.MapStrStrDeep(v.Val(), tags...)
|
||||
}
|
||||
|
||||
// MapStrVarDeep converts <v> to map[string]*Var recursively.
|
||||
|
||||
@ -22,6 +22,17 @@ func Encrypt(data interface{}) (encrypt string, err error) {
|
||||
return EncryptBytes(gconv.Bytes(data))
|
||||
}
|
||||
|
||||
// MustEncrypt encrypts any type of variable using MD5 algorithms.
|
||||
// It uses gconv package to convert <v> to its bytes type.
|
||||
// It panics if any error occurs.
|
||||
func MustEncrypt(data interface{}) string {
|
||||
result, err := Encrypt(data)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// EncryptBytes encrypts <data> using MD5 algorithms.
|
||||
func EncryptBytes(data []byte) (encrypt string, err error) {
|
||||
h := md5.New()
|
||||
@ -31,11 +42,31 @@ func EncryptBytes(data []byte) (encrypt string, err error) {
|
||||
return fmt.Sprintf("%x", h.Sum(nil)), nil
|
||||
}
|
||||
|
||||
// MustEncryptBytes encrypts <data> using MD5 algorithms.
|
||||
// It panics if any error occurs.
|
||||
func MustEncryptBytes(data []byte) string {
|
||||
result, err := EncryptBytes(data)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// EncryptBytes encrypts string <data> using MD5 algorithms.
|
||||
func EncryptString(data string) (encrypt string, err error) {
|
||||
return EncryptBytes([]byte(data))
|
||||
}
|
||||
|
||||
// MustEncryptString encrypts string <data> using MD5 algorithms.
|
||||
// It panics if any error occurs.
|
||||
func MustEncryptString(data string) string {
|
||||
result, err := EncryptString(data)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// EncryptFile encrypts file content of <path> using MD5 algorithms.
|
||||
func EncryptFile(path string) (encrypt string, err error) {
|
||||
f, err := os.Open(path)
|
||||
@ -50,3 +81,13 @@ func EncryptFile(path string) (encrypt string, err error) {
|
||||
}
|
||||
return fmt.Sprintf("%x", h.Sum(nil)), nil
|
||||
}
|
||||
|
||||
// MustEncryptFile encrypts file content of <path> using MD5 algorithms.
|
||||
// It panics if any error occurs.
|
||||
func MustEncryptFile(path string) string {
|
||||
result, err := EncryptFile(path)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@ -37,3 +37,13 @@ func EncryptFile(path string) (encrypt string, err error) {
|
||||
}
|
||||
return hex.EncodeToString(h.Sum(nil)), nil
|
||||
}
|
||||
|
||||
// MustEncryptFile encrypts file content of <path> using SHA1 algorithms.
|
||||
// It panics if any error occurs.
|
||||
func MustEncryptFile(path string) string {
|
||||
result, err := EncryptFile(path)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@ -16,24 +16,24 @@ import (
|
||||
"github.com/gogf/gf/os/glog"
|
||||
|
||||
"github.com/gogf/gf/container/gmap"
|
||||
"github.com/gogf/gf/container/gring"
|
||||
"github.com/gogf/gf/container/gtype"
|
||||
"github.com/gogf/gf/container/gvar"
|
||||
"github.com/gogf/gf/os/gcache"
|
||||
"github.com/gogf/gf/util/grand"
|
||||
)
|
||||
|
||||
// 数据库操作接口
|
||||
// DB is the interface for ORM operations.
|
||||
type DB interface {
|
||||
// 建立数据库连接方法(开发者一般不需要直接调用)
|
||||
// Open creates a raw connection object for database with given node configuration.
|
||||
// Note that it is not recommended using the this function manually.
|
||||
Open(config *ConfigNode) (*sql.DB, error)
|
||||
|
||||
// SQL操作方法 API
|
||||
// Query APIs.
|
||||
Query(query string, args ...interface{}) (*sql.Rows, error)
|
||||
Exec(sql string, args ...interface{}) (sql.Result, error)
|
||||
Prepare(sql string, execOnMaster ...bool) (*sql.Stmt, error)
|
||||
|
||||
// 内部实现API的方法(不同数据库可覆盖这些方法实现自定义的操作)
|
||||
// Internal APIs for CURD, which can be overwrote for custom CURD implements.
|
||||
doQuery(link dbLink, query string, args ...interface{}) (rows *sql.Rows, err error)
|
||||
doGetAll(link dbLink, query string, args ...interface{}) (result Result, err error)
|
||||
doExec(link dbLink, query string, args ...interface{}) (result sql.Result, err error)
|
||||
@ -43,7 +43,7 @@ type DB interface {
|
||||
doUpdate(link dbLink, table string, data interface{}, condition string, args ...interface{}) (result sql.Result, err error)
|
||||
doDelete(link dbLink, table string, condition string, args ...interface{}) (result sql.Result, err error)
|
||||
|
||||
// 数据库查询
|
||||
// Query APIs for convenience purpose.
|
||||
GetAll(query string, args ...interface{}) (Result, error)
|
||||
GetOne(query string, args ...interface{}) (Record, error)
|
||||
GetValue(query string, args ...interface{}) (Value, error)
|
||||
@ -52,41 +52,35 @@ type DB interface {
|
||||
GetStructs(objPointerSlice interface{}, query string, args ...interface{}) error
|
||||
GetScan(objPointer interface{}, query string, args ...interface{}) error
|
||||
|
||||
// 创建底层数据库master/slave链接对象
|
||||
// Master/Slave support.
|
||||
Master() (*sql.DB, error)
|
||||
Slave() (*sql.DB, error)
|
||||
|
||||
// Ping
|
||||
// Ping.
|
||||
PingMaster() error
|
||||
PingSlave() error
|
||||
|
||||
// 开启事务操作
|
||||
// Transaction.
|
||||
Begin() (*TX, error)
|
||||
|
||||
// 数据表插入/更新/保存操作
|
||||
Insert(table string, data interface{}, batch ...int) (sql.Result, error)
|
||||
Replace(table string, data interface{}, batch ...int) (sql.Result, error)
|
||||
Save(table string, data interface{}, batch ...int) (sql.Result, error)
|
||||
|
||||
// 数据表插入/更新/保存操作(批量)
|
||||
BatchInsert(table string, list interface{}, batch ...int) (sql.Result, error)
|
||||
BatchReplace(table string, list interface{}, batch ...int) (sql.Result, error)
|
||||
BatchSave(table string, list interface{}, batch ...int) (sql.Result, error)
|
||||
|
||||
// 数据修改/删除
|
||||
Update(table string, data interface{}, condition interface{}, args ...interface{}) (sql.Result, error)
|
||||
Delete(table string, condition interface{}, args ...interface{}) (sql.Result, error)
|
||||
|
||||
// 创建链式操作对象
|
||||
// Create model.
|
||||
From(tables string) *Model
|
||||
Table(tables string) *Model
|
||||
|
||||
// 设置管理
|
||||
// Configuration methods.
|
||||
SetDebug(debug bool)
|
||||
SetSchema(schema string)
|
||||
GetQueriedSqls() []*Sql
|
||||
GetLastSql() *Sql
|
||||
PrintQueriedSqls()
|
||||
SetLogger(logger *glog.Logger)
|
||||
GetLogger() *glog.Logger
|
||||
SetMaxIdleConnCount(n int)
|
||||
@ -95,11 +89,14 @@ type DB interface {
|
||||
Tables() (tables []string, err error)
|
||||
TableFields(table string) (map[string]*TableField, error)
|
||||
|
||||
// 内部方法接口
|
||||
// Internal methods.
|
||||
getCache() *gcache.Cache
|
||||
getChars() (charLeft string, charRight string)
|
||||
getDebug() bool
|
||||
getPrefix() string
|
||||
quoteWord(s string) string
|
||||
quoteString(s string) string
|
||||
handleTableName(table string) string
|
||||
doSetSchema(sqlDb *sql.DB, schema string) error
|
||||
filterFields(table string, data map[string]interface{}) map[string]interface{}
|
||||
convertValue(fieldValue []byte, fieldType string) interface{}
|
||||
@ -119,9 +116,9 @@ type dbBase struct {
|
||||
db DB // 数据库对象
|
||||
group string // 配置分组名称
|
||||
debug *gtype.Bool // (默认关闭)是否开启调试模式,当开启时会启用一些调试特性
|
||||
sqls *gring.Ring // (debug=true时有效)已执行的SQL列表
|
||||
cache *gcache.Cache // 数据库缓存,包括底层连接池对象缓存及查询缓存;需要注意的是,事务查询不支持查询缓存
|
||||
schema *gtype.String // 手动切换的数据库名称
|
||||
prefix string // 表名前缀
|
||||
tables map[string]map[string]string // 数据库表结构
|
||||
logger *glog.Logger // 日志管理对象
|
||||
maxIdleConnCount int // 连接池最大限制的连接数
|
||||
@ -141,13 +138,14 @@ type Sql struct {
|
||||
|
||||
// 表字段结构信息
|
||||
type TableField struct {
|
||||
Index int // 用于字段排序(map类型是无序的)
|
||||
Index int // 用于字段排序(因为map类型是无序的)
|
||||
Name string // 字段名称
|
||||
Type string // 字段类型
|
||||
Null bool // 是否可为null
|
||||
Key string // 索引信息
|
||||
Default interface{} // 默认值
|
||||
Extra string // 其他信息
|
||||
Comment string // 字段描述
|
||||
}
|
||||
|
||||
// 返回数据表记录值
|
||||
@ -179,7 +177,7 @@ var (
|
||||
instances = gmap.NewStrAnyMap(true)
|
||||
)
|
||||
|
||||
// New creates ORM DB object with global configurations.
|
||||
// New creates and returns an ORM object with global configurations.
|
||||
// The parameter <name> specifies the configuration group name,
|
||||
// which is DEFAULT_GROUP_NAME in default.
|
||||
func New(name ...string) (db DB, err error) {
|
||||
@ -201,6 +199,7 @@ func New(name ...string) (db DB, err error) {
|
||||
cache: gcache.New(),
|
||||
schema: gtype.NewString(),
|
||||
logger: glog.New(),
|
||||
prefix: node.Prefix,
|
||||
maxConnLifetime: gDEFAULT_CONN_MAX_LIFE_TIME,
|
||||
}
|
||||
switch node.Type {
|
||||
@ -222,7 +221,7 @@ func New(name ...string) (db DB, err error) {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
return nil, errors.New(fmt.Sprintf("empty database configuration for item name '%s'", group))
|
||||
return nil, errors.New(fmt.Sprintf(`database configuration node "%s" is not found`, group))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -15,8 +15,6 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
|
||||
"github.com/gogf/gf/container/gvar"
|
||||
"github.com/gogf/gf/os/gcache"
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
@ -25,69 +23,14 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
gDEFAULT_DEBUG_SQL_LENGTH = 1000
|
||||
gPATH_FILTER_KEY = "/database/gdb/gdb"
|
||||
gPATH_FILTER_KEY = "/database/gdb/gdb"
|
||||
)
|
||||
|
||||
var (
|
||||
wordReg = regexp.MustCompile(`^[a-zA-Z0-9\-_]+$`) // Regular expression object for a word.
|
||||
lastOperatorReg = regexp.MustCompile(`[<>=]+\s*$`) // Regular expression object for a string which has operator at its tail.
|
||||
// lastOperatorReg is the regular expression object for a string which has operator at its tail.
|
||||
lastOperatorReg = regexp.MustCompile(`[<>=]+\s*$`)
|
||||
)
|
||||
|
||||
// 获取最近一条执行的sql
|
||||
func (bs *dbBase) GetLastSql() *Sql {
|
||||
if bs.sqls == nil {
|
||||
return nil
|
||||
}
|
||||
if v := bs.sqls.Val(); v != nil {
|
||||
return v.(*Sql)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 获取已经执行的SQL列表(仅在debug=true时有效)
|
||||
func (bs *dbBase) GetQueriedSqls() []*Sql {
|
||||
if bs.sqls == nil {
|
||||
return nil
|
||||
}
|
||||
array := make([]*Sql, 0)
|
||||
bs.sqls.Prev()
|
||||
bs.sqls.RLockIteratorPrev(func(value interface{}) bool {
|
||||
if value == nil {
|
||||
return false
|
||||
}
|
||||
array = append(array, value.(*Sql))
|
||||
return true
|
||||
})
|
||||
return array
|
||||
}
|
||||
|
||||
// 打印已经执行的SQL列表(仅在debug=true时有效)
|
||||
func (bs *dbBase) PrintQueriedSqls() {
|
||||
sqlSlice := bs.GetQueriedSqls()
|
||||
for k, v := range sqlSlice {
|
||||
fmt.Println(len(sqlSlice)-k, ":")
|
||||
fmt.Println(" Sql :", v.Sql)
|
||||
fmt.Println(" Args :", v.Args)
|
||||
fmt.Println(" Format :", v.Format)
|
||||
fmt.Println(" Error :", v.Error)
|
||||
fmt.Println(" Start :", gtime.NewFromTimeStamp(v.Start).Format("Y-m-d H:i:s.u"))
|
||||
fmt.Println(" End :", gtime.NewFromTimeStamp(v.End).Format("Y-m-d H:i:s.u"))
|
||||
fmt.Println(" Cost :", v.End-v.Start, "ms")
|
||||
}
|
||||
}
|
||||
|
||||
// 打印SQL对象(仅在debug=true时有效)
|
||||
func (bs *dbBase) printSql(v *Sql) {
|
||||
s := fmt.Sprintf("[%d ms] %s", v.End-v.Start, v.Format)
|
||||
if v.Error != nil {
|
||||
s += "\nError: " + v.Error.Error()
|
||||
bs.logger.StackWithFilter(gPATH_FILTER_KEY).Error(s)
|
||||
} else {
|
||||
bs.logger.StackWithFilter(gPATH_FILTER_KEY).Debug(s)
|
||||
}
|
||||
}
|
||||
|
||||
// 数据库sql查询操作,主要执行查询
|
||||
func (bs *dbBase) Query(query string, args ...interface{}) (rows *sql.Rows, err error) {
|
||||
link, err := bs.db.Slave()
|
||||
@ -102,9 +45,9 @@ func (bs *dbBase) doQuery(link dbLink, query string, args ...interface{}) (rows
|
||||
query, args = formatQuery(query, args)
|
||||
query = bs.db.handleSqlBeforeExec(query)
|
||||
if bs.db.getDebug() {
|
||||
mTime1 := gtime.Millisecond()
|
||||
mTime1 := gtime.TimestampMicro()
|
||||
rows, err = link.Query(query, args...)
|
||||
mTime2 := gtime.Millisecond()
|
||||
mTime2 := gtime.TimestampMicro()
|
||||
s := &Sql{
|
||||
Sql: query,
|
||||
Args: args,
|
||||
@ -113,7 +56,6 @@ func (bs *dbBase) doQuery(link dbLink, query string, args ...interface{}) (rows
|
||||
Start: mTime1,
|
||||
End: mTime2,
|
||||
}
|
||||
bs.sqls.Put(s)
|
||||
bs.printSql(s)
|
||||
} else {
|
||||
rows, err = link.Query(query, args...)
|
||||
@ -140,9 +82,9 @@ func (bs *dbBase) doExec(link dbLink, query string, args ...interface{}) (result
|
||||
query, args = formatQuery(query, args)
|
||||
query = bs.db.handleSqlBeforeExec(query)
|
||||
if bs.db.getDebug() {
|
||||
mTime1 := gtime.Millisecond()
|
||||
mTime1 := gtime.TimestampMilli()
|
||||
result, err = link.Exec(query, args...)
|
||||
mTime2 := gtime.Millisecond()
|
||||
mTime2 := gtime.TimestampMilli()
|
||||
s := &Sql{
|
||||
Sql: query,
|
||||
Args: args,
|
||||
@ -151,7 +93,6 @@ func (bs *dbBase) doExec(link dbLink, query string, args ...interface{}) (result
|
||||
Start: mTime1,
|
||||
End: mTime2,
|
||||
}
|
||||
bs.sqls.Put(s)
|
||||
bs.printSql(s)
|
||||
} else {
|
||||
result, err = link.Exec(query, args...)
|
||||
@ -350,7 +291,7 @@ func (bs *dbBase) doInsert(link dbLink, table string, data interface{}, option i
|
||||
var values []string
|
||||
var params []interface{}
|
||||
var dataMap Map
|
||||
table = bs.db.quoteWord(table)
|
||||
table = bs.db.handleTableName(table)
|
||||
// 使用反射判断data数据类型,如果为slice类型,那么自动转为批量操作
|
||||
rv := reflect.ValueOf(data)
|
||||
kind := rv.Kind()
|
||||
@ -419,7 +360,7 @@ func (bs *dbBase) BatchSave(table string, list interface{}, batch ...int) (sql.R
|
||||
func (bs *dbBase) doBatchInsert(link dbLink, table string, list interface{}, option int, batch ...int) (result sql.Result, err error) {
|
||||
var keys, values []string
|
||||
var params []interface{}
|
||||
table = bs.db.quoteWord(table)
|
||||
table = bs.db.handleTableName(table)
|
||||
listMap := (List)(nil)
|
||||
switch v := list.(type) {
|
||||
case Result:
|
||||
@ -539,7 +480,7 @@ func (bs *dbBase) Update(table string, data interface{}, condition interface{},
|
||||
// CURD操作:数据更新,统一采用sql预处理。
|
||||
// data参数支持string/map/struct/*struct类型类型。
|
||||
func (bs *dbBase) doUpdate(link dbLink, table string, data interface{}, condition string, args ...interface{}) (result sql.Result, err error) {
|
||||
table = bs.db.quoteWord(table)
|
||||
table = bs.db.handleTableName(table)
|
||||
updates := ""
|
||||
// 使用反射进行类型判断
|
||||
rv := reflect.ValueOf(data)
|
||||
@ -591,7 +532,7 @@ func (bs *dbBase) doDelete(link dbLink, table string, condition string, args ...
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
table = bs.db.quoteWord(table)
|
||||
table = bs.db.handleTableName(table)
|
||||
return bs.db.doExec(link, fmt.Sprintf("DELETE FROM %s%s", table, condition), args...)
|
||||
}
|
||||
|
||||
@ -600,6 +541,11 @@ func (bs *dbBase) getCache() *gcache.Cache {
|
||||
return bs.cache
|
||||
}
|
||||
|
||||
// 获得表名前缀
|
||||
func (bs *dbBase) getPrefix() string {
|
||||
return bs.prefix
|
||||
}
|
||||
|
||||
// 将数据查询的列表数据*sql.Rows转换为Result类型
|
||||
func (bs *dbBase) rowsToResult(rows *sql.Rows) (Result, error) {
|
||||
if !rows.Next() {
|
||||
@ -648,14 +594,40 @@ func (bs *dbBase) rowsToResult(rows *sql.Rows) (Result, error) {
|
||||
return records, nil
|
||||
}
|
||||
|
||||
// 使用关键字操作符转义给定字符串。
|
||||
// 如果给定的字符串不为单词,那么不转义,直接返回该字符串。
|
||||
// handleTableName adds prefix string and quote chars for the table. It handles table string like:
|
||||
// "user", "user u", "user,user_detail", "user u, user_detail ut", "user as u, user_detail as ut".
|
||||
//
|
||||
// Note that, this will automatically checks the table prefix whether already added, if true it does
|
||||
// nothing to the table name, or else adds the prefix to the table name.
|
||||
func (bs *dbBase) handleTableName(table string) string {
|
||||
charLeft, charRight := bs.db.getChars()
|
||||
prefix := bs.db.getPrefix()
|
||||
return doHandleTableName(table, prefix, charLeft, charRight)
|
||||
}
|
||||
|
||||
// quoteWord checks given string <s> a word, if true quotes it with security chars of the database
|
||||
// and returns the quoted string; or else return <s> without any change.
|
||||
func (bs *dbBase) quoteWord(s string) string {
|
||||
charLeft, charRight := bs.db.getChars()
|
||||
if wordReg.MatchString(s) && !gstr.ContainsAny(s, charLeft+charRight) {
|
||||
return charLeft + s + charRight
|
||||
return doQuoteWord(s, charLeft, charRight)
|
||||
}
|
||||
|
||||
// quoteString quotes string with quote chars. Strings like:
|
||||
// "user", "user u", "user,user_detail", "user u, user_detail ut", "u.id asc".
|
||||
func (bs *dbBase) quoteString(s string) string {
|
||||
charLeft, charRight := bs.db.getChars()
|
||||
return doQuoteString(s, charLeft, charRight)
|
||||
}
|
||||
|
||||
// 打印SQL对象(仅在debug=true时有效)
|
||||
func (bs *dbBase) printSql(v *Sql) {
|
||||
s := fmt.Sprintf("[%d ms] %s", v.End-v.Start, v.Format)
|
||||
if v.Error != nil {
|
||||
s += "\nError: " + v.Error.Error()
|
||||
bs.logger.StackWithFilter(gPATH_FILTER_KEY).Error(s)
|
||||
} else {
|
||||
bs.logger.StackWithFilter(gPATH_FILTER_KEY).Debug(s)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// 动态切换数据库
|
||||
|
||||
@ -12,8 +12,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/os/glog"
|
||||
|
||||
"github.com/gogf/gf/container/gring"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -36,6 +34,7 @@ type ConfigNode struct {
|
||||
Type string // 数据库类型:mysql, sqlite, mssql, pgsql, oracle
|
||||
Role string // (可选,默认为master)数据库的角色,用于主从操作分离,至少需要有一个master,参数值:master, slave
|
||||
Debug bool // (可选)开启调试模式
|
||||
Prefix string // (可选)表名前缀
|
||||
Weight int // (可选)用于负载均衡的权重计算,当集群中只有一个节点时,权重没有任何意义
|
||||
Charset string // (可选,默认为 utf8)编码,默认为 utf8
|
||||
LinkInfo string // (可选)自定义链接信息,当该字段被设置值时,以上链接字段(Host,Port,User,Pass,Name)将失效(该字段是一个扩展功能)
|
||||
@ -159,9 +158,6 @@ func (bs *dbBase) SetDebug(debug bool) {
|
||||
return
|
||||
}
|
||||
bs.debug.Set(debug)
|
||||
if debug && bs.sqls == nil {
|
||||
bs.sqls = gring.New(gDEFAULT_DEBUG_SQL_LENGTH, true)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取是否开启调试服务
|
||||
|
||||
@ -14,6 +14,7 @@ import (
|
||||
"github.com/gogf/gf/internal/empty"
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@ -24,17 +25,17 @@ import (
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
)
|
||||
|
||||
// Type assert api for String.
|
||||
// apiString is the type assert api for String.
|
||||
type apiString interface {
|
||||
String() string
|
||||
}
|
||||
|
||||
// Type assert api for Iterator.
|
||||
// apiIterator is the type assert api for Iterator.
|
||||
type apiIterator interface {
|
||||
Iterator(f func(key, value interface{}) bool)
|
||||
}
|
||||
|
||||
// Type assert api for Interfaces.
|
||||
// apiInterfacesis the type assert api for Interfaces.
|
||||
type apiInterfaces interface {
|
||||
Interfaces() []interface{}
|
||||
}
|
||||
@ -45,23 +46,124 @@ const (
|
||||
ORM_TAG_FOR_PRIMARY = "primary"
|
||||
)
|
||||
|
||||
// 获得struct对象对应的where查询条件
|
||||
var (
|
||||
// quoteWordReg is the regular expression object for a word check.
|
||||
quoteWordReg = regexp.MustCompile(`^[a-zA-Z0-9\-_]+$`)
|
||||
)
|
||||
|
||||
// handleTableName adds prefix string and quote chars for the table. It handles table string like:
|
||||
// "user", "user u", "user,user_detail", "user u, user_detail ut", "user as u, user_detail as ut".
|
||||
//
|
||||
// Note that, this will automatically checks the table prefix whether already added, if true it does
|
||||
// nothing to the table name, or else adds the prefix to the table name.
|
||||
func doHandleTableName(table, prefix, charLeft, charRight string) string {
|
||||
array1 := gstr.SplitAndTrim(table, ",")
|
||||
for k1, v1 := range array1 {
|
||||
array2 := gstr.SplitAndTrim(v1, " ")
|
||||
// Trim the security chars.
|
||||
array2[0] = gstr.TrimLeftStr(array2[0], charLeft)
|
||||
array2[0] = gstr.TrimRightStr(array2[0], charRight)
|
||||
// If the table name already has the prefix, skips the prefix adding.
|
||||
if len(array2[0]) <= len(prefix) || array2[0][:len(prefix)] != prefix {
|
||||
array2[0] = prefix + array2[0]
|
||||
}
|
||||
// Add the security chars.
|
||||
array2[0] = doQuoteWord(array2[0], charLeft, charRight)
|
||||
array1[k1] = gstr.Join(array2, " ")
|
||||
}
|
||||
return gstr.Join(array1, ",")
|
||||
}
|
||||
|
||||
// doQuoteWord checks given string <s> a word, if true quotes it with <charLeft> and <charRight>
|
||||
// and returns the quoted string; or else returns <s> without any change.
|
||||
func doQuoteWord(s, charLeft, charRight string) string {
|
||||
if quoteWordReg.MatchString(s) && !gstr.ContainsAny(s, charLeft+charRight) {
|
||||
return charLeft + s + charRight
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// doQuoteString quotes string with quote chars. It handles strings like:
|
||||
// "user", "user u", "user,user_detail", "user u, user_detail ut", "u.id asc".
|
||||
func doQuoteString(s, charLeft, charRight string) string {
|
||||
array1 := gstr.SplitAndTrim(s, ",")
|
||||
for k1, v1 := range array1 {
|
||||
array2 := gstr.SplitAndTrim(v1, " ")
|
||||
array3 := gstr.SplitAndTrim(array2[0], ".")
|
||||
if len(array3) == 1 {
|
||||
array3[0] = doQuoteWord(array3[0], charLeft, charRight)
|
||||
} else if len(array3) == 2 {
|
||||
array3[1] = doQuoteWord(array3[1], charLeft, charRight)
|
||||
}
|
||||
array2[0] = gstr.Join(array3, ".")
|
||||
array1[k1] = gstr.Join(array2, " ")
|
||||
}
|
||||
return gstr.Join(array1, ",")
|
||||
}
|
||||
|
||||
// GetWhereConditionOfStruct returns the where condition sql and arguments by given struct pointer.
|
||||
// This function automatically retrieves primary or unique field and its attribute value as condition.
|
||||
func GetWhereConditionOfStruct(pointer interface{}) (where string, args []interface{}) {
|
||||
array := ([]string)(nil)
|
||||
for tag, field := range structs.TagMapField(pointer, []string{ORM_TAG_FOR_STRUCT}, true) {
|
||||
array = strings.Split(tag, ",")
|
||||
for _, field := range structs.TagFields(pointer, []string{ORM_TAG_FOR_STRUCT}, true) {
|
||||
array = strings.Split(field.Tag, ",")
|
||||
if len(array) > 1 && gstr.InArray([]string{ORM_TAG_FOR_UNIQUE, ORM_TAG_FOR_PRIMARY}, array[1]) {
|
||||
return array[0], []interface{}{field.Value()}
|
||||
}
|
||||
if len(where) > 0 {
|
||||
where += " "
|
||||
}
|
||||
where += tag + "=?"
|
||||
where += field.Tag + "=?"
|
||||
args = append(args, field.Value())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetPrimaryKey retrieves and returns primary key field name from given struct.
|
||||
func GetPrimaryKey(pointer interface{}) string {
|
||||
array := ([]string)(nil)
|
||||
for _, field := range structs.TagFields(pointer, []string{ORM_TAG_FOR_STRUCT}, true) {
|
||||
array = strings.Split(field.Tag, ",")
|
||||
if len(array) > 1 && array[1] == ORM_TAG_FOR_PRIMARY {
|
||||
return array[0]
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetPrimaryKeyCondition returns a new where condition by primary field name.
|
||||
// The optional parameter <where> is like follows:
|
||||
// 123, []int{1, 2, 3}, "john", []string{"john", "smith"}
|
||||
// g.Map{"id": g.Slice{1,2,3}}, g.Map{"id": 1, "name": "john"}, etc.
|
||||
//
|
||||
// Note that it returns the given <where> parameter directly if there's the <primary> is empty.
|
||||
func GetPrimaryKeyCondition(primary string, where ...interface{}) (newWhereCondition []interface{}) {
|
||||
if len(where) == 0 {
|
||||
return nil
|
||||
}
|
||||
if primary == "" {
|
||||
return where
|
||||
}
|
||||
if len(where) == 1 {
|
||||
rv := reflect.ValueOf(where[0])
|
||||
kind := rv.Kind()
|
||||
if kind == reflect.Ptr {
|
||||
rv = rv.Elem()
|
||||
kind = rv.Kind()
|
||||
}
|
||||
switch kind {
|
||||
case reflect.Map, reflect.Struct:
|
||||
break
|
||||
|
||||
default:
|
||||
return []interface{}{map[string]interface{}{
|
||||
primary: where[0],
|
||||
}}
|
||||
}
|
||||
}
|
||||
return where
|
||||
}
|
||||
|
||||
// 获得orm标签与属性的映射关系
|
||||
func GetOrmMappingOfStruct(pointer interface{}) map[string]string {
|
||||
mapping := make(map[string]string)
|
||||
@ -113,7 +215,6 @@ func formatWhere(db DB, where interface{}, args []interface{}, omitEmpty bool) (
|
||||
})
|
||||
break
|
||||
}
|
||||
// TODO garray support.
|
||||
for key, value := range varToMapDeep(where) {
|
||||
if omitEmpty && empty.IsEmpty(value) {
|
||||
continue
|
||||
@ -135,7 +236,7 @@ func formatWhere(db DB, where interface{}, args []interface{}, omitEmpty bool) (
|
||||
if gstr.Pos(newWhere, "?") == -1 {
|
||||
if lastOperatorReg.MatchString(newWhere) {
|
||||
newWhere += "?"
|
||||
} else if wordReg.MatchString(newWhere) {
|
||||
} else if quoteWordReg.MatchString(newWhere) {
|
||||
newWhere += "=?"
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -20,7 +20,8 @@ import (
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
)
|
||||
|
||||
// convertValue converts field value from database type to golang variable type.
|
||||
// convertValue automatically checks and converts field value from database type
|
||||
// to golang variable type.
|
||||
func (bs *dbBase) convertValue(fieldValue []byte, fieldType string) interface{} {
|
||||
t, _ := gregex.ReplaceString(`\(.+\)`, "", fieldType)
|
||||
t = strings.ToLower(t)
|
||||
@ -97,9 +98,9 @@ func (bs *dbBase) convertValue(fieldValue []byte, fieldType string) interface{}
|
||||
}
|
||||
}
|
||||
|
||||
// 将map的数据按照fields进行过滤,只保留与表字段同名的数据
|
||||
// filterFields removes all key-value pairs which are not the field of given table.
|
||||
func (bs *dbBase) filterFields(table string, data map[string]interface{}) map[string]interface{} {
|
||||
// It must use data copy here to avoid changing the origin data map.
|
||||
// It must use data copy here to avoid its changing the origin data map.
|
||||
newDataMap := make(map[string]interface{}, len(data))
|
||||
if fields, err := bs.db.TableFields(table); err == nil {
|
||||
for k, v := range data {
|
||||
@ -111,7 +112,7 @@ func (bs *dbBase) filterFields(table string, data map[string]interface{}) map[st
|
||||
return newDataMap
|
||||
}
|
||||
|
||||
// 返回当前数据库所有的数据表名称
|
||||
// Tables returns the table name array of current schema.
|
||||
func (bs *dbBase) Tables() (tables []string, err error) {
|
||||
result := (Result)(nil)
|
||||
result, err = bs.GetAll(`SHOW TABLES`)
|
||||
@ -126,12 +127,15 @@ func (bs *dbBase) Tables() (tables []string, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// 获得指定表表的数据结构,构造成map哈希表返回,其中键名为表字段名称,键值为字段数据结构.
|
||||
// TableFields retrieves and returns the fields of given table.
|
||||
// Note that it returns a map containing the field name and its corresponding fields.
|
||||
// As a map is unsorted, the TableField struct has a "Index" field marks its sequence in the fields.
|
||||
//
|
||||
// It's using cache feature to enhance the performance, which is never expired util the process restarts.
|
||||
func (bs *dbBase) TableFields(table string) (fields map[string]*TableField, err error) {
|
||||
// 缓存不存在时会查询数据表结构,缓存后不过期,直至程序重启(重新部署)
|
||||
v := bs.cache.GetOrSetFunc("table_fields_"+table, func() interface{} {
|
||||
result := (Result)(nil)
|
||||
result, err = bs.GetAll(fmt.Sprintf(`SHOW COLUMNS FROM %s`, bs.db.quoteWord(table)))
|
||||
result, err = bs.GetAll(fmt.Sprintf(`SHOW FULL COLUMNS FROM %s`, bs.db.quoteWord(table)))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
@ -145,6 +149,7 @@ func (bs *dbBase) TableFields(table string) (fields map[string]*TableField, err
|
||||
Key: m["Key"].String(),
|
||||
Default: m["Default"].Val(),
|
||||
Extra: m["Extra"].String(),
|
||||
Comment: m["Comment"].String(),
|
||||
}
|
||||
}
|
||||
return fields
|
||||
|
||||
@ -9,23 +9,24 @@ package gdb
|
||||
import (
|
||||
"database/sql"
|
||||
"github.com/gogf/gf/container/gmap"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
|
||||
"github.com/gogf/gf/encoding/gparser"
|
||||
)
|
||||
|
||||
// 将记录结果转换为JSON字符串
|
||||
// Json converts <r> to JSON format content.
|
||||
func (r Record) Json() string {
|
||||
content, _ := gparser.VarToJson(r.Map())
|
||||
return string(content)
|
||||
return gconv.UnsafeBytesToStr(content)
|
||||
}
|
||||
|
||||
// 将记录结果转换为XML字符串
|
||||
// Xml converts <r> to XML format content.
|
||||
func (r Record) Xml(rootTag ...string) string {
|
||||
content, _ := gparser.VarToXml(r.Map(), rootTag...)
|
||||
return string(content)
|
||||
return gconv.UnsafeBytesToStr(content)
|
||||
}
|
||||
|
||||
// 将Record转换为Map类型
|
||||
// Map converts <r> to map[string]interface{}.
|
||||
func (r Record) Map() Map {
|
||||
m := make(map[string]interface{})
|
||||
for k, v := range r {
|
||||
@ -34,12 +35,13 @@ func (r Record) Map() Map {
|
||||
return m
|
||||
}
|
||||
|
||||
// 将Record转换为常用的gmap.StrAnyMap类型
|
||||
// GMap converts <r> to a gmap.
|
||||
func (r Record) GMap() *gmap.StrAnyMap {
|
||||
return gmap.NewStrAnyMapFrom(r.Map())
|
||||
}
|
||||
|
||||
// 将Map变量映射到指定的struct对象中,注意参数应当是一个对象的指针
|
||||
// Struct converts <r> to a struct.
|
||||
// Note that the parameter <pointer> should be type of *struct/**struct.
|
||||
func (r Record) Struct(pointer interface{}) error {
|
||||
if r == nil {
|
||||
return sql.ErrNoRows
|
||||
|
||||
@ -14,19 +14,19 @@ import (
|
||||
"github.com/gogf/gf/encoding/gparser"
|
||||
)
|
||||
|
||||
// 将结果集转换为JSON字符串
|
||||
// Json converts <r> to JSON format content.
|
||||
func (r Result) Json() string {
|
||||
content, _ := gparser.VarToJson(r.List())
|
||||
return string(content)
|
||||
}
|
||||
|
||||
// 将结果集转换为XML字符串
|
||||
// Xml converts <r> to XML format content.
|
||||
func (r Result) Xml(rootTag ...string) string {
|
||||
content, _ := gparser.VarToXml(r.List(), rootTag...)
|
||||
return string(content)
|
||||
}
|
||||
|
||||
// 将结果集转换为List类型返回,便于json处理
|
||||
// List converts <r> to a List.
|
||||
func (r Result) List() List {
|
||||
l := make(List, len(r))
|
||||
for k, v := range r {
|
||||
@ -35,7 +35,7 @@ func (r Result) List() List {
|
||||
return l
|
||||
}
|
||||
|
||||
// 将结果列表按照指定的字段值做map[string]Map
|
||||
// MapKeyStr converts <r> to a map[string]Map of which key is specified by <key>.
|
||||
func (r Result) MapKeyStr(key string) map[string]Map {
|
||||
m := make(map[string]Map)
|
||||
for _, item := range r {
|
||||
@ -46,7 +46,7 @@ func (r Result) MapKeyStr(key string) map[string]Map {
|
||||
return m
|
||||
}
|
||||
|
||||
// 将结果列表按照指定的字段值做map[int]Map
|
||||
// MapKeyInt converts <r> to a map[int]Map of which key is specified by <key>.
|
||||
func (r Result) MapKeyInt(key string) map[int]Map {
|
||||
m := make(map[int]Map)
|
||||
for _, item := range r {
|
||||
@ -57,7 +57,7 @@ func (r Result) MapKeyInt(key string) map[int]Map {
|
||||
return m
|
||||
}
|
||||
|
||||
// 将结果列表按照指定的字段值做map[uint]Map
|
||||
// MapKeyUint converts <r> to a map[uint]Map of which key is specified by <key>.
|
||||
func (r Result) MapKeyUint(key string) map[uint]Map {
|
||||
m := make(map[uint]Map)
|
||||
for _, item := range r {
|
||||
@ -68,7 +68,7 @@ func (r Result) MapKeyUint(key string) map[uint]Map {
|
||||
return m
|
||||
}
|
||||
|
||||
// 将结果列表按照指定的字段值做map[string]Record
|
||||
// RecordKeyInt converts <r> to a map[int]Record of which key is specified by <key>.
|
||||
func (r Result) RecordKeyStr(key string) map[string]Record {
|
||||
m := make(map[string]Record)
|
||||
for _, item := range r {
|
||||
@ -79,7 +79,7 @@ func (r Result) RecordKeyStr(key string) map[string]Record {
|
||||
return m
|
||||
}
|
||||
|
||||
// 将结果列表按照指定的字段值做map[int]Record
|
||||
// RecordKeyInt converts <r> to a map[int]Record of which key is specified by <key>.
|
||||
func (r Result) RecordKeyInt(key string) map[int]Record {
|
||||
m := make(map[int]Record)
|
||||
for _, item := range r {
|
||||
@ -90,7 +90,7 @@ func (r Result) RecordKeyInt(key string) map[int]Record {
|
||||
return m
|
||||
}
|
||||
|
||||
// 将结果列表按照指定的字段值做map[uint]Record
|
||||
// RecordKeyUint converts <r> to a map[uint]Record of which key is specified by <key>.
|
||||
func (r Result) RecordKeyUint(key string) map[uint]Record {
|
||||
m := make(map[uint]Record)
|
||||
for _, item := range r {
|
||||
@ -101,7 +101,8 @@ func (r Result) RecordKeyUint(key string) map[uint]Record {
|
||||
return m
|
||||
}
|
||||
|
||||
// 将结果列表转换为指定对象的slice。
|
||||
// Structs converts <r> to struct slice.
|
||||
// Note that the parameter <pointer> should be type of *[]struct/*[]*struct.
|
||||
func (r Result) Structs(pointer interface{}) (err error) {
|
||||
l := len(r)
|
||||
if l == 0 {
|
||||
|
||||
@ -21,14 +21,16 @@ const (
|
||||
TABLE = "user"
|
||||
SCHEMA1 = "test1"
|
||||
SCHEMA2 = "test2"
|
||||
PREFIX1 = "gf_"
|
||||
)
|
||||
|
||||
var (
|
||||
db gdb.DB
|
||||
db gdb.DB
|
||||
dbPrefix gdb.DB
|
||||
)
|
||||
|
||||
func InitMysql() {
|
||||
node := gdb.ConfigNode{
|
||||
nodeDefault := gdb.ConfigNode{
|
||||
Host: "127.0.0.1",
|
||||
Port: "3306",
|
||||
User: "root",
|
||||
@ -42,35 +44,62 @@ func InitMysql() {
|
||||
MaxOpenConnCount: 10,
|
||||
MaxConnLifetime: 600,
|
||||
}
|
||||
gdb.AddConfigNode("test", node)
|
||||
gdb.AddConfigNode(gdb.DEFAULT_GROUP_NAME, node)
|
||||
nodePrefix := nodeDefault
|
||||
nodePrefix.Prefix = PREFIX1
|
||||
gdb.AddConfigNode("test", nodeDefault)
|
||||
gdb.AddConfigNode("prefix", nodePrefix)
|
||||
gdb.AddConfigNode(gdb.DEFAULT_GROUP_NAME, nodeDefault)
|
||||
// Default db.
|
||||
if r, err := gdb.New(); err != nil {
|
||||
gtest.Error(err)
|
||||
} else {
|
||||
db = r
|
||||
}
|
||||
|
||||
schemaTemplate := "CREATE DATABASE IF NOT EXISTS `%s` CHARACTER SET UTF8"
|
||||
if _, err := db.Exec(fmt.Sprintf(schemaTemplate, SCHEMA1)); err != nil {
|
||||
gtest.Error(err)
|
||||
}
|
||||
|
||||
if _, err := db.Exec(fmt.Sprintf(schemaTemplate, SCHEMA2)); err != nil {
|
||||
gtest.Error(err)
|
||||
}
|
||||
|
||||
db.SetSchema(SCHEMA1)
|
||||
createTable(TABLE)
|
||||
|
||||
// Prefix db.
|
||||
if r, err := gdb.New("prefix"); err != nil {
|
||||
gtest.Error(err)
|
||||
} else {
|
||||
dbPrefix = r
|
||||
}
|
||||
if _, err := dbPrefix.Exec(fmt.Sprintf(schemaTemplate, SCHEMA1)); err != nil {
|
||||
gtest.Error(err)
|
||||
}
|
||||
if _, err := dbPrefix.Exec(fmt.Sprintf(schemaTemplate, SCHEMA2)); err != nil {
|
||||
gtest.Error(err)
|
||||
}
|
||||
dbPrefix.SetSchema(SCHEMA1)
|
||||
createTable(TABLE)
|
||||
}
|
||||
|
||||
func createTable(table ...string) (name string) {
|
||||
func createTable(table ...string) string {
|
||||
return createTableWithDb(db, table...)
|
||||
}
|
||||
|
||||
func createInitTable(table ...string) string {
|
||||
return createInitTableWithDb(db, table...)
|
||||
}
|
||||
|
||||
func dropTable(table string) {
|
||||
dropTableWithDb(db, table)
|
||||
}
|
||||
|
||||
func createTableWithDb(db gdb.DB, table ...string) (name string) {
|
||||
if len(table) > 0 {
|
||||
name = table[0]
|
||||
} else {
|
||||
name = fmt.Sprintf(`%s_%d`, TABLE, gtime.Nanosecond())
|
||||
}
|
||||
dropTable(name)
|
||||
dropTableWithDb(db, name)
|
||||
if _, err := db.Exec(fmt.Sprintf(`
|
||||
CREATE TABLE %s (
|
||||
id int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
@ -86,8 +115,8 @@ func createTable(table ...string) (name string) {
|
||||
return
|
||||
}
|
||||
|
||||
func createInitTable(table ...string) (name string) {
|
||||
name = createTable(table...)
|
||||
func createInitTableWithDb(db gdb.DB, table ...string) (name string) {
|
||||
name = createTableWithDb(db, table...)
|
||||
array := garray.New(true)
|
||||
for i := 1; i <= INIT_DATA_SIZE; i++ {
|
||||
array.Append(g.Map{
|
||||
@ -98,7 +127,8 @@ func createInitTable(table ...string) (name string) {
|
||||
"create_time": gtime.NewFromStr("2018-10-24 10:00:00").String(),
|
||||
})
|
||||
}
|
||||
result, err := db.Table(name).Data(array.Slice()).Insert()
|
||||
|
||||
result, err := db.BatchInsert(name, array.Slice())
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
n, e := result.RowsAffected()
|
||||
@ -107,7 +137,7 @@ func createInitTable(table ...string) (name string) {
|
||||
return
|
||||
}
|
||||
|
||||
func dropTable(table string) {
|
||||
func dropTableWithDb(db gdb.DB, table string) {
|
||||
if _, err := db.Exec(fmt.Sprintf("DROP TABLE IF EXISTS `%s`", table)); err != nil {
|
||||
gtest.Error(err)
|
||||
}
|
||||
|
||||
77
database/gdb/gdb_unit_z_func_test.go
Normal file
77
database/gdb/gdb_unit_z_func_test.go
Normal file
@ -0,0 +1,77 @@
|
||||
// Copyright 2019 gf Author(https://github.com/gogf/gf). 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 gdb
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/test/gtest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_Func_doQuoteWord(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
array := map[string]string{
|
||||
"user": "`user`",
|
||||
"user u": "user u",
|
||||
"user_detail": "`user_detail`",
|
||||
"user,user_detail": "user,user_detail",
|
||||
"user u, user_detail ut": "user u, user_detail ut",
|
||||
"u.id asc": "u.id asc",
|
||||
"u.id asc, ut.uid desc": "u.id asc, ut.uid desc",
|
||||
}
|
||||
for k, v := range array {
|
||||
gtest.Assert(doQuoteWord(k, "`", "`"), v)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Func_doQuoteString(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
// "user", "user u", "user,user_detail", "user u, user_detail ut", "u.id asc".
|
||||
array := map[string]string{
|
||||
"user": "`user`",
|
||||
"user u": "`user` u",
|
||||
"user,user_detail": "`user`,`user_detail`",
|
||||
"user u, user_detail ut": "`user` u,`user_detail` ut",
|
||||
"u.id asc": "u.`id` asc",
|
||||
"u.id asc, ut.uid desc": "u.`id` asc,ut.`uid` desc",
|
||||
}
|
||||
for k, v := range array {
|
||||
gtest.Assert(doQuoteString(k, "`", "`"), v)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Func_addTablePrefix(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
prefix := ""
|
||||
array := map[string]string{
|
||||
"user": "`user`",
|
||||
"user u": "`user` u",
|
||||
"user as u": "`user` as u",
|
||||
"user,user_detail": "`user`,`user_detail`",
|
||||
"user u, user_detail ut": "`user` u,`user_detail` ut",
|
||||
"user as u, user_detail as ut": "`user` as u,`user_detail` as ut",
|
||||
}
|
||||
for k, v := range array {
|
||||
gtest.Assert(doHandleTableName(k, prefix, "`", "`"), v)
|
||||
}
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
prefix := "gf_"
|
||||
array := map[string]string{
|
||||
"user": "`gf_user`",
|
||||
"user u": "`gf_user` u",
|
||||
"user as u": "`gf_user` as u",
|
||||
"user,user_detail": "`gf_user`,`gf_user_detail`",
|
||||
"user u, user_detail ut": "`gf_user` u,`gf_user_detail` ut",
|
||||
"user as u, user_detail as ut": "`gf_user` as u,`gf_user_detail` as ut",
|
||||
}
|
||||
for k, v := range array {
|
||||
gtest.Assert(doHandleTableName(k, prefix, "`", "`"), v)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -8,6 +8,7 @@ package gdb_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/container/garray"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -251,17 +252,20 @@ func Test_DB_BatchInsert(t *testing.T) {
|
||||
gtest.Assert(n, 1)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func Test_DB_BatchInsert_Struct(t *testing.T) {
|
||||
// batch insert struct
|
||||
gtest.Case(t, func() {
|
||||
table := createTable()
|
||||
defer dropTable(table)
|
||||
|
||||
type User struct {
|
||||
Id int `gconv:"id"`
|
||||
Passport string `gconv:"passport"`
|
||||
Password string `gconv:"password"`
|
||||
NickName string `gconv:"nickname"`
|
||||
CreateTime *gtime.Time `gconv:"create_time"`
|
||||
Id int `c:"id"`
|
||||
Passport string `c:"passport"`
|
||||
Password string `c:"password"`
|
||||
NickName string `c:"nickname"`
|
||||
CreateTime *gtime.Time `c:"create_time"`
|
||||
}
|
||||
user := &User{
|
||||
Id: 1,
|
||||
@ -275,7 +279,6 @@ func Test_DB_BatchInsert(t *testing.T) {
|
||||
n, _ := result.RowsAffected()
|
||||
gtest.Assert(n, 1)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func Test_DB_Save(t *testing.T) {
|
||||
@ -1052,6 +1055,109 @@ func Test_DB_TableField(t *testing.T) {
|
||||
gtest.Assert(result[0], data)
|
||||
}
|
||||
|
||||
func Test_DB_Prefix(t *testing.T) {
|
||||
db := dbPrefix
|
||||
name := fmt.Sprintf(`%s_%d`, TABLE, gtime.TimestampNano())
|
||||
table := PREFIX1 + name
|
||||
createTableWithDb(db, table)
|
||||
defer dropTable(table)
|
||||
|
||||
gtest.Case(t, func() {
|
||||
id := 10000
|
||||
result, err := db.Insert(name, g.Map{
|
||||
"id": id,
|
||||
"passport": fmt.Sprintf(`user_%d`, id),
|
||||
"password": fmt.Sprintf(`pass_%d`, id),
|
||||
"nickname": fmt.Sprintf(`name_%d`, id),
|
||||
"create_time": gtime.NewFromStr("2018-10-24 10:00:00").String(),
|
||||
})
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
n, e := result.RowsAffected()
|
||||
gtest.Assert(e, nil)
|
||||
gtest.Assert(n, 1)
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
id := 10000
|
||||
result, err := db.Replace(name, g.Map{
|
||||
"id": id,
|
||||
"passport": fmt.Sprintf(`user_%d`, id),
|
||||
"password": fmt.Sprintf(`pass_%d`, id),
|
||||
"nickname": fmt.Sprintf(`name_%d`, id),
|
||||
"create_time": gtime.NewFromStr("2018-10-24 10:00:01").String(),
|
||||
})
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
n, e := result.RowsAffected()
|
||||
gtest.Assert(e, nil)
|
||||
gtest.Assert(n, 2)
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
id := 10000
|
||||
result, err := db.Save(name, g.Map{
|
||||
"id": id,
|
||||
"passport": fmt.Sprintf(`user_%d`, id),
|
||||
"password": fmt.Sprintf(`pass_%d`, id),
|
||||
"nickname": fmt.Sprintf(`name_%d`, id),
|
||||
"create_time": gtime.NewFromStr("2018-10-24 10:00:02").String(),
|
||||
})
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
n, e := result.RowsAffected()
|
||||
gtest.Assert(e, nil)
|
||||
gtest.Assert(n, 2)
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
id := 10000
|
||||
result, err := db.Update(name, g.Map{
|
||||
"id": id,
|
||||
"passport": fmt.Sprintf(`user_%d`, id),
|
||||
"password": fmt.Sprintf(`pass_%d`, id),
|
||||
"nickname": fmt.Sprintf(`name_%d`, id),
|
||||
"create_time": gtime.NewFromStr("2018-10-24 10:00:03").String(),
|
||||
}, "id=?", id)
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
n, e := result.RowsAffected()
|
||||
gtest.Assert(e, nil)
|
||||
gtest.Assert(n, 1)
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
id := 10000
|
||||
result, err := db.Delete(name, "id=?", id)
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
n, e := result.RowsAffected()
|
||||
gtest.Assert(e, nil)
|
||||
gtest.Assert(n, 1)
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
array := garray.New(true)
|
||||
for i := 1; i <= INIT_DATA_SIZE; i++ {
|
||||
array.Append(g.Map{
|
||||
"id": i,
|
||||
"passport": fmt.Sprintf(`user_%d`, i),
|
||||
"password": fmt.Sprintf(`pass_%d`, i),
|
||||
"nickname": fmt.Sprintf(`name_%d`, i),
|
||||
"create_time": gtime.NewFromStr("2018-10-24 10:00:00").String(),
|
||||
})
|
||||
}
|
||||
|
||||
result, err := db.BatchInsert(name, array.Slice())
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
n, e := result.RowsAffected()
|
||||
gtest.Assert(e, nil)
|
||||
gtest.Assert(n, INIT_DATA_SIZE)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func Test_Model_InnerJoin(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
table1 := createInitTable("user1")
|
||||
|
||||
@ -200,7 +200,7 @@ func Test_Model_Update(t *testing.T) {
|
||||
defer dropTable(table)
|
||||
// UPDATE...LIMIT
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).Data("nickname", "T100").OrderBy("id desc").Limit(2).Update()
|
||||
result, err := db.Table(table).Data("nickname", "T100").Order("id desc").Limit(2).Update()
|
||||
gtest.Assert(err, nil)
|
||||
n, _ := result.RowsAffected()
|
||||
gtest.Assert(n, 2)
|
||||
@ -246,10 +246,10 @@ func Test_Model_Clone(t *testing.T) {
|
||||
count, err := md.Count()
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
record, err := md.OrderBy("id DESC").One()
|
||||
record, err := md.Order("id DESC").One()
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
result, err := md.OrderBy("id ASC").All()
|
||||
result, err := md.Order("id ASC").All()
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
gtest.Assert(count, 2)
|
||||
@ -327,7 +327,7 @@ func Test_Model_Safe(t *testing.T) {
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(count, 2)
|
||||
|
||||
all, err := md2.OrderBy("id asc").All()
|
||||
all, err := md2.Order("id asc").All()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(all), 2)
|
||||
gtest.Assert(all[0]["id"].Int(), 1)
|
||||
@ -342,7 +342,7 @@ func Test_Model_Safe(t *testing.T) {
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(count, 3)
|
||||
|
||||
all, err = md3.OrderBy("id asc").All()
|
||||
all, err = md3.Order("id asc").All()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(all), 3)
|
||||
gtest.Assert(all[0]["id"].Int(), 4)
|
||||
@ -371,6 +371,44 @@ func Test_Model_All(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Model_FindAll(t *testing.T) {
|
||||
table := createInitTable()
|
||||
defer dropTable(table)
|
||||
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).FindAll(5)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(result), 1)
|
||||
gtest.Assert(result[0]["id"].Int(), 5)
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).Order("id asc").FindAll("id", 8)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(result), 1)
|
||||
gtest.Assert(result[0]["id"].Int(), 8)
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).Order("id asc").FindAll(g.Slice{3, 9})
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(result), 2)
|
||||
gtest.Assert(result[0]["id"].Int(), 3)
|
||||
gtest.Assert(result[1]["id"].Int(), 9)
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).FindAll()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(result), INIT_DATA_SIZE)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).Where("id<0").FindAll()
|
||||
gtest.Assert(result, nil)
|
||||
gtest.Assert(err, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Model_One(t *testing.T) {
|
||||
table := createInitTable()
|
||||
defer dropTable(table)
|
||||
@ -387,9 +425,45 @@ func Test_Model_One(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Model_FindOne(t *testing.T) {
|
||||
table := createInitTable()
|
||||
defer dropTable(table)
|
||||
|
||||
gtest.Case(t, func() {
|
||||
record, err := db.Table(table).FindOne(1)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(record["nickname"].String(), "name_1")
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
record, err := db.Table(table).FindOne(3)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(record["nickname"].String(), "name_3")
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
record, err := db.Table(table).Where("id", 1).FindOne()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(record["nickname"].String(), "name_1")
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
record, err := db.Table(table).FindOne("id", 9)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(record["nickname"].String(), "name_9")
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
record, err := db.Table(table).Where("id", 0).FindOne()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(record, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Model_Value(t *testing.T) {
|
||||
table := createInitTable()
|
||||
defer dropTable(table)
|
||||
|
||||
gtest.Case(t, func() {
|
||||
value, err := db.Table(table).Fields("nickname").Where("id", 1).Value()
|
||||
gtest.Assert(err, nil)
|
||||
@ -403,6 +477,35 @@ func Test_Model_Value(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Model_FindValue(t *testing.T) {
|
||||
table := createInitTable()
|
||||
defer dropTable(table)
|
||||
|
||||
gtest.Case(t, func() {
|
||||
value, err := db.Table(table).FindValue("nickname", 1)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(value.String(), "name_1")
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
value, err := db.Table(table).Order("id desc").FindValue("nickname")
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(value.String(), "name_10")
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
value, err := db.Table(table).Fields("nickname").Where("id", 1).FindValue()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(value.String(), "name_1")
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
value, err := db.Table(table).Fields("nickname").Where("id", 0).FindValue()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(value, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Model_Count(t *testing.T) {
|
||||
table := createInitTable()
|
||||
defer dropTable(table)
|
||||
@ -413,6 +516,26 @@ func Test_Model_Count(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Model_FindCount(t *testing.T) {
|
||||
table := createInitTable()
|
||||
defer dropTable(table)
|
||||
gtest.Case(t, func() {
|
||||
count, err := db.Table(table).FindCount(g.Slice{1, 3})
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(count, 2)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
count, err := db.Table(table).FindCount(g.Slice{1, 300000})
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(count, 1)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
count, err := db.Table(table).FindCount()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(count, INIT_DATA_SIZE)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Model_Select(t *testing.T) {
|
||||
table := createInitTable()
|
||||
defer dropTable(table)
|
||||
@ -514,7 +637,7 @@ func Test_Model_Structs(t *testing.T) {
|
||||
CreateTime gtime.Time
|
||||
}
|
||||
var users []User
|
||||
err := db.Table(table).OrderBy("id asc").Structs(&users)
|
||||
err := db.Table(table).Order("id asc").Structs(&users)
|
||||
if err != nil {
|
||||
gtest.Error(err)
|
||||
}
|
||||
@ -537,7 +660,7 @@ func Test_Model_Structs(t *testing.T) {
|
||||
CreateTime *gtime.Time
|
||||
}
|
||||
var users []*User
|
||||
err := db.Table(table).OrderBy("id asc").Structs(&users)
|
||||
err := db.Table(table).Order("id asc").Structs(&users)
|
||||
if err != nil {
|
||||
gtest.Error(err)
|
||||
}
|
||||
@ -560,7 +683,7 @@ func Test_Model_Structs(t *testing.T) {
|
||||
CreateTime *gtime.Time
|
||||
}
|
||||
var users []*User
|
||||
err := db.Table(table).OrderBy("id asc").Scan(&users)
|
||||
err := db.Table(table).Order("id asc").Scan(&users)
|
||||
if err != nil {
|
||||
gtest.Error(err)
|
||||
}
|
||||
@ -629,7 +752,7 @@ func Test_Model_Scan(t *testing.T) {
|
||||
CreateTime gtime.Time
|
||||
}
|
||||
var users []User
|
||||
err := db.Table(table).OrderBy("id asc").Scan(&users)
|
||||
err := db.Table(table).Order("id asc").Scan(&users)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(users), INIT_DATA_SIZE)
|
||||
gtest.Assert(users[0].Id, 1)
|
||||
@ -649,7 +772,7 @@ func Test_Model_Scan(t *testing.T) {
|
||||
CreateTime *gtime.Time
|
||||
}
|
||||
var users []*User
|
||||
err := db.Table(table).OrderBy("id asc").Scan(&users)
|
||||
err := db.Table(table).Order("id asc").Scan(&users)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(users), INIT_DATA_SIZE)
|
||||
gtest.Assert(users[0].Id, 1)
|
||||
@ -683,7 +806,7 @@ func Test_Model_OrderBy(t *testing.T) {
|
||||
defer dropTable(table)
|
||||
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).OrderBy("id DESC").Select()
|
||||
result, err := db.Table(table).Order("id DESC").Select()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(result), INIT_DATA_SIZE)
|
||||
gtest.Assert(result[0]["nickname"].String(), fmt.Sprintf("name_%d", INIT_DATA_SIZE))
|
||||
@ -724,7 +847,7 @@ func Test_Model_Where(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).Where(g.Map{
|
||||
"passport like": "user_1%",
|
||||
}).OrderBy("id asc").All()
|
||||
}).Order("id asc").All()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(result), 2)
|
||||
gtest.Assert(result[0].GMap().Get("id"), 1)
|
||||
@ -870,7 +993,7 @@ func Test_Model_Where(t *testing.T) {
|
||||
"create_time > 0": nil,
|
||||
"id": g.Slice{1, 2, 3},
|
||||
}
|
||||
result, err := db.Table(table).Where(conditions).OrderBy("id asc").All()
|
||||
result, err := db.Table(table).Where(conditions).Order("id asc").All()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(result), 3)
|
||||
gtest.Assert(result[0]["id"].Int(), 1)
|
||||
@ -885,7 +1008,7 @@ func Test_Model_Where(t *testing.T) {
|
||||
"create_time > ?": 0,
|
||||
"id in(?)": g.Slice{1, 2, 3},
|
||||
}
|
||||
result, err := db.Table(table).Where(conditions).OrderBy("id asc").All()
|
||||
result, err := db.Table(table).Where(conditions).Order("id asc").All()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(result), 3)
|
||||
gtest.Assert(result[0]["id"].Int(), 1)
|
||||
@ -906,7 +1029,7 @@ func Test_Model_Where(t *testing.T) {
|
||||
})
|
||||
// slice single
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).Where("id IN(?)", g.Slice{1, 3}).OrderBy("id ASC").All()
|
||||
result, err := db.Table(table).Where("id IN(?)", g.Slice{1, 3}).Order("id ASC").All()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(result), 2)
|
||||
gtest.Assert(result[0]["id"].Int(), 1)
|
||||
@ -914,7 +1037,7 @@ func Test_Model_Where(t *testing.T) {
|
||||
})
|
||||
// slice + string
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).Where("nickname=? AND id IN(?)", "name_3", g.Slice{1, 3}).OrderBy("id ASC").All()
|
||||
result, err := db.Table(table).Where("nickname=? AND id IN(?)", "name_3", g.Slice{1, 3}).Order("id ASC").All()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(result), 1)
|
||||
gtest.Assert(result[0]["id"].Int(), 3)
|
||||
@ -924,7 +1047,7 @@ func Test_Model_Where(t *testing.T) {
|
||||
result, err := db.Table(table).Where(g.Map{
|
||||
"id": g.Slice{1, 3},
|
||||
"nickname": "name_3",
|
||||
}).OrderBy("id ASC").All()
|
||||
}).Order("id ASC").All()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(result), 1)
|
||||
gtest.Assert(result[0]["id"].Int(), 3)
|
||||
@ -938,7 +1061,265 @@ func Test_Model_Where(t *testing.T) {
|
||||
result, err := db.Table(table).Where(User{
|
||||
Ids: []int{1, 3},
|
||||
Nickname: "name_3",
|
||||
}).OrderBy("id ASC").All()
|
||||
}).Order("id ASC").All()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(result), 1)
|
||||
gtest.Assert(result[0]["id"].Int(), 3)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Model_WherePri(t *testing.T) {
|
||||
table := createInitTable()
|
||||
defer dropTable(table)
|
||||
|
||||
// primary key
|
||||
gtest.Case(t, func() {
|
||||
one, err := db.Table(table).WherePri(3).One()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.AssertNE(one, nil)
|
||||
gtest.Assert(one["id"].Int(), 3)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
all, err := db.Table(table).WherePri(g.Slice{3, 9}).Order("id asc").All()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(all), 2)
|
||||
gtest.Assert(all[0]["id"].Int(), 3)
|
||||
gtest.Assert(all[1]["id"].Int(), 9)
|
||||
})
|
||||
|
||||
// string
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).WherePri("id=? and nickname=?", 3, "name_3").One()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.AssertGT(len(result), 0)
|
||||
gtest.Assert(result["id"].Int(), 3)
|
||||
})
|
||||
// slice parameter
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).WherePri("id=? and nickname=?", g.Slice{3, "name_3"}).One()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.AssertGT(len(result), 0)
|
||||
gtest.Assert(result["id"].Int(), 3)
|
||||
})
|
||||
// map like
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).WherePri(g.Map{
|
||||
"passport like": "user_1%",
|
||||
}).Order("id asc").All()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(result), 2)
|
||||
gtest.Assert(result[0].GMap().Get("id"), 1)
|
||||
gtest.Assert(result[1].GMap().Get("id"), 10)
|
||||
})
|
||||
// map + slice parameter
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).WherePri(g.Map{
|
||||
"id": g.Slice{1, 2, 3},
|
||||
"passport": g.Slice{"user_2", "user_3"},
|
||||
}).And("id=? and nickname=?", g.Slice{3, "name_3"}).One()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.AssertGT(len(result), 0)
|
||||
gtest.Assert(result["id"].Int(), 3)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).WherePri(g.Map{
|
||||
"id": g.Slice{1, 2, 3},
|
||||
"passport": g.Slice{"user_2", "user_3"},
|
||||
}).Or("nickname=?", g.Slice{"name_4"}).And("id", 3).One()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.AssertGT(len(result), 0)
|
||||
gtest.Assert(result["id"].Int(), 3)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).WherePri("id=3", g.Slice{}).One()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.AssertGT(len(result), 0)
|
||||
gtest.Assert(result["id"].Int(), 3)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).WherePri("id=?", g.Slice{3}).One()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.AssertGT(len(result), 0)
|
||||
gtest.Assert(result["id"].Int(), 3)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).WherePri("id", 3).One()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.AssertGT(len(result), 0)
|
||||
gtest.Assert(result["id"].Int(), 3)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).WherePri("id", 3).WherePri("nickname", "name_3").One()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(result["id"].Int(), 3)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).WherePri("id", 3).And("nickname", "name_3").One()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(result["id"].Int(), 3)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).WherePri("id", 30).Or("nickname", "name_3").One()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(result["id"].Int(), 3)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).WherePri("id", 30).Or("nickname", "name_3").And("id>?", 1).One()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(result["id"].Int(), 3)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).WherePri("id", 30).Or("nickname", "name_3").And("id>", 1).One()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(result["id"].Int(), 3)
|
||||
})
|
||||
// slice
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).WherePri("id=? AND nickname=?", g.Slice{3, "name_3"}...).One()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(result["id"].Int(), 3)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).WherePri("id=? AND nickname=?", g.Slice{3, "name_3"}).One()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(result["id"].Int(), 3)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).WherePri("passport like ? and nickname like ?", g.Slice{"user_3", "name_3"}).One()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(result["id"].Int(), 3)
|
||||
})
|
||||
// map
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).WherePri(g.Map{"id": 3, "nickname": "name_3"}).One()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(result["id"].Int(), 3)
|
||||
})
|
||||
// map key operator
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).WherePri(g.Map{"id>": 1, "id<": 3}).One()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(result["id"].Int(), 2)
|
||||
})
|
||||
|
||||
// gmap.Map
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).WherePri(gmap.NewFrom(g.MapAnyAny{"id": 3, "nickname": "name_3"})).One()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(result["id"].Int(), 3)
|
||||
})
|
||||
// gmap.Map key operator
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).WherePri(gmap.NewFrom(g.MapAnyAny{"id>": 1, "id<": 3})).One()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(result["id"].Int(), 2)
|
||||
})
|
||||
|
||||
// list map
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).WherePri(gmap.NewListMapFrom(g.MapAnyAny{"id": 3, "nickname": "name_3"})).One()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(result["id"].Int(), 3)
|
||||
})
|
||||
// list map key operator
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).WherePri(gmap.NewListMapFrom(g.MapAnyAny{"id>": 1, "id<": 3})).One()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(result["id"].Int(), 2)
|
||||
})
|
||||
|
||||
// tree map
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).WherePri(gmap.NewTreeMapFrom(gutil.ComparatorString, g.MapAnyAny{"id": 3, "nickname": "name_3"})).One()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(result["id"].Int(), 3)
|
||||
})
|
||||
// tree map key operator
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).WherePri(gmap.NewTreeMapFrom(gutil.ComparatorString, g.MapAnyAny{"id>": 1, "id<": 3})).One()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(result["id"].Int(), 2)
|
||||
})
|
||||
|
||||
// complicated where 1
|
||||
gtest.Case(t, func() {
|
||||
//db.SetDebug(true)
|
||||
conditions := g.Map{
|
||||
"nickname like ?": "%name%",
|
||||
"id between ? and ?": g.Slice{1, 3},
|
||||
"id > 0": nil,
|
||||
"create_time > 0": nil,
|
||||
"id": g.Slice{1, 2, 3},
|
||||
}
|
||||
result, err := db.Table(table).WherePri(conditions).Order("id asc").All()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(result), 3)
|
||||
gtest.Assert(result[0]["id"].Int(), 1)
|
||||
})
|
||||
// complicated where 2
|
||||
gtest.Case(t, func() {
|
||||
//db.SetDebug(true)
|
||||
conditions := g.Map{
|
||||
"nickname like ?": "%name%",
|
||||
"id between ? and ?": g.Slice{1, 3},
|
||||
"id >= ?": 1,
|
||||
"create_time > ?": 0,
|
||||
"id in(?)": g.Slice{1, 2, 3},
|
||||
}
|
||||
result, err := db.Table(table).WherePri(conditions).Order("id asc").All()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(result), 3)
|
||||
gtest.Assert(result[0]["id"].Int(), 1)
|
||||
})
|
||||
// struct
|
||||
gtest.Case(t, func() {
|
||||
type User struct {
|
||||
Id int `json:"id"`
|
||||
Nickname string `gconv:"nickname"`
|
||||
}
|
||||
result, err := db.Table(table).WherePri(User{3, "name_3"}).One()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(result["id"].Int(), 3)
|
||||
|
||||
result, err = db.Table(table).WherePri(&User{3, "name_3"}).One()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(result["id"].Int(), 3)
|
||||
})
|
||||
// slice single
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).WherePri("id IN(?)", g.Slice{1, 3}).Order("id ASC").All()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(result), 2)
|
||||
gtest.Assert(result[0]["id"].Int(), 1)
|
||||
gtest.Assert(result[1]["id"].Int(), 3)
|
||||
})
|
||||
// slice + string
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).WherePri("nickname=? AND id IN(?)", "name_3", g.Slice{1, 3}).Order("id ASC").All()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(result), 1)
|
||||
gtest.Assert(result[0]["id"].Int(), 3)
|
||||
})
|
||||
// slice + map
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table(table).WherePri(g.Map{
|
||||
"id": g.Slice{1, 3},
|
||||
"nickname": "name_3",
|
||||
}).Order("id ASC").All()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(result), 1)
|
||||
gtest.Assert(result[0]["id"].Int(), 3)
|
||||
})
|
||||
// slice + struct
|
||||
gtest.Case(t, func() {
|
||||
type User struct {
|
||||
Ids []int `json:"id"`
|
||||
Nickname string `gconv:"nickname"`
|
||||
}
|
||||
result, err := db.Table(table).WherePri(User{
|
||||
Ids: []int{1, 3},
|
||||
Nickname: "name_3",
|
||||
}).Order("id ASC").All()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(result), 1)
|
||||
gtest.Assert(result[0]["id"].Int(), 3)
|
||||
@ -969,7 +1350,7 @@ func Test_Model_Offset(t *testing.T) {
|
||||
table := createInitTable()
|
||||
defer dropTable(table)
|
||||
|
||||
result, err := db.Table(table).Limit(2).Offset(5).OrderBy("id").Select()
|
||||
result, err := db.Table(table).Limit(2).Offset(5).Order("id").Select()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(result), 2)
|
||||
gtest.Assert(result[0]["id"], 6)
|
||||
@ -980,7 +1361,7 @@ func Test_Model_ForPage(t *testing.T) {
|
||||
table := createInitTable()
|
||||
defer dropTable(table)
|
||||
|
||||
result, err := db.Table(table).ForPage(3, 3).OrderBy("id").Select()
|
||||
result, err := db.Table(table).ForPage(3, 3).Order("id").Select()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(result), 3)
|
||||
gtest.Assert(result[0]["id"], 7)
|
||||
@ -1153,7 +1534,7 @@ func Test_Model_Option_List(t *testing.T) {
|
||||
gtest.Assert(err, nil)
|
||||
n, _ := r.RowsAffected()
|
||||
gtest.Assert(n, 2)
|
||||
list, err := db.Table(table).OrderBy("id asc").All()
|
||||
list, err := db.Table(table).Order("id asc").All()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(list), 2)
|
||||
gtest.Assert(list[0]["id"].String(), "1")
|
||||
@ -1187,7 +1568,7 @@ func Test_Model_Option_List(t *testing.T) {
|
||||
gtest.Assert(err, nil)
|
||||
n, _ := r.RowsAffected()
|
||||
gtest.Assert(n, 2)
|
||||
list, err := db.Table(table).OrderBy("id asc").All()
|
||||
list, err := db.Table(table).Order("id asc").All()
|
||||
g.Dump(list)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(list), 2)
|
||||
@ -1232,7 +1613,7 @@ func Test_Model_FieldsEx(t *testing.T) {
|
||||
defer dropTable(table)
|
||||
// Select.
|
||||
gtest.Case(t, func() {
|
||||
r, err := db.Table(table).FieldsEx("create_time, id").Where("id in (?)", g.Slice{1, 2}).OrderBy("id asc").All()
|
||||
r, err := db.Table(table).FieldsEx("create_time, id").Where("id in (?)", g.Slice{1, 2}).Order("id asc").All()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(r), 2)
|
||||
gtest.Assert(len(r[0]), 3)
|
||||
@ -1260,3 +1641,34 @@ func Test_Model_FieldsEx(t *testing.T) {
|
||||
gtest.AssertNE(one["password"], "456")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Model_Prefix(t *testing.T) {
|
||||
db := dbPrefix
|
||||
table := fmt.Sprintf(`%s_%d`, TABLE, gtime.Nanosecond())
|
||||
createInitTableWithDb(db, PREFIX1+table)
|
||||
defer dropTable(PREFIX1 + table)
|
||||
// Select.
|
||||
gtest.Case(t, func() {
|
||||
r, err := db.Table(table).Where("id in (?)", g.Slice{1, 2}).Order("id asc").All()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(r), 2)
|
||||
gtest.Assert(r[0]["id"], "1")
|
||||
gtest.Assert(r[1]["id"], "2")
|
||||
})
|
||||
// Select with alias.
|
||||
gtest.Case(t, func() {
|
||||
r, err := db.Table(table+" as u").Where("u.id in (?)", g.Slice{1, 2}).Order("u.id asc").All()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(r), 2)
|
||||
gtest.Assert(r[0]["id"], "1")
|
||||
gtest.Assert(r[1]["id"], "2")
|
||||
})
|
||||
// Select with alias and join statement.
|
||||
gtest.Case(t, func() {
|
||||
r, err := db.Table(table+" as u1").LeftJoin(table+" as u2", "u2.id=u1.id").Where("u1.id in (?)", g.Slice{1, 2}).Order("u1.id asc").All()
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(len(r), 2)
|
||||
gtest.Assert(r[0]["id"], "1")
|
||||
gtest.Assert(r[1]["id"], "2")
|
||||
})
|
||||
}
|
||||
|
||||
@ -667,10 +667,10 @@ func Test_TX_GetScan(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_TX_Delete(t *testing.T) {
|
||||
table := createInitTable()
|
||||
defer dropTable(table)
|
||||
|
||||
gtest.Case(t, func() {
|
||||
table := createInitTable()
|
||||
defer dropTable(table)
|
||||
tx, err := db.Begin()
|
||||
if err != nil {
|
||||
gtest.Error(err)
|
||||
@ -688,4 +688,30 @@ func Test_TX_Delete(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
table := createInitTable()
|
||||
defer dropTable(table)
|
||||
tx, err := db.Begin()
|
||||
if err != nil {
|
||||
gtest.Error(err)
|
||||
}
|
||||
if _, err := tx.Delete(table, nil); err != nil {
|
||||
gtest.Error(err)
|
||||
}
|
||||
if n, err := tx.Table(table).Count(); err != nil {
|
||||
gtest.Error(err)
|
||||
} else {
|
||||
gtest.Assert(n, 0)
|
||||
}
|
||||
if err := tx.Rollback(); err != nil {
|
||||
gtest.Error(err)
|
||||
}
|
||||
if n, err := db.Table(table).Count(); err != nil {
|
||||
gtest.Error(err)
|
||||
} else {
|
||||
gtest.Assert(n, INIT_DATA_SIZE)
|
||||
gtest.AssertNE(n, 0)
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
@ -20,13 +20,6 @@ func Encode(src []byte) []byte {
|
||||
return dst
|
||||
}
|
||||
|
||||
// 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)
|
||||
return src[:n], err
|
||||
}
|
||||
|
||||
// EncodeString encodes string with BASE64 algorithm.
|
||||
func EncodeString(src string) string {
|
||||
return EncodeToString([]byte(src))
|
||||
@ -46,6 +39,16 @@ func EncodeFile(path string) ([]byte, error) {
|
||||
return Encode(content), nil
|
||||
}
|
||||
|
||||
// MustEncodeFile encodes file content of <path> using BASE64 algorithms.
|
||||
// It panics if any error occurs.
|
||||
func MustEncodeFile(path string) []byte {
|
||||
result, err := EncodeFile(path)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// EncodeFileToString encodes file content of <path> to string using BASE64 algorithms.
|
||||
func EncodeFileToString(path string) (string, error) {
|
||||
content, err := EncodeFile(path)
|
||||
@ -55,13 +58,60 @@ func EncodeFileToString(path string) (string, error) {
|
||||
return gconv.UnsafeBytesToStr(content), nil
|
||||
}
|
||||
|
||||
// DecodeString decodes string with BASE64 algorithm.
|
||||
func DecodeString(str string) ([]byte, error) {
|
||||
return Decode([]byte(str))
|
||||
// MustEncodeFileToString encodes file content of <path> to string using BASE64 algorithms.
|
||||
// It panics if any error occurs.
|
||||
func MustEncodeFileToString(path string) string {
|
||||
result, err := EncodeFileToString(path)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Decode decodes bytes with BASE64 algorithm.
|
||||
func Decode(data []byte) ([]byte, error) {
|
||||
src := make([]byte, base64.StdEncoding.DecodedLen(len(data)))
|
||||
n, err := base64.StdEncoding.Decode(src, data)
|
||||
return src[:n], err
|
||||
}
|
||||
|
||||
// MustDecode decodes bytes with BASE64 algorithm.
|
||||
// It panics if any error occurs.
|
||||
func MustDecode(data []byte) []byte {
|
||||
result, err := Decode(data)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// DecodeString decodes string with BASE64 algorithm.
|
||||
func DecodeToString(str string) (string, error) {
|
||||
b, err := DecodeString(str)
|
||||
func DecodeString(data string) ([]byte, error) {
|
||||
return Decode([]byte(data))
|
||||
}
|
||||
|
||||
// MustDecodeString decodes string with BASE64 algorithm.
|
||||
// It panics if any error occurs.
|
||||
func MustDecodeString(data string) []byte {
|
||||
result, err := DecodeString(data)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// DecodeString decodes string with BASE64 algorithm.
|
||||
func DecodeToString(data string) (string, error) {
|
||||
b, err := DecodeString(data)
|
||||
return gconv.UnsafeBytesToStr(b), err
|
||||
}
|
||||
|
||||
// MustDecodeToString decodes string with BASE64 algorithm.
|
||||
// It panics if any error occurs.
|
||||
func MustDecodeToString(data string) string {
|
||||
result, err := DecodeToString(data)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@ -78,7 +78,7 @@ func (j *Json) GetVars(pattern string, def ...interface{}) []*gvar.Var {
|
||||
return gvar.New(j.Get(pattern, def...)).Vars()
|
||||
}
|
||||
|
||||
// GetMap gets the value by specified <pattern>,
|
||||
// GetMap retrieves the value by specified <pattern>,
|
||||
// and converts it to map[string]interface{}.
|
||||
func (j *Json) GetMap(pattern string, def ...interface{}) map[string]interface{} {
|
||||
result := j.Get(pattern, def...)
|
||||
@ -88,6 +88,16 @@ func (j *Json) GetMap(pattern string, def ...interface{}) map[string]interface{}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetMapStrStr retrieves the value by specified <pattern>,
|
||||
// and converts it to map[string]string.
|
||||
func (j *Json) GetMapStrStr(pattern string, def ...interface{}) map[string]string {
|
||||
result := j.Get(pattern, def...)
|
||||
if result != nil {
|
||||
return gconv.MapStrStr(result)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetJson gets the value by specified <pattern>,
|
||||
// and converts it to a un-concurrent-safe Json object.
|
||||
func (j *Json) GetJson(pattern string, def ...interface{}) *Json {
|
||||
|
||||
@ -12,25 +12,12 @@ import (
|
||||
"github.com/gogf/gf/encoding/gtoml"
|
||||
"github.com/gogf/gf/encoding/gxml"
|
||||
"github.com/gogf/gf/encoding/gyaml"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
)
|
||||
|
||||
func (j *Json) ToXml(rootTag ...string) ([]byte, error) {
|
||||
return gxml.Encode(j.ToMap(), rootTag...)
|
||||
}
|
||||
|
||||
func (j *Json) ToXmlString(rootTag ...string) (string, error) {
|
||||
b, e := j.ToXml(rootTag...)
|
||||
return string(b), e
|
||||
}
|
||||
|
||||
func (j *Json) ToXmlIndent(rootTag ...string) ([]byte, error) {
|
||||
return gxml.EncodeWithIndent(j.ToMap(), rootTag...)
|
||||
}
|
||||
|
||||
func (j *Json) ToXmlIndentString(rootTag ...string) (string, error) {
|
||||
b, e := j.ToXmlIndent(rootTag...)
|
||||
return string(b), e
|
||||
}
|
||||
// ========================================================================
|
||||
// JSON
|
||||
// ========================================================================
|
||||
|
||||
func (j *Json) ToJson() ([]byte, error) {
|
||||
j.mu.RLock()
|
||||
@ -54,6 +41,80 @@ func (j *Json) ToJsonIndentString() (string, error) {
|
||||
return string(b), e
|
||||
}
|
||||
|
||||
func (j *Json) MustToJson() []byte {
|
||||
result, err := j.ToJson()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (j *Json) MustToJsonString() string {
|
||||
return gconv.UnsafeBytesToStr(j.MustToJson())
|
||||
}
|
||||
|
||||
func (j *Json) MustToJsonIndent() []byte {
|
||||
result, err := j.ToJsonIndent()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (j *Json) MustToJsonIndentString() string {
|
||||
return gconv.UnsafeBytesToStr(j.MustToJsonIndent())
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// XML
|
||||
// ========================================================================
|
||||
|
||||
func (j *Json) ToXml(rootTag ...string) ([]byte, error) {
|
||||
return gxml.Encode(j.ToMap(), rootTag...)
|
||||
}
|
||||
|
||||
func (j *Json) ToXmlString(rootTag ...string) (string, error) {
|
||||
b, e := j.ToXml(rootTag...)
|
||||
return string(b), e
|
||||
}
|
||||
|
||||
func (j *Json) ToXmlIndent(rootTag ...string) ([]byte, error) {
|
||||
return gxml.EncodeWithIndent(j.ToMap(), rootTag...)
|
||||
}
|
||||
|
||||
func (j *Json) ToXmlIndentString(rootTag ...string) (string, error) {
|
||||
b, e := j.ToXmlIndent(rootTag...)
|
||||
return string(b), e
|
||||
}
|
||||
|
||||
func (j *Json) MustToXml(rootTag ...string) []byte {
|
||||
result, err := j.ToXml(rootTag...)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (j *Json) MustToXmlString(rootTag ...string) string {
|
||||
return gconv.UnsafeBytesToStr(j.MustToXml(rootTag...))
|
||||
}
|
||||
|
||||
func (j *Json) MustToXmlIndent(rootTag ...string) []byte {
|
||||
result, err := j.ToXmlIndent(rootTag...)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (j *Json) MustToXmlIndentString(rootTag ...string) string {
|
||||
return gconv.UnsafeBytesToStr(j.MustToXmlIndent(rootTag...))
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// YAML
|
||||
// ========================================================================
|
||||
|
||||
func (j *Json) ToYaml() ([]byte, error) {
|
||||
j.mu.RLock()
|
||||
defer j.mu.RUnlock()
|
||||
@ -65,6 +126,22 @@ func (j *Json) ToYamlString() (string, error) {
|
||||
return string(b), e
|
||||
}
|
||||
|
||||
func (j *Json) MustToYaml() []byte {
|
||||
result, err := j.ToYaml()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (j *Json) MustToYamlString() string {
|
||||
return gconv.UnsafeBytesToStr(j.MustToYaml())
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// TOML
|
||||
// ========================================================================
|
||||
|
||||
func (j *Json) ToToml() ([]byte, error) {
|
||||
j.mu.RLock()
|
||||
defer j.mu.RUnlock()
|
||||
@ -76,6 +153,22 @@ func (j *Json) ToTomlString() (string, error) {
|
||||
return string(b), e
|
||||
}
|
||||
|
||||
func (j *Json) MustToToml() []byte {
|
||||
result, err := j.ToToml()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (j *Json) MustToTomlString() string {
|
||||
return gconv.UnsafeBytesToStr(j.MustToToml())
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// INI
|
||||
// ========================================================================
|
||||
|
||||
func (j *Json) ToIni() ([]byte, error) {
|
||||
j.mu.RLock()
|
||||
defer j.mu.RUnlock()
|
||||
@ -86,3 +179,15 @@ func (j *Json) ToIniString() (string, error) {
|
||||
b, e := j.ToToml()
|
||||
return string(b), e
|
||||
}
|
||||
|
||||
func (j *Json) MustToIni() []byte {
|
||||
result, err := j.ToIni()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (j *Json) MustToIniString() string {
|
||||
return gconv.UnsafeBytesToStr(j.MustToIni())
|
||||
}
|
||||
|
||||
@ -25,11 +25,10 @@ import (
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
)
|
||||
|
||||
// New creates a Json object with any variable type of <data>,
|
||||
// but <data> should be a map or slice for data access reason,
|
||||
// or it will make no sense.
|
||||
// The <unsafe> param specifies whether using this Json object
|
||||
// in un-concurrent-safe context, which is false in default.
|
||||
// New creates a Json object with any variable type of <data>, but <data> should be a map or slice
|
||||
// for data access reason, or it will make no sense.
|
||||
// The <safe> param specifies whether using this Json object in concurrent-safe context, which is
|
||||
// false in default.
|
||||
func New(data interface{}, safe ...bool) *Json {
|
||||
j := (*Json)(nil)
|
||||
switch data.(type) {
|
||||
@ -61,7 +60,8 @@ func New(data interface{}, safe ...bool) *Json {
|
||||
}
|
||||
case reflect.Map, reflect.Struct:
|
||||
i := interface{}(nil)
|
||||
i = gconv.Map(data, "json")
|
||||
// Note that it uses MapDeep function implementing the converting.
|
||||
i = gconv.MapDeep(data, "json")
|
||||
j = &Json{
|
||||
p: &i,
|
||||
c: byte(gDEFAULT_SPLIT_CHAR),
|
||||
|
||||
@ -6,13 +6,9 @@
|
||||
|
||||
package gparser
|
||||
|
||||
func VarToXml(value interface{}, rootTag ...string) ([]byte, error) {
|
||||
return New(value).ToXml(rootTag...)
|
||||
}
|
||||
|
||||
func VarToXmlIndent(value interface{}, rootTag ...string) ([]byte, error) {
|
||||
return New(value).ToXmlIndent(rootTag...)
|
||||
}
|
||||
// ========================================================================
|
||||
// JSON
|
||||
// ========================================================================
|
||||
|
||||
func VarToJson(value interface{}) ([]byte, error) {
|
||||
return New(value).ToJson()
|
||||
@ -30,14 +26,114 @@ func VarToJsonIndentString(value interface{}) (string, error) {
|
||||
return New(value).ToJsonIndentString()
|
||||
}
|
||||
|
||||
func MustToJson(value interface{}) []byte {
|
||||
return New(value).MustToJson()
|
||||
}
|
||||
|
||||
func MustToJsonString(value interface{}) string {
|
||||
return New(value).MustToJsonString()
|
||||
}
|
||||
|
||||
func MustToJsonIndent(value interface{}) []byte {
|
||||
return New(value).MustToJsonIndent()
|
||||
}
|
||||
|
||||
func MustToJsonIndentString(value interface{}) string {
|
||||
return New(value).MustToJsonIndentString()
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// XML
|
||||
// ========================================================================
|
||||
|
||||
func VarToXml(value interface{}, rootTag ...string) ([]byte, error) {
|
||||
return New(value).ToXml(rootTag...)
|
||||
}
|
||||
|
||||
func VarToXmlString(value interface{}, rootTag ...string) (string, error) {
|
||||
return New(value).ToXmlString(rootTag...)
|
||||
}
|
||||
|
||||
func VarToXmlIndent(value interface{}, rootTag ...string) ([]byte, error) {
|
||||
return New(value).ToXmlIndent(rootTag...)
|
||||
}
|
||||
|
||||
func VarToXmlIndentString(value interface{}, rootTag ...string) (string, error) {
|
||||
return New(value).ToXmlIndentString(rootTag...)
|
||||
}
|
||||
|
||||
func MustToXml(value interface{}, rootTag ...string) []byte {
|
||||
return New(value).MustToXml(rootTag...)
|
||||
}
|
||||
|
||||
func MustToXmlString(value interface{}, rootTag ...string) string {
|
||||
return New(value).MustToXmlString(rootTag...)
|
||||
}
|
||||
|
||||
func MustToXmlIndent(value interface{}, rootTag ...string) []byte {
|
||||
return New(value).MustToXmlIndent(rootTag...)
|
||||
}
|
||||
|
||||
func MustToXmlIndentString(value interface{}, rootTag ...string) string {
|
||||
return New(value).MustToXmlIndentString(rootTag...)
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// YAML
|
||||
// ========================================================================
|
||||
|
||||
func VarToYaml(value interface{}) ([]byte, error) {
|
||||
return New(value).ToYaml()
|
||||
}
|
||||
|
||||
func VarToYamlString(value interface{}) (string, error) {
|
||||
return New(value).ToYamlString()
|
||||
}
|
||||
|
||||
func MustToYaml(value interface{}) []byte {
|
||||
return New(value).MustToYaml()
|
||||
}
|
||||
|
||||
func MustToYamlString(value interface{}) string {
|
||||
return New(value).MustToYamlString()
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// TOML
|
||||
// ========================================================================
|
||||
|
||||
func VarToToml(value interface{}) ([]byte, error) {
|
||||
return New(value).ToToml()
|
||||
}
|
||||
|
||||
func VarToTomlString(value interface{}) (string, error) {
|
||||
return New(value).ToTomlString()
|
||||
}
|
||||
|
||||
func MustToToml(value interface{}) []byte {
|
||||
return New(value).MustToToml()
|
||||
}
|
||||
|
||||
func MustToTomlString(value interface{}) string {
|
||||
return New(value).MustToTomlString()
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// INI
|
||||
// ========================================================================
|
||||
|
||||
func VarToIni(value interface{}) ([]byte, error) {
|
||||
return New(value).ToIni()
|
||||
}
|
||||
|
||||
func VarToIniString(value interface{}) (string, error) {
|
||||
return New(value).ToIniString()
|
||||
}
|
||||
|
||||
func MustToIni(value interface{}) []byte {
|
||||
return New(value).MustToIni()
|
||||
}
|
||||
|
||||
func MustToIniString(value interface{}) string {
|
||||
return New(value).MustToIniString()
|
||||
}
|
||||
|
||||
@ -8,7 +8,6 @@
|
||||
package gxml
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/clbanning/mxj"
|
||||
@ -16,7 +15,7 @@ import (
|
||||
"github.com/gogf/gf/text/gregex"
|
||||
)
|
||||
|
||||
// 将XML内容解析为map变量
|
||||
// Decode parses <content> into and returns as map.
|
||||
func Decode(content []byte) (map[string]interface{}, error) {
|
||||
res, err := convert(content)
|
||||
if err != nil {
|
||||
@ -25,23 +24,42 @@ func Decode(content []byte) (map[string]interface{}, error) {
|
||||
return mxj.NewMapXml(res)
|
||||
}
|
||||
|
||||
// 将map变量解析为XML格式内容
|
||||
func Encode(v map[string]interface{}, rootTag ...string) ([]byte, error) {
|
||||
return mxj.Map(v).Xml(rootTag...)
|
||||
// DecodeWithoutRoot parses <content> into a map, and returns the map without root level.
|
||||
func DecodeWithoutRoot(content []byte) (map[string]interface{}, error) {
|
||||
res, err := convert(content)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m, err := mxj.NewMapXml(res)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, v := range m {
|
||||
if r, ok := v.(map[string]interface{}); ok {
|
||||
return r, nil
|
||||
}
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func EncodeWithIndent(v map[string]interface{}, rootTag ...string) ([]byte, error) {
|
||||
return mxj.Map(v).XmlIndent("", "\t", rootTag...)
|
||||
// Encode encodes map <m> to a XML format content as bytes.
|
||||
// The optional parameter <rootTag> is used to specify the XML root tag.
|
||||
func Encode(m map[string]interface{}, rootTag ...string) ([]byte, error) {
|
||||
return mxj.Map(m).Xml(rootTag...)
|
||||
}
|
||||
|
||||
// XML格式内容直接转换为JSON格式内容
|
||||
// Encode encodes map <m> to a XML format content as bytes with indent.
|
||||
// The optional parameter <rootTag> is used to specify the XML root tag.
|
||||
func EncodeWithIndent(m map[string]interface{}, rootTag ...string) ([]byte, error) {
|
||||
return mxj.Map(m).XmlIndent("", "\t", rootTag...)
|
||||
}
|
||||
|
||||
// ToJson converts <content> as XML format into JSON format bytes.
|
||||
func ToJson(content []byte) ([]byte, error) {
|
||||
res, err := convert(content)
|
||||
if err != nil {
|
||||
fmt.Println("convert error. ", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mv, err := mxj.NewMapXml(res)
|
||||
if err == nil {
|
||||
return mv.Json()
|
||||
@ -50,7 +68,7 @@ func ToJson(content []byte) ([]byte, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// XML字符集预处理
|
||||
// convert converts the encoding of given XML content from XML root tag into UTF-8 encoding content.
|
||||
func convert(xml []byte) (res []byte, err error) {
|
||||
patten := `<\?xml.*encoding\s*=\s*['|"](.*?)['|"].*\?>`
|
||||
matchStr, err := gregex.MatchString(patten, string(xml))
|
||||
|
||||
@ -80,7 +80,7 @@ func Test_XmlToJson(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Decode(t *testing.T) {
|
||||
func Test_Decode1(t *testing.T) {
|
||||
for _, v := range testData {
|
||||
srcXml, dstXml := buildXml(v.otherEncoding, v.utf8)
|
||||
if len(srcXml) == 0 && len(dstXml) == 0 {
|
||||
@ -106,6 +106,32 @@ func Test_Decode(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Decode2(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
content := `
|
||||
<?xml version="1.0" encoding="UTF-8"?><doc><username>johngcn</username><password1>123456</password1><password2>123456</password2></doc>
|
||||
`
|
||||
m, err := gxml.Decode([]byte(content))
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(m["doc"].(map[string]interface{})["username"], "johngcn")
|
||||
gtest.Assert(m["doc"].(map[string]interface{})["password1"], "123456")
|
||||
gtest.Assert(m["doc"].(map[string]interface{})["password2"], "123456")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_DecodeWitoutRoot(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
content := `
|
||||
<?xml version="1.0" encoding="UTF-8"?><doc><username>johngcn</username><password1>123456</password1><password2>123456</password2></doc>
|
||||
`
|
||||
m, err := gxml.DecodeWithoutRoot([]byte(content))
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(m["username"], "johngcn")
|
||||
gtest.Assert(m["password1"], "123456")
|
||||
gtest.Assert(m["password2"], "123456")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Encode(t *testing.T) {
|
||||
m := make(map[string]interface{})
|
||||
v := map[string]interface{}{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user