Files
lijiaoqiao/supply-api/internal/audit/service/audit_service_db.go

97 lines
2.7 KiB
Go
Raw Normal View History

package service
import (
"context"
"errors"
"lijiaoqiao/supply-api/internal/audit/model"
"lijiaoqiao/supply-api/internal/audit/repository"
)
// DatabaseAuditService 数据库-backed审计服务
type DatabaseAuditService struct {
repo repository.AuditRepository
}
// NewDatabaseAuditService 创建数据库-backed审计服务
func NewDatabaseAuditService(repo repository.AuditRepository) *DatabaseAuditService {
return &DatabaseAuditService{repo: repo}
}
// Ensure interface
var _ AuditStoreInterface = (*DatabaseAuditService)(nil)
// Emit 发送审计事件
func (s *DatabaseAuditService) Emit(ctx context.Context, event *model.AuditEvent) error {
// 验证事件
if event == nil {
return ErrInvalidInput
}
if event.EventName == "" {
return ErrMissingEventName
}
// 检查幂等键
if event.IdempotencyKey != "" {
existing, err := s.repo.GetByIdempotencyKey(ctx, event.IdempotencyKey)
if err != nil {
return err
}
if existing != nil {
// 幂等键已存在检查payload是否一致
if isSamePayload(existing, event) {
return repository.ErrDuplicateIdempotencyKey
}
return ErrIdempotencyConflict
}
}
// 发送事件
if err := s.repo.Emit(ctx, event); err != nil {
if errors.Is(err, repository.ErrDuplicateIdempotencyKey) {
return repository.ErrDuplicateIdempotencyKey
}
return err
}
return nil
}
// Query 查询审计事件
func (s *DatabaseAuditService) Query(ctx context.Context, filter *EventFilter) ([]*model.AuditEvent, int64, error) {
if filter == nil {
filter = &EventFilter{}
}
// 转换 filter 类型
repoFilter := &repository.EventFilter{
TenantID: filter.TenantID,
Category: filter.Category,
EventName: filter.EventName,
Limit: filter.Limit,
Offset: filter.Offset,
}
if !filter.StartTime.IsZero() {
repoFilter.StartTime = &filter.StartTime
}
if !filter.EndTime.IsZero() {
repoFilter.EndTime = &filter.EndTime
}
return s.repo.Query(ctx, repoFilter)
}
// GetByIdempotencyKey 根据幂等键获取事件
func (s *DatabaseAuditService) GetByIdempotencyKey(ctx context.Context, key string) (*model.AuditEvent, error) {
return s.repo.GetByIdempotencyKey(ctx, key)
}
// NewDatabaseAuditServiceWithPool 从数据库连接池创建审计服务
func NewDatabaseAuditServiceWithPool(pool interface {
Query(ctx context.Context, sql string, args ...interface{}) (interface{}, error)
Exec(ctx context.Context, sql string, args ...interface{}) (interface{}, error)
}) *DatabaseAuditService {
// 注意这里需要一个适配器来将通用的pool接口转换为pgxpool.Pool
// 在实际使用中,应该直接使用 NewDatabaseAuditService(repo)
// 这个函数仅用于类型兼容性
return nil
}