A community based topic aggregation platform built on atproto
1package postgres 2 3import ( 4 "context" 5 "database/sql" 6 "fmt" 7 "strings" 8 9 "Coves/internal/core/users" 10) 11 12type postgresUserRepo struct { 13 db *sql.DB 14} 15 16// NewUserRepository creates a new PostgreSQL user repository 17func NewUserRepository(db *sql.DB) users.UserRepository { 18 return &postgresUserRepo{db: db} 19} 20 21// Create inserts a new user into the users table 22func (r *postgresUserRepo) Create(ctx context.Context, user *users.User) (*users.User, error) { 23 query := ` 24 INSERT INTO users (did, handle, pds_url) 25 VALUES ($1, $2, $3) 26 RETURNING did, handle, pds_url, created_at, updated_at` 27 28 err := r.db.QueryRowContext(ctx, query, user.DID, user.Handle, user.PDSURL). 29 Scan(&user.DID, &user.Handle, &user.PDSURL, &user.CreatedAt, &user.UpdatedAt) 30 31 if err != nil { 32 // Check for unique constraint violations 33 if strings.Contains(err.Error(), "duplicate key") { 34 if strings.Contains(err.Error(), "users_pkey") { 35 return nil, fmt.Errorf("user with DID already exists") 36 } 37 if strings.Contains(err.Error(), "users_handle_key") { 38 return nil, fmt.Errorf("handle already taken") 39 } 40 } 41 return nil, fmt.Errorf("failed to create user: %w", err) 42 } 43 44 return user, nil 45} 46 47// GetByDID retrieves a user by their DID 48func (r *postgresUserRepo) GetByDID(ctx context.Context, did string) (*users.User, error) { 49 user := &users.User{} 50 query := `SELECT did, handle, pds_url, created_at, updated_at FROM users WHERE did = $1` 51 52 err := r.db.QueryRowContext(ctx, query, did). 53 Scan(&user.DID, &user.Handle, &user.PDSURL, &user.CreatedAt, &user.UpdatedAt) 54 55 if err == sql.ErrNoRows { 56 return nil, fmt.Errorf("user not found") 57 } 58 if err != nil { 59 return nil, fmt.Errorf("failed to get user by DID: %w", err) 60 } 61 62 return user, nil 63} 64 65// GetByHandle retrieves a user by their handle 66func (r *postgresUserRepo) GetByHandle(ctx context.Context, handle string) (*users.User, error) { 67 user := &users.User{} 68 query := `SELECT did, handle, pds_url, created_at, updated_at FROM users WHERE handle = $1` 69 70 err := r.db.QueryRowContext(ctx, query, handle). 71 Scan(&user.DID, &user.Handle, &user.PDSURL, &user.CreatedAt, &user.UpdatedAt) 72 73 if err == sql.ErrNoRows { 74 return nil, fmt.Errorf("user not found") 75 } 76 if err != nil { 77 return nil, fmt.Errorf("failed to get user by handle: %w", err) 78 } 79 80 return user, nil 81} 82 83// UpdateHandle updates the handle for a user with the given DID 84func (r *postgresUserRepo) UpdateHandle(ctx context.Context, did, newHandle string) (*users.User, error) { 85 user := &users.User{} 86 query := ` 87 UPDATE users 88 SET handle = $2, updated_at = NOW() 89 WHERE did = $1 90 RETURNING did, handle, pds_url, created_at, updated_at` 91 92 err := r.db.QueryRowContext(ctx, query, did, newHandle). 93 Scan(&user.DID, &user.Handle, &user.PDSURL, &user.CreatedAt, &user.UpdatedAt) 94 95 if err == sql.ErrNoRows { 96 return nil, fmt.Errorf("user not found") 97 } 98 if err != nil { 99 // Check for unique constraint violation on handle 100 if strings.Contains(err.Error(), "duplicate key") && strings.Contains(err.Error(), "users_handle_key") { 101 return nil, fmt.Errorf("handle already taken") 102 } 103 return nil, fmt.Errorf("failed to update handle: %w", err) 104 } 105 106 return user, nil 107}