feat(database): 新增命令行参数解析、空值检查和数据库配置管理功能
- 实现了 command 包用于控制台参数和选项解析 - 添加了 empty 包提供变量空值/零值检查功能 - 集成了 Viper 库进行配置文件管理和环境变量支持 - 提供了数据库配置初始化和默认值设置功能 - 实现了配置值获取、设置和结构化解析方法 - 添加了服务器、数据库和JWT配置的便捷获取方法 - 实现了完整的数据库接口定义和事务管理功能
This commit is contained in:
@@ -0,0 +1,243 @@
|
||||
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package empty provides functions for checking empty/nil variables.
|
||||
package empty
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"git.magicany.cc/black1552/gin-base/database/reflection"
|
||||
)
|
||||
|
||||
// iString is used for type assert api for String().
|
||||
type iString interface {
|
||||
String() string
|
||||
}
|
||||
|
||||
// iInterfaces is used for type assert api for Interfaces.
|
||||
type iInterfaces interface {
|
||||
Interfaces() []any
|
||||
}
|
||||
|
||||
// iMapStrAny is the interface support for converting struct parameter to map.
|
||||
type iMapStrAny interface {
|
||||
MapStrAny() map[string]any
|
||||
}
|
||||
|
||||
type iTime interface {
|
||||
Date() (year int, month time.Month, day int)
|
||||
IsZero() bool
|
||||
}
|
||||
|
||||
// IsEmpty checks whether given `value` empty.
|
||||
// It returns true if `value` is in: 0, nil, false, "", len(slice/map/chan) == 0,
|
||||
// or else it returns false.
|
||||
//
|
||||
// The parameter `traceSource` is used for tracing to the source variable if given `value` is type of pointer
|
||||
// that also points to a pointer. It returns true if the source is empty when `traceSource` is true.
|
||||
// Note that it might use reflect feature which affects performance a little.
|
||||
func IsEmpty(value any, traceSource ...bool) bool {
|
||||
if value == nil {
|
||||
return true
|
||||
}
|
||||
// It firstly checks the variable as common types using assertion to enhance the performance,
|
||||
// and then using reflection.
|
||||
switch result := value.(type) {
|
||||
case int:
|
||||
return result == 0
|
||||
case int8:
|
||||
return result == 0
|
||||
case int16:
|
||||
return result == 0
|
||||
case int32:
|
||||
return result == 0
|
||||
case int64:
|
||||
return result == 0
|
||||
case uint:
|
||||
return result == 0
|
||||
case uint8:
|
||||
return result == 0
|
||||
case uint16:
|
||||
return result == 0
|
||||
case uint32:
|
||||
return result == 0
|
||||
case uint64:
|
||||
return result == 0
|
||||
case float32:
|
||||
return result == 0
|
||||
case float64:
|
||||
return result == 0
|
||||
case bool:
|
||||
return !result
|
||||
case string:
|
||||
return result == ""
|
||||
case []byte:
|
||||
return len(result) == 0
|
||||
case []rune:
|
||||
return len(result) == 0
|
||||
case []int:
|
||||
return len(result) == 0
|
||||
case []string:
|
||||
return len(result) == 0
|
||||
case []float32:
|
||||
return len(result) == 0
|
||||
case []float64:
|
||||
return len(result) == 0
|
||||
case map[string]any:
|
||||
return len(result) == 0
|
||||
|
||||
default:
|
||||
// Finally, using reflect.
|
||||
var rv reflect.Value
|
||||
if v, ok := value.(reflect.Value); ok {
|
||||
rv = v
|
||||
} else {
|
||||
rv = reflect.ValueOf(value)
|
||||
if IsNil(rv) {
|
||||
return true
|
||||
}
|
||||
|
||||
// =========================
|
||||
// Common interfaces checks.
|
||||
// =========================
|
||||
if f, ok := value.(iTime); ok {
|
||||
if f == (*time.Time)(nil) {
|
||||
return true
|
||||
}
|
||||
return f.IsZero()
|
||||
}
|
||||
if f, ok := value.(iString); ok {
|
||||
if f == nil {
|
||||
return true
|
||||
}
|
||||
return f.String() == ""
|
||||
}
|
||||
if f, ok := value.(iInterfaces); ok {
|
||||
if f == nil {
|
||||
return true
|
||||
}
|
||||
return len(f.Interfaces()) == 0
|
||||
}
|
||||
if f, ok := value.(iMapStrAny); ok {
|
||||
if f == nil {
|
||||
return true
|
||||
}
|
||||
return len(f.MapStrAny()) == 0
|
||||
}
|
||||
}
|
||||
|
||||
switch rv.Kind() {
|
||||
case reflect.Bool:
|
||||
return !rv.Bool()
|
||||
|
||||
case
|
||||
reflect.Int,
|
||||
reflect.Int8,
|
||||
reflect.Int16,
|
||||
reflect.Int32,
|
||||
reflect.Int64:
|
||||
return rv.Int() == 0
|
||||
|
||||
case
|
||||
reflect.Uint,
|
||||
reflect.Uint8,
|
||||
reflect.Uint16,
|
||||
reflect.Uint32,
|
||||
reflect.Uint64,
|
||||
reflect.Uintptr:
|
||||
return rv.Uint() == 0
|
||||
|
||||
case
|
||||
reflect.Float32,
|
||||
reflect.Float64:
|
||||
return rv.Float() == 0
|
||||
|
||||
case reflect.String:
|
||||
return rv.Len() == 0
|
||||
|
||||
case reflect.Struct:
|
||||
var fieldValueInterface any
|
||||
for i := 0; i < rv.NumField(); i++ {
|
||||
fieldValueInterface, _ = reflection.ValueToInterface(rv.Field(i))
|
||||
if !IsEmpty(fieldValueInterface) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
||||
case
|
||||
reflect.Chan,
|
||||
reflect.Map,
|
||||
reflect.Slice,
|
||||
reflect.Array:
|
||||
return rv.Len() == 0
|
||||
|
||||
case reflect.Pointer:
|
||||
if len(traceSource) > 0 && traceSource[0] {
|
||||
return IsEmpty(rv.Elem())
|
||||
}
|
||||
return rv.IsNil()
|
||||
|
||||
case
|
||||
reflect.Func,
|
||||
reflect.Interface,
|
||||
reflect.UnsafePointer:
|
||||
return rv.IsNil()
|
||||
|
||||
case reflect.Invalid:
|
||||
return true
|
||||
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IsNil checks whether given `value` is nil, especially for any type value.
|
||||
// Parameter `traceSource` is used for tracing to the source variable if given `value` is type of pointer
|
||||
// that also points to a pointer. It returns nil if the source is nil when `traceSource` is true.
|
||||
// Note that it might use reflect feature which affects performance a little.
|
||||
func IsNil(value any, traceSource ...bool) bool {
|
||||
if value == nil {
|
||||
return true
|
||||
}
|
||||
var rv reflect.Value
|
||||
if v, ok := value.(reflect.Value); ok {
|
||||
rv = v
|
||||
} else {
|
||||
rv = reflect.ValueOf(value)
|
||||
}
|
||||
switch rv.Kind() {
|
||||
case reflect.Chan,
|
||||
reflect.Map,
|
||||
reflect.Slice,
|
||||
reflect.Func,
|
||||
reflect.Interface,
|
||||
reflect.UnsafePointer:
|
||||
return !rv.IsValid() || rv.IsNil()
|
||||
|
||||
case reflect.Pointer:
|
||||
if len(traceSource) > 0 && traceSource[0] {
|
||||
for rv.Kind() == reflect.Pointer {
|
||||
rv = rv.Elem()
|
||||
}
|
||||
if !rv.IsValid() {
|
||||
return true
|
||||
}
|
||||
if rv.Kind() == reflect.Pointer {
|
||||
return rv.IsNil()
|
||||
}
|
||||
} else {
|
||||
return !rv.IsValid() || rv.IsNil()
|
||||
}
|
||||
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user