slack5-1770544098/services/preferences-api/internal/adapter/postgres/preferences.go
rdev-worker a31f57382b
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
build: /implement-feature user-preferences
2026-02-08 10:47:23 +00:00

96 lines
2.3 KiB
Go

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
}