slack5-1770541397/services/preferences-api/internal/adapter/postgres/preferences.go
rdev-worker e3e19a3fa8
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
build: /implement-feature user-preferences
2026-02-08 09:29:22 +00:00

85 lines
2.4 KiB
Go

// Package postgres provides PostgreSQL implementations of port interfaces.
package postgres
import (
"context"
"database/sql"
"encoding/json"
"errors"
"time"
"github.com/jmoiron/sqlx"
"git.threesix.ai/jordan/slack5-1770541397/pkg/logging"
"git.threesix.ai/jordan/slack5-1770541397/services/preferences-api/internal/domain"
"git.threesix.ai/jordan/slack5-1770541397/services/preferences-api/internal/port"
)
// preferencesRow represents a row in the user_preferences table.
type preferencesRow struct {
UserID string `db:"user_id"`
Preferences []byte `db:"preferences"`
UpdatedAt time.Time `db:"updated_at"`
}
// PreferencesRepository implements port.PreferencesRepository using PostgreSQL.
type PreferencesRepository struct {
db *sqlx.DB
logger *logging.Logger
}
var _ port.PreferencesRepository = (*PreferencesRepository)(nil)
// NewPreferencesRepository creates a new PostgreSQL preferences repository.
func NewPreferencesRepository(db *sqlx.DB, logger *logging.Logger) *PreferencesRepository {
return &PreferencesRepository{
db: db,
logger: logger.WithComponent("PreferencesRepository"),
}
}
// Get retrieves preferences for a user by ID.
// Returns domain.ErrPreferencesNotFound if no row exists.
func (r *PreferencesRepository) Get(ctx context.Context, userID domain.UserID) (*domain.UserPreferences, error) {
var row preferencesRow
err := r.db.GetContext(ctx, &row,
`SELECT user_id, preferences, updated_at FROM user_preferences WHERE user_id = $1`,
string(userID),
)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, domain.ErrPreferencesNotFound
}
return nil, err
}
var prefs domain.Preferences
if err := json.Unmarshal(row.Preferences, &prefs); err != nil {
return nil, err
}
return &domain.UserPreferences{
UserID: domain.UserID(row.UserID),
Preferences: prefs,
UpdatedAt: row.UpdatedAt,
}, nil
}
// Upsert creates or replaces preferences for a user.
func (r *PreferencesRepository) 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 user_preferences (user_id, preferences, updated_at)
VALUES ($1, $2, $3)
ON CONFLICT (user_id) DO UPDATE SET
preferences = $2,
updated_at = $3
`, string(prefs.UserID), prefsJSON, prefs.UpdatedAt)
return err
}