Compare commits
24 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
f50930ec74 | |
|
|
d50f150d98 | |
|
|
0238ec9a01 | |
|
|
1cc976ed72 | |
|
|
7d3ddc62e3 | |
|
|
427f568db6 | |
|
|
828e19de93 | |
|
|
1e18be8326 | |
|
|
21e9f7c79d | |
|
|
93fbb99ee0 | |
|
|
d41b554acf | |
|
|
7b6026950a | |
|
|
80ad00f98d | |
|
|
3209cfe830 | |
|
|
ed7d18a72a | |
|
|
f710f03be0 | |
|
|
5d7e584ffd | |
|
|
6661ad7fb3 | |
|
|
af31b688cf | |
|
|
abf5529019 | |
|
|
4a3339fcfb | |
|
|
7925439270 | |
|
|
a656e00daa | |
|
|
ca82c166d0 |
|
|
@ -60,6 +60,7 @@ func SetDefault() {
|
|||
viper.Set("SERVER.mode", "release")
|
||||
viper.Set("DATABASE.type", "sqlite")
|
||||
viper.Set("DATABASE.dns", gfile.Join(gfile.Pwd(), "db", "database.db"))
|
||||
viper.Set("DATABASE.debug", true)
|
||||
viper.Set("JWT.secret", "SET-YOUR-SECRET")
|
||||
viper.Set("JWT.expire", 86400)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,8 +15,9 @@ type ServerConfig struct {
|
|||
|
||||
// DataBaseConfig 数据库配置
|
||||
type DataBaseConfig struct {
|
||||
Dns string `mapstructure:"dns"`
|
||||
Type string `mapstructure:"type"`
|
||||
Dns string `mapstructure:"dns"`
|
||||
Type string `mapstructure:"type"`
|
||||
Debug bool `mapstructure:"debug"` // 是否开启 GORM 查询日志
|
||||
}
|
||||
|
||||
// JwtConfig JWT配置
|
||||
|
|
|
|||
89
crud/curd.go
89
crud/curd.go
|
|
@ -16,12 +16,13 @@ type ctx = context.Context
|
|||
|
||||
// IDao -------------------------- 核心接口定义 --------------------------
|
||||
// IDao GORM 版本的Dao接口,提供GORM DB实例和表相关信息
|
||||
type IDao interface {
|
||||
type IDao[T any] interface {
|
||||
DB() *gorm.DB // 返回GORM的DB实例
|
||||
Table() string // 返回表名
|
||||
PrimaryKey() string // 返回主键字段名(如:id)
|
||||
Ctx(ctx context.Context) *gorm.DB // 绑定上下文的DB实例
|
||||
Transaction(ctx context.Context, f func(ctx context.Context, tx *gorm.DB) error) error // 事务方法
|
||||
Column() *T
|
||||
}
|
||||
|
||||
// Paginate -------------------------- 分页结构体定义 --------------------------
|
||||
|
|
@ -47,9 +48,9 @@ var pageInfo = []string{
|
|||
}
|
||||
|
||||
// Crud -------------------------- 泛型CURD核心结构体 --------------------------
|
||||
// Crud GORM 版本的泛型CURD封装,R为对应的模型结构体
|
||||
type Crud[R any] struct {
|
||||
Dao IDao
|
||||
// Crud GORM 版本的泛型CURD封装,R为对应的模型结构体, C为对应模型结构体的字段结构体
|
||||
type Crud[R any, C any] struct {
|
||||
Dao IDao[C]
|
||||
}
|
||||
|
||||
// -------------------------- 工具方法:字段名转换(保持原代码的命名风格转换) --------------------------
|
||||
|
|
@ -77,8 +78,12 @@ func caseConvert(key string, toSnake bool) string {
|
|||
return result.String()
|
||||
}
|
||||
|
||||
func (c Crud[R, C]) Columns() *C {
|
||||
return c.Dao.Column()
|
||||
}
|
||||
|
||||
// BuildWhere -------------------------- 原BuildWhere对应实现:构建查询条件map --------------------------
|
||||
func (c Crud[R]) BuildWhere(req any, changeWhere any, subWhere any, removeFields []string, isSnake ...bool) map[string]any {
|
||||
func (c Crud[R, C]) BuildWhere(req any, changeWhere any, subWhere any, removeFields []string, isSnake ...bool) map[string]any {
|
||||
// 默认使用小写下划线方式
|
||||
toSnake := true
|
||||
if len(isSnake) > 0 && !isSnake[0] {
|
||||
|
|
@ -170,7 +175,7 @@ func (c Crud[R]) BuildWhere(req any, changeWhere any, subWhere any, removeFields
|
|||
}
|
||||
|
||||
// BuildMap -------------------------- 原 BuildMap 对应实现:构建变更条件 map --------------------------
|
||||
func (c Crud[R]) BuildMap(op string, value any, field ...string) map[string]any {
|
||||
func (c Crud[R, C]) BuildMap(op string, value any, field ...string) map[string]any {
|
||||
res := map[string]any{
|
||||
"op": op,
|
||||
"field": "",
|
||||
|
|
@ -201,8 +206,8 @@ type WhereCondition struct {
|
|||
// ).
|
||||
// AND(map[string]any{"deleted": 0}).
|
||||
// Build()
|
||||
func (c Crud[R]) BuildWhereAndOr() *WhereBuilder[R] {
|
||||
return &WhereBuilder[R]{
|
||||
func (c Crud[R, C]) BuildWhereAndOr() *WhereBuilder[R, C] {
|
||||
return &WhereBuilder[R, C]{
|
||||
conditions: make([]WhereCondition, 0),
|
||||
crud: c,
|
||||
}
|
||||
|
|
@ -210,13 +215,13 @@ func (c Crud[R]) BuildWhereAndOr() *WhereBuilder[R] {
|
|||
|
||||
// WhereBuilder -------------------------- WHERE 条件构建器 --------------------------
|
||||
// WhereBuilder 流式构建 WHERE 条件(R 为模型类型参数)
|
||||
type WhereBuilder[R any] struct {
|
||||
type WhereBuilder[R any, C any] struct {
|
||||
conditions []WhereCondition
|
||||
crud Crud[R]
|
||||
crud Crud[R, C]
|
||||
}
|
||||
|
||||
// AND 添加 AND 条件
|
||||
func (wb *WhereBuilder[R]) AND(conditions ...interface{}) *WhereBuilder[R] {
|
||||
func (wb *WhereBuilder[R, C]) AND(conditions ...interface{}) *WhereBuilder[R, C] {
|
||||
if len(conditions) > 0 {
|
||||
wb.conditions = append(wb.conditions, WhereCondition{
|
||||
AND: conditions,
|
||||
|
|
@ -226,7 +231,7 @@ func (wb *WhereBuilder[R]) AND(conditions ...interface{}) *WhereBuilder[R] {
|
|||
}
|
||||
|
||||
// OR 添加 OR 条件(OR 条件内部是或关系)
|
||||
func (wb *WhereBuilder[R]) OR(conditions ...interface{}) *WhereBuilder[R] {
|
||||
func (wb *WhereBuilder[R, C]) OR(conditions ...interface{}) *WhereBuilder[R, C] {
|
||||
if len(conditions) > 0 {
|
||||
wb.conditions = append(wb.conditions, WhereCondition{
|
||||
OR: conditions,
|
||||
|
|
@ -237,7 +242,7 @@ func (wb *WhereBuilder[R]) OR(conditions ...interface{}) *WhereBuilder[R] {
|
|||
|
||||
// Build 构建最终的查询条件
|
||||
// 返回格式:map[string]any 或者可以直接用于 GORM 的 Where 子句
|
||||
func (wb *WhereBuilder[R]) Build() interface{} {
|
||||
func (wb *WhereBuilder[R, C]) Build() interface{} {
|
||||
if len(wb.conditions) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -279,7 +284,7 @@ func (wb *WhereBuilder[R]) Build() interface{} {
|
|||
}
|
||||
|
||||
// buildORCondition 构建 OR 条件
|
||||
func (wb *WhereBuilder[R]) buildORCondition(orConds []interface{}) map[string]interface{} {
|
||||
func (wb *WhereBuilder[R, C]) buildORCondition(orConds []interface{}) map[string]interface{} {
|
||||
if len(orConds) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -312,8 +317,8 @@ func (wb *WhereBuilder[R]) buildORCondition(orConds []interface{}) map[string]in
|
|||
// db.Where("status = ?", 1).
|
||||
// Where(db.Where("age >= ?", 18).Or("age < ? AND vip = ?", 18, true)).
|
||||
// Find(&users)
|
||||
func (c Crud[R]) BuildWhereGORM(query interface{}, args ...interface{}) *GORMWhereBuilder[R] {
|
||||
return &GORMWhereBuilder[R]{
|
||||
func (c Crud[R, C]) BuildWhereGORM(query interface{}, args ...interface{}) *GORMWhereBuilder[R, C] {
|
||||
return &GORMWhereBuilder[R, C]{
|
||||
DB: c.Dao.DB(),
|
||||
crud: c,
|
||||
query: query,
|
||||
|
|
@ -323,15 +328,15 @@ func (c Crud[R]) BuildWhereGORM(query interface{}, args ...interface{}) *GORMWhe
|
|||
|
||||
// GORMWhereBuilder -------------------------- GORM 原生 WHERE 构建器 --------------------------
|
||||
// GORMWhereBuilder 使用 GORM 原生 API 构建复杂查询(R 为模型类型参数)
|
||||
type GORMWhereBuilder[R any] struct {
|
||||
type GORMWhereBuilder[R any, C any] struct {
|
||||
*gorm.DB
|
||||
crud Crud[R]
|
||||
crud Crud[R, C]
|
||||
query interface{}
|
||||
args []interface{}
|
||||
}
|
||||
|
||||
// Where 添加 WHERE 条件(AND 关系)
|
||||
func (gwb *GORMWhereBuilder[R]) Where(query interface{}, args ...interface{}) *GORMWhereBuilder[R] {
|
||||
func (gwb *GORMWhereBuilder[R, C]) Where(query interface{}, args ...interface{}) *GORMWhereBuilder[R, C] {
|
||||
// 如果当前已经有查询条件,先应用
|
||||
if gwb.query != nil {
|
||||
gwb = gwb.Where(gwb.query, gwb.args...)
|
||||
|
|
@ -342,7 +347,7 @@ func (gwb *GORMWhereBuilder[R]) Where(query interface{}, args ...interface{}) *G
|
|||
}
|
||||
|
||||
// Or 添加 OR 条件
|
||||
func (gwb *GORMWhereBuilder[R]) Or(query interface{}, args ...interface{}) *GORMWhereBuilder[R] {
|
||||
func (gwb *GORMWhereBuilder[R, C]) Or(query interface{}, args ...interface{}) *GORMWhereBuilder[R, C] {
|
||||
// 如果当前有未应用的查询条件,先应用
|
||||
if gwb.query != nil {
|
||||
gwb = gwb.Where(gwb.query, gwb.args...)
|
||||
|
|
@ -353,7 +358,7 @@ func (gwb *GORMWhereBuilder[R]) Or(query interface{}, args ...interface{}) *GORM
|
|||
}
|
||||
|
||||
// Not 添加 NOT 条件
|
||||
func (gwb *GORMWhereBuilder[R]) Not(query interface{}, args ...interface{}) *GORMWhereBuilder[R] {
|
||||
func (gwb *GORMWhereBuilder[R, C]) Not(query interface{}, args ...interface{}) *GORMWhereBuilder[R, C] {
|
||||
if gwb.query != nil {
|
||||
gwb = gwb.Where(gwb.query, gwb.args...)
|
||||
gwb.query = nil
|
||||
|
|
@ -364,7 +369,7 @@ func (gwb *GORMWhereBuilder[R]) Not(query interface{}, args ...interface{}) *GOR
|
|||
}
|
||||
|
||||
// Find 执行查询并返回结果
|
||||
func (gwb *GORMWhereBuilder[R]) Find(items interface{}) error {
|
||||
func (gwb *GORMWhereBuilder[R, C]) Find(items interface{}) error {
|
||||
// 应用剩余的查询条件
|
||||
if gwb.query != nil {
|
||||
gwb = gwb.Where(gwb.query, gwb.args...)
|
||||
|
|
@ -373,7 +378,7 @@ func (gwb *GORMWhereBuilder[R]) Find(items interface{}) error {
|
|||
}
|
||||
|
||||
// First 查询第一条记录
|
||||
func (gwb *GORMWhereBuilder[R]) First(result interface{}) error {
|
||||
func (gwb *GORMWhereBuilder[R, C]) First(result interface{}) error {
|
||||
if gwb.query != nil {
|
||||
gwb = gwb.Where(gwb.query, gwb.args...)
|
||||
}
|
||||
|
|
@ -381,7 +386,7 @@ func (gwb *GORMWhereBuilder[R]) First(result interface{}) error {
|
|||
}
|
||||
|
||||
// Count 统计记录数
|
||||
func (gwb *GORMWhereBuilder[R]) Count(count *int64) error {
|
||||
func (gwb *GORMWhereBuilder[R, C]) Count(count *int64) error {
|
||||
if gwb.query != nil {
|
||||
gwb = gwb.Where(gwb.query, gwb.args...)
|
||||
}
|
||||
|
|
@ -389,7 +394,7 @@ func (gwb *GORMWhereBuilder[R]) Count(count *int64) error {
|
|||
}
|
||||
|
||||
// ClearField -------------------------- 原ClearField对应实现:清理请求参数并返回有效map --------------------------
|
||||
func (c Crud[R]) ClearField(req any, delField []string, subField ...map[string]any) map[string]any {
|
||||
func (c Crud[R, C]) ClearField(req any, delField []string, subField ...map[string]any) map[string]any {
|
||||
reqMap := convToMap(req)
|
||||
resultMap := make(map[string]any)
|
||||
|
||||
|
|
@ -418,7 +423,7 @@ func (c Crud[R]) ClearField(req any, delField []string, subField ...map[string]a
|
|||
}
|
||||
|
||||
// ClearFieldPage -------------------------- 原ClearFieldPage对应实现:清理参数+分页查询 --------------------------
|
||||
func (c Crud[R]) ClearFieldPage(ctx ctx, req any, delField []string, where any, page *Paginate, order any, with map[string]func(db *gorm.DB) *gorm.DB) (items []*R, total int64, err error) {
|
||||
func (c Crud[R, C]) ClearFieldPage(ctx ctx, req any, delField []string, where any, page *Paginate, order any, with map[string]func(db *gorm.DB) *gorm.DB) (items []*R, total int64, err error) {
|
||||
// 1. 清理请求参数
|
||||
filterMap := c.ClearField(req, delField)
|
||||
|
||||
|
|
@ -459,7 +464,7 @@ func (c Crud[R]) ClearFieldPage(ctx ctx, req any, delField []string, where any,
|
|||
}
|
||||
|
||||
// ClearFieldList -------------------------- 原ClearFieldList对应实现:清理参数+列表查询(不分页) --------------------------
|
||||
func (c Crud[R]) ClearFieldList(ctx ctx, req any, delField []string, where any, order any, with map[string]func(db *gorm.DB) *gorm.DB) (items []*R, err error) {
|
||||
func (c Crud[R, C]) ClearFieldList(ctx ctx, req any, delField []string, where any, order any, with map[string]func(db *gorm.DB) *gorm.DB) (items []*R, err error) {
|
||||
filterMap := c.ClearField(req, delField)
|
||||
db := c.Dao.Ctx(ctx).Model(new(R))
|
||||
|
||||
|
|
@ -480,7 +485,7 @@ func (c Crud[R]) ClearFieldList(ctx ctx, req any, delField []string, where any,
|
|||
}
|
||||
|
||||
// ClearFieldOne -------------------------- 原ClearFieldOne对应实现:清理参数+单条查询 --------------------------
|
||||
func (c Crud[R]) ClearFieldOne(ctx ctx, req any, delField []string, where any, order any, with map[string]func(db *gorm.DB) *gorm.DB) (item *R, err error) {
|
||||
func (c Crud[R, C]) ClearFieldOne(ctx ctx, req any, delField []string, where any, order any, with map[string]func(db *gorm.DB) *gorm.DB) (item *R, err error) {
|
||||
item = new(R)
|
||||
filterMap := c.ClearField(req, delField)
|
||||
db := c.Dao.Ctx(ctx).Model(item)
|
||||
|
|
@ -506,7 +511,7 @@ func (c Crud[R]) ClearFieldOne(ctx ctx, req any, delField []string, where any, o
|
|||
}
|
||||
|
||||
// Value -------------------------- 原Value对应实现:查询单个字段值 --------------------------
|
||||
func (c Crud[R]) Value(ctx ctx, where any, field any) (interface{}, error) {
|
||||
func (c Crud[R, C]) Value(ctx ctx, where any, field any) (interface{}, error) {
|
||||
var result interface{}
|
||||
db := c.Dao.Ctx(ctx).Model(new(R)).Where(where)
|
||||
|
||||
|
|
@ -530,7 +535,7 @@ func (c Crud[R]) Value(ctx ctx, where any, field any) (interface{}, error) {
|
|||
}
|
||||
|
||||
// DeletePri -------------------------- 原DeletePri对应实现:按主键删除 --------------------------
|
||||
func (c Crud[R]) DeletePri(ctx ctx, primaryKey any) error {
|
||||
func (c Crud[R, C]) DeletePri(ctx ctx, primaryKey any) error {
|
||||
db := c.Dao.Ctx(ctx).Model(new(R))
|
||||
// 按主键字段构建查询
|
||||
pk := c.Dao.PrimaryKey()
|
||||
|
|
@ -541,12 +546,12 @@ func (c Crud[R]) DeletePri(ctx ctx, primaryKey any) error {
|
|||
}
|
||||
|
||||
// DeleteWhere -------------------------- 原DeleteWhere对应实现:按条件删除 --------------------------
|
||||
func (c Crud[R]) DeleteWhere(ctx ctx, where any) error {
|
||||
func (c Crud[R, C]) DeleteWhere(ctx ctx, where any) error {
|
||||
return c.Dao.Ctx(ctx).Model(new(R)).Where(where).Delete(new(R)).Error
|
||||
}
|
||||
|
||||
// Sum -------------------------- 原Sum对应实现:字段求和 --------------------------
|
||||
func (c Crud[R]) Sum(ctx ctx, where any, field string) float64 {
|
||||
func (c Crud[R, C]) Sum(ctx ctx, where any, field string) float64 {
|
||||
var sum float64
|
||||
if field == "" {
|
||||
panic("求和字段不能为空")
|
||||
|
|
@ -560,7 +565,7 @@ func (c Crud[R]) Sum(ctx ctx, where any, field string) float64 {
|
|||
}
|
||||
|
||||
// ArrayField -------------------------- 原ArrayField对应实现:查询指定字段数组 --------------------------
|
||||
func (c Crud[R]) ArrayField(ctx ctx, where any, field any) []interface{} {
|
||||
func (c Crud[R, C]) ArrayField(ctx ctx, where any, field any) []interface{} {
|
||||
var result []interface{}
|
||||
db := c.Dao.Ctx(ctx).Model(new(R)).Where(where)
|
||||
|
||||
|
|
@ -584,7 +589,7 @@ func (c Crud[R]) ArrayField(ctx ctx, where any, field any) []interface{} {
|
|||
}
|
||||
|
||||
// FindPri -------------------------- 原FindPri对应实现:按主键查询单条记录 --------------------------
|
||||
func (c Crud[R]) FindPri(ctx ctx, primaryKey any, with map[string]func(db *gorm.DB) *gorm.DB) (model *R) {
|
||||
func (c Crud[R, C]) FindPri(ctx ctx, primaryKey any, with map[string]func(db *gorm.DB) *gorm.DB) (model *R) {
|
||||
model = new(R)
|
||||
db := c.Dao.Ctx(ctx).Model(model)
|
||||
pk := c.Dao.PrimaryKey()
|
||||
|
|
@ -607,7 +612,7 @@ func (c Crud[R]) FindPri(ctx ctx, primaryKey any, with map[string]func(db *gorm.
|
|||
}
|
||||
|
||||
// -------------------------- 原First对应实现:按条件查询第一条记录 --------------------------
|
||||
func (c Crud[R]) First(ctx ctx, where any, order any, with map[string]func(db *gorm.DB) *gorm.DB) (model *R) {
|
||||
func (c Crud[R, C]) First(ctx ctx, where any, order any, with map[string]func(db *gorm.DB) *gorm.DB) (model *R) {
|
||||
model = new(R)
|
||||
db := c.Dao.Ctx(ctx).Model(model)
|
||||
|
||||
|
|
@ -631,7 +636,7 @@ func (c Crud[R]) First(ctx ctx, where any, order any, with map[string]func(db *g
|
|||
}
|
||||
|
||||
// -------------------------- 原Exists对应实现:判断记录是否存在 --------------------------
|
||||
func (c Crud[R]) Exists(ctx ctx, where any) (exists bool) {
|
||||
func (c Crud[R, C]) Exists(ctx ctx, where any) (exists bool) {
|
||||
var count int64
|
||||
err := c.Dao.Ctx(ctx).Model(new(R)).Where(where).Count(&count).Error
|
||||
if err != nil {
|
||||
|
|
@ -641,7 +646,7 @@ func (c Crud[R]) Exists(ctx ctx, where any) (exists bool) {
|
|||
}
|
||||
|
||||
// -------------------------- 原All对应实现:查询所有符合条件的记录 --------------------------
|
||||
func (c Crud[R]) All(ctx ctx, where any, order any, with map[string]func(db *gorm.DB) *gorm.DB) (items []*R) {
|
||||
func (c Crud[R, C]) All(ctx ctx, where any, order any, with map[string]func(db *gorm.DB) *gorm.DB) (items []*R) {
|
||||
db := c.Dao.Ctx(ctx).Model(new(R))
|
||||
|
||||
if with != nil {
|
||||
|
|
@ -664,7 +669,7 @@ func (c Crud[R]) All(ctx ctx, where any, order any, with map[string]func(db *gor
|
|||
}
|
||||
|
||||
// -------------------------- 原Count对应实现:统计记录总数 --------------------------
|
||||
func (c Crud[R]) Count(ctx ctx, where any) (count int64) {
|
||||
func (c Crud[R, C]) Count(ctx ctx, where any) (count int64) {
|
||||
err := c.Dao.Ctx(ctx).Model(new(R)).Where(where).Count(&count).Error
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
panic(fmt.Sprintf("Count查询错误: %v", err))
|
||||
|
|
@ -673,7 +678,7 @@ func (c Crud[R]) Count(ctx ctx, where any) (count int64) {
|
|||
}
|
||||
|
||||
// -------------------------- 原Save对应实现:新增/更新记录(对应GORM的Save) --------------------------
|
||||
func (c Crud[R]) Save(ctx ctx, data any) {
|
||||
func (c Crud[R, C]) Save(ctx ctx, data any) {
|
||||
err := c.Dao.Ctx(ctx).Model(new(R)).Create(data).Error
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Save保存错误: %v", err))
|
||||
|
|
@ -681,7 +686,7 @@ func (c Crud[R]) Save(ctx ctx, data any) {
|
|||
}
|
||||
|
||||
// -------------------------- 原Update对应实现:按条件更新记录 --------------------------
|
||||
func (c Crud[R]) Update(ctx ctx, where any, data any) (count int64) {
|
||||
func (c Crud[R, C]) Update(ctx ctx, where any, data any) (count int64) {
|
||||
result := c.Dao.Ctx(ctx).Model(new(R)).Where(where).Updates(data)
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
panic(fmt.Sprintf("Update更新错误: %v", result.Error.Error()))
|
||||
|
|
@ -690,7 +695,7 @@ func (c Crud[R]) Update(ctx ctx, where any, data any) (count int64) {
|
|||
}
|
||||
|
||||
// -------------------------- 原UpdatePri对应实现:按主键更新记录 --------------------------
|
||||
func (c Crud[R]) UpdatePri(ctx ctx, primaryKey any, data any) (count int64) {
|
||||
func (c Crud[R, C]) UpdatePri(ctx ctx, primaryKey any, data any) (count int64) {
|
||||
db := c.Dao.Ctx(ctx).Model(new(R))
|
||||
pk := c.Dao.PrimaryKey()
|
||||
|
||||
|
|
@ -706,7 +711,7 @@ func (c Crud[R]) UpdatePri(ctx ctx, primaryKey any, data any) (count int64) {
|
|||
}
|
||||
|
||||
// -------------------------- 原Paginate对应实现:分页查询 --------------------------
|
||||
func (c Crud[R]) Paginate(ctx context.Context, where any, p Paginate, with map[string]func(db *gorm.DB) *gorm.DB, order any) (items []*R, total int64) {
|
||||
func (c Crud[R, C]) Paginate(ctx context.Context, where any, p Paginate, with map[string]func(db *gorm.DB) *gorm.DB, order any) (items []*R, total int64) {
|
||||
db := c.Dao.Ctx(ctx).Model(new(R))
|
||||
|
||||
// 1. 构建查询条件
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ func TestBuildWhere(t *testing.T) {
|
|||
// TestBuildMap 测试 BuildMap 方法
|
||||
func TestBuildMap(t *testing.T) {
|
||||
// 创建一个空的 Crud 实例用于测试(不需要实际的 Dao)
|
||||
var crud Crud[interface{}]
|
||||
var crud Crud[interface{}, interface{}]
|
||||
|
||||
t.Run("BuildMapWithoutField", func(t *testing.T) {
|
||||
result := crud.BuildMap(">", 18)
|
||||
|
|
@ -131,7 +131,7 @@ func TestBuildMap(t *testing.T) {
|
|||
|
||||
// TestClearField 测试 ClearField 方法
|
||||
func TestClearField(t *testing.T) {
|
||||
var crud Crud[interface{}]
|
||||
var crud Crud[interface{}, interface{}]
|
||||
|
||||
t.Run("ClearFieldBasic", func(t *testing.T) {
|
||||
req := struct {
|
||||
|
|
@ -210,7 +210,7 @@ func TestClearField(t *testing.T) {
|
|||
|
||||
// TestBuildWhereAndOr 测试 BuildWhereAndOr 方法
|
||||
func TestBuildWhereAndOr(t *testing.T) {
|
||||
var crud Crud[interface{}]
|
||||
var crud Crud[interface{}, interface{}]
|
||||
|
||||
t.Run("SimpleAND", func(t *testing.T) {
|
||||
where := crud.BuildWhereAndOr().
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
package base
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type IdModel struct {
|
||||
Id int `json:"id" gorm:"column:id;type:int(11);common:id"`
|
||||
}
|
||||
type TimeModel struct {
|
||||
CreateTime string `json:"create_time" gorm:"column:create_time;type:varchar(255);common:创建时间"`
|
||||
UpdateTime string `json:"update_time" gorm:"column:update_time;type:varchar(255);common:更新时间"`
|
||||
}
|
||||
|
||||
func (tm *TimeModel) BeforeCreate(scope *gorm.DB) error {
|
||||
scope.Set("create_time", gtime.Datetime())
|
||||
scope.Set("update_time", gtime.Datetime())
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tm *TimeModel) BeforeUpdate(scope *gorm.DB) error {
|
||||
scope.Set("update_time", gtime.Datetime())
|
||||
return nil
|
||||
}
|
||||
|
||||
//func (tm *TimeModel) AfterFind(scope *gorm.DB) error {
|
||||
// tm.CreateTime = gtime.New(tm.CreateTime).String()
|
||||
// tm.UpdateTime = gtime.New(tm.UpdateTime).String()
|
||||
// return nil
|
||||
//}
|
||||
|
|
@ -3,6 +3,7 @@ package database
|
|||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.magicany.cc/black1552/gin-base/config"
|
||||
"git.magicany.cc/black1552/gin-base/log"
|
||||
|
|
@ -11,6 +12,7 @@ import (
|
|||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
"gorm.io/gorm/schema"
|
||||
)
|
||||
|
||||
|
|
@ -24,24 +26,39 @@ var (
|
|||
|
||||
func init() {
|
||||
if g.IsEmpty(dns) {
|
||||
log.Error("gormDns未配置", "请检查配置文件")
|
||||
log.Error("gormDns 未配置", "请检查配置文件")
|
||||
return
|
||||
}
|
||||
switch config.GetConfigValue("database.type", "sqlite").String() {
|
||||
case "mysql":
|
||||
log.Info("使用mysql数据库")
|
||||
log.Info("使用 mysql 数据库")
|
||||
mysqlInit()
|
||||
case "sqlite":
|
||||
log.Info("使用sqlite数据库")
|
||||
log.Info("使用 sqlite 数据库")
|
||||
sqliteInit()
|
||||
}
|
||||
Db, err = gorm.Open(Type, &gorm.Config{
|
||||
|
||||
// 构建 GORM 配置
|
||||
gormConfig := &gorm.Config{
|
||||
SkipDefaultTransaction: true,
|
||||
NowFunc: func() time.Time {
|
||||
return time.Now().Local()
|
||||
},
|
||||
// 命名策略:保持与模型一致,避免字段/表名转换问题
|
||||
NamingStrategy: schema.NamingStrategy{
|
||||
SingularTable: true, // 表名禁用复数形式(例如 User 对应 user 表,而非 users)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// 根据配置决定是否开启 GORM 查询日志
|
||||
if config.GetConfigValue("database.debug", false).Bool() {
|
||||
log.Info("已开启 GORM 查询日志")
|
||||
gormConfig.Logger = logger.Default.LogMode(logger.Info)
|
||||
} else {
|
||||
gormConfig.Logger = logger.Default.LogMode(logger.Silent)
|
||||
}
|
||||
|
||||
Db, err = gorm.Open(Type, gormConfig)
|
||||
if err != nil {
|
||||
log.Error("数据库连接失败: ", err)
|
||||
return
|
||||
|
|
|
|||
68
go.mod
68
go.mod
|
|
@ -3,7 +3,7 @@ module git.magicany.cc/black1552/gin-base
|
|||
go 1.25.0
|
||||
|
||||
require (
|
||||
git.magicany.cc/black1552/gf-common v1.0.1011
|
||||
git.magicany.cc/black1552/gf-common v1.0.1017
|
||||
github.com/eclipse/paho.mqtt.golang v1.5.1
|
||||
github.com/fsnotify/fsnotify v1.9.0
|
||||
github.com/gin-gonic/gin v1.12.0
|
||||
|
|
@ -12,25 +12,27 @@ require (
|
|||
github.com/golang-jwt/jwt/v5 v5.3.1
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/spf13/viper v1.21.0
|
||||
golang.org/x/crypto v0.48.0
|
||||
golang.org/x/crypto v0.49.0
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||
gorm.io/driver/mysql v1.6.0
|
||||
gorm.io/driver/sqlite v1.6.0
|
||||
gorm.io/gorm v1.31.1
|
||||
)
|
||||
|
||||
require (
|
||||
filippo.io/edwards25519 v1.1.1 // indirect
|
||||
filippo.io/edwards25519 v1.2.0 // indirect
|
||||
github.com/BurntSushi/toml v1.6.0 // indirect
|
||||
github.com/bytedance/gopkg v0.1.3 // indirect
|
||||
github.com/bytedance/gopkg v0.1.4 // indirect
|
||||
github.com/bytedance/sonic v1.15.0 // indirect
|
||||
github.com/bytedance/sonic/loader v0.5.0 // indirect
|
||||
github.com/bytedance/sonic/loader v0.5.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/clbanning/mxj/v2 v2.7.0 // indirect
|
||||
github.com/clipperhouse/displaywidth v0.10.0 // indirect
|
||||
github.com/clipperhouse/uax29/v2 v2.6.0 // indirect
|
||||
github.com/cloudwego/base64x v0.1.6 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/emirpasic/gods/v2 v2.0.0-alpha // indirect
|
||||
github.com/fatih/color v1.18.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.12 // indirect
|
||||
github.com/fatih/color v1.19.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.13 // indirect
|
||||
github.com/gin-contrib/sse v1.1.0 // indirect
|
||||
github.com/glebarez/go-sqlite v1.22.0 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
|
|
@ -38,9 +40,9 @@ require (
|
|||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.30.1 // indirect
|
||||
github.com/go-sql-driver/mysql v1.9.2 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
||||
github.com/goccy/go-json v0.10.5 // indirect
|
||||
github.com/go-sql-driver/mysql v1.9.3 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
|
||||
github.com/goccy/go-json v0.10.6 // indirect
|
||||
github.com/goccy/go-yaml v1.19.2 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/grokify/html-strip-tags-go v0.1.0 // indirect
|
||||
|
|
@ -52,21 +54,19 @@ require (
|
|||
github.com/magiconair/properties v1.8.10 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.22 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.21 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/ncruces/go-strftime v1.0.0 // indirect
|
||||
github.com/olekukonko/errors v1.1.0 // indirect
|
||||
github.com/olekukonko/ll v0.0.9 // indirect
|
||||
github.com/olekukonko/tablewriter v1.1.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||
github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 // indirect
|
||||
github.com/olekukonko/errors v1.2.0 // indirect
|
||||
github.com/olekukonko/ll v0.1.8 // indirect
|
||||
github.com/olekukonko/tablewriter v1.1.4 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.3.0 // indirect
|
||||
github.com/quic-go/qpack v0.6.0 // indirect
|
||||
github.com/quic-go/quic-go v0.59.0 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/sagikazarmark/locafero v0.11.0 // indirect
|
||||
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
|
||||
github.com/sagikazarmark/locafero v0.12.0 // indirect
|
||||
github.com/spf13/afero v1.15.0 // indirect
|
||||
github.com/spf13/cast v1.10.0 // indirect
|
||||
github.com/spf13/pflag v1.0.10 // indirect
|
||||
|
|
@ -74,22 +74,22 @@ require (
|
|||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.3.1 // indirect
|
||||
go.mongodb.org/mongo-driver/v2 v2.5.0 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/otel v1.38.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.38.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.38.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.38.0 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||
go.opentelemetry.io/otel v1.42.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.42.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.42.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.42.0 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/arch v0.22.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa // indirect
|
||||
golang.org/x/net v0.51.0 // indirect
|
||||
golang.org/x/sync v0.19.0 // indirect
|
||||
golang.org/x/sys v0.41.0 // indirect
|
||||
golang.org/x/text v0.34.0 // indirect
|
||||
google.golang.org/protobuf v1.36.10 // indirect
|
||||
golang.org/x/arch v0.25.0 // indirect
|
||||
golang.org/x/net v0.52.0 // indirect
|
||||
golang.org/x/sync v0.20.0 // indirect
|
||||
golang.org/x/sys v0.42.0 // indirect
|
||||
golang.org/x/text v0.35.0 // indirect
|
||||
golang.org/x/tools v0.43.0 // indirect
|
||||
google.golang.org/protobuf v1.36.11 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
modernc.org/libc v1.68.0 // indirect
|
||||
modernc.org/libc v1.70.0 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
modernc.org/memory v1.11.0 // indirect
|
||||
modernc.org/sqlite v1.46.1 // indirect
|
||||
modernc.org/sqlite v1.48.0 // indirect
|
||||
)
|
||||
|
|
|
|||
159
go.sum
159
go.sum
|
|
@ -1,17 +1,23 @@
|
|||
filippo.io/edwards25519 v1.1.1 h1:YpjwWWlNmGIDyXOn8zLzqiD+9TyIlPhGFG96P39uBpw=
|
||||
filippo.io/edwards25519 v1.1.1/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
git.magicany.cc/black1552/gf-common v1.0.1011 h1:utJu6F5xTi/Wbr19cXvVN3xi75nbqS3QE0U8sp8naFo=
|
||||
git.magicany.cc/black1552/gf-common v1.0.1011/go.mod h1:TRyOXXb0no1RqiCtbVgg7/V7+v3m6dlS0Sg6fcfKOgw=
|
||||
filippo.io/edwards25519 v1.2.0 h1:crnVqOiS4jqYleHd9vaKZ+HKtHfllngJIiOpNpoJsjo=
|
||||
filippo.io/edwards25519 v1.2.0/go.mod h1:xzAOLCNug/yB62zG1bQ8uziwrIqIuxhctzJT18Q77mc=
|
||||
git.magicany.cc/black1552/gf-common v1.0.1017 h1:KP0e32CSOzIYg8Nfqj7zwGakO6Co9HYTuiDZupK7LsU=
|
||||
git.magicany.cc/black1552/gf-common v1.0.1017/go.mod h1:ln6bd5oXxPNsktr8xI3itmsqpVBn1j+4W7iaS0g7S0Q=
|
||||
github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
|
||||
github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M=
|
||||
github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM=
|
||||
github.com/bytedance/gopkg v0.1.4 h1:oZnQwnX82KAIWb7033bEwtxvTqXcYMxDBaQxo5JJHWM=
|
||||
github.com/bytedance/gopkg v0.1.4/go.mod h1:v1zWfPm21Fb+OsyXN2VAHdL6TBb2L88anLQgdyje6R4=
|
||||
github.com/bytedance/sonic v1.15.0 h1:/PXeWFaR5ElNcVE84U0dOHjiMHQOwNIx3K4ymzh/uSE=
|
||||
github.com/bytedance/sonic v1.15.0/go.mod h1:tFkWrPz0/CUCLEF4ri4UkHekCIcdnkqXw9VduqpJh0k=
|
||||
github.com/bytedance/sonic/loader v0.5.0 h1:gXH3KVnatgY7loH5/TkeVyXPfESoqSBSBEiDd5VjlgE=
|
||||
github.com/bytedance/sonic/loader v0.5.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo=
|
||||
github.com/bytedance/sonic/loader v0.5.1 h1:Ygpfa9zwRCCKSlrp5bBP/b/Xzc3VxsAW+5NIYXrOOpI=
|
||||
github.com/bytedance/sonic/loader v0.5.1/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=
|
||||
github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
|
||||
github.com/clipperhouse/displaywidth v0.10.0 h1:GhBG8WuerxjFQQYeuZAeVTuyxuX+UraiZGD4HJQ3Y8g=
|
||||
github.com/clipperhouse/displaywidth v0.10.0/go.mod h1:XqJajYsaiEwkxOj4bowCTMcT1SgvHo9flfF3jQasdbs=
|
||||
github.com/clipperhouse/uax29/v2 v2.6.0 h1:z0cDbUV+aPASdFb2/ndFnS9ts/WNXgTNNGFoKXuhpos=
|
||||
github.com/clipperhouse/uax29/v2 v2.6.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g=
|
||||
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
|
||||
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
|
|
@ -23,14 +29,14 @@ github.com/eclipse/paho.mqtt.golang v1.5.1 h1:/VSOv3oDLlpqR2Epjn1Q7b2bSTplJIeV2I
|
|||
github.com/eclipse/paho.mqtt.golang v1.5.1/go.mod h1:1/yJCneuyOoCOzKSsOTUc0AJfpsItBGWvYpBLimhArU=
|
||||
github.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=
|
||||
github.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=
|
||||
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
||||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
||||
github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w=
|
||||
github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw=
|
||||
github.com/gabriel-vasile/mimetype v1.4.12/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||
github.com/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM=
|
||||
github.com/gabriel-vasile/mimetype v1.4.13/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
|
||||
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
|
||||
github.com/gin-gonic/gin v1.12.0 h1:b3YAbrZtnf8N//yjKeU2+MQsh2mY5htkZidOM7O0wG8=
|
||||
|
|
@ -52,12 +58,12 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
|
|||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.30.1 h1:f3zDSN/zOma+w6+1Wswgd9fLkdwy06ntQJp0BBvFG0w=
|
||||
github.com/go-playground/validator/v10 v10.30.1/go.mod h1:oSuBIQzuJxL//3MelwSLD5hc2Tu889bF0Idm9Dg26cM=
|
||||
github.com/go-sql-driver/mysql v1.9.2 h1:4cNKDYQ1I84SXslGddlsrMhc8k4LeDVj6Ad6WRjiHuU=
|
||||
github.com/go-sql-driver/mysql v1.9.2/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo=
|
||||
github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
|
||||
github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=
|
||||
github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/goccy/go-json v0.10.6 h1:p8HrPJzOakx/mn/bQtjgNjdTcN+/S6FcG2CTtQOrHVU=
|
||||
github.com/goccy/go-json v0.10.6/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=
|
||||
github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||
github.com/gogf/gf/v2 v2.10.0 h1:rzDROlyqGMe/eM6dCalSR8dZOuMIdLhmxKSH1DGhbFs=
|
||||
|
|
@ -97,10 +103,8 @@ github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHP
|
|||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/mattn/go-runewidth v0.0.21 h1:jJKAZiQH+2mIinzCJIaIG9Be1+0NR+5sz/lYEEjdM8w=
|
||||
github.com/mattn/go-runewidth v0.0.21/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
|
|
@ -108,14 +112,16 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
|
|||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
|
||||
github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||
github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=
|
||||
github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=
|
||||
github.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=
|
||||
github.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=
|
||||
github.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=
|
||||
github.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
||||
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||
github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 h1:zrbMGy9YXpIeTnGj4EljqMiZsIcE09mmF8XsD5AYOJc=
|
||||
github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6/go.mod h1:rEKTHC9roVVicUIfZK7DYrdIoM0EOr8mK1Hj5s3JjH0=
|
||||
github.com/olekukonko/errors v1.2.0 h1:10Zcn4GeV59t/EGqJc8fUjtFT/FuUh5bTMzZ1XwmCRo=
|
||||
github.com/olekukonko/errors v1.2.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=
|
||||
github.com/olekukonko/ll v0.1.8 h1:ysHCJRGHYKzmBSdz9w5AySztx7lG8SQY+naTGYUbsz8=
|
||||
github.com/olekukonko/ll v0.1.8/go.mod h1:RPRC6UcscfFZgjo1nulkfMH5IM0QAYim0LfnMvUuozw=
|
||||
github.com/olekukonko/tablewriter v1.1.4 h1:ORUMI3dXbMnRlRggJX3+q7OzQFDdvgbN9nVWj1drm6I=
|
||||
github.com/olekukonko/tablewriter v1.1.4/go.mod h1:+kedxuyTtgoZLwif3P1Em4hARJs+mVnzKxmsCL/C5RY=
|
||||
github.com/pelletier/go-toml/v2 v2.3.0 h1:k59bC/lIZREW0/iVaQR8nDHxVq8OVlIzYCOJf421CaM=
|
||||
github.com/pelletier/go-toml/v2 v2.3.0/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
|
||||
|
|
@ -124,15 +130,10 @@ github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SA
|
|||
github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc=
|
||||
github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
|
||||
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw=
|
||||
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/sagikazarmark/locafero v0.12.0 h1:/NQhBAkUb4+fH1jivKHWusDYFjMOOKU88eegjfxfHb4=
|
||||
github.com/sagikazarmark/locafero v0.12.0/go.mod h1:sZh36u/YSZ918v0Io+U9ogLYQJ9tLLBmM4eneO6WwsI=
|
||||
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
|
||||
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
|
||||
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
|
||||
|
|
@ -160,45 +161,43 @@ github.com/ugorji/go/codec v1.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY
|
|||
github.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
|
||||
go.mongodb.org/mongo-driver/v2 v2.5.0 h1:yXUhImUjjAInNcpTcAlPHiT7bIXhshCTL3jVBkF3xaE=
|
||||
go.mongodb.org/mongo-driver/v2 v2.5.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
||||
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
||||
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
||||
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
||||
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/otel v1.42.0 h1:lSQGzTgVR3+sgJDAU/7/ZMjN9Z+vUip7leaqBKy4sho=
|
||||
go.opentelemetry.io/otel v1.42.0/go.mod h1:lJNsdRMxCUIWuMlVJWzecSMuNjE7dOYyWlqOXWkdqCc=
|
||||
go.opentelemetry.io/otel/metric v1.42.0 h1:2jXG+3oZLNXEPfNmnpxKDeZsFI5o4J+nz6xUlaFdF/4=
|
||||
go.opentelemetry.io/otel/metric v1.42.0/go.mod h1:RlUN/7vTU7Ao/diDkEpQpnz3/92J9ko05BIwxYa2SSI=
|
||||
go.opentelemetry.io/otel/sdk v1.42.0 h1:LyC8+jqk6UJwdrI/8VydAq/hvkFKNHZVIWuslJXYsDo=
|
||||
go.opentelemetry.io/otel/sdk v1.42.0/go.mod h1:rGHCAxd9DAph0joO4W6OPwxjNTYWghRWmkHuGbayMts=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.42.0 h1:D/1QR46Clz6ajyZ3G8SgNlTJKBdGp84q9RKCAZ3YGuA=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.42.0/go.mod h1:Ua6AAlDKdZ7tdvaQKfSmnFTdHx37+J4ba8MwVCYM5hc=
|
||||
go.opentelemetry.io/otel/trace v1.42.0 h1:OUCgIPt+mzOnaUTpOQcBiM/PLQ/Op7oq6g4LenLmOYY=
|
||||
go.opentelemetry.io/otel/trace v1.42.0/go.mod h1:f3K9S+IFqnumBkKhRJMeaZeNk9epyhnCmQh/EysQCdc=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
|
||||
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
|
||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
golang.org/x/arch v0.22.0 h1:c/Zle32i5ttqRXjdLyyHZESLD/bB90DCU1g9l/0YBDI=
|
||||
golang.org/x/arch v0.22.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A=
|
||||
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
||||
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
|
||||
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0=
|
||||
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA=
|
||||
golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8=
|
||||
golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w=
|
||||
golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=
|
||||
golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
|
||||
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/arch v0.25.0 h1:qnk6Ksugpi5Bz32947rkUgDt9/s5qvqDPl/gBKdMJLE=
|
||||
golang.org/x/arch v0.25.0/go.mod h1:0X+GdSIP+kL5wPmpK7sdkEVTt2XoYP0cSjQSbZBwOi8=
|
||||
golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
|
||||
golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
|
||||
golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI=
|
||||
golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY=
|
||||
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
|
||||
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
|
||||
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
||||
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
|
||||
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
|
||||
golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=
|
||||
golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=
|
||||
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
|
||||
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
||||
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
|
||||
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
|
||||
golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s=
|
||||
golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
|
|
@ -209,24 +208,22 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
|||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gorm.io/driver/mysql v1.6.0 h1:eNbLmNTpPpTOVZi8MMxCi2aaIm0ZpInbORNXDwyLGvg=
|
||||
gorm.io/driver/mysql v1.6.0/go.mod h1:D/oCC2GWK3M/dqoLxnOlaNKmXz8WNTfcS9y5ovaSqKo=
|
||||
gorm.io/driver/sqlite v1.6.0 h1:WHRRrIiulaPiPFmDcod6prc4l2VGVWHz80KspNsxSfQ=
|
||||
gorm.io/driver/sqlite v1.6.0/go.mod h1:AO9V1qIQddBESngQUKWL9yoH93HIeA1X6V633rBwyT8=
|
||||
gorm.io/gorm v1.31.1 h1:7CA8FTFz/gRfgqgpeKIBcervUn3xSyPUmr6B2WXJ7kg=
|
||||
gorm.io/gorm v1.31.1/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs=
|
||||
modernc.org/cc/v4 v4.27.1 h1:9W30zRlYrefrDV2JE2O8VDtJ1yPGownxciz5rrbQZis=
|
||||
modernc.org/cc/v4 v4.27.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
|
||||
modernc.org/ccgo/v4 v4.30.2 h1:4yPaaq9dXYXZ2V8s1UgrC3KIj580l2N4ClrLwnbv2so=
|
||||
modernc.org/ccgo/v4 v4.30.2/go.mod h1:yZMnhWEdW0qw3EtCndG1+ldRrVGS+bIwyWmAWzS0XEw=
|
||||
modernc.org/fileutil v1.3.40 h1:ZGMswMNc9JOCrcrakF1HrvmergNLAmxOPjizirpfqBA=
|
||||
modernc.org/fileutil v1.3.40/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc=
|
||||
modernc.org/ccgo/v4 v4.32.0 h1:hjG66bI/kqIPX1b2yT6fr/jt+QedtP2fqojG2VrFuVw=
|
||||
modernc.org/ccgo/v4 v4.32.0/go.mod h1:6F08EBCx5uQc38kMGl+0Nm0oWczoo1c7cgpzEry7Uc0=
|
||||
modernc.org/fileutil v1.4.0 h1:j6ZzNTftVS054gi281TyLjHPp6CPHr2KCxEXjEbD6SM=
|
||||
modernc.org/fileutil v1.4.0/go.mod h1:EqdKFDxiByqxLk8ozOxObDSfcVOv/54xDs/DUHdvCUU=
|
||||
modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
|
||||
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
|
||||
modernc.org/gc/v3 v3.1.2 h1:ZtDCnhonXSZexk/AYsegNRV1lJGgaNZJuKjJSWKyEqo=
|
||||
modernc.org/gc/v3 v3.1.2/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY=
|
||||
modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=
|
||||
modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=
|
||||
modernc.org/libc v1.68.0 h1:PJ5ikFOV5pwpW+VqCK1hKJuEWsonkIJhhIXyuF/91pQ=
|
||||
modernc.org/libc v1.68.0/go.mod h1:NnKCYeoYgsEqnY3PgvNgAeaJnso968ygU8Z0DxjoEc0=
|
||||
modernc.org/libc v1.70.0 h1:U58NawXqXbgpZ/dcdS9kMshu08aiA6b7gusEusqzNkw=
|
||||
modernc.org/libc v1.70.0/go.mod h1:OVmxFGP1CI/Z4L3E0Q3Mf1PDE0BucwMkcXjjLntvHJo=
|
||||
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
|
||||
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
|
||||
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
|
||||
|
|
@ -235,8 +232,8 @@ modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
|
|||
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
|
||||
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
|
||||
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
|
||||
modernc.org/sqlite v1.46.1 h1:eFJ2ShBLIEnUWlLy12raN0Z1plqmFX9Qe3rjQTKt6sU=
|
||||
modernc.org/sqlite v1.46.1/go.mod h1:CzbrU2lSB1DKUusvwGz7rqEKIq+NUd8GWuBBZDs9/nA=
|
||||
modernc.org/sqlite v1.48.0 h1:ElZyLop3Q2mHYk5IFPPXADejZrlHu7APbpB0sF78bq4=
|
||||
modernc.org/sqlite v1.48.0/go.mod h1:hWjRO6Tj/5Ik8ieqxQybiEOUXy0NJFNp2tpvVpKlvig=
|
||||
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
|
||||
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
|
||||
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
package log
|
||||
114
log/log.go
114
log/log.go
|
|
@ -5,6 +5,7 @@ import (
|
|||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
|
|
@ -16,8 +17,11 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
logPath string
|
||||
sysLog *log.Logger
|
||||
logPath string
|
||||
sysLog *log.Logger
|
||||
filePath string
|
||||
currentDate string // 当前日志文件对应的日期
|
||||
fileLogger *lumberjack.Logger
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -59,10 +63,103 @@ func (w *logWriter) Write(p []byte) (n int, err error) {
|
|||
return len(p), nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
// cleanOldLogs 删除指定天数之前的日志文件(包括主文件和备份文件)
|
||||
func cleanOldLogs(days int) {
|
||||
if !gfile.Exists(logPath) {
|
||||
return
|
||||
}
|
||||
|
||||
// 获取所有日志文件
|
||||
files, err := gfile.DirNames(logPath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
for _, file := range files {
|
||||
path := filepath.Join(logPath, file)
|
||||
if gfile.IsDir(path) {
|
||||
continue
|
||||
}
|
||||
|
||||
var dateStr string
|
||||
var matched bool
|
||||
|
||||
// 匹配主日志文件格式:log-YYYY-MM-DD.log
|
||||
if strings.HasPrefix(file, "log-") && strings.HasSuffix(file, ".log") {
|
||||
// 检查是否是主文件(没有备份时间戳)
|
||||
// 主文件格式:log-2026-04-25.log
|
||||
// 备份文件格式:log-2026-04-25-2026-04-25T10-30-45.123.log
|
||||
parts := strings.Split(strings.TrimSuffix(file, ".log"), "-")
|
||||
if len(parts) == 4 {
|
||||
// 主文件:log-YYYY-MM-DD
|
||||
dateStr = parts[1] + "-" + parts[2] + "-" + parts[3]
|
||||
matched = true
|
||||
} else if len(parts) > 4 {
|
||||
// 备份文件:log-YYYY-MM-DD-YYYY-MM-DDTHH-MM-SS.mmm
|
||||
// 提取主日期部分(第一个日期)
|
||||
dateStr = parts[1] + "-" + parts[2] + "-" + parts[3]
|
||||
matched = true
|
||||
}
|
||||
}
|
||||
|
||||
if !matched {
|
||||
continue
|
||||
}
|
||||
|
||||
// 解析日期
|
||||
fileTime, err := time.Parse("2006-01-02", dateStr)
|
||||
if err != nil {
|
||||
continue // 日期格式不正确,跳过
|
||||
}
|
||||
|
||||
// 计算文件年龄
|
||||
tage := now.Sub(fileTime)
|
||||
if tage.Hours() > float64(days*24) {
|
||||
// 超过指定天数,删除文件
|
||||
err = os.Remove(path)
|
||||
if err == nil {
|
||||
Info(fmt.Sprintf("已删除过期日志文件:%s", file))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// checkAndRotateLogFile 检查是否需要切换日志文件(跨天时)
|
||||
func checkAndRotateLogFile() {
|
||||
date := gtime.Date()
|
||||
if currentDate != date {
|
||||
// 日期变化,需要重新初始化
|
||||
currentDate = date
|
||||
filePath = gfile.Join(logPath, fmt.Sprintf("log-%s.log", currentDate))
|
||||
fileLogger = &lumberjack.Logger{
|
||||
Filename: filePath,
|
||||
MaxSize: 2, // 单个文件最大 10MB
|
||||
MaxBackups: 5, // 最多保留 5 个备份
|
||||
MaxAge: 30, // 保留 30 天
|
||||
Compress: false, // 启用压缩
|
||||
}
|
||||
// 创建新的 writer
|
||||
multiWriter := &logWriter{
|
||||
console: os.Stdout,
|
||||
file: fileLogger,
|
||||
}
|
||||
sysLog = log.New(multiWriter, "", 0)
|
||||
|
||||
// 清理 30 天前的旧日志
|
||||
cleanOldLogs(30)
|
||||
}
|
||||
}
|
||||
|
||||
func Init() {
|
||||
if sysLog != nil {
|
||||
checkAndRotateLogFile() // 检查是否需要切换文件
|
||||
return
|
||||
}
|
||||
logPath = gfile.Join(gfile.Pwd(), "logs")
|
||||
filePath := gfile.Join(logPath, fmt.Sprintf("log-%s.log", gtime.Date()))
|
||||
fileLogger := &lumberjack.Logger{
|
||||
currentDate = gtime.Date()
|
||||
filePath = gfile.Join(logPath, fmt.Sprintf("log-%s.log", currentDate))
|
||||
fileLogger = &lumberjack.Logger{
|
||||
Filename: filePath,
|
||||
MaxSize: 2, // 单个文件最大 10MB
|
||||
MaxBackups: 5, // 最多保留 5 个备份
|
||||
|
|
@ -75,22 +172,29 @@ func init() {
|
|||
file: fileLogger,
|
||||
}
|
||||
sysLog = log.New(multiWriter, "", 0)
|
||||
|
||||
// 启动时清理 30 天前的旧日志
|
||||
cleanOldLogs(30)
|
||||
}
|
||||
|
||||
func Info(v ...any) {
|
||||
Init()
|
||||
sysLog.SetPrefix(fmt.Sprintf("[%s] %s[INFO]%s ", time.Now().Format("2006-01-02 15:04:05"), Green, Reset))
|
||||
sysLog.Println(fmt.Sprint(v...))
|
||||
}
|
||||
func Error(v ...any) {
|
||||
Init()
|
||||
sysLog.SetPrefix(fmt.Sprintf("[%s] %s[ERROR]%s ", time.Now().Format("2006-01-02 15:04:05"), Red, Reset))
|
||||
msg := fmt.Sprint(v...)
|
||||
sysLog.Println(msg, strings.TrimSpace(string(debug.Stack())))
|
||||
}
|
||||
func Warn(v ...any) {
|
||||
Init()
|
||||
sysLog.SetPrefix(fmt.Sprintf("[%s] %s[WARN]%s ", time.Now().Format("2006-01-02 15:04:05"), Yellow, Reset))
|
||||
sysLog.Println(fmt.Sprint(v...))
|
||||
}
|
||||
func Debug(v ...any) {
|
||||
Init()
|
||||
sysLog.SetPrefix(fmt.Sprintf("[%s] %s[DEBUG]%s ", time.Now().Format("2006-01-02 15:04:05"), Blue, Reset))
|
||||
sysLog.Println(fmt.Sprint(v...))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,8 +33,9 @@ func New() *gin.Engine {
|
|||
// @Param *gin.Engine 路由实例
|
||||
// 设置监听挂壁
|
||||
func Run(g *gin.Engine) {
|
||||
addr := config.GetConfigValue("server.addr", ":8080").String()
|
||||
s := &http.Server{
|
||||
Addr: config.GetConfigValue("server.addr", ":8080").String(),
|
||||
Addr: addr,
|
||||
Handler: g,
|
||||
ReadTimeout: 60 * time.Second,
|
||||
ReadHeaderTimeout: 60 * time.Second,
|
||||
|
|
@ -44,15 +45,24 @@ func Run(g *gin.Engine) {
|
|||
}
|
||||
go func() {
|
||||
if err := s.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||
log.Error("服务器启动失败:", err)
|
||||
// 检查是否是端口被占用的错误
|
||||
if strings.Contains(err.Error(), "address already in use") ||
|
||||
strings.Contains(err.Error(), "Only one usage of each socket address") {
|
||||
log.Error(fmt.Sprintf("服务器启动失败:%s 端口已被占用,请检查是否有其他程序正在使用该端口", addr))
|
||||
} else {
|
||||
log.Error("服务器启动失败:", err)
|
||||
}
|
||||
os.Exit(1) // 启动失败则退出程序
|
||||
}
|
||||
}()
|
||||
time.Sleep(time.Second)
|
||||
log.Info("服务器启动成功....")
|
||||
if strings.Contains(s.Addr, "127.0.0.1") || strings.Contains(s.Addr, "0.0.0.0") || strings.Contains(s.Addr, "locahost") {
|
||||
log.Info("请使用打开:", fmt.Sprintf("http://%s\n", s.Addr))
|
||||
} else {
|
||||
log.Info("请使用打开:", fmt.Sprintf("http://localhost%s\n", s.Addr))
|
||||
}
|
||||
|
||||
// 等待中断信号以优雅地关闭服务器
|
||||
quit := make(chan os.Signal, 1)
|
||||
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
|
|
|||
Loading…
Reference in New Issue