package preferences import ( "context" "time" "github.com/google/uuid" "github.com/jackc/pgx/v5/pgxpool" ) // допустимые значения (для валидации) var AllowedDrinks = map[string]bool{ "beer": true, "wine": true, "whiskey": true, "vodka": true, "cocktail": true, "rum": true, "gin": true, "tequila": true, "cider": true, "champagne": true, "non_alcoholic": true, } var AllowedActivities = map[string]bool{ "walk": true, "dinner": true, "bar": true, "cafe": true, "travel": true, "movie": true, "concert": true, "sport": true, "cooking": true, "gaming": true, "reading": true, "other": true, } var AllowedPurposes = map[string]bool{ "chat": true, "drink": true, "walk": true, "dinner": true, "travel": true, "relationship": true, "friendship": true, "other": true, } type Prefs struct { UserID uuid.UUID `json:"user_id"` Drinks []string `json:"drinks"` Activities []string `json:"activities"` Purposes []string `json:"purposes"` Language string `json:"language"` UpdatedAt time.Time `json:"updated_at"` } type Repo struct { pool *pgxpool.Pool } func NewRepo(pool *pgxpool.Pool) *Repo { return &Repo{pool: pool} } func (r *Repo) Get(ctx context.Context, userID uuid.UUID) (*Prefs, error) { p := &Prefs{UserID: userID, Drinks: []string{}, Activities: []string{}, Purposes: []string{}, Language: "ru"} err := r.pool.QueryRow(ctx, ` SELECT drinks, activities, purposes, COALESCE(language, 'ru'), updated_at FROM user_preferences WHERE user_id=$1`, userID, ).Scan(&p.Drinks, &p.Activities, &p.Purposes, &p.Language, &p.UpdatedAt) if err != nil { // no row = defaults p.UpdatedAt = time.Now() return p, nil } return p, nil } func (r *Repo) Upsert(ctx context.Context, p *Prefs) error { _, err := r.pool.Exec(ctx, ` INSERT INTO user_preferences (user_id, drinks, activities, purposes, language, updated_at) VALUES ($1, $2, $3, $4, $5, NOW()) ON CONFLICT (user_id) DO UPDATE SET drinks = EXCLUDED.drinks, activities = EXCLUDED.activities, purposes = EXCLUDED.purposes, language = EXCLUDED.language, updated_at = NOW()`, p.UserID, p.Drinks, p.Activities, p.Purposes, p.Language, ) return err } func (r *Repo) Validate(values []string, allowed map[string]bool) []string { out := make([]string, 0, len(values)) seen := make(map[string]bool) for _, v := range values { v = trimLower(v) if v == "" || seen[v] { continue } if allowed[v] { out = append(out, v) seen[v] = true } } return out } func trimLower(s string) string { out := []rune{} for _, r := range s { if r >= 'A' && r <= 'Z' { r = r + 32 } out = append(out, r) } return string(out) }