96 lines
2.8 KiB
Go
96 lines
2.8 KiB
Go
package postgres
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"fmt"
|
|
"time"
|
|
|
|
"git.threesix.ai/jordan/slack5-1770574304/services/preferences-api/internal/domain"
|
|
"git.threesix.ai/jordan/slack5-1770574304/services/preferences-api/internal/port"
|
|
)
|
|
|
|
// Compile-time verification that PreferenceRepository implements port.PreferenceRepository.
|
|
var _ port.PreferenceRepository = (*PreferenceRepository)(nil)
|
|
|
|
// PreferenceRepository is a PostgreSQL implementation of port.PreferenceRepository.
|
|
type PreferenceRepository struct {
|
|
db *sql.DB
|
|
}
|
|
|
|
// NewPreferenceRepository creates a new PostgreSQL preference repository.
|
|
// It ensures the schema exists on creation.
|
|
func NewPreferenceRepository(db *sql.DB) (*PreferenceRepository, error) {
|
|
r := &PreferenceRepository{db: db}
|
|
if err := r.ensureSchema(); err != nil {
|
|
return nil, fmt.Errorf("ensure schema: %w", err)
|
|
}
|
|
return r, nil
|
|
}
|
|
|
|
// ensureSchema creates the user_preferences table if it does not exist.
|
|
func (r *PreferenceRepository) ensureSchema() error {
|
|
_, err := r.db.Exec(`
|
|
CREATE TABLE IF NOT EXISTS user_preferences (
|
|
user_id TEXT PRIMARY KEY,
|
|
theme TEXT NOT NULL DEFAULT 'system',
|
|
language TEXT NOT NULL DEFAULT 'en',
|
|
notify_email BOOLEAN NOT NULL DEFAULT true,
|
|
notify_push BOOLEAN NOT NULL DEFAULT true,
|
|
notify_digest TEXT NOT NULL DEFAULT 'weekly',
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
)
|
|
`)
|
|
return err
|
|
}
|
|
|
|
// Get returns the preferences for a user by ID.
|
|
// Returns nil, nil when no preferences exist.
|
|
func (r *PreferenceRepository) Get(ctx context.Context, userID string) (*domain.UserPreferences, error) {
|
|
var p domain.UserPreferences
|
|
var updatedAt time.Time
|
|
|
|
err := r.db.QueryRowContext(ctx,
|
|
`SELECT user_id, theme, language, notify_email, notify_push, notify_digest, updated_at
|
|
FROM user_preferences WHERE user_id = $1`, userID,
|
|
).Scan(
|
|
&p.UserID,
|
|
&p.Theme,
|
|
&p.Language,
|
|
&p.Notifications.Email,
|
|
&p.Notifications.Push,
|
|
&p.Notifications.Digest,
|
|
&updatedAt,
|
|
)
|
|
if err == sql.ErrNoRows {
|
|
return nil, nil
|
|
}
|
|
if err != nil {
|
|
return nil, fmt.Errorf("get preferences: %w", err)
|
|
}
|
|
|
|
p.UpdatedAt = updatedAt
|
|
return &p, nil
|
|
}
|
|
|
|
// Upsert creates or replaces preferences for a user.
|
|
func (r *PreferenceRepository) Upsert(ctx context.Context, prefs *domain.UserPreferences) error {
|
|
_, err := r.db.ExecContext(ctx, `
|
|
INSERT INTO user_preferences (user_id, theme, language, notify_email, notify_push, notify_digest, updated_at)
|
|
VALUES ($1, $2, $3, $4, $5, $6, NOW())
|
|
ON CONFLICT (user_id) DO UPDATE SET
|
|
theme = $2,
|
|
language = $3,
|
|
notify_email = $4,
|
|
notify_push = $5,
|
|
notify_digest = $6,
|
|
updated_at = NOW()
|
|
`, prefs.UserID, prefs.Theme, prefs.Language,
|
|
prefs.Notifications.Email, prefs.Notifications.Push, prefs.Notifications.Digest,
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("upsert preferences: %w", err)
|
|
}
|
|
return nil
|
|
}
|