package postgres import ( "context" "database/sql" "encoding/json" "fmt" "time" "github.com/google/uuid" "github.com/jmoiron/sqlx" "github.com/RyanCopley/skybridge/user/internal/domain" "github.com/RyanCopley/skybridge/user/internal/repository/interfaces" ) type userProfileRepository struct { db *sqlx.DB } // NewUserProfileRepository creates a new user profile repository func NewUserProfileRepository(db *sqlx.DB) interfaces.UserProfileRepository { return &userProfileRepository{db: db} } func (r *userProfileRepository) Create(ctx context.Context, profile *domain.UserProfile) error { profile.CreatedAt = time.Now() profile.UpdatedAt = time.Now() // Convert preferences to JSON var preferencesJSON []byte if profile.Preferences != nil { var err error preferencesJSON, err = json.Marshal(profile.Preferences) if err != nil { return fmt.Errorf("failed to marshal preferences: %w", err) } } query := ` INSERT INTO user_profiles ( user_id, bio, location, website, timezone, language, preferences, created_at, updated_at ) VALUES ( $1, $2, $3, $4, $5, $6, $7, $8, $9 )` _, err := r.db.ExecContext(ctx, query, profile.UserID, profile.Bio, profile.Location, profile.Website, profile.Timezone, profile.Language, preferencesJSON, profile.CreatedAt, profile.UpdatedAt, ) if err != nil { return fmt.Errorf("failed to create user profile: %w", err) } return nil } func (r *userProfileRepository) GetByUserID(ctx context.Context, userID uuid.UUID) (*domain.UserProfile, error) { query := ` SELECT user_id, bio, location, website, timezone, language, preferences, created_at, updated_at FROM user_profiles WHERE user_id = $1` row := r.db.QueryRowContext(ctx, query, userID) var profile domain.UserProfile var preferencesJSON sql.NullString err := row.Scan( &profile.UserID, &profile.Bio, &profile.Location, &profile.Website, &profile.Timezone, &profile.Language, &preferencesJSON, &profile.CreatedAt, &profile.UpdatedAt, ) if err != nil { if err == sql.ErrNoRows { return nil, fmt.Errorf("user profile not found") } return nil, fmt.Errorf("failed to get user profile: %w", err) } // Parse preferences JSON if preferencesJSON.Valid && preferencesJSON.String != "" { var preferences map[string]interface{} err = json.Unmarshal([]byte(preferencesJSON.String), &preferences) if err != nil { return nil, fmt.Errorf("failed to unmarshal preferences: %w", err) } profile.Preferences = preferences } return &profile, nil } func (r *userProfileRepository) Update(ctx context.Context, profile *domain.UserProfile) error { profile.UpdatedAt = time.Now() // Convert preferences to JSON var preferencesJSON []byte if profile.Preferences != nil { var err error preferencesJSON, err = json.Marshal(profile.Preferences) if err != nil { return fmt.Errorf("failed to marshal preferences: %w", err) } } query := ` UPDATE user_profiles SET bio = $2, location = $3, website = $4, timezone = $5, language = $6, preferences = $7, updated_at = $8 WHERE user_id = $1` result, err := r.db.ExecContext(ctx, query, profile.UserID, profile.Bio, profile.Location, profile.Website, profile.Timezone, profile.Language, preferencesJSON, profile.UpdatedAt, ) if err != nil { return fmt.Errorf("failed to update user profile: %w", err) } rowsAffected, err := result.RowsAffected() if err != nil { return fmt.Errorf("failed to get affected rows: %w", err) } if rowsAffected == 0 { return fmt.Errorf("user profile not found") } return nil } func (r *userProfileRepository) Delete(ctx context.Context, userID uuid.UUID) error { query := `DELETE FROM user_profiles WHERE user_id = $1` result, err := r.db.ExecContext(ctx, query, userID) if err != nil { return fmt.Errorf("failed to delete user profile: %w", err) } rowsAffected, err := result.RowsAffected() if err != nil { return fmt.Errorf("failed to get affected rows: %w", err) } if rowsAffected == 0 { return fmt.Errorf("user profile not found") } return nil }