优化结构
This commit is contained in:
@@ -46,7 +46,7 @@ func waitForDataScopeAuditCount(t *testing.T, db *gorm.DB, want int64) {
|
||||
|
||||
func TestDataScopeAuditWriterFlushesBatch(t *testing.T) {
|
||||
db := openDataScopeAuditTestDB(t, "data-scope-audit-batch")
|
||||
d := &Data{gormDB: newReloadableDB(db, nil)}
|
||||
d := &Data{gormDB: newReloadableDB(db)}
|
||||
w := newDataScopeAuditWriterWithOptions(d, slog.New(slog.NewTextHandler(io.Discard, nil)), 8, 2, time.Hour)
|
||||
d.auditLog = w
|
||||
t.Cleanup(w.Close)
|
||||
@@ -59,7 +59,7 @@ func TestDataScopeAuditWriterFlushesBatch(t *testing.T) {
|
||||
func TestDataScopeAuditWriterUsesReloadedDatabase(t *testing.T) {
|
||||
first := openDataScopeAuditTestDB(t, "data-scope-audit-first")
|
||||
second := openDataScopeAuditTestDB(t, "data-scope-audit-second")
|
||||
d := &Data{gormDB: newReloadableDB(first, nil)}
|
||||
d := &Data{gormDB: newReloadableDB(first)}
|
||||
w := newDataScopeAuditWriterWithOptions(d, slog.New(slog.NewTextHandler(io.Discard, nil)), 8, 100, 10*time.Millisecond)
|
||||
d.auditLog = w
|
||||
t.Cleanup(w.Close)
|
||||
|
||||
@@ -16,11 +16,11 @@ import (
|
||||
|
||||
func TestGORMLoggerUsesApplicationCategories(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
appLogger, cleanup := logging.NewZapLogger(root, "application.log", logging.Options{Level: "info", Format: "json"})
|
||||
appLogger, control := logging.NewReloadableZapLogger(root, "application.log", logging.Options{Level: "info", Format: "json"})
|
||||
databaseLogger := gormkit.NewLogger(appLogger, logger.Info)
|
||||
databaseLogger.Trace(context.Background(), time.Now(), func() (string, int64) { return "SELECT 1", 1 }, nil)
|
||||
databaseLogger.Trace(context.Background(), time.Now(), func() (string, int64) { return "SELECT missing", 0 }, errors.New("database failure"))
|
||||
cleanup()
|
||||
control.Close()
|
||||
|
||||
date := time.Now().Format("2006-01-02")
|
||||
for _, name := range []string{"application.log", filepath.Join("sql", "application.log"), filepath.Join("error", "error.log")} {
|
||||
|
||||
@@ -247,7 +247,7 @@ func TestPersistRuntimeConfigReplacesActiveStorage(t *testing.T) {
|
||||
}
|
||||
d := &Data{
|
||||
runtime: config.NewStore(&config.Config{Data: &config.Data{}, Admin: currentAdmin}),
|
||||
gormDB: newReloadableDB(db, nil),
|
||||
gormDB: newReloadableDB(db),
|
||||
storage: currentStorage,
|
||||
}
|
||||
d.databaseReady.Store(true)
|
||||
|
||||
@@ -165,7 +165,7 @@ func (r *rollback) run() {
|
||||
|
||||
// newReloadableDB owns only the hot-swappable database handle. Domain-specific
|
||||
// callbacks are attached by Data when a pool becomes active.
|
||||
func newReloadableDB(db *gorm.DB, _ ...dataScopeAuditEnqueue) *reloadable[*gorm.DB] {
|
||||
func newReloadableDB(db *gorm.DB) *reloadable[*gorm.DB] {
|
||||
return newReloadable(db, closeGormDB)
|
||||
}
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ func (r *announcementRepo) List(ctx context.Context, filter system.AnnouncementF
|
||||
if filter.StartCreatedAt != nil && filter.EndCreatedAt != nil {
|
||||
db = db.Where("created_at BETWEEN ? AND ?", filter.StartCreatedAt, filter.EndCreatedAt)
|
||||
}
|
||||
return listRows(db.Order("id desc"), filter.Page, filter.PageSize, filter.PageSize > 0, func(po announcementPO) *system.Announcement {
|
||||
return listRows(db.Order("id desc"), filter.Page, filter.PageSize, rowQueryOptions{Paginate: filter.PageSize > 0}, func(po announcementPO) *system.Announcement {
|
||||
return announcementToBiz(po)
|
||||
})
|
||||
}
|
||||
@@ -83,7 +83,7 @@ func (r *announcementRepo) UserOptions(ctx context.Context) ([]system.UserOption
|
||||
}
|
||||
// The generated data-source endpoint is best effort: return collected
|
||||
// options even when the underlying scan reports an error.
|
||||
_ = r.data.DB().WithContext(ctx).Table("sys_users").Select("nick_name AS label, id AS value").Scan(&rows).Error
|
||||
_ = r.data.DB().WithContext(ctx).Model(&userPO{}).Select("nick_name AS label, id AS value").Scan(&rows).Error
|
||||
items := make([]system.UserOption, 0, len(rows))
|
||||
for _, row := range rows {
|
||||
items = append(items, system.UserOption{Label: row.Label, Value: row.Value})
|
||||
|
||||
@@ -249,11 +249,8 @@ func (r *authorityAccessRepo) CopyAuthority(ctx context.Context, sourceID uint,
|
||||
}
|
||||
value.CreatedAt, value.UpdatedAt = po.CreatedAt, po.UpdatedAt
|
||||
value.DataScope, value.DefaultRouter = po.DataScope, po.DefaultRouter
|
||||
copyLinks := func(table string, destination any, columns map[string]any) error {
|
||||
return tx.Table(table).Where(columns).Find(destination).Error
|
||||
}
|
||||
var menus []authorityMenuPO
|
||||
if err := copyLinks("sys_authority_menus", &menus, map[string]any{"sys_authority_authority_id": sourceID}); err != nil {
|
||||
if err := tx.Model(&authorityMenuPO{}).Where("sys_authority_authority_id = ?", sourceID).Find(&menus).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if strict && len(menus) > 0 {
|
||||
@@ -316,7 +313,7 @@ func (r *authorityAccessRepo) CopyAuthority(ctx context.Context, sourceID uint,
|
||||
}
|
||||
}
|
||||
var buttons []authorityButtonPO
|
||||
if err := copyLinks("sys_authority_btns", &buttons, map[string]any{"authority_id": sourceID}); err != nil {
|
||||
if err := tx.Model(&authorityButtonPO{}).Where("authority_id = ?", sourceID).Find(&buttons).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if strict && len(buttons) > 0 {
|
||||
|
||||
@@ -35,7 +35,7 @@ func (r *auditQueryRepo) ListDataAccess(ctx context.Context, page, size int, q *
|
||||
db = db.Where("target_table LIKE ?", "%"+q.TargetTable+"%")
|
||||
}
|
||||
}
|
||||
pos, total, err := queryRows[DataAccessLogPO](db.Order("id desc"), page, size, true, true)
|
||||
pos, total, err := queryRows[DataAccessLogPO](db.Order("id desc"), page, size, rowQueryOptions{Paginate: true, Required: true})
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ func (r *auditQueryRepo) ListErrors(ctx context.Context, page, size int, q *syst
|
||||
db = db.Where("info LIKE ?", "%"+*q.Info+"%")
|
||||
}
|
||||
}
|
||||
return listRows(db.Order("created_at desc"), page, size, true, func(po errorRecordPO) *system.ErrorRecord {
|
||||
return listRows(db.Order("created_at desc"), page, size, rowQueryOptions{Paginate: true}, func(po errorRecordPO) *system.ErrorRecord {
|
||||
return errorFromPO(po)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -10,13 +10,18 @@ import (
|
||||
// count the filtered query, apply the bounded page, load POs, and convert them
|
||||
// at the data/biz boundary. Domain-specific filters and ordering stay in each
|
||||
// repository.
|
||||
func queryRows[PO any](db *gorm.DB, page, size int, paginate, required bool) ([]PO, int64, error) {
|
||||
type rowQueryOptions struct {
|
||||
Paginate bool
|
||||
Required bool
|
||||
}
|
||||
|
||||
func queryRows[PO any](db *gorm.DB, page, size int, options rowQueryOptions) ([]PO, int64, error) {
|
||||
var total int64
|
||||
if err := db.Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
if paginate {
|
||||
if required {
|
||||
if options.Paginate {
|
||||
if options.Required {
|
||||
db = pagination.ApplyRequired(db, page, size, 100)
|
||||
} else {
|
||||
db = pagination.Apply(db, page, size, 100)
|
||||
@@ -29,8 +34,8 @@ func queryRows[PO any](db *gorm.DB, page, size int, paginate, required bool) ([]
|
||||
return pos, total, nil
|
||||
}
|
||||
|
||||
func listRows[PO any, DO any](db *gorm.DB, page, size int, paginate bool, convert func(PO) *DO) ([]*DO, int64, error) {
|
||||
pos, total, err := queryRows[PO](db, page, size, paginate, false)
|
||||
func listRows[PO any, DO any](db *gorm.DB, page, size int, options rowQueryOptions, convert func(PO) *DO) ([]*DO, int64, error) {
|
||||
pos, total, err := queryRows[PO](db, page, size, options)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ func (r *auditQueryRepo) ListLogins(ctx context.Context, page, size int, q *syst
|
||||
db = db.Where("created_at <= ?", *q.EndCreatedAt)
|
||||
}
|
||||
}
|
||||
pos, total, err := queryRows[loginLogPO](db.Order("id desc"), page, size, true, true)
|
||||
pos, total, err := queryRows[loginLogPO](db.Order("id desc"), page, size, rowQueryOptions{Paginate: true, Required: true})
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ func (r *auditQueryRepo) ListOperations(ctx context.Context, page, size int, q *
|
||||
db = db.Where("status = ?", q.Status)
|
||||
}
|
||||
}
|
||||
pos, total, err := queryRows[operationPO](db.Order("id desc"), page, size, true, true)
|
||||
pos, total, err := queryRows[operationPO](db.Order("id desc"), page, size, rowQueryOptions{Paginate: true, Required: true})
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ func (r *parameterRepo) ListParameters(ctx context.Context, page, size int, q *s
|
||||
db = db.Where(clause.Like{Column: clause.Column{Name: "key"}, Value: "%" + q.Key + "%"})
|
||||
}
|
||||
}
|
||||
return listRows(db.Order("id desc"), page, size, true, func(po parameterPO) *system.SystemParameter {
|
||||
return listRows(db.Order("id desc"), page, size, rowQueryOptions{Paginate: true}, func(po parameterPO) *system.SystemParameter {
|
||||
return parameterFromPO(po)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -85,5 +85,5 @@ func (r *securityRepo) SaveSecurityConfig(ctx context.Context, v *system.Securit
|
||||
}
|
||||
|
||||
func (r *securityRepo) BackfillPasswordUpdatedAt(ctx context.Context, at time.Time) error {
|
||||
return r.data.DB().WithContext(ctx).Table("sys_users").Where("password_updated_at IS NULL").Update("password_updated_at", at).Error
|
||||
return r.data.DB().WithContext(ctx).Model(&userPO{}).Where("password_updated_at IS NULL").Update("password_updated_at", at).Error
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ func (r *userRepo) loadUser(ctx context.Context, po *userPO) (*system.User, erro
|
||||
return nil, err
|
||||
}
|
||||
var authorityPOs []authorityPO
|
||||
if err := r.data.DB().WithContext(ctx).Table("sys_authorities").Joins("JOIN sys_user_authority ON sys_user_authority.sys_authority_authority_id = sys_authorities.authority_id").Where("sys_user_authority.sys_user_id = ? AND sys_authorities.deleted_at IS NULL", po.ID).Find(&authorityPOs).Error; err != nil {
|
||||
if err := r.data.DB().WithContext(ctx).Model(&authorityPO{}).Joins("JOIN sys_user_authority ON sys_user_authority.sys_authority_authority_id = sys_authorities.authority_id").Where("sys_user_authority.sys_user_id = ? AND sys_authorities.deleted_at IS NULL", po.ID).Find(&authorityPOs).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authorities := make([]system.Authority, 0, len(authorityPOs))
|
||||
@@ -68,7 +68,7 @@ func (r *userRepo) loadUser(ctx context.Context, po *userPO) (*system.User, erro
|
||||
return nil, err
|
||||
}
|
||||
var departmentPOs []departmentPO
|
||||
if err := r.data.DB().WithContext(ctx).Table("sys_departments").Joins("JOIN sys_user_departments ON sys_user_departments.sys_department_id = sys_departments.id").Where("sys_user_departments.sys_user_id = ? AND sys_departments.deleted_at IS NULL", po.ID).Find(&departmentPOs).Error; err != nil {
|
||||
if err := r.data.DB().WithContext(ctx).Model(&departmentPO{}).Joins("JOIN sys_user_departments ON sys_user_departments.sys_department_id = sys_departments.id").Where("sys_user_departments.sys_user_id = ? AND sys_departments.deleted_at IS NULL", po.ID).Find(&departmentPOs).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
departments := make([]system.Department, 0, len(departmentPOs))
|
||||
@@ -86,7 +86,7 @@ func (r *userRepo) loadUser(ctx context.Context, po *userPO) (*system.User, erro
|
||||
}
|
||||
}
|
||||
var positionPOs []positionPO
|
||||
if err := r.data.DB().WithContext(ctx).Table("sys_positions").Joins("JOIN sys_user_positions ON sys_user_positions.sys_position_id = sys_positions.id").Where("sys_user_positions.sys_user_id = ? AND sys_positions.deleted_at IS NULL", po.ID).Find(&positionPOs).Error; err != nil {
|
||||
if err := r.data.DB().WithContext(ctx).Model(&positionPO{}).Joins("JOIN sys_user_positions ON sys_user_positions.sys_position_id = sys_positions.id").Where("sys_user_positions.sys_user_id = ? AND sys_positions.deleted_at IS NULL", po.ID).Find(&positionPOs).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
positions := make([]system.Position, 0, len(positionPOs))
|
||||
@@ -238,7 +238,7 @@ func (r *userRepo) HasAuthorityMenu(ctx context.Context, authorityID uint, name
|
||||
|
||||
func (r *userRepo) MenusByAuthority(ctx context.Context, authorityID uint) ([]*system.Menu, error) {
|
||||
var pos []menuPO
|
||||
err := r.data.DB().WithContext(ctx).Table("sys_base_menus").
|
||||
err := r.data.DB().WithContext(ctx).Model(&menuPO{}).
|
||||
Joins("JOIN sys_authority_menus ON sys_authority_menus.sys_base_menu_id = sys_base_menus.id").
|
||||
Where("sys_authority_menus.sys_authority_authority_id = ? AND sys_base_menus.deleted_at IS NULL", authorityID).
|
||||
Order("sys_base_menus.sort").Scan(&pos).Error
|
||||
@@ -266,7 +266,7 @@ func (r *userRepo) MenusByAuthority(ctx context.Context, authorityID uint) ([]*s
|
||||
menu.Parameters = append(menu.Parameters, menuParameterFromPO(parameter))
|
||||
}
|
||||
var buttons []menuButtonPO
|
||||
if err := r.data.DB().WithContext(ctx).Table("sys_base_menu_btns").Joins("JOIN sys_authority_btns ON sys_authority_btns.sys_base_menu_btn_id = sys_base_menu_btns.id").Where("sys_authority_btns.authority_id = ? AND sys_authority_btns.sys_menu_id IN ?", authorityID, menuIDs).Find(&buttons).Error; err != nil {
|
||||
if err := r.data.DB().WithContext(ctx).Model(&menuButtonPO{}).Joins("JOIN sys_authority_btns ON sys_authority_btns.sys_base_menu_btn_id = sys_base_menu_btns.id").Where("sys_authority_btns.authority_id = ? AND sys_authority_btns.sys_menu_id IN ?", authorityID, menuIDs).Find(&buttons).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, button := range buttons {
|
||||
|
||||
Reference in New Issue
Block a user