package processor import ( "context" "sync" "time" "eslogad-be/internal/contract" "eslogad-be/internal/repository" "eslogad-be/internal/transformer" "github.com/google/uuid" ) // CachedUserProcessor wraps UserProcessor with caching for frequently accessed users type CachedUserProcessor struct { userRepo *repository.UserRepositoryImpl profileRepo *repository.UserProfileRepository cache map[uuid.UUID]*cacheEntry mu sync.RWMutex ttl time.Duration } type cacheEntry struct { user *contract.UserResponse expiresAt time.Time } func NewCachedUserProcessor(userRepo *repository.UserRepositoryImpl, profileRepo *repository.UserProfileRepository, userRoleProc UserRoleProcessor) *CachedUserProcessor { return &CachedUserProcessor{ userRepo: userRepo, profileRepo: profileRepo, cache: make(map[uuid.UUID]*cacheEntry), ttl: 5 * time.Minute, // Cache for 5 minutes } } func (p *CachedUserProcessor) GetUserByIDCached(ctx context.Context, id uuid.UUID) (*contract.UserResponse, error) { p.mu.RLock() if entry, exists := p.cache[id]; exists { if entry.expiresAt.After(time.Now()) { p.mu.RUnlock() return entry.user, nil } } p.mu.RUnlock() // Not in cache or expired, fetch from database using the light method user, err := p.userRepo.GetByIDLight(ctx, id) if err != nil { return nil, err } // Convert to contract response resp := &contract.UserResponse{ ID: user.ID, Email: user.Email, Name: user.Name, IsActive: user.IsActive, CreatedAt: user.CreatedAt, UpdatedAt: user.UpdatedAt, } // Store in cache p.mu.Lock() p.cache[id] = &cacheEntry{ user: resp, expiresAt: time.Now().Add(p.ttl), } p.mu.Unlock() // Clean expired entries periodically go p.cleanExpiredEntries() return resp, nil } // GetUserByIDFull retrieves full user with all relationships - no caching func (p *CachedUserProcessor) GetUserByIDFull(ctx context.Context, id uuid.UUID) (*contract.UserResponse, error) { user, err := p.userRepo.GetByID(ctx, id) if err != nil { return nil, err } resp := transformer.EntityToContract(user) if resp != nil { if roles, err := p.userRepo.GetRolesByUserID(ctx, resp.ID); err == nil { resp.Roles = transformer.RolesToContract(roles) } } return resp, nil } // InvalidateCache removes a user from cache func (p *CachedUserProcessor) InvalidateCache(userID uuid.UUID) { p.mu.Lock() delete(p.cache, userID) p.mu.Unlock() } // cleanExpiredEntries removes expired cache entries func (p *CachedUserProcessor) cleanExpiredEntries() { p.mu.Lock() defer p.mu.Unlock() now := time.Now() for id, entry := range p.cache { if entry.expiresAt.Before(now) { delete(p.cache, id) } } }