package memory import ( "context" "crypto/rand" "sync" "github.com/snip/backend/internal/domain" ) type UserRepo struct { mu sync.RWMutex byID map[string]*domain.User byKey map[string]string // provider|subject -> id } func NewUserRepo() *UserRepo { return &UserRepo{byID: make(map[string]*domain.User), byKey: make(map[string]string)} } func (r *UserRepo) Upsert(_ context.Context, u *domain.User) (*domain.User, error) { r.mu.Lock() defer r.mu.Unlock() key := u.Provider + "|" + u.Subject if id, ok := r.byKey[key]; ok { existing := r.byID[id] existing.Email = u.Email existing.Name = u.Name cp := *existing return &cp, nil } id := randomID() u.ID = id r.byID[id] = u r.byKey[key] = id cp := *u return &cp, nil } func (r *UserRepo) GetByID(_ context.Context, id string) (*domain.User, error) { r.mu.RLock() defer r.mu.RUnlock() u, ok := r.byID[id] if !ok { return nil, domain.ErrNotFound } cp := *u return &cp, nil } func randomID() string { const hex = "0123456789abcdef" b := make([]byte, 16) _, _ = rand.Read(b) out := make([]byte, 16) for i := range out { out[i] = hex[int(b[i])%16] } return "u_" + string(out) }