package application
import (
"database/sql"
"errors"
"fmt"
"reflect"
"runtime"
"strings"
"sync"
)
// 将结果scan至结构体,copy至 sqlx库: https://github.com/jmoiron/sqlx
func scanAll(rows *sql.Rows, dest interface{}, structOnly bool) error {
var v, vp reflect.Value
value := reflect.ValueOf(dest)
// json.Unmarshal returns errors for these
if value.Kind() != reflect.Ptr {
return errors.New("must pass a pointer, not a value, to StructScan destination")
}
if value.IsNil() {
return errors.New("nil pointer passed to StructScan destination")
}
direct := reflect.Indirect(value)
slice, err := baseType(value.Type(), reflect.Slice)
if err != nil {
return err
}
direct.SetLen(0)
isPtr := slice.Elem().Kind() == reflect.Ptr
base := Deref(slice.Elem())
scannable := isScannable(base)
if structOnly && scannable {
return structOnlyError(base)
}
columns, err := rows.Columns()
if err != nil {
return err
}
// if it's a base type make sure it only has 1 column; if not return an error
if scannable && len(columns) > 1 {
return fmt.Errorf("non-struct dest type %s with >1 columns (%d)", base.Kind(), len(columns))
}
if !scannable {
var values []interface{}
var m *Mapper = mapper()
fields := m.TraversalsByName(base, columns)
// if we are not unsafe and are missing fields, return an error
if f, err := missingFields(fields); err != nil {
return fmt.Errorf("missing destination name %s in %T", columns[f], dest)
}
values = make([]interface{}, len(columns))
for rows.Next() {
// create a new struct type (which returns PtrTo) and indirect it
vp = reflect.New(base)
v = reflect.Indirect(vp)
err = fieldsByTraversal(v, fields, values, true)
if err != nil {
return err
}
// scan into the struct field pointers and append to our results
err = rows.Scan(values...)
if err != nil {
return err
}
if isPtr {
direct.Set(reflect.Append(direct, vp))
} else {
direct.Set(reflect.Append(direct, v))
}
}
} else {
for rows.Next() {
vp = reflect.New(base)
err = rows.Scan(vp.Interface())
if err != nil {
return err
}
// append
if isPtr {
direct.Set(reflect.Append(direct, vp))
} else {
direct.Set(reflect.Append(direct, reflect.Indirect(vp)))
}
}
}
return rows.Err()
}
func baseType(t reflect.Type, expected reflect.Kind) (reflect.Type, error) {
t = Deref(t)
if t.Kind() != expected {
return nil, fmt.Errorf("expected %s but got %s", expected, t.Kind())
}
return t, nil
}
// structOnlyError returns an error appropriate for type when a non-scannable
// struct is expected but something else is given
func structOnlyError(t reflect.Type) error {
isStruct := t.Kind() == reflect.Struct
isScanner := reflect.PtrTo(t).Implements(_scannerInterface)
if !isStruct {
return fmt.Errorf("expected %s but got %s", reflect.Struct, t.Kind())
}
if isScanner {
return fmt.Errorf("structscan expects a struct dest but the provided struct type %s implements scanner", t.Name())
}
return fmt.Errorf("expected a struct, but struct %s has no exported fields", t.Name())
}
var _scannerInterface = reflect.TypeOf((*sql.Scanner)(nil)).Elem()
func isScannable(t reflect.Type) bool {
if reflect.PtrTo(t).Implements(_scannerInterface) {
return true
}
if t.Kind() != reflect.Struct {
return true
}
// it's not important that we use the right mapper for this particular object,
// we're only concerned on how many exported fields this struct has
return len(mapper().TypeMap(t).Index) == 0
}
var NameMapper = strings.ToLower
var origMapper = reflect.ValueOf(NameMapper)
// Rather than creating on init, this is created when necessary so that
// importers have time to customize the NameMapper.
var mpr *Mapper
// mprMu protects mpr.
var mprMu sync.Mutex
// mapper returns a valid mapper using the configured NameMapper func.
func mapper() *Mapper {
mprMu.Lock()
defer mprMu.Unlock()
if mpr == nil {
mpr = NewMapperFunc("db", NameMapper)
} else if origMapper != reflect.ValueOf(NameMapper) {
// if NameMapper has changed, create a new mapper
mpr = NewMapperFunc("db", NameMapper)
origMapper = reflect.ValueOf(NameMapper)
}
return mpr
}
func missingFields(transversals [][]int) (field int, err error) {
for i, t := range transversals {
if len(t) == 0 {
return i, errors.New("missing field")
}
}
return 0, nil
}
// fieldsByName fills a values interface with fields from the passed value based
// on the traversals in int. If ptrs is true, return addresses instead of values.
// We write this instead of using FieldsByName to save allocations and map lookups
// when iterating over many rows. Empty traversals will get an interface pointer.
// Because of the necessity of requesting ptrs or values, it's considered a bit too
// specialized for inclusion in reflectx itself.
func fieldsByTraversal(v reflect.Value, traversals [][]int, values []interface{}, ptrs bool) error {
v = reflect.Indirect(v)
if v.Kind() != reflect.Struct {
return errors.New("argument not a struct")
}
for i, traversal := range traversals {
if len(traversal) == 0 {
values[i] = new(interface{})
continue
}
f := FieldByIndexes(v, traversal)
if ptrs {
values[i] = f.Addr().Interface()
} else {
values[i] = f.Interface()
}
}
return nil
}
// A FieldInfo is metadata for a struct field.
type FieldInfo struct {
Index []int
Path string
Field reflect.StructField
Zero reflect.Value
Name string
Options map[string]string
Embedded bool
Children []*FieldInfo
Parent *FieldInfo
}
// A StructMap is an index of field metadata for a struct.
type StructMap struct {
Tree *FieldInfo
Index []*FieldInfo
Paths map[string]*FieldInfo
Names map[string]*FieldInfo
}
// GetByPath returns a *FieldInfo for a given string path.
func (f StructMap) GetByPath(path string) *FieldInfo {
return f.Paths[path]
}
// GetByTraversal returns a *FieldInfo for a given integer path. It is
// analogous to reflect.FieldByIndex, but using the cached traversal
// rather than re-executing the reflect machinery each time.
func (f StructMap) GetByTraversal(index []int) *FieldInfo {
if len(index) == 0 {
return nil
}
tree := f.Tree
for _, i := range index {
if i >= len(tree.Children) || tree.Children[i] == nil {
return nil
}
tree = tree.Children[i]
}
return tree
}
// Mapper is a general purpose mapper of names to struct fields. A Mapper
// behaves like most marshallers in the standard library, obeying a field tag
// for name mapping but also providing a basic transform function.
type Mapper struct {
cache map[reflect.Type]*StructMap
tagName string
tagMapFunc func(string) string
mapFunc func(string) string
mutex sync.Mutex
}
// NewMapper returns a new mapper using the tagName as its struct field tag.
// If tagName is the empty string, it is ignored.
func NewMapper(tagName string) *Mapper {
return &Mapper{
cache: make(map[reflect.Type]*StructMap),
tagName: tagName,
}
}
// NewMapperTagFunc returns a new mapper which contains a mapper for field names
// AND a mapper for tag values. This is useful for tags like json which can
// have values like "name,omitempty".
func NewMapperTagFunc(tagName string, mapFunc, tagMapFunc func(string) string) *Mapper {
return &Mapper{
cache: make(map[reflect.Type]*StructMap),
tagName: tagName,
mapFunc: mapFunc,
tagMapFunc: tagMapFunc,
}
}
// NewMapperFunc returns a new mapper which optionally obeys a field tag and
// a struct field name mapper func given by f. Tags will take precedence, but
// for any other field, the mapped name will be f(field.Name)
func NewMapperFunc(tagName string, f func(string) string) *Mapper {
return &Mapper{
cache: make(map[reflect.Type]*StructMap),
tagName: tagName,
mapFunc: f,
}
}
// TypeMap returns a mapping of field strings to int slices representing
// the traversal down the struct to reach the field.
func (m *Mapper) TypeMa
没有合适的资源?快使用搜索试试~ 我知道了~
mayfly-go-master.zip
共435个文件
go:217个
vue:87个
ts:67个
0 下载量 152 浏览量
2022-12-29
13:54:38
上传
评论
收藏 1.16MB ZIP 举报
温馨提示
web版linux(终端 文件 脚本 进程)、数据库(mysql pgsql)、redis(单机 哨兵 集群)、mongo统一管理操作平台。
资源推荐
资源详情
资源评论
收起资源包目录
mayfly-go-master.zip (435个子文件)
my.cnf 246B
font.css 92B
.env.development 84B
Dockerfile 521B
.env 177B
.eslintignore 117B
.gitignore 244B
.gitignore 231B
sqlx.go 17KB
struct_utils.go 16KB
redis.go 16KB
db.go 15KB
db.go 13KB
timed_cache.go 10KB
redis_app.go 10KB
account.go 9KB
model.go 7KB
sshtunnel.go 7KB
machine.go 7KB
db_sql_exec.go 6KB
stats.go 6KB
machine.go 6KB
crypto_utils.go 6KB
machine_file.go 6KB
mongo_app.go 6KB
machine_file.go 5KB
mongo.go 5KB
httpclient.go 5KB
tag_tree.go 5KB
struct_utils_test.go 5KB
machine_test.go 5KB
machine.go 4KB
terminal_session.go 4KB
team.go 4KB
team.go 4KB
mysql_meta.go 4KB
pgsql_meta.go 3KB
str_utils.go 3KB
redis.go 3KB
account.go 3KB
req_ctx.go 3KB
machine_file.go 3KB
db.go 3KB
permission_handler.go 3KB
machine_script.go 3KB
role_app.go 3KB
role_repo.go 3KB
resource_app.go 3KB
role.go 2KB
team.go 2KB
machine.go 2KB
log_handler.go 2KB
machine_script.go 2KB
router.go 2KB
machine.go 2KB
mongo.go 2KB
resource_repo.go 2KB
db.go 2KB
vo.go 2KB
redis_repo.go 2KB
account_app.go 2KB
config.go 2KB
tag_tree.go 2KB
resource.go 2KB
mongo_repo.go 2KB
syslog_app.go 2KB
ginx.go 2KB
form.go 2KB
tree_utils.go 2KB
machine_script.go 2KB
machine.go 2KB
token.go 2KB
team_member.go 2KB
db.go 2KB
logger.go 2KB
gorm.go 1KB
role.go 1KB
ws.go 1KB
assert.go 1KB
redis.go 1KB
resource.go 1KB
resource.go 1KB
recorder.go 1KB
terminal.go 1KB
machine_script.go 1KB
machine_file.go 1KB
index.go 1KB
config_app.go 1KB
result.go 1KB
tag_tree.go 1KB
redis.go 1KB
rediscli.go 1KB
tag_tree.go 1KB
mongo.go 1KB
role.go 1KB
server.go 1KB
msg_app.go 1KB
meta.go 1KB
account_repo.go 1KB
array_utils.go 1KB
共 435 条
- 1
- 2
- 3
- 4
- 5
资源评论
m0_72731342
- 粉丝: 2
- 资源: 1832
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- Python脚本,用于从用户那里获取两个数字,并计算它们的和、差、积和商
- 编程题类别+样题.rar
- hiprint for Vue2/Vue3 打印、打印设计、可视化设计器、报表设计、元素编辑、可视化打印编辑
- python从网络上获取某个网页的内容,并解析HTML,提取并打印出页面上的所有链接
- python从用户输入中读取两个数字,并计算它们的和
- python从一个文本文件中读取数据,统计文件中每个单词的出现次数
- 一套权限管理系统的用户界面(UI)实现
- python从一个文本文件中读取数据,然后计算并打印出文件中单词的频率
- 基于Java的PPT文档生成器设计源码
- 从用户输入中获取两个数字,并计算它们的和
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功