mirror of
https://gitee.com/johng/gf
synced 2026-06-10 11:27:17 +08:00
Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9227139cf8 | |||
| f2190e50b2 | |||
| c4537b4753 | |||
| 167d58490b | |||
| d36aceb9f1 | |||
| eb31922124 | |||
| bec9f5a847 | |||
| 506552c3a9 | |||
| 2bacc77224 | |||
| bc53f265af | |||
| 344f232c36 | |||
| 27b677b0c0 | |||
| a5a0e381bd | |||
| d528d7f5ab | |||
| 821c71bd8d | |||
| 604a10400d | |||
| 9219471f67 | |||
| fe5d2e5685 | |||
| 0a89daa513 | |||
| d6e6ddf996 | |||
| 5dbda8aedc | |||
| 134e4cf28f | |||
| 56a85abef7 | |||
| 80c6ceaf26 | |||
| a10f428715 | |||
| 597f7468e9 | |||
| 5db8851213 |
@ -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()
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
package article
|
||||
|
||||
// Fill with you ideas below.
|
||||
@ -1,68 +0,0 @@
|
||||
// ==========================================================================
|
||||
// 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()
|
||||
}
|
||||
@ -1,362 +0,0 @@
|
||||
// ==========================================================================
|
||||
// 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,33 +0,0 @@
|
||||
{
|
||||
"viewpath" : "/home/www/templates/",
|
||||
"database" : {
|
||||
"default" : [
|
||||
{
|
||||
"host" : "127.0.0.1",
|
||||
"port" : "3306",
|
||||
"user" : "root",
|
||||
"pass" : "123456",
|
||||
"name" : "test",
|
||||
"type" : "mysql",
|
||||
"role" : "master",
|
||||
"charset" : "utf8",
|
||||
"priority" : "1"
|
||||
},
|
||||
{
|
||||
"host" : "127.0.0.1",
|
||||
"port" : "3306",
|
||||
"user" : "root",
|
||||
"pass" : "123456",
|
||||
"name" : "test",
|
||||
"type" : "mysql",
|
||||
"role" : "master",
|
||||
"charset" : "utf8",
|
||||
"priority" : "1"
|
||||
}
|
||||
]
|
||||
},
|
||||
"redis" : {
|
||||
"disk" : "127.0.0.1:6379,0",
|
||||
"cache" : "127.0.0.1:6379,1"
|
||||
}
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
viewpath = "/home/www/templates"
|
||||
|
||||
# MySQL数据库配置
|
||||
[database]
|
||||
debug = true
|
||||
link = "mysql:root:12345678@tcp(127.0.0.1:3306)/gf"
|
||||
|
||||
|
||||
[redis]
|
||||
disk = "127.0.0.1:6379,0"
|
||||
cache = "127.0.0.1:6379,1"
|
||||
@ -1,35 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<config>
|
||||
<!-- 模板引擎目录 -->
|
||||
<viewpath>/home/www/templates/</viewpath>
|
||||
<!-- MySQL数据库配置 -->
|
||||
<database>
|
||||
<default>
|
||||
<host>127.0.0.1</host>
|
||||
<port>3306</port>
|
||||
<user>root</user>
|
||||
<pass>123456</pass>
|
||||
<name>test</name>
|
||||
<role>master</role>
|
||||
<type>mysql</type>
|
||||
<charset>utf8</charset>
|
||||
<priority>1</priority>
|
||||
</default>
|
||||
<default>
|
||||
<host>127.0.0.1</host>
|
||||
<port>3306</port>
|
||||
<user>root</user>
|
||||
<pass>123456</pass>
|
||||
<name>test</name>
|
||||
<role>master</role>
|
||||
<type>mysql</type>
|
||||
<charset>utf8</charset>
|
||||
<priority>1</priority>
|
||||
</default>
|
||||
</database>
|
||||
<!-- Redis数据库配置 -->
|
||||
<redis>
|
||||
<disk>127.0.0.1:6379,0</disk>
|
||||
<cache>127.0.0.1:6379,1</cache>
|
||||
</redis>
|
||||
</config>
|
||||
@ -1,27 +0,0 @@
|
||||
# 模板引擎目录
|
||||
viewpath: /home/www/templates/
|
||||
# MySQL数据库配置
|
||||
database:
|
||||
default:
|
||||
- host: 127.0.0.1
|
||||
port: 3306
|
||||
user: root
|
||||
pass: "8692651"
|
||||
name: test
|
||||
type: mysql
|
||||
role: master
|
||||
charset: utf8
|
||||
priority: 1
|
||||
- host: 127.0.0.1
|
||||
port: 3306
|
||||
user: root
|
||||
pass: "8692651"
|
||||
name: test
|
||||
type: mysql
|
||||
role: master
|
||||
charset: utf8
|
||||
priority: 1
|
||||
# Redis数据库配置
|
||||
redis:
|
||||
default: 127.0.0.1:6379,0
|
||||
cache : 127.0.0.1:6379,2
|
||||
@ -1,25 +0,0 @@
|
||||
package demo
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func init() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/apple", Apple)
|
||||
s.BindHandler("/pen", Pen)
|
||||
s.BindHandler("/apple-pen", ApplePen)
|
||||
}
|
||||
|
||||
func Apple(r *ghttp.Request) {
|
||||
r.Response.Write("Apple")
|
||||
}
|
||||
|
||||
func Pen(r *ghttp.Request) {
|
||||
r.Response.Write("Pen")
|
||||
}
|
||||
|
||||
func ApplePen(r *ghttp.Request) {
|
||||
r.Response.Write("Apple-Pen")
|
||||
}
|
||||
@ -1,16 +0,0 @@
|
||||
package demo
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
type Order struct{}
|
||||
|
||||
func init() {
|
||||
g.Server().BindObject("/{.struct}-{.method}", new(Order))
|
||||
}
|
||||
|
||||
func (o *Order) List(r *ghttp.Request) {
|
||||
r.Response.Write("List")
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
package demo
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/gins"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func init() {
|
||||
ghttp.GetServer().BindHandler("/config", func(r *ghttp.Request) {
|
||||
r.Response.Write(gins.Config().GetString("database.default.0.host"))
|
||||
})
|
||||
}
|
||||
@ -1,16 +0,0 @@
|
||||
package demo
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
)
|
||||
|
||||
func init() {
|
||||
ghttp.GetServer().BindHandler("/cookie", Cookie)
|
||||
}
|
||||
|
||||
func Cookie(r *ghttp.Request) {
|
||||
datetime := r.Cookie.Get("datetime")
|
||||
r.Cookie.Set("datetime", gtime.Datetime())
|
||||
r.Response.Write("datetime:" + datetime)
|
||||
}
|
||||
@ -1,20 +0,0 @@
|
||||
package demo
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
type ControllerDomain struct{}
|
||||
|
||||
// 初始化控制器对象,并绑定操作到Web Server
|
||||
func init() {
|
||||
// 只有localhost域名下才能访问该对象,
|
||||
// 对应URL为:http://localhost:8199/test/show
|
||||
// 通过该地址将无法访问到内容:http://127.0.0.1:8199/test/show
|
||||
ghttp.GetServer().Domain("localhost").BindObject("/domain", &ControllerDomain{})
|
||||
}
|
||||
|
||||
// 用于对象映射
|
||||
func (d *ControllerDomain) Show(r *ghttp.Request) {
|
||||
r.Response.Write("It's show time bibi!")
|
||||
}
|
||||
@ -1,24 +0,0 @@
|
||||
package demo
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/gmvc"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
type ControllerExit struct {
|
||||
gmvc.Controller
|
||||
}
|
||||
|
||||
func (c *ControllerExit) Init(r *ghttp.Request) {
|
||||
c.Controller.Init(r)
|
||||
c.Response.Write("exit, it will not print \"show\"")
|
||||
c.Request.Exit()
|
||||
}
|
||||
|
||||
func (c *ControllerExit) Show() {
|
||||
c.Response.Write("show")
|
||||
}
|
||||
|
||||
func init() {
|
||||
ghttp.GetServer().BindController("/exit", &ControllerExit{})
|
||||
}
|
||||
@ -1,36 +0,0 @@
|
||||
package demo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func Form(r *ghttp.Request) {
|
||||
fmt.Println(r.GetPostMap())
|
||||
fmt.Println(r.GetPostString("name"))
|
||||
fmt.Println(r.GetPostString("age"))
|
||||
|
||||
}
|
||||
|
||||
func FormShow(r *ghttp.Request) {
|
||||
r.Response.Write(`
|
||||
<html>
|
||||
<head>
|
||||
<title>表单提交</title>
|
||||
</head>
|
||||
<body>
|
||||
<form enctype="application/x-www-form-urlencoded" action="/form" method="post">
|
||||
<input type="input" name="name" />
|
||||
<input type="input" name="age" />
|
||||
<input type="submit" value="submit" />
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
`)
|
||||
}
|
||||
|
||||
func init() {
|
||||
ghttp.GetServer().BindHandler("/form", Form)
|
||||
ghttp.GetServer().BindHandler("/form/show", FormShow)
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
package demo
|
||||
|
||||
import "github.com/gogf/gf/net/ghttp"
|
||||
|
||||
func init() {
|
||||
ghttp.GetServer().BindHandler("/", func(r *ghttp.Request) {
|
||||
r.Response.Write("Hello World!")
|
||||
})
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
package demo
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/frame/gmvc"
|
||||
)
|
||||
|
||||
type Method struct {
|
||||
gmvc.Controller
|
||||
}
|
||||
|
||||
func init() {
|
||||
// 第三个参数指定主要注册的方法,其他方法不注册,方法名称会自动追加到给定路由后面,构成新路由
|
||||
// 以下注册会中注册两个新路由: /method/name, /method/age
|
||||
g.Server().BindController("/method", new(Method), "Name, Age")
|
||||
// 绑定路由到指定的方法执行,以下注册只会注册一个路由: /method-name
|
||||
g.Server().BindControllerMethod("/method-name", new(Method), "Name")
|
||||
}
|
||||
|
||||
func (c *Method) Name() {
|
||||
c.Response.Write("John")
|
||||
}
|
||||
|
||||
func (c *Method) Age() {
|
||||
c.Response.Write("18")
|
||||
}
|
||||
|
||||
func (c *Method) Info() {
|
||||
c.Response.Write("Info")
|
||||
}
|
||||
@ -1,20 +0,0 @@
|
||||
package demo
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
type Object struct{}
|
||||
|
||||
func init() {
|
||||
g.Server().BindObject("/object", new(Object))
|
||||
}
|
||||
|
||||
func (o *Object) Index(r *ghttp.Request) {
|
||||
r.Response.Write("object index")
|
||||
}
|
||||
|
||||
func (o *Object) Show(r *ghttp.Request) {
|
||||
r.Response.Write("object show")
|
||||
}
|
||||
@ -1,31 +0,0 @@
|
||||
package demo
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
type ObjectMethod struct{}
|
||||
|
||||
func init() {
|
||||
obj := &ObjectMethod{}
|
||||
g.Server().BindObject("/object-method", obj, "Show1, Show2, Show3")
|
||||
g.Server().BindObjectMethod("/object-method-show1", obj, "Show1")
|
||||
g.Server().Domain("localhost").BindObject("/object-method", obj, "Show4")
|
||||
}
|
||||
|
||||
func (o *ObjectMethod) Show1(r *ghttp.Request) {
|
||||
r.Response.Write("show 1")
|
||||
}
|
||||
|
||||
func (o *ObjectMethod) Show2(r *ghttp.Request) {
|
||||
r.Response.Write("show 2")
|
||||
}
|
||||
|
||||
func (o *ObjectMethod) Show3(r *ghttp.Request) {
|
||||
r.Response.Write("show 3")
|
||||
}
|
||||
|
||||
func (o *ObjectMethod) Show4(r *ghttp.Request) {
|
||||
r.Response.Write("show 4")
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
package demo
|
||||
|
||||
import "github.com/gogf/gf/net/ghttp"
|
||||
|
||||
// 测试绑定对象
|
||||
type ObjectRest struct{}
|
||||
|
||||
func init() {
|
||||
ghttp.GetServer().BindObjectRest("/object-rest", &ObjectRest{})
|
||||
}
|
||||
|
||||
// RESTFul - GET
|
||||
func (o *ObjectRest) Get(r *ghttp.Request) {
|
||||
r.Response.Write("RESTFul HTTP Method GET")
|
||||
}
|
||||
|
||||
// RESTFul - POST
|
||||
func (c *ObjectRest) Post(r *ghttp.Request) {
|
||||
r.Response.Write("RESTFul HTTP Method POST")
|
||||
}
|
||||
|
||||
// RESTFul - DELETE
|
||||
func (c *ObjectRest) Delete(r *ghttp.Request) {
|
||||
r.Response.Write("RESTFul HTTP Method DELETE")
|
||||
}
|
||||
|
||||
// 该方法无法映射,将会无法访问到
|
||||
func (c *ObjectRest) Hello(r *ghttp.Request) {
|
||||
r.Response.Write("Hello")
|
||||
}
|
||||
@ -1,25 +0,0 @@
|
||||
package demo
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
type Product struct {
|
||||
total int
|
||||
}
|
||||
|
||||
func init() {
|
||||
p := &Product{}
|
||||
g.Server().BindHandler("/product/total", p.Total)
|
||||
g.Server().BindHandler("/product/list/{page}.html", p.List)
|
||||
}
|
||||
|
||||
func (p *Product) Total(r *ghttp.Request) {
|
||||
p.total++
|
||||
r.Response.Write("total: ", p.total)
|
||||
}
|
||||
|
||||
func (p *Product) List(r *ghttp.Request) {
|
||||
r.Response.Write("page: ", r.Get("page"))
|
||||
}
|
||||
@ -1,34 +0,0 @@
|
||||
package demo
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/frame/gmvc"
|
||||
)
|
||||
|
||||
type Rest struct {
|
||||
gmvc.Controller
|
||||
}
|
||||
|
||||
func init() {
|
||||
g.Server().BindControllerRest("/rest", &Rest{})
|
||||
}
|
||||
|
||||
// RESTFul - GET
|
||||
func (c *Rest) Get() {
|
||||
c.Response.Write("RESTFul HTTP Method GET")
|
||||
}
|
||||
|
||||
// RESTFul - POST
|
||||
func (c *Rest) Post() {
|
||||
c.Response.Write("RESTFul HTTP Method POST")
|
||||
}
|
||||
|
||||
// RESTFul - DELETE
|
||||
func (c *Rest) Delete() {
|
||||
c.Response.Write("RESTFul HTTP Method DELETE")
|
||||
}
|
||||
|
||||
// 该方法无法映射,将会无法访问到
|
||||
func (c *Rest) Hello() {
|
||||
c.Response.Write("Hello")
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
package demo
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/frame/gmvc"
|
||||
)
|
||||
|
||||
type ControllerRule struct {
|
||||
gmvc.Controller
|
||||
}
|
||||
|
||||
func init() {
|
||||
g.Server().BindController("/rule/{method}/:name", &ControllerRule{})
|
||||
}
|
||||
|
||||
func (c *ControllerRule) Show() {
|
||||
c.Response.Write(c.Request.Get("name"))
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
package demo
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func init() {
|
||||
ghttp.GetServer().BindHandler("/session", Session)
|
||||
}
|
||||
|
||||
func Session(r *ghttp.Request) {
|
||||
id := r.Session.GetInt("id")
|
||||
r.Session.Set("id", id+1)
|
||||
r.Response.Write("id:" + strconv.Itoa(id))
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
package demo
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/gmvc"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
type ControllerTemplate struct {
|
||||
gmvc.Controller
|
||||
}
|
||||
|
||||
func (c *ControllerTemplate) Info() {
|
||||
c.View.Assign("name", "john")
|
||||
c.View.Assigns(map[string]interface{}{
|
||||
"age": 18,
|
||||
"score": 100,
|
||||
})
|
||||
c.View.Display("view/user/index.tpl")
|
||||
}
|
||||
|
||||
func init() {
|
||||
ghttp.GetServer().BindController("/template", &ControllerTemplate{})
|
||||
}
|
||||
@ -1,16 +0,0 @@
|
||||
package demo
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func init() {
|
||||
ghttp.GetServer().BindHandler("/template2", func(r *ghttp.Request) {
|
||||
content, _ := g.View().Parse("index.tpl", map[string]interface{}{
|
||||
"id": 123,
|
||||
"name": "john",
|
||||
})
|
||||
r.Response.Write(content)
|
||||
})
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
package demo
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/gins"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func init() {
|
||||
gins.View().SetPath("/home/www/template/")
|
||||
ghttp.GetServer().BindHandler("/template3", func(r *ghttp.Request) {
|
||||
content, _ := gins.View().Parse("index.tpl", map[string]interface{}{
|
||||
"id": 123,
|
||||
"name": "john",
|
||||
})
|
||||
r.Response.Write(content)
|
||||
})
|
||||
}
|
||||
@ -1,40 +0,0 @@
|
||||
package demo
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
"github.com/gogf/gf/os/gfile"
|
||||
)
|
||||
|
||||
func Upload(r *ghttp.Request) {
|
||||
if f, h, e := r.FormFile("upload-file"); e == nil {
|
||||
defer f.Close()
|
||||
fname := gfile.Basename(h.Filename)
|
||||
buffer := make([]byte, h.Size)
|
||||
f.Read(buffer)
|
||||
gfile.PutBytes("/tmp/"+fname, buffer)
|
||||
r.Response.Write(fname + " uploaded successly")
|
||||
} else {
|
||||
r.Response.Write(e.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func UploadShow(r *ghttp.Request) {
|
||||
r.Response.Write(`
|
||||
<html>
|
||||
<head>
|
||||
<title>上传文件</title>
|
||||
</head>
|
||||
<body>
|
||||
<form enctype="multipart/form-data" action="/upload" method="post">
|
||||
<input type="file" name="upload-file" />
|
||||
<input type="submit" value="upload" />
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
`)
|
||||
}
|
||||
|
||||
func init() {
|
||||
ghttp.GetServer().BindHandler("/upload", Upload)
|
||||
ghttp.GetServer().BindHandler("/upload/show", UploadShow)
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
package demo
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/frame/gmvc"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
gmvc.Controller
|
||||
}
|
||||
|
||||
func init() {
|
||||
s := g.Server()
|
||||
s.BindController("/user", new(User))
|
||||
s.BindController("/user/{.method}/{uid}", new(User), "Info")
|
||||
s.BindController("/user/{.method}/{page}.html", new(User), "List")
|
||||
}
|
||||
|
||||
func (u *User) Index() {
|
||||
u.Response.Write("User")
|
||||
}
|
||||
|
||||
func (u *User) Info() {
|
||||
u.Response.Write("Info - Uid: ", u.Request.Get("uid"))
|
||||
}
|
||||
|
||||
func (u *User) List() {
|
||||
u.Response.Write("List - Page: ", u.Request.Get("page"))
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
package stats
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
var (
|
||||
total int
|
||||
)
|
||||
|
||||
func init() {
|
||||
g.Server().BindHandler("/stats/total", showTotal)
|
||||
}
|
||||
|
||||
func showTotal(r *ghttp.Request) {
|
||||
total++
|
||||
r.Response.Write("total:", total)
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/.example/frame/mvc/app/model/article"
|
||||
)
|
||||
|
||||
func main() {
|
||||
m := article.Model
|
||||
m.All()
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>上传文件</title>
|
||||
</head>
|
||||
<body>
|
||||
<form enctype="multipart/form-data" action="/upload" method="post">
|
||||
<input type="file" name="upload-file" />
|
||||
<input type="submit" value="upload" />
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,2 +0,0 @@
|
||||
<h3>This is footer</h3>
|
||||
<div style="color:red">tpl vals: {{.}}</div>
|
||||
@ -1,11 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h3>This is index</h3>
|
||||
<p>tpl vals: {{.}}</p>
|
||||
{{include "user/footer.tpl" }}
|
||||
</body>
|
||||
</html>
|
||||
@ -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
|
||||
@ -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,4 +1,7 @@
|
||||
|
||||
[database]
|
||||
debug = true
|
||||
link = "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
|
||||
|
||||
[redis]
|
||||
default = "127.0.0.1:6379,0"
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
)
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
a := "aaaaa_post"
|
||||
b := "aaaaa_"
|
||||
c := gstr.TrimLeftStr(a, b)
|
||||
fmt.Println(c)
|
||||
type User struct {
|
||||
Id int
|
||||
}
|
||||
u1 := &User{1}
|
||||
u2 := *u1
|
||||
u2.Id = 2
|
||||
fmt.Println(u1)
|
||||
fmt.Println(u2)
|
||||
}
|
||||
|
||||
11
.example/other/test2.go
Normal file
11
.example/other/test2.go
Normal file
@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
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)
|
||||
}
|
||||
@ -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))
|
||||
}
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
# Donators
|
||||
|
||||
We currently accept donation by Alipay/WechatPay, please note your github/gitee account in your payment bill.
|
||||
|
||||
|
||||
| Name | Channel | Amount | Comment
|
||||
|---|---|--- | ---
|
||||
@ -36,7 +38,10 @@
|
||||
|*洁|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"/>
|
||||
|
||||
@ -625,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()
|
||||
|
||||
@ -637,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()
|
||||
|
||||
@ -570,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()
|
||||
|
||||
@ -562,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>.
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -22,17 +22,18 @@ import (
|
||||
"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)
|
||||
@ -42,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)
|
||||
@ -51,36 +52,33 @@ 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)
|
||||
SetLogger(logger *glog.Logger)
|
||||
@ -88,53 +86,54 @@ type DB interface {
|
||||
SetMaxIdleConnCount(n int)
|
||||
SetMaxOpenConnCount(n int)
|
||||
SetMaxConnLifetime(d time.Duration)
|
||||
Tables() (tables []string, err error)
|
||||
TableFields(table string) (map[string]*TableField, error)
|
||||
Tables(schema ...string) (tables []string, err error)
|
||||
TableFields(table string, schema ...string) (map[string]*TableField, error)
|
||||
|
||||
// 内部方法接口
|
||||
// Internal methods.
|
||||
getCache() *gcache.Cache
|
||||
getChars() (charLeft string, charRight string)
|
||||
getDebug() bool
|
||||
getPrefix() string
|
||||
getMaster(schema ...string) (*sql.DB, error)
|
||||
getSlave(schema ...string) (*sql.DB, error)
|
||||
quoteWord(s string) string
|
||||
quoteString(s string) string
|
||||
doSetSchema(sqlDb *sql.DB, schema string) error
|
||||
filterFields(table string, data map[string]interface{}) map[string]interface{}
|
||||
handleTableName(table string) string
|
||||
filterFields(schema, table string, data map[string]interface{}) map[string]interface{}
|
||||
convertValue(fieldValue []byte, fieldType string) interface{}
|
||||
rowsToResult(rows *sql.Rows) (Result, error)
|
||||
handleSqlBeforeExec(sql string) string
|
||||
}
|
||||
|
||||
// 执行底层数据库操作的核心接口
|
||||
// dbLink is a common database function wrapper interface for internal usage.
|
||||
type dbLink interface {
|
||||
Query(query string, args ...interface{}) (*sql.Rows, error)
|
||||
Exec(sql string, args ...interface{}) (sql.Result, error)
|
||||
Prepare(sql string) (*sql.Stmt, error)
|
||||
}
|
||||
|
||||
// 数据库链接对象
|
||||
// dbBase is the base struct for database management.
|
||||
type dbBase struct {
|
||||
db DB // 数据库对象
|
||||
group string // 配置分组名称
|
||||
debug *gtype.Bool // (默认关闭)是否开启调试模式,当开启时会启用一些调试特性
|
||||
cache *gcache.Cache // 数据库缓存,包括底层连接池对象缓存及查询缓存;需要注意的是,事务查询不支持查询缓存
|
||||
schema *gtype.String // 手动切换的数据库名称
|
||||
prefix string // 表名前缀
|
||||
tables map[string]map[string]string // 数据库表结构
|
||||
logger *glog.Logger // 日志管理对象
|
||||
maxIdleConnCount int // 连接池最大限制的连接数
|
||||
maxOpenConnCount int // 连接池最大打开的连接数
|
||||
maxConnLifetime time.Duration // 连接对象可重复使用的时间长度
|
||||
db DB // DB interface object.
|
||||
group string // Configuration group name.
|
||||
debug *gtype.Bool // Enable debug mode for the database.
|
||||
cache *gcache.Cache // Cache manager.
|
||||
schema *gtype.String // Custom schema for this object.
|
||||
prefix string // Table prefix.
|
||||
logger *glog.Logger // Logger.
|
||||
maxIdleConnCount int // Max idle connection count.
|
||||
maxOpenConnCount int // Max open connection count.
|
||||
maxConnLifetime time.Duration // Max TTL for a connection.
|
||||
}
|
||||
|
||||
// 执行的SQL对象
|
||||
// Sql is the sql recording struct.
|
||||
type Sql struct {
|
||||
Sql string // SQL语句(可能带有预处理占位符)
|
||||
Args []interface{} // 预处理参数值列表
|
||||
Format string // 格式化后的SQL语句(仅供参考)
|
||||
Error error // 执行结果(nil为成功)
|
||||
Start int64 // 执行开始时间(毫秒)
|
||||
End int64 // 执行结束时间(毫秒)
|
||||
Sql string // SQL string(may contain reserved char '?').
|
||||
Args []interface{} // Arguments for this sql.
|
||||
Format string // Formatted sql which contains arguments in the sql.
|
||||
Error error // Execution result.
|
||||
Start int64 // Start execution timestamp in milliseconds.
|
||||
End int64 // End execution timestamp in milliseconds.
|
||||
}
|
||||
|
||||
// 表字段结构信息
|
||||
@ -313,25 +312,36 @@ func getConfigNodeByWeight(cg ConfigGroup) *ConfigNode {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 获得底层数据库链接对象
|
||||
func (bs *dbBase) getSqlDb(master bool) (sqlDb *sql.DB, err error) {
|
||||
// 负载均衡
|
||||
// getSqlDb retrieves and returns a underlying database connection object.
|
||||
// The parameter <master> specifies whether retrieves master node connection if
|
||||
// master-slave nodes are configured.
|
||||
func (bs *dbBase) getSqlDb(master bool, schema ...string) (sqlDb *sql.DB, err error) {
|
||||
// Load balance.
|
||||
node, err := getConfigNodeByGroup(bs.group, master)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// 默认值设定
|
||||
// Default value checks.
|
||||
if node.Charset == "" {
|
||||
node.Charset = "utf8"
|
||||
}
|
||||
// 缓存连接对象(该对象其实是一个连接池对象)
|
||||
// Changes the schema.
|
||||
nodeSchema := bs.schema.Val()
|
||||
if len(schema) > 0 && schema[0] != "" {
|
||||
nodeSchema = schema[0]
|
||||
}
|
||||
if nodeSchema != "" {
|
||||
// Value copy.
|
||||
n := *node
|
||||
n.Name = nodeSchema
|
||||
node = &n
|
||||
}
|
||||
// Cache the underlying connection object by node.
|
||||
v := bs.cache.GetOrSetFuncLock(node.String(), func() interface{} {
|
||||
sqlDb, err = bs.db.Open(node)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
// 接口对象可能会覆盖这些连接参数,所以这里优先判断有误设置连接池属性。
|
||||
// 若无设置则使用配置节点的连接池参数
|
||||
if bs.maxIdleConnCount > 0 {
|
||||
sqlDb.SetMaxIdleConns(bs.maxIdleConnCount)
|
||||
} else if node.MaxIdleConnCount > 0 {
|
||||
@ -354,30 +364,41 @@ func (bs *dbBase) getSqlDb(master bool) (sqlDb *sql.DB, err error) {
|
||||
if v != nil && sqlDb == nil {
|
||||
sqlDb = v.(*sql.DB)
|
||||
}
|
||||
// 是否开启调试模式
|
||||
if node.Debug {
|
||||
bs.db.SetDebug(node.Debug)
|
||||
}
|
||||
// 是否手动选择数据库
|
||||
if v := bs.schema.Val(); v != "" {
|
||||
if e := bs.db.doSetSchema(sqlDb, v); e != nil {
|
||||
err = e
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 切换当前数据库对象操作的数据库。
|
||||
// SetSchema changes the schema for this database connection object.
|
||||
// Importantly note that when schema configuration changed for the database,
|
||||
// it affects all operations on the database object in the future.
|
||||
func (bs *dbBase) SetSchema(schema string) {
|
||||
bs.schema.Set(schema)
|
||||
}
|
||||
|
||||
// 创建底层数据库master链接对象。
|
||||
// Master creates and returns a connection from master node if master-slave configured.
|
||||
// It returns the default connection if master-slave not configured.
|
||||
func (bs *dbBase) Master() (*sql.DB, error) {
|
||||
return bs.getSqlDb(true)
|
||||
return bs.getSqlDb(true, bs.schema.Val())
|
||||
}
|
||||
|
||||
// 创建底层数据库slave链接对象。
|
||||
// Slave creates and returns a connection from slave node if master-slave configured.
|
||||
// It returns the default connection if master-slave not configured.
|
||||
func (bs *dbBase) Slave() (*sql.DB, error) {
|
||||
return bs.getSqlDb(false)
|
||||
return bs.getSqlDb(false, bs.schema.Val())
|
||||
}
|
||||
|
||||
// getMaster acts like function Master but with additional <schema> parameter specifying
|
||||
// the schema for the connection. It is defined for internal usage.
|
||||
// Also see Master.
|
||||
func (bs *dbBase) getMaster(schema ...string) (*sql.DB, error) {
|
||||
return bs.getSqlDb(true, schema...)
|
||||
}
|
||||
|
||||
// getSlave acts like function Slave but with additional <schema> parameter specifying
|
||||
// the schema for the connection. It is defined for internal usage.
|
||||
// Also see Slave.
|
||||
func (bs *dbBase) getSlave(schema ...string) (*sql.DB, error) {
|
||||
return bs.getSqlDb(false, schema...)
|
||||
}
|
||||
|
||||
@ -31,17 +31,6 @@ var (
|
||||
lastOperatorReg = regexp.MustCompile(`[<>=]+\s*$`)
|
||||
)
|
||||
|
||||
// 打印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()
|
||||
@ -56,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.TimestampMilli()
|
||||
rows, err = link.Query(query, args...)
|
||||
mTime2 := gtime.Millisecond()
|
||||
mTime2 := gtime.TimestampMilli()
|
||||
s := &Sql{
|
||||
Sql: query,
|
||||
Args: args,
|
||||
@ -302,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()
|
||||
@ -371,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:
|
||||
@ -491,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)
|
||||
@ -543,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...)
|
||||
}
|
||||
|
||||
@ -605,6 +594,17 @@ 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 {
|
||||
@ -619,8 +619,13 @@ func (bs *dbBase) quoteString(s string) string {
|
||||
return doQuoteString(s, charLeft, charRight)
|
||||
}
|
||||
|
||||
// 动态切换数据库
|
||||
func (bs *dbBase) doSetSchema(sqlDb *sql.DB, schema string) error {
|
||||
_, err := sqlDb.Exec("USE " + schema)
|
||||
return err
|
||||
// 打印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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,8 +51,31 @@ var (
|
||||
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 return <s> without any change.
|
||||
// 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
|
||||
@ -78,23 +101,6 @@ func doQuoteString(s, charLeft, charRight string) string {
|
||||
return gstr.Join(array1, ",")
|
||||
}
|
||||
|
||||
// addTablePrefix adds prefix string to 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 should be used before any quoting function calls.
|
||||
func addTablePrefix(table, prefix string) string {
|
||||
if prefix == "" {
|
||||
return table
|
||||
}
|
||||
array1 := gstr.SplitAndTrim(table, ",")
|
||||
for k1, v1 := range array1 {
|
||||
array2 := gstr.SplitAndTrim(v1, " ")
|
||||
array2[0] = prefix + array2[0]
|
||||
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{}) {
|
||||
|
||||
@ -24,6 +24,7 @@ import (
|
||||
type Model struct {
|
||||
db DB // Underlying DB interface.
|
||||
tx *TX // Underlying TX interface.
|
||||
schema string // Custom database schema.
|
||||
linkType int // Mark for operation on master or slave.
|
||||
tablesInit string // Table names when model initialization.
|
||||
tables string // Operation table names, which can be more than one table names and aliases, like: "user", "user u", "user u, user_detail ud".
|
||||
@ -67,8 +68,7 @@ const (
|
||||
// The parameter <tables> can be more than one table names, like :
|
||||
// "user", "user u", "user, user_detail", "user u, user_detail ud"
|
||||
func (bs *dbBase) Table(table string) *Model {
|
||||
table = addTablePrefix(table, bs.db.getPrefix())
|
||||
table = bs.db.quoteString(table)
|
||||
table = bs.db.handleTableName(table)
|
||||
return &Model{
|
||||
db: bs.db,
|
||||
tablesInit: table,
|
||||
@ -81,8 +81,15 @@ func (bs *dbBase) Table(table string) *Model {
|
||||
}
|
||||
}
|
||||
|
||||
// Model is alias of dbBase.Table.
|
||||
// See dbBase.Table.
|
||||
func (bs *dbBase) Model(tables string) *Model {
|
||||
return bs.db.Table(tables)
|
||||
}
|
||||
|
||||
// From is alias of dbBase.Table.
|
||||
// See dbBase.Table.
|
||||
// Deprecated.
|
||||
func (bs *dbBase) From(tables string) *Model {
|
||||
return bs.db.Table(tables)
|
||||
}
|
||||
@ -90,8 +97,7 @@ func (bs *dbBase) From(tables string) *Model {
|
||||
// Table acts like dbBase.Table except it operates on transaction.
|
||||
// See dbBase.Table.
|
||||
func (tx *TX) Table(table string) *Model {
|
||||
table = addTablePrefix(table, tx.db.getPrefix())
|
||||
table = tx.db.quoteString(table)
|
||||
table = tx.db.handleTableName(table)
|
||||
return &Model{
|
||||
db: tx.db,
|
||||
tx: tx,
|
||||
@ -105,8 +111,15 @@ func (tx *TX) Table(table string) *Model {
|
||||
}
|
||||
}
|
||||
|
||||
// Model is alias of tx.Table.
|
||||
// See tx.Table.
|
||||
func (tx *TX) Model(tables string) *Model {
|
||||
return tx.Table(tables)
|
||||
}
|
||||
|
||||
// From is alias of tx.Table.
|
||||
// See tx.Table.
|
||||
// Deprecated.
|
||||
func (tx *TX) From(tables string) *Model {
|
||||
return tx.Table(tables)
|
||||
}
|
||||
@ -125,6 +138,13 @@ func (m *Model) TX(tx *TX) *Model {
|
||||
return model
|
||||
}
|
||||
|
||||
// Schema sets the schema for current operation.
|
||||
func (m *Model) Schema(schema string) *Model {
|
||||
model := m.getModel()
|
||||
model.schema = schema
|
||||
return model
|
||||
}
|
||||
|
||||
// Clone creates and returns a new model which is a clone of current model.
|
||||
// Note that it uses deep-copy for the clone.
|
||||
func (m *Model) Clone() *Model {
|
||||
@ -186,27 +206,21 @@ func (m *Model) getModel() *Model {
|
||||
// LeftJoin does "LEFT JOIN ... ON ..." statement on the model.
|
||||
func (m *Model) LeftJoin(table string, on string) *Model {
|
||||
model := m.getModel()
|
||||
table = addTablePrefix(table, m.db.getPrefix())
|
||||
table = m.db.quoteString(table)
|
||||
model.tables += fmt.Sprintf(" LEFT JOIN %s ON (%s)", table, on)
|
||||
model.tables += fmt.Sprintf(" LEFT JOIN %s ON (%s)", m.db.handleTableName(table), on)
|
||||
return model
|
||||
}
|
||||
|
||||
// RightJoin does "RIGHT JOIN ... ON ..." statement on the model.
|
||||
func (m *Model) RightJoin(table string, on string) *Model {
|
||||
model := m.getModel()
|
||||
table = addTablePrefix(table, m.db.getPrefix())
|
||||
table = m.db.quoteString(table)
|
||||
model.tables += fmt.Sprintf(" RIGHT JOIN %s ON (%s)", table, on)
|
||||
model.tables += fmt.Sprintf(" RIGHT JOIN %s ON (%s)", m.db.handleTableName(table), on)
|
||||
return model
|
||||
}
|
||||
|
||||
// InnerJoin does "INNER JOIN ... ON ..." statement on the model.
|
||||
func (m *Model) InnerJoin(table string, on string) *Model {
|
||||
model := m.getModel()
|
||||
table = addTablePrefix(table, m.db.getPrefix())
|
||||
table = m.db.quoteString(table)
|
||||
model.tables += fmt.Sprintf(" INNER JOIN %s ON (%s)", table, on)
|
||||
model.tables += fmt.Sprintf(" INNER JOIN %s ON (%s)", m.db.handleTableName(table), on)
|
||||
return model
|
||||
}
|
||||
|
||||
@ -501,7 +515,7 @@ func (m *Model) Insert(data ...interface{}) (result sql.Result, err error) {
|
||||
batch = m.batch
|
||||
}
|
||||
return m.db.doBatchInsert(
|
||||
m.getLink(),
|
||||
m.getLink(true),
|
||||
m.tables,
|
||||
m.filterDataForInsertOrUpdate(list),
|
||||
gINSERT_OPTION_DEFAULT,
|
||||
@ -510,7 +524,7 @@ func (m *Model) Insert(data ...interface{}) (result sql.Result, err error) {
|
||||
} else if data, ok := m.data.(Map); ok {
|
||||
// Single insert.
|
||||
return m.db.doInsert(
|
||||
m.getLink(),
|
||||
m.getLink(true),
|
||||
m.tables,
|
||||
m.filterDataForInsertOrUpdate(data),
|
||||
gINSERT_OPTION_DEFAULT,
|
||||
@ -541,7 +555,7 @@ func (m *Model) Replace(data ...interface{}) (result sql.Result, err error) {
|
||||
batch = m.batch
|
||||
}
|
||||
return m.db.doBatchInsert(
|
||||
m.getLink(),
|
||||
m.getLink(true),
|
||||
m.tables,
|
||||
m.filterDataForInsertOrUpdate(list),
|
||||
gINSERT_OPTION_REPLACE,
|
||||
@ -550,7 +564,7 @@ func (m *Model) Replace(data ...interface{}) (result sql.Result, err error) {
|
||||
} else if data, ok := m.data.(Map); ok {
|
||||
// Single insert.
|
||||
return m.db.doInsert(
|
||||
m.getLink(),
|
||||
m.getLink(true),
|
||||
m.tables,
|
||||
m.filterDataForInsertOrUpdate(data),
|
||||
gINSERT_OPTION_REPLACE,
|
||||
@ -584,7 +598,7 @@ func (m *Model) Save(data ...interface{}) (result sql.Result, err error) {
|
||||
batch = m.batch
|
||||
}
|
||||
return m.db.doBatchInsert(
|
||||
m.getLink(),
|
||||
m.getLink(true),
|
||||
m.tables,
|
||||
m.filterDataForInsertOrUpdate(list),
|
||||
gINSERT_OPTION_SAVE,
|
||||
@ -593,7 +607,7 @@ func (m *Model) Save(data ...interface{}) (result sql.Result, err error) {
|
||||
} else if data, ok := m.data.(Map); ok {
|
||||
// Single save.
|
||||
return m.db.doInsert(
|
||||
m.getLink(),
|
||||
m.getLink(true),
|
||||
m.tables,
|
||||
m.filterDataForInsertOrUpdate(data),
|
||||
gINSERT_OPTION_SAVE,
|
||||
@ -627,7 +641,7 @@ func (m *Model) Update(dataAndWhere ...interface{}) (result sql.Result, err erro
|
||||
}
|
||||
condition, conditionArgs := m.formatCondition(false)
|
||||
return m.db.doUpdate(
|
||||
m.getLink(),
|
||||
m.getLink(true),
|
||||
m.tables,
|
||||
m.filterDataForInsertOrUpdate(m.data),
|
||||
condition,
|
||||
@ -648,7 +662,7 @@ func (m *Model) Delete(where ...interface{}) (result sql.Result, err error) {
|
||||
}
|
||||
}()
|
||||
condition, conditionArgs := m.formatCondition(false)
|
||||
return m.db.doDelete(m.getLink(), m.tables, condition, conditionArgs...)
|
||||
return m.db.doDelete(m.getLink(true), m.tables, condition, conditionArgs...)
|
||||
}
|
||||
|
||||
// Select is alias of Model.All.
|
||||
@ -881,6 +895,15 @@ func (m *Model) FindCount(where ...interface{}) (int, error) {
|
||||
return m.Count()
|
||||
}
|
||||
|
||||
// FindScan retrieves and returns the record/records by Model.WherePri and Model.Scan.
|
||||
// Also see Model.WherePri and Model.Scan.
|
||||
func (m *Model) FindScan(pointer interface{}, where ...interface{}) error {
|
||||
if len(where) > 0 {
|
||||
return m.WherePri(where[0], where[1:]...).Scan(pointer)
|
||||
}
|
||||
return m.Scan(pointer)
|
||||
}
|
||||
|
||||
// Chunk iterates the table with given size and callback function.
|
||||
func (m *Model) Chunk(limit int, callback func(result Result, err error) bool) {
|
||||
page := m.start
|
||||
@ -926,7 +949,7 @@ func (m *Model) filterDataForInsertOrUpdate(data interface{}) interface{} {
|
||||
// Note that, it does not filter list item, which is also type of map, for "omit empty" feature.
|
||||
func (m *Model) doFilterDataMapForInsertOrUpdate(data Map, allowOmitEmpty bool) Map {
|
||||
if m.filter {
|
||||
data = m.db.filterFields(m.tables, data)
|
||||
data = m.db.filterFields(m.schema, m.tables, data)
|
||||
}
|
||||
// Remove key-value pairs of which the value is empty.
|
||||
if allowOmitEmpty && m.option&OPTION_OMITEMPTY > 0 {
|
||||
@ -953,16 +976,25 @@ func (m *Model) doFilterDataMapForInsertOrUpdate(data Map, allowOmitEmpty bool)
|
||||
}
|
||||
|
||||
// getLink returns the underlying database link object with configured <linkType> attribute.
|
||||
func (m *Model) getLink() dbLink {
|
||||
// The parameter <master> specifies whether using the master node if master-slave configured.
|
||||
func (m *Model) getLink(master bool) dbLink {
|
||||
if m.tx != nil {
|
||||
return m.tx.tx
|
||||
}
|
||||
switch m.linkType {
|
||||
linkType := m.linkType
|
||||
if linkType == 0 {
|
||||
if master {
|
||||
linkType = gLINK_TYPE_MASTER
|
||||
} else {
|
||||
linkType = gLINK_TYPE_SLAVE
|
||||
}
|
||||
}
|
||||
switch linkType {
|
||||
case gLINK_TYPE_MASTER:
|
||||
link, _ := m.db.Master()
|
||||
link, _ := m.db.getMaster(m.schema)
|
||||
return link
|
||||
case gLINK_TYPE_SLAVE:
|
||||
link, _ := m.db.Slave()
|
||||
link, _ := m.db.getSlave(m.schema)
|
||||
return link
|
||||
}
|
||||
return nil
|
||||
@ -981,7 +1013,7 @@ func (m *Model) getAll(query string, args ...interface{}) (result Result, err er
|
||||
return v.(Result), nil
|
||||
}
|
||||
}
|
||||
result, err = m.db.doGetAll(m.getLink(), query, args...)
|
||||
result, err = m.db.doGetAll(m.getLink(false), query, args...)
|
||||
// Cache the result.
|
||||
if len(cacheKey) > 0 && err == nil {
|
||||
if m.cacheDuration < 0 {
|
||||
|
||||
@ -3,11 +3,11 @@
|
||||
// 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.
|
||||
// 说明:
|
||||
// 1.需要导入sqlserver驱动: github.com/denisenkom/go-mssqldb
|
||||
// 2.不支持save/replace方法
|
||||
// 3.不支持LastInsertId方法
|
||||
//
|
||||
// Note:
|
||||
// 1. It needs manually import: _ "github.com/lib/pq"
|
||||
// 2. It does not support Save/Replace features.
|
||||
// 3. It does not support LastInsertId.
|
||||
|
||||
package gdb
|
||||
|
||||
@ -20,19 +20,19 @@ import (
|
||||
"github.com/gogf/gf/text/gregex"
|
||||
)
|
||||
|
||||
// 数据库链接对象
|
||||
type dbMssql struct {
|
||||
*dbBase
|
||||
}
|
||||
|
||||
// 创建SQL操作对象
|
||||
func (db *dbMssql) Open(config *ConfigNode) (*sql.DB, error) {
|
||||
source := ""
|
||||
if config.LinkInfo != "" {
|
||||
source = config.LinkInfo
|
||||
} else {
|
||||
source = fmt.Sprintf("user id=%s;password=%s;server=%s;port=%s;database=%s;encrypt=disable",
|
||||
config.User, config.Pass, config.Host, config.Port, config.Name)
|
||||
source = fmt.Sprintf(
|
||||
"user id=%s;password=%s;server=%s;port=%s;database=%s;encrypt=disable",
|
||||
config.User, config.Pass, config.Host, config.Port, config.Name,
|
||||
)
|
||||
}
|
||||
if db, err := sql.Open("sqlserver", source); err == nil {
|
||||
return db, nil
|
||||
@ -41,76 +41,68 @@ func (db *dbMssql) Open(config *ConfigNode) (*sql.DB, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// 获得关键字操作符
|
||||
func (db *dbMssql) getChars() (charLeft string, charRight string) {
|
||||
return "\"", "\""
|
||||
}
|
||||
|
||||
// 在执行sql之前对sql进行进一步处理
|
||||
func (db *dbMssql) handleSqlBeforeExec(query string) string {
|
||||
index := 0
|
||||
str, _ := gregex.ReplaceStringFunc("\\?", query, func(s string) string {
|
||||
index++
|
||||
return fmt.Sprintf("@p%d", index)
|
||||
})
|
||||
|
||||
str, _ = gregex.ReplaceString("\"", "", str)
|
||||
|
||||
return db.parseSql(str)
|
||||
}
|
||||
|
||||
//将MYSQL的SQL语法转换为MSSQL的语法
|
||||
//1.由于mssql不支持limit写法所以需要对mysql中的limit用法做转换
|
||||
func (db *dbMssql) parseSql(sql string) string {
|
||||
//下面的正则表达式匹配出SELECT和INSERT的关键字后分别做不同的处理,如有LIMIT则将LIMIT的关键字也匹配出
|
||||
// SELECT * FROM USER WHERE ID=1 LIMIT 1
|
||||
if m, _ := gregex.MatchString(`^SELECT(.+)LIMIT 1$`, sql); len(m) > 1 {
|
||||
return fmt.Sprintf(`SELECT TOP 1 %s`, m[1])
|
||||
}
|
||||
// SELECT * FROM USER WHERE AGE>18 ORDER BY ID DESC LIMIT 100, 200
|
||||
patten := `^\s*(?i)(SELECT)|(LIMIT\s*(\d+)\s*,\s*(\d+))`
|
||||
if gregex.IsMatchString(patten, sql) == false {
|
||||
//fmt.Println("not matched..")
|
||||
return sql
|
||||
}
|
||||
|
||||
res, err := gregex.MatchAllString(patten, sql)
|
||||
if err != nil {
|
||||
//fmt.Println("MatchString error.", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
index := 0
|
||||
keyword := strings.TrimSpace(res[index][0])
|
||||
keyword = strings.ToUpper(keyword)
|
||||
|
||||
index++
|
||||
switch keyword {
|
||||
case "SELECT":
|
||||
//不含LIMIT关键字则不处理
|
||||
if len(res) < 2 || (strings.HasPrefix(res[index][0], "LIMIT") == false && strings.HasPrefix(res[index][0], "limit") == false) {
|
||||
// 不含LIMIT关键字则不处理
|
||||
if len(res) < 2 ||
|
||||
(strings.HasPrefix(res[index][0], "LIMIT") == false &&
|
||||
strings.HasPrefix(res[index][0], "limit") == false) {
|
||||
break
|
||||
}
|
||||
|
||||
//不含LIMIT则不处理
|
||||
// 不含LIMIT则不处理
|
||||
if gregex.IsMatchString("((?i)SELECT)(.+)((?i)LIMIT)", sql) == false {
|
||||
break
|
||||
}
|
||||
|
||||
//判断SQL中是否含有order by
|
||||
// 判断SQL中是否含有order by
|
||||
selectStr := ""
|
||||
orderbyStr := ""
|
||||
haveOrderby := gregex.IsMatchString("((?i)SELECT)(.+)((?i)ORDER BY)", sql)
|
||||
if haveOrderby {
|
||||
//取order by 前面的字符串
|
||||
orderStr := ""
|
||||
haveOrder := gregex.IsMatchString("((?i)SELECT)(.+)((?i)ORDER BY)", sql)
|
||||
if haveOrder {
|
||||
// 取order by 前面的字符串
|
||||
queryExpr, _ := gregex.MatchString("((?i)SELECT)(.+)((?i)ORDER BY)", sql)
|
||||
|
||||
if len(queryExpr) != 4 || strings.EqualFold(queryExpr[1], "SELECT") == false || strings.EqualFold(queryExpr[3], "ORDER BY") == false {
|
||||
break
|
||||
}
|
||||
selectStr = queryExpr[2]
|
||||
|
||||
//取order by表达式的值
|
||||
orderbyExpr, _ := gregex.MatchString("((?i)ORDER BY)(.+)((?i)LIMIT)", sql)
|
||||
if len(orderbyExpr) != 4 || strings.EqualFold(orderbyExpr[1], "ORDER BY") == false || strings.EqualFold(orderbyExpr[3], "LIMIT") == false {
|
||||
// 取order by表达式的值
|
||||
orderExpr, _ := gregex.MatchString("((?i)ORDER BY)(.+)((?i)LIMIT)", sql)
|
||||
if len(orderExpr) != 4 || strings.EqualFold(orderExpr[1], "ORDER BY") == false || strings.EqualFold(orderExpr[3], "LIMIT") == false {
|
||||
break
|
||||
}
|
||||
orderbyStr = orderbyExpr[2]
|
||||
orderStr = orderExpr[2]
|
||||
} else {
|
||||
queryExpr, _ := gregex.MatchString("((?i)SELECT)(.+)((?i)LIMIT)", sql)
|
||||
if len(queryExpr) != 4 || strings.EqualFold(queryExpr[1], "SELECT") == false || strings.EqualFold(queryExpr[3], "LIMIT") == false {
|
||||
@ -119,7 +111,7 @@ func (db *dbMssql) parseSql(sql string) string {
|
||||
selectStr = queryExpr[2]
|
||||
}
|
||||
|
||||
//取limit后面的取值范围
|
||||
// 取limit后面的取值范围
|
||||
first, limit := 0, 0
|
||||
for i := 1; i < len(res[index]); i++ {
|
||||
if len(strings.TrimSpace(res[index][i])) == 0 {
|
||||
@ -133,53 +125,69 @@ func (db *dbMssql) parseSql(sql string) string {
|
||||
}
|
||||
}
|
||||
|
||||
if haveOrderby {
|
||||
sql = fmt.Sprintf("SELECT * FROM (SELECT ROW_NUMBER() OVER (ORDER BY %s) as ROWNUMBER_, %s ) as TMP_ WHERE TMP_.ROWNUMBER_ > %d AND TMP_.ROWNUMBER_ <= %d", orderbyStr, selectStr, first, limit)
|
||||
if haveOrder {
|
||||
sql = fmt.Sprintf(
|
||||
"SELECT * FROM "+
|
||||
"(SELECT ROW_NUMBER() OVER (ORDER BY %s) as ROWNUMBER_, %s ) as TMP_ "+
|
||||
"WHERE TMP_.ROWNUMBER_ > %d AND TMP_.ROWNUMBER_ <= %d",
|
||||
orderStr, selectStr, first, limit,
|
||||
)
|
||||
} else {
|
||||
if first == 0 {
|
||||
first = limit
|
||||
} else {
|
||||
first = limit - first
|
||||
}
|
||||
sql = fmt.Sprintf("SELECT * FROM (SELECT TOP %d * FROM (SELECT TOP %d %s) as TMP1_ ) as TMP2_ ", first, limit, selectStr)
|
||||
sql = fmt.Sprintf(
|
||||
"SELECT * FROM (SELECT TOP %d * FROM (SELECT TOP %d %s) as TMP1_ ) as TMP2_ ",
|
||||
first, limit, selectStr,
|
||||
)
|
||||
}
|
||||
default:
|
||||
}
|
||||
return sql
|
||||
}
|
||||
|
||||
// 返回当前数据库所有的数据表名称
|
||||
// TODO
|
||||
func (bs *dbMssql) Tables() (tables []string, err error) {
|
||||
func (db *dbMssql) Tables(schema ...string) (tables []string, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// 获得指定表表的数据结构,构造成map哈希表返回,其中键名为表字段名称,键值暂无用途(默认为字段数据类型).
|
||||
func (db *dbMssql) TableFields(table string) (fields map[string]*TableField, err error) {
|
||||
// 缓存不存在时会查询数据表结构,缓存后不过期,直至程序重启(重新部署)
|
||||
v := db.cache.GetOrSetFunc("mssql_table_fields_"+table, func() interface{} {
|
||||
result := (Result)(nil)
|
||||
result, err = db.GetAll(fmt.Sprintf(`
|
||||
SELECT c.name as FIELD, CASE t.name
|
||||
WHEN 'numeric' THEN t.name + '(' + convert(varchar(20),c.xprec) + ',' + convert(varchar(20),c.xscale) + ')'
|
||||
WHEN 'char' THEN t.name + '(' + convert(varchar(20),c.length)+ ')'
|
||||
WHEN 'varchar' THEN t.name + '(' + convert(varchar(20),c.length)+ ')'
|
||||
ELSE t.name + '(' + convert(varchar(20),c.length)+ ')' END as TYPE
|
||||
FROM systypes t,syscolumns c WHERE t.xtype=c.xtype AND c.id = (SELECT id FROM sysobjects WHERE name='%s') ORDER BY c.colid`, strings.ToUpper(table)))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
fields = make(map[string]*TableField)
|
||||
for i, m := range result {
|
||||
// SQLServer返回的field为大写的需要转为小写的
|
||||
fields[strings.ToLower(m["FIELD"].String())] = &TableField{
|
||||
Index: i,
|
||||
Name: strings.ToLower(m["FIELD"].String()),
|
||||
Type: strings.ToLower(m["TYPE"].String()),
|
||||
func (db *dbMssql) TableFields(table string, schema ...string) (fields map[string]*TableField, err error) {
|
||||
checkSchema := db.schema.Val()
|
||||
if len(schema) > 0 && schema[0] != "" {
|
||||
checkSchema = schema[0]
|
||||
}
|
||||
v := db.cache.GetOrSetFunc(
|
||||
fmt.Sprintf(`mssql_table_fields_%s_%s`, table, checkSchema), func() interface{} {
|
||||
var result Result
|
||||
var link *sql.DB
|
||||
link, err = db.getSlave(checkSchema)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fields
|
||||
}, 0)
|
||||
result, err = db.doGetAll(link, fmt.Sprintf(`
|
||||
SELECT c.name as FIELD, CASE t.name
|
||||
WHEN 'numeric' THEN t.name + '(' + convert(varchar(20),c.xprec) + ',' + convert(varchar(20),c.xscale) + ')'
|
||||
WHEN 'char' THEN t.name + '(' + convert(varchar(20),c.length)+ ')'
|
||||
WHEN 'varchar' THEN t.name + '(' + convert(varchar(20),c.length)+ ')'
|
||||
ELSE t.name + '(' + convert(varchar(20),c.length)+ ')' END as TYPE
|
||||
FROM systypes t,syscolumns c WHERE t.xtype=c.xtype
|
||||
AND c.id = (SELECT id FROM sysobjects WHERE name='%s')
|
||||
ORDER BY c.colid`, strings.ToUpper(table)))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
fields = make(map[string]*TableField)
|
||||
for i, m := range result {
|
||||
fields[strings.ToLower(m["FIELD"].String())] = &TableField{
|
||||
Index: i,
|
||||
Name: strings.ToLower(m["FIELD"].String()),
|
||||
Type: strings.ToLower(m["TYPE"].String()),
|
||||
}
|
||||
}
|
||||
return fields
|
||||
}, 0)
|
||||
if err == nil {
|
||||
fields = v.(map[string]*TableField)
|
||||
}
|
||||
|
||||
@ -13,19 +13,20 @@ import (
|
||||
_ "github.com/gf-third/mysql"
|
||||
)
|
||||
|
||||
// 数据库链接对象
|
||||
type dbMysql struct {
|
||||
*dbBase
|
||||
}
|
||||
|
||||
// 创建SQL操作对象,内部采用了lazy link处理
|
||||
// Open creates and returns a underlying database connection with given configuration.
|
||||
func (db *dbMysql) Open(config *ConfigNode) (*sql.DB, error) {
|
||||
var source string
|
||||
if config.LinkInfo != "" {
|
||||
source = config.LinkInfo
|
||||
} else {
|
||||
source = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=%s&multiStatements=true&parseTime=true&loc=Local",
|
||||
config.User, config.Pass, config.Host, config.Port, config.Name, config.Charset)
|
||||
source = fmt.Sprintf(
|
||||
"%s:%s@tcp(%s:%s)/%s?charset=%s&multiStatements=true&parseTime=true&loc=Local",
|
||||
config.User, config.Pass, config.Host, config.Port, config.Name, config.Charset,
|
||||
)
|
||||
}
|
||||
if db, err := sql.Open("gf-mysql", source); err == nil {
|
||||
return db, nil
|
||||
@ -34,12 +35,12 @@ func (db *dbMysql) Open(config *ConfigNode) (*sql.DB, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// 获得关键字操作符
|
||||
// getChars returns the quote chars for field.
|
||||
func (db *dbMysql) getChars() (charLeft string, charRight string) {
|
||||
return "`", "`"
|
||||
}
|
||||
|
||||
// 在执行sql之前对sql进行进一步处理
|
||||
func (db *dbMysql) handleSqlBeforeExec(query string) string {
|
||||
return query
|
||||
// handleSqlBeforeExec handles the sql before posts it to database.
|
||||
func (db *dbMysql) handleSqlBeforeExec(sql string) string {
|
||||
return sql
|
||||
}
|
||||
|
||||
@ -3,10 +3,11 @@
|
||||
// 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.
|
||||
// 说明:
|
||||
// 1.需要导入oracle驱动: github.com/mattn/go-oci8
|
||||
// 2.不支持save/replace方法,可以调用这2个方法估计会报错,还没测试过,(应该是可以通过oracle的merge来实现这2个功能的,还没仔细研究)
|
||||
// 3.不支持LastInsertId方法
|
||||
//
|
||||
// Note:
|
||||
// 1. It needs manually import: _ "github.com/mattn/go-oci8"
|
||||
// 2. It does not support Save/Replace features.
|
||||
// 3. It does not support LastInsertId.
|
||||
|
||||
package gdb
|
||||
|
||||
@ -21,7 +22,6 @@ import (
|
||||
"github.com/gogf/gf/text/gregex"
|
||||
)
|
||||
|
||||
// 数据库链接对象
|
||||
type dbOracle struct {
|
||||
*dbBase
|
||||
}
|
||||
@ -31,7 +31,6 @@ const (
|
||||
tableAlias2 = "GFORM2"
|
||||
)
|
||||
|
||||
// 创建SQL操作对象
|
||||
func (db *dbOracle) Open(config *ConfigNode) (*sql.DB, error) {
|
||||
var source string
|
||||
if config.LinkInfo != "" {
|
||||
@ -46,36 +45,28 @@ func (db *dbOracle) Open(config *ConfigNode) (*sql.DB, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// 获得关键字操作符
|
||||
func (db *dbOracle) getChars() (charLeft string, charRight string) {
|
||||
return "\"", "\""
|
||||
}
|
||||
|
||||
// 在执行sql之前对sql进行进一步处理
|
||||
func (db *dbOracle) handleSqlBeforeExec(query string) string {
|
||||
index := 0
|
||||
str, _ := gregex.ReplaceStringFunc("\\?", query, func(s string) string {
|
||||
index++
|
||||
return fmt.Sprintf(":%d", index)
|
||||
})
|
||||
|
||||
str, _ = gregex.ReplaceString("\"", "", str)
|
||||
|
||||
return db.parseSql(str)
|
||||
}
|
||||
|
||||
//由于ORACLE中对LIMIT和批量插入的语法与MYSQL不一致,所以这里需要对LIMIT和批量插入做语法上的转换
|
||||
func (db *dbOracle) parseSql(sql string) string {
|
||||
//下面的正则表达式匹配出SELECT和INSERT的关键字后分别做不同的处理,如有LIMIT则将LIMIT的关键字也匹配出
|
||||
patten := `^\s*(?i)(SELECT)|(LIMIT\s*(\d+)\s*,\s*(\d+))`
|
||||
if gregex.IsMatchString(patten, sql) == false {
|
||||
//fmt.Println("not matched..")
|
||||
return sql
|
||||
}
|
||||
|
||||
res, err := gregex.MatchAllString(patten, sql)
|
||||
if err != nil {
|
||||
//fmt.Println("MatchString error.", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
@ -86,12 +77,12 @@ func (db *dbOracle) parseSql(sql string) string {
|
||||
index++
|
||||
switch keyword {
|
||||
case "SELECT":
|
||||
//不含LIMIT关键字则不处理
|
||||
// 不含LIMIT关键字则不处理
|
||||
if len(res) < 2 || (strings.HasPrefix(res[index][0], "LIMIT") == false && strings.HasPrefix(res[index][0], "limit") == false) {
|
||||
break
|
||||
}
|
||||
|
||||
//取limit前面的字符串
|
||||
// 取limit前面的字符串
|
||||
if gregex.IsMatchString("((?i)SELECT)(.+)((?i)LIMIT)", sql) == false {
|
||||
break
|
||||
}
|
||||
@ -101,7 +92,7 @@ func (db *dbOracle) parseSql(sql string) string {
|
||||
break
|
||||
}
|
||||
|
||||
//取limit后面的取值范围
|
||||
// 取limit后面的取值范围
|
||||
first, limit := 0, 0
|
||||
for i := 1; i < len(res[index]); i++ {
|
||||
if len(strings.TrimSpace(res[index][i])) == 0 {
|
||||
@ -121,38 +112,39 @@ func (db *dbOracle) parseSql(sql string) string {
|
||||
return sql
|
||||
}
|
||||
|
||||
// 返回当前数据库所有的数据表名称
|
||||
// TODO
|
||||
func (bs *dbOracle) Tables() (tables []string, err error) {
|
||||
func (db *dbOracle) Tables(schema ...string) (tables []string, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// 获得指定表表的数据结构,构造成map哈希表返回,其中键名为表字段名称,键值为字段数据结构.
|
||||
func (db *dbOracle) TableFields(table string) (fields map[string]*TableField, err error) {
|
||||
// 缓存不存在时会查询数据表结构,缓存后不过期,直至程序重启(重新部署)
|
||||
v := db.cache.GetOrSetFunc("oracle_table_fields_"+table, func() interface{} {
|
||||
result := (Result)(nil)
|
||||
result, err = db.GetAll(fmt.Sprintf(`
|
||||
SELECT COLUMN_NAME AS FIELD, CASE DATA_TYPE
|
||||
WHEN 'NUMBER' THEN DATA_TYPE||'('||DATA_PRECISION||','||DATA_SCALE||')'
|
||||
WHEN 'FLOAT' THEN DATA_TYPE||'('||DATA_PRECISION||','||DATA_SCALE||')'
|
||||
ELSE DATA_TYPE||'('||DATA_LENGTH||')' END AS TYPE
|
||||
FROM USER_TAB_COLUMNS WHERE TABLE_NAME = '%s' ORDER BY COLUMN_ID`, strings.ToUpper(table)))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
fields = make(map[string]*TableField)
|
||||
for i, m := range result {
|
||||
// ORACLE返回的值默认都是大写的,需要转为小写
|
||||
fields[strings.ToLower(m["FIELD"].String())] = &TableField{
|
||||
Index: i,
|
||||
Name: strings.ToLower(m["FIELD"].String()),
|
||||
Type: strings.ToLower(m["TYPE"].String()),
|
||||
func (db *dbOracle) TableFields(table string, schema ...string) (fields map[string]*TableField, err error) {
|
||||
checkSchema := db.schema.Val()
|
||||
if len(schema) > 0 && schema[0] != "" {
|
||||
checkSchema = schema[0]
|
||||
}
|
||||
v := db.cache.GetOrSetFunc(
|
||||
fmt.Sprintf(`oracle_table_fields_%s_%s`, table, checkSchema),
|
||||
func() interface{} {
|
||||
result := (Result)(nil)
|
||||
result, err = db.GetAll(fmt.Sprintf(`
|
||||
SELECT COLUMN_NAME AS FIELD, CASE DATA_TYPE
|
||||
WHEN 'NUMBER' THEN DATA_TYPE||'('||DATA_PRECISION||','||DATA_SCALE||')'
|
||||
WHEN 'FLOAT' THEN DATA_TYPE||'('||DATA_PRECISION||','||DATA_SCALE||')'
|
||||
ELSE DATA_TYPE||'('||DATA_LENGTH||')' END AS TYPE
|
||||
FROM USER_TAB_COLUMNS WHERE TABLE_NAME = '%s' ORDER BY COLUMN_ID`, strings.ToUpper(table)))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fields
|
||||
}, 0)
|
||||
fields = make(map[string]*TableField)
|
||||
for i, m := range result {
|
||||
fields[strings.ToLower(m["FIELD"].String())] = &TableField{
|
||||
Index: i,
|
||||
Name: strings.ToLower(m["FIELD"].String()),
|
||||
Type: strings.ToLower(m["TYPE"].String()),
|
||||
}
|
||||
}
|
||||
return fields
|
||||
}, 0)
|
||||
if err == nil {
|
||||
fields = v.(map[string]*TableField)
|
||||
}
|
||||
|
||||
@ -3,6 +3,11 @@
|
||||
// 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.
|
||||
//
|
||||
// Note:
|
||||
// 1. It needs manually import: _ "github.com/lib/pq"
|
||||
// 2. It does not support Save/Replace features.
|
||||
// 3. It does not support LastInsertId.
|
||||
|
||||
package gdb
|
||||
|
||||
@ -14,26 +19,19 @@ import (
|
||||
"github.com/gogf/gf/text/gregex"
|
||||
)
|
||||
|
||||
// PostgreSQL的适配.
|
||||
//
|
||||
// 使用时需要import:
|
||||
//
|
||||
// _ "github.com/lib/pq"
|
||||
//
|
||||
// @todo 需要完善replace和save的操作覆盖
|
||||
|
||||
// 数据库链接对象
|
||||
type dbPgsql struct {
|
||||
*dbBase
|
||||
}
|
||||
|
||||
// 创建SQL操作对象,内部采用了lazy link处理
|
||||
func (db *dbPgsql) Open(config *ConfigNode) (*sql.DB, error) {
|
||||
var source string
|
||||
if config.LinkInfo != "" {
|
||||
source = config.LinkInfo
|
||||
} else {
|
||||
source = fmt.Sprintf("user=%s password=%s host=%s port=%s dbname=%s sslmode=disable", config.User, config.Pass, config.Host, config.Port, config.Name)
|
||||
source = fmt.Sprintf(
|
||||
"user=%s password=%s host=%s port=%s dbname=%s sslmode=disable",
|
||||
config.User, config.Pass, config.Host, config.Port, config.Name,
|
||||
)
|
||||
}
|
||||
if db, err := sql.Open("postgres", source); err == nil {
|
||||
return db, nil
|
||||
@ -42,59 +40,58 @@ func (db *dbPgsql) Open(config *ConfigNode) (*sql.DB, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// 动态切换数据库
|
||||
func (db *dbPgsql) setSchema(sqlDb *sql.DB, schema string) error {
|
||||
_, err := sqlDb.Exec("SET search_path TO " + schema)
|
||||
return err
|
||||
}
|
||||
|
||||
// 获得关键字操作符
|
||||
func (db *dbPgsql) getChars() (charLeft string, charRight string) {
|
||||
return "\"", "\""
|
||||
}
|
||||
|
||||
// 在执行sql之前对sql进行进一步处理
|
||||
func (db *dbPgsql) handleSqlBeforeExec(query string) string {
|
||||
func (db *dbPgsql) handleSqlBeforeExec(sql string) string {
|
||||
index := 0
|
||||
query, _ = gregex.ReplaceStringFunc("\\?", query, func(s string) string {
|
||||
sql, _ = gregex.ReplaceStringFunc("\\?", sql, func(s string) string {
|
||||
index++
|
||||
return fmt.Sprintf("$%d", index)
|
||||
})
|
||||
// 分页语法替换
|
||||
query, _ = gregex.ReplaceString(` LIMIT (\d+),\s*(\d+)`, ` LIMIT $1 OFFSET $2`, query)
|
||||
return query
|
||||
sql, _ = gregex.ReplaceString(` LIMIT (\d+),\s*(\d+)`, ` LIMIT $1 OFFSET $2`, sql)
|
||||
return sql
|
||||
}
|
||||
|
||||
// 返回当前数据库所有的数据表名称
|
||||
// TODO
|
||||
func (bs *dbPgsql) Tables() (tables []string, err error) {
|
||||
func (db *dbPgsql) Tables(schema ...string) (tables []string, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// 获得指定表表的数据结构,构造成map哈希表返回,其中键名为表字段名称,键值为字段数据结构.
|
||||
func (db *dbPgsql) TableFields(table string) (fields map[string]*TableField, err error) {
|
||||
// 缓存不存在时会查询数据表结构,缓存后不过期,直至程序重启(重新部署)
|
||||
func (db *dbPgsql) TableFields(table string, schema ...string) (fields map[string]*TableField, err error) {
|
||||
table, _ = gregex.ReplaceString("\"", "", table)
|
||||
v := db.cache.GetOrSetFunc("pgsql_table_fields_"+table, func() interface{} {
|
||||
result := (Result)(nil)
|
||||
result, err = db.GetAll(fmt.Sprintf(`
|
||||
SELECT a.attname AS field, t.typname AS type FROM pg_class c, pg_attribute a
|
||||
LEFT OUTER JOIN pg_description b ON a.attrelid=b.objoid AND a.attnum = b.objsubid,pg_type t
|
||||
WHERE c.relname = '%s' and a.attnum > 0 and a.attrelid = c.oid and a.atttypid = t.oid ORDER BY a.attnum`, strings.ToLower(table)))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
fields = make(map[string]*TableField)
|
||||
for i, m := range result {
|
||||
fields[m["field"].String()] = &TableField{
|
||||
Index: i,
|
||||
Name: m["field"].String(),
|
||||
Type: m["type"].String(),
|
||||
checkSchema := db.schema.Val()
|
||||
if len(schema) > 0 && schema[0] != "" {
|
||||
checkSchema = schema[0]
|
||||
}
|
||||
v := db.cache.GetOrSetFunc(
|
||||
fmt.Sprintf(`pgsql_table_fields_%s_%s`, table, checkSchema), func() interface{} {
|
||||
var result Result
|
||||
var link *sql.DB
|
||||
link, err = db.getSlave(checkSchema)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fields
|
||||
}, 0)
|
||||
result, err = db.doGetAll(link, fmt.Sprintf(`
|
||||
SELECT a.attname AS field, t.typname AS type FROM pg_class c, pg_attribute a
|
||||
LEFT OUTER JOIN pg_description b ON a.attrelid=b.objoid AND a.attnum = b.objsubid,pg_type t
|
||||
WHERE c.relname = '%s' and a.attnum > 0 and a.attrelid = c.oid and a.atttypid = t.oid
|
||||
ORDER BY a.attnum`, strings.ToLower(table)))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
fields = make(map[string]*TableField)
|
||||
for i, m := range result {
|
||||
fields[m["field"].String()] = &TableField{
|
||||
Index: i,
|
||||
Name: m["field"].String(),
|
||||
Type: m["type"].String(),
|
||||
}
|
||||
}
|
||||
return fields
|
||||
}, 0)
|
||||
if err == nil {
|
||||
fields = v.(map[string]*TableField)
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user