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