package repository import ( "context" "errors" "time" "gorm.io/gorm" "github.com/dhao2001/mygo/internal/model" ) // CredentialRepository provides access to alternative credential records. type CredentialRepository interface { Create(ctx context.Context, cred *model.Credential) error FindByID(ctx context.Context, id string) (*model.Credential, error) FindByUserID(ctx context.Context, userID string) ([]model.Credential, error) FindByUserIDAndType(ctx context.Context, userID, credType string) ([]model.Credential, error) FindByHash(ctx context.Context, hash string) (*model.Credential, error) UpdateLastUsed(ctx context.Context, id string) error Delete(ctx context.Context, id string) error } type credentialRepository struct { db *gorm.DB } // NewCredentialRepository creates a CredentialRepository backed by GORM. func NewCredentialRepository(db *gorm.DB) CredentialRepository { return &credentialRepository{db: db} } func (r *credentialRepository) Create(ctx context.Context, cred *model.Credential) error { result := r.db.WithContext(ctx).Create(cred) if result.Error != nil { if isDuplicateKeyError(result.Error) { return model.ErrDuplicate } return result.Error } return nil } func (r *credentialRepository) FindByID(ctx context.Context, id string) (*model.Credential, error) { var cred model.Credential result := r.db.WithContext(ctx).First(&cred, "id = ?", id) if errors.Is(result.Error, gorm.ErrRecordNotFound) { return nil, model.ErrNotFound } if result.Error != nil { return nil, result.Error } return &cred, nil } func (r *credentialRepository) FindByUserID(ctx context.Context, userID string) ([]model.Credential, error) { var creds []model.Credential result := r.db.WithContext(ctx).Where("user_id = ?", userID).Find(&creds) if result.Error != nil { return nil, result.Error } return creds, nil } func (r *credentialRepository) FindByUserIDAndType(ctx context.Context, userID, credType string) ([]model.Credential, error) { var creds []model.Credential result := r.db.WithContext(ctx).Where("user_id = ? AND type = ?", userID, credType).Find(&creds) if result.Error != nil { return nil, result.Error } return creds, nil } func (r *credentialRepository) FindByHash(ctx context.Context, hash string) (*model.Credential, error) { var cred model.Credential result := r.db.WithContext(ctx).First(&cred, "secret_hash = ?", hash) if errors.Is(result.Error, gorm.ErrRecordNotFound) { return nil, model.ErrNotFound } if result.Error != nil { return nil, result.Error } return &cred, nil } func (r *credentialRepository) UpdateLastUsed(ctx context.Context, id string) error { now := time.Now() result := r.db.WithContext(ctx).Model(&model.Credential{}).Where("id = ?", id).Update("last_used_at", now) if result.Error != nil { return result.Error } return nil } func (r *credentialRepository) Delete(ctx context.Context, id string) error { result := r.db.WithContext(ctx).Delete(&model.Credential{}, "id = ?", id) if result.Error != nil { return result.Error } return nil }