package postgres import ( "context" "database/sql" "encoding/json" "errors" "time" "github.com/jmoiron/sqlx" "git.threesix.ai/jordan/slack5-1770606136/services/preferences-api/internal/domain" "git.threesix.ai/jordan/slack5-1770606136/services/preferences-api/internal/port" ) // PreferenceRepository implements port.PreferenceRepository using PostgreSQL. type PreferenceRepository struct { db *sqlx.DB } // Compile-time interface verification. var _ port.PreferenceRepository = (*PreferenceRepository)(nil) // NewPreferenceRepository creates a new PostgreSQL preference repository. func NewPreferenceRepository(db *sqlx.DB) *PreferenceRepository { return &PreferenceRepository{db: db} } // preferenceRow represents a database row from the preferences table. type preferenceRow struct { UserID string `db:"user_id"` Preferences []byte `db:"preferences"` CreatedAt time.Time `db:"created_at"` UpdatedAt time.Time `db:"updated_at"` } // Get returns preferences for a user. // Returns nil, nil when no row exists. func (r *PreferenceRepository) Get(ctx context.Context, userID string) (*domain.UserPreferences, error) { var row preferenceRow err := r.db.GetContext(ctx, &row, `SELECT user_id, preferences, created_at, updated_at FROM preferences WHERE user_id = $1`, userID, ) if err != nil { if errors.Is(err, sql.ErrNoRows) { return nil, nil } return nil, err } prefs := make(map[string]any) if err := json.Unmarshal(row.Preferences, &prefs); err != nil { return nil, err } return &domain.UserPreferences{ UserID: row.UserID, Preferences: prefs, CreatedAt: row.CreatedAt, UpdatedAt: row.UpdatedAt, }, nil } // Upsert creates or updates preferences for a user. func (r *PreferenceRepository) Upsert(ctx context.Context, prefs *domain.UserPreferences) error { prefsJSON, err := json.Marshal(prefs.Preferences) if err != nil { return err } _, err = r.db.ExecContext(ctx, `INSERT INTO preferences (user_id, preferences, updated_at) VALUES ($1, $2, NOW()) ON CONFLICT (user_id) DO UPDATE SET preferences = $2, updated_at = NOW()`, prefs.UserID, prefsJSON, ) return err }