package base import ( "context" "mayfly-go/pkg/contextx" "mayfly-go/pkg/gormx" "mayfly-go/pkg/model" "mayfly-go/pkg/utils/collx" "time" "gorm.io/gorm" ) // 基础repo接口 type Repo[T model.ModelI] interface { // GetModel 获取表的模型实例 GetModel() T // 新增一个实体 Insert(ctx context.Context, e T) error // 使用指定gorm db执行,主要用于事务执行 InsertWithDb(ctx context.Context, db *gorm.DB, e T) error // 批量新增实体 BatchInsert(ctx context.Context, models []T) error // 使用指定gorm db执行,主要用于事务执行 BatchInsertWithDb(ctx context.Context, db *gorm.DB, models []T) error // 根据实体id更新实体信息 UpdateById(ctx context.Context, e T, columns ...string) error // 使用指定gorm db执行,主要用于事务执行 UpdateByIdWithDb(ctx context.Context, db *gorm.DB, e T, columns ...string) error // UpdateByCond 更新满足条件的数据 // @param values 需要模型结构体或map // @param cond 条件 UpdateByCond(ctx context.Context, values any, cond any) error // UpdateByCondWithDb 更新满足条件的数据 // @param values 需要模型结构体或map UpdateByCondWithDb(ctx context.Context, db *gorm.DB, values any, cond any) error // 保存实体,实体IsCreate返回true则新增,否则更新 Save(ctx context.Context, e T) error // 保存实体,实体IsCreate返回true则新增,否则更新。 // 使用指定gorm db执行,主要用于事务执行 SaveWithDb(ctx context.Context, db *gorm.DB, e T) error // 根据实体主键删除实体 DeleteById(ctx context.Context, id ...uint64) error // 使用指定gorm db执行,主要用于事务执行 DeleteByIdWithDb(ctx context.Context, db *gorm.DB, id ...uint64) error // 根据实体条件删除实体 DeleteByCond(ctx context.Context, cond any) error // 使用指定gorm db执行,主要用于事务执行 DeleteByCondWithDb(ctx context.Context, db *gorm.DB, cond any) error // ExecBySql 执行原生sql ExecBySql(sql string, params ...any) error // 根据实体id查询 GetById(e T, id uint64, cols ...string) error // 根据实体id数组查询对应实体列表,并将响应结果映射至list GetByIds(list any, ids []uint64, orderBy ...string) error // GetByCond 根据实体条件查询实体信息(单个结果集) GetByCond(cond any) error // SelectByCond 根据实体条件查询数据映射至res SelectByCond(cond any, res any) error // PageByCond 根据查询条件分页查询 PageByCond(cond any, pageParam *model.PageParam, toModels any) (*model.PageResult[any], error) // SelectBySql 根据sql语句查询数据 SelectBySql(sql string, res any, params ...any) error // 根据指定条件统计model表的数量 CountByCond(cond any) int64 } // 基础repo接口 type RepoImpl[T model.ModelI] struct { M T // 模型实例 } func (br *RepoImpl[T]) Insert(ctx context.Context, e T) error { if db := contextx.GetDb(ctx); db != nil { return br.InsertWithDb(ctx, db, e) } return gormx.Insert(br.fillBaseInfo(ctx, e)) } func (br *RepoImpl[T]) InsertWithDb(ctx context.Context, db *gorm.DB, e T) error { return gormx.InsertWithDb(db, br.fillBaseInfo(ctx, e)) } func (br *RepoImpl[T]) BatchInsert(ctx context.Context, es []T) error { if db := contextx.GetDb(ctx); db != nil { return br.BatchInsertWithDb(ctx, db, es) } for _, e := range es { br.fillBaseInfo(ctx, e) } return gormx.BatchInsert[T](es) } // 使用指定gorm db执行,主要用于事务执行 func (br *RepoImpl[T]) BatchInsertWithDb(ctx context.Context, db *gorm.DB, es []T) error { for _, e := range es { br.fillBaseInfo(ctx, e) } return gormx.BatchInsertWithDb[T](db, es) } func (br *RepoImpl[T]) UpdateById(ctx context.Context, e T, columns ...string) error { return br.UpdateByIdWithDb(ctx, contextx.GetDb(ctx), e, columns...) } func (br *RepoImpl[T]) UpdateByIdWithDb(ctx context.Context, db *gorm.DB, e T, columns ...string) error { if db == nil { return gormx.UpdateById(br.fillBaseInfo(ctx, e), columns...) } return gormx.UpdateByIdWithDb(db, br.fillBaseInfo(ctx, e), columns...) } func (br *RepoImpl[T]) UpdateByCond(ctx context.Context, values any, cond any) error { return br.UpdateByCondWithDb(ctx, contextx.GetDb(ctx), values, cond) } func (br *RepoImpl[T]) UpdateByCondWithDb(ctx context.Context, db *gorm.DB, values any, cond any) error { if e, ok := values.(T); ok { // 先随机设置一个id,让fillBaseInfo不填充create信息 e.SetId(1) e = br.fillBaseInfo(ctx, e) // model的主键值需为空,否则会带上主键条件 e.SetId(0) values = e } else { var mapValues map[string]any // 非model实体,则为map if m, ok := values.(map[string]any); ok { mapValues = m } else if collxm, ok := values.(collx.M); ok { mapValues = map[string]any(collxm) } if len(mapValues) > 0 { mapValues[model.UpdateTimeColumn] = time.Now() if la := contextx.GetLoginAccount(ctx); la != nil { mapValues[model.ModifierColumn] = la.Username mapValues[model.ModifierIdColumn] = la.Id } values = mapValues } } if db == nil { return gormx.UpdateByCond(br.GetModel(), values, toQueryCond(cond)) } return gormx.UpdateByCondWithDb(db, br.GetModel(), values, toQueryCond(cond)) } func (br *RepoImpl[T]) Save(ctx context.Context, e T) error { if e.IsCreate() { return br.Insert(ctx, e) } return br.UpdateById(ctx, e) } func (br *RepoImpl[T]) SaveWithDb(ctx context.Context, db *gorm.DB, e T) error { if e.IsCreate() { return br.InsertWithDb(ctx, db, e) } return br.UpdateByIdWithDb(ctx, db, e) } func (br *RepoImpl[T]) DeleteById(ctx context.Context, id ...uint64) error { if db := contextx.GetDb(ctx); db != nil { return br.DeleteByIdWithDb(ctx, db, id...) } return gormx.DeleteById(br.GetModel(), id...) } func (br *RepoImpl[T]) DeleteByIdWithDb(ctx context.Context, db *gorm.DB, id ...uint64) error { return gormx.DeleteByIdWithDb(db, br.GetModel(), id...) } func (br *RepoImpl[T]) DeleteByCond(ctx context.Context, cond any) error { if db := contextx.GetDb(ctx); db != nil { return br.DeleteByCondWithDb(ctx, db, cond) } return gormx.DeleteByCond(br.GetModel(), toQueryCond(cond)) } func (br *RepoImpl[T]) DeleteByCondWithDb(ctx context.Context, db *gorm.DB, cond any) error { return gormx.DeleteByCondWithDb(db, br.GetModel(), toQueryCond(cond)) } func (br *RepoImpl[T]) ExecBySql(sql string, params ...any) error { return gormx.ExecSql(sql, params...) } func (br *RepoImpl[T]) GetById(e T, id uint64, cols ...string) error { if err := gormx.GetById(e, id, cols...); err != nil { return err } return nil } func (br *RepoImpl[T]) GetByIds(list any, ids []uint64, orderBy ...string) error { return br.SelectByCond(model.NewCond().In(model.IdColumn, ids).OrderBy(orderBy...), list) } func (br *RepoImpl[T]) GetByCond(cond any) error { return gormx.GetByCond(br.GetModel(), toQueryCond(cond)) } func (br *RepoImpl[T]) SelectByCond(cond any, res any) error { return gormx.SelectByCond(br.GetModel(), toQueryCond(cond).Dest(res)) } func (br *RepoImpl[T]) PageByCond(cond any, pageParam *model.PageParam, toModels any) (*model.PageResult[any], error) { return gormx.PageByCond(br.GetModel(), toQueryCond(cond), pageParam, toModels) } func (br *RepoImpl[T]) SelectBySql(sql string, res any, params ...any) error { return gormx.SelectBySql(sql, res, params...) } func (br *RepoImpl[T]) CountByCond(cond any) int64 { return gormx.CountByCond(br.GetModel(), toQueryCond(cond)) } // GetModel 获取表的模型实例 func (br *RepoImpl[T]) GetModel() T { return br.M } // 从上下文获取登录账号信息,并赋值至实体 func (br *RepoImpl[T]) fillBaseInfo(ctx context.Context, e T) T { // 默认使用数据库id策略, 若要改变则实体结构体自行覆盖FillBaseInfo方法。可参考 sys/entity.Resource e.FillBaseInfo(model.IdGenTypeNone, contextx.GetLoginAccount(ctx)) return e } // toQueryCond 统一转为*model.QueryCond func toQueryCond(cond any) *model.QueryCond { if qc, ok := cond.(*model.QueryCond); ok { return qc } return model.NewModelCond(cond) }