package postgres import ( "context" "database/sql" "encoding/json" "time" "git.threesix.ai/jordan/slack5-1770544098/services/preferences-api/internal/domain" ) // PreferencesRepository implements port.PreferencesRepository using PostgreSQL. type PreferencesRepository struct { db *sql.DB } // NewPreferencesRepository creates a new PostgreSQL-backed preferences repository. func NewPreferencesRepository(db *sql.DB) *PreferencesRepository { return &PreferencesRepository{db: db} } // Get returns preferences for a user by ID. // Returns nil when no preferences exist for the user. func (r *PreferencesRepository) Get(ctx context.Context, userID string) (*domain.UserPreferences, error) { var ( prefsJSON []byte createdAt time.Time updatedAt time.Time ) err := r.db.QueryRowContext(ctx, `SELECT preferences, created_at, updated_at FROM user_preferences WHERE user_id = $1`, userID, ).Scan(&prefsJSON, &createdAt, &updatedAt) if err == sql.ErrNoRows { return nil, nil } if err != nil { return nil, err } var prefs map[string]any if err := json.Unmarshal(prefsJSON, &prefs); err != nil { return nil, err } return &domain.UserPreferences{ UserID: userID, Preferences: prefs, CreatedAt: createdAt, UpdatedAt: updatedAt, }, nil } // Upsert creates or updates preferences for a user using JSONB merge. // Returns the full merged preferences after upsert. func (r *PreferencesRepository) Upsert(ctx context.Context, userID string, prefs map[string]any) (*domain.UserPreferences, error) { prefsJSON, err := json.Marshal(prefs) if err != nil { return nil, err } var ( resultJSON []byte createdAt time.Time updatedAt time.Time ) err = r.db.QueryRowContext(ctx, ` INSERT INTO user_preferences (user_id, preferences, created_at, updated_at) VALUES ($1, $2, NOW(), NOW()) ON CONFLICT (user_id) DO UPDATE SET preferences = user_preferences.preferences || $2, updated_at = NOW() RETURNING preferences, created_at, updated_at`, userID, prefsJSON, ).Scan(&resultJSON, &createdAt, &updatedAt) if err != nil { return nil, err } var merged map[string]any if err := json.Unmarshal(resultJSON, &merged); err != nil { return nil, err } return &domain.UserPreferences{ UserID: userID, Preferences: merged, CreatedAt: createdAt, UpdatedAt: updatedAt, }, nil }