feat(database): 新增命令行参数解析、空值检查和数据库配置管理功能
- 实现了 command 包用于控制台参数和选项解析 - 添加了 empty 包提供变量空值/零值检查功能 - 集成了 Viper 库进行配置文件管理和环境变量支持 - 提供了数据库配置初始化和默认值设置功能 - 实现了配置值获取、设置和结构化解析方法 - 添加了服务器、数据库和JWT配置的便捷获取方法 - 实现了完整的数据库接口定义和事务管理功能
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
// Copyright GoFrame 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 utils provides some utility functions for internal usage.
|
||||
package utils
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright GoFrame 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 utils
|
||||
|
||||
import "reflect"
|
||||
|
||||
// IsArray checks whether given value is array/slice.
|
||||
// Note that it uses reflect internally implementing this feature.
|
||||
func IsArray(value any) bool {
|
||||
rv := reflect.ValueOf(value)
|
||||
kind := rv.Kind()
|
||||
if kind == reflect.Pointer {
|
||||
rv = rv.Elem()
|
||||
kind = rv.Kind()
|
||||
}
|
||||
switch kind {
|
||||
case reflect.Array, reflect.Slice:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
// Copyright GoFrame 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 utils
|
||||
|
||||
import "git.magicany.cc/black1552/gin-base/database/command"
|
||||
|
||||
const (
|
||||
// Debug key for checking if in debug mode.
|
||||
commandEnvKeyForDebugKey = "gf.debug"
|
||||
)
|
||||
|
||||
// isDebugEnabled marks whether GoFrame debug mode is enabled.
|
||||
var isDebugEnabled = false
|
||||
|
||||
func init() {
|
||||
// Debugging configured.
|
||||
value := command.GetOptWithEnv(commandEnvKeyForDebugKey)
|
||||
if value == "" || value == "0" || value == "false" {
|
||||
isDebugEnabled = false
|
||||
} else {
|
||||
isDebugEnabled = true
|
||||
}
|
||||
}
|
||||
|
||||
// IsDebugEnabled checks and returns whether debug mode is enabled.
|
||||
// The debug mode is enabled when command argument "gf.debug" or environment "GF_DEBUG" is passed.
|
||||
func IsDebugEnabled() bool {
|
||||
return isDebugEnabled
|
||||
}
|
||||
|
||||
// SetDebugEnabled enables/disables the internal debug info.
|
||||
func SetDebugEnabled(enabled bool) {
|
||||
isDebugEnabled = enabled
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright GoFrame 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 utils
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// ReadCloser implements the io.ReadCloser interface
|
||||
// which is used for reading request body content multiple times.
|
||||
//
|
||||
// Note that it cannot be closed.
|
||||
type ReadCloser struct {
|
||||
index int // Current read position.
|
||||
content []byte // Content.
|
||||
repeatable bool // Mark the content can be repeatable read.
|
||||
}
|
||||
|
||||
// NewReadCloser creates and returns a RepeatReadCloser object.
|
||||
func NewReadCloser(content []byte, repeatable bool) io.ReadCloser {
|
||||
return &ReadCloser{
|
||||
content: content,
|
||||
repeatable: repeatable,
|
||||
}
|
||||
}
|
||||
|
||||
// Read implements the io.ReadCloser interface.
|
||||
func (b *ReadCloser) Read(p []byte) (n int, err error) {
|
||||
// Make it repeatable reading.
|
||||
if b.index >= len(b.content) && b.repeatable {
|
||||
b.index = 0
|
||||
}
|
||||
n = copy(p, b.content[b.index:])
|
||||
b.index += n
|
||||
if b.index >= len(b.content) {
|
||||
return n, io.EOF
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// Close implements the io.ReadCloser interface.
|
||||
func (b *ReadCloser) Close() error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
// Copyright GoFrame 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 utils
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"git.magicany.cc/black1552/gin-base/database/empty"
|
||||
)
|
||||
|
||||
// IsNil checks whether `value` is nil, especially for any type value.
|
||||
func IsNil(value any) bool {
|
||||
return empty.IsNil(value)
|
||||
}
|
||||
|
||||
// IsEmpty checks whether `value` is empty.
|
||||
func IsEmpty(value any) bool {
|
||||
return empty.IsEmpty(value)
|
||||
}
|
||||
|
||||
// IsInt checks whether `value` is type of int.
|
||||
func IsInt(value any) bool {
|
||||
switch value.(type) {
|
||||
case int, *int, int8, *int8, int16, *int16, int32, *int32, int64, *int64:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsUint checks whether `value` is type of uint.
|
||||
func IsUint(value any) bool {
|
||||
switch value.(type) {
|
||||
case uint, *uint, uint8, *uint8, uint16, *uint16, uint32, *uint32, uint64, *uint64:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsFloat checks whether `value` is type of float.
|
||||
func IsFloat(value any) bool {
|
||||
switch value.(type) {
|
||||
case float32, *float32, float64, *float64:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsSlice checks whether `value` is type of slice.
|
||||
func IsSlice(value any) bool {
|
||||
var (
|
||||
reflectValue = reflect.ValueOf(value)
|
||||
reflectKind = reflectValue.Kind()
|
||||
)
|
||||
for reflectKind == reflect.Pointer {
|
||||
reflectValue = reflectValue.Elem()
|
||||
reflectKind = reflectValue.Kind()
|
||||
}
|
||||
switch reflectKind {
|
||||
case reflect.Slice, reflect.Array:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsMap checks whether `value` is type of map.
|
||||
func IsMap(value any) bool {
|
||||
var (
|
||||
reflectValue = reflect.ValueOf(value)
|
||||
reflectKind = reflectValue.Kind()
|
||||
)
|
||||
for reflectKind == reflect.Pointer {
|
||||
reflectValue = reflectValue.Elem()
|
||||
reflectKind = reflectValue.Kind()
|
||||
}
|
||||
switch reflectKind {
|
||||
case reflect.Map:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsStruct checks whether `value` is type of struct.
|
||||
func IsStruct(value any) bool {
|
||||
reflectType := reflect.TypeOf(value)
|
||||
if reflectType == nil {
|
||||
return false
|
||||
}
|
||||
reflectKind := reflectType.Kind()
|
||||
for reflectKind == reflect.Pointer {
|
||||
reflectType = reflectType.Elem()
|
||||
reflectKind = reflectType.Kind()
|
||||
}
|
||||
switch reflectKind {
|
||||
case reflect.Struct:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright GoFrame 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 utils
|
||||
|
||||
import "fmt"
|
||||
|
||||
// ListToMapByKey converts `list` to a map[string]any of which key is specified by `key`.
|
||||
// Note that the item value may be type of slice.
|
||||
func ListToMapByKey(list []map[string]any, key string) map[string]any {
|
||||
var (
|
||||
s = ""
|
||||
m = make(map[string]any)
|
||||
tempMap = make(map[string][]any)
|
||||
hasMultiValues bool
|
||||
)
|
||||
for _, item := range list {
|
||||
if k, ok := item[key]; ok {
|
||||
s = fmt.Sprintf(`%v`, k)
|
||||
tempMap[s] = append(tempMap[s], item)
|
||||
if len(tempMap[s]) > 1 {
|
||||
hasMultiValues = true
|
||||
}
|
||||
}
|
||||
}
|
||||
for k, v := range tempMap {
|
||||
if hasMultiValues {
|
||||
m[k] = v
|
||||
} else {
|
||||
m[k] = v[0]
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright GoFrame 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 utils
|
||||
|
||||
// MapPossibleItemByKey tries to find the possible key-value pair for given key ignoring cases and symbols.
|
||||
//
|
||||
// Note that this function might be of low performance.
|
||||
func MapPossibleItemByKey(data map[string]any, key string) (foundKey string, foundValue any) {
|
||||
if len(data) == 0 {
|
||||
return
|
||||
}
|
||||
if v, ok := data[key]; ok {
|
||||
return key, v
|
||||
}
|
||||
// Loop checking.
|
||||
for k, v := range data {
|
||||
if EqualFoldWithoutChars(k, key) {
|
||||
return k, v
|
||||
}
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// MapContainsPossibleKey checks if the given `key` is contained in given map `data`.
|
||||
// It checks the key ignoring cases and symbols.
|
||||
//
|
||||
// Note that this function might be of low performance.
|
||||
func MapContainsPossibleKey(data map[string]any, key string) bool {
|
||||
if k, _ := MapPossibleItemByKey(data, key); k != "" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright GoFrame 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 utils
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// CanCallIsNil Can reflect.Value call reflect.Value.IsNil.
|
||||
// It can avoid reflect.Value.IsNil panics.
|
||||
func CanCallIsNil(v any) bool {
|
||||
rv, ok := v.(reflect.Value)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
switch rv.Kind() {
|
||||
case reflect.Interface, reflect.Chan, reflect.Func, reflect.Map, reflect.Pointer, reflect.Slice, reflect.UnsafePointer:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
// Copyright GoFrame 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 utils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// DefaultTrimChars are the characters which are stripped by Trim* functions in default.
|
||||
var DefaultTrimChars = string([]byte{
|
||||
'\t', // Tab.
|
||||
'\v', // Vertical tab.
|
||||
'\n', // New line (line feed).
|
||||
'\r', // Carriage return.
|
||||
'\f', // New page.
|
||||
' ', // Ordinary space.
|
||||
0x00, // NUL-byte.
|
||||
0x85, // Delete.
|
||||
0xA0, // Non-breaking space.
|
||||
})
|
||||
|
||||
// IsLetterUpper checks whether the given byte b is in upper case.
|
||||
func IsLetterUpper(b byte) bool {
|
||||
if b >= byte('A') && b <= byte('Z') {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsLetterLower checks whether the given byte b is in lower case.
|
||||
func IsLetterLower(b byte) bool {
|
||||
if b >= byte('a') && b <= byte('z') {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsLetter checks whether the given byte b is a letter.
|
||||
func IsLetter(b byte) bool {
|
||||
return IsLetterUpper(b) || IsLetterLower(b)
|
||||
}
|
||||
|
||||
// IsNumeric checks whether the given string s is numeric.
|
||||
// Note that float string like "123.456" is also numeric.
|
||||
func IsNumeric(s string) bool {
|
||||
var (
|
||||
dotCount = 0
|
||||
length = len(s)
|
||||
)
|
||||
if length == 0 {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < length; i++ {
|
||||
if (s[i] == '-' || s[i] == '+') && i == 0 {
|
||||
if length == 1 {
|
||||
return false
|
||||
}
|
||||
continue
|
||||
}
|
||||
if s[i] == '.' {
|
||||
dotCount++
|
||||
if i > 0 && i < length-1 && s[i-1] >= '0' && s[i-1] <= '9' {
|
||||
continue
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if s[i] < '0' || s[i] > '9' {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return dotCount <= 1
|
||||
}
|
||||
|
||||
// UcFirst returns a copy of the string s with the first letter mapped to its upper case.
|
||||
func UcFirst(s string) string {
|
||||
if len(s) == 0 {
|
||||
return s
|
||||
}
|
||||
if IsLetterLower(s[0]) {
|
||||
return string(s[0]-32) + s[1:]
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// ReplaceByMap returns a copy of `origin`,
|
||||
// which is replaced by a map in unordered way, case-sensitively.
|
||||
func ReplaceByMap(origin string, replaces map[string]string) string {
|
||||
for k, v := range replaces {
|
||||
origin = strings.ReplaceAll(origin, k, v)
|
||||
}
|
||||
return origin
|
||||
}
|
||||
|
||||
// RemoveSymbols removes all symbols from string and lefts only numbers and letters.
|
||||
func RemoveSymbols(s string) string {
|
||||
b := make([]rune, 0, len(s))
|
||||
for _, c := range s {
|
||||
if c > 127 {
|
||||
b = append(b, c)
|
||||
} else if (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') {
|
||||
b = append(b, c)
|
||||
}
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// EqualFoldWithoutChars checks string `s1` and `s2` equal case-insensitively,
|
||||
// with/without chars '-'/'_'/'.'/' '.
|
||||
func EqualFoldWithoutChars(s1, s2 string) bool {
|
||||
return strings.EqualFold(RemoveSymbols(s1), RemoveSymbols(s2))
|
||||
}
|
||||
|
||||
// SplitAndTrim splits string `str` by a string `delimiter` to an array,
|
||||
// and calls Trim to every element of this array. It ignores the elements
|
||||
// which are empty after Trim.
|
||||
func SplitAndTrim(str, delimiter string, characterMask ...string) []string {
|
||||
array := make([]string, 0)
|
||||
for _, v := range strings.Split(str, delimiter) {
|
||||
v = Trim(v, characterMask...)
|
||||
if v != "" {
|
||||
array = append(array, v)
|
||||
}
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
// Trim strips whitespace (or other characters) from the beginning and end of a string.
|
||||
// The optional parameter `characterMask` specifies the additional stripped characters.
|
||||
func Trim(str string, characterMask ...string) string {
|
||||
trimChars := DefaultTrimChars
|
||||
if len(characterMask) > 0 {
|
||||
trimChars += characterMask[0]
|
||||
}
|
||||
return strings.Trim(str, trimChars)
|
||||
}
|
||||
|
||||
// FormatCmdKey formats string `s` as command key using uniformed format.
|
||||
func FormatCmdKey(s string) string {
|
||||
return strings.ToLower(strings.ReplaceAll(s, "_", "."))
|
||||
}
|
||||
|
||||
// FormatEnvKey formats string `s` as environment key using uniformed format.
|
||||
func FormatEnvKey(s string) string {
|
||||
return strings.ToUpper(strings.ReplaceAll(s, ".", "_"))
|
||||
}
|
||||
|
||||
// StripSlashes un-quotes a quoted string by AddSlashes.
|
||||
func StripSlashes(str string) string {
|
||||
var buf bytes.Buffer
|
||||
l, skip := len(str), false
|
||||
for i, char := range str {
|
||||
if skip {
|
||||
skip = false
|
||||
} else if char == '\\' {
|
||||
if i+1 < l && str[i+1] == '\\' {
|
||||
skip = true
|
||||
}
|
||||
continue
|
||||
}
|
||||
buf.WriteRune(char)
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// IsASCII checks whether given string is ASCII characters.
|
||||
func IsASCII(s string) bool {
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] > unicode.MaxASCII {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
Reference in New Issue
Block a user