package postgres import ( "context" "errors" "fmt" "github.com/jackc/pgx/v5" ) type User struct { ID string PublicID string Status string Nickname *string AvatarURL *string } type CreateUserParams struct { PublicID string Status string } type queryRower interface { QueryRow(context.Context, string, ...any) pgx.Row } func (s *Store) FindUserByMobile(ctx context.Context, tx Tx, countryCode, mobile string) (*User, error) { row := tx.QueryRow(ctx, ` SELECT u.id, u.user_public_id, u.status, u.nickname, u.avatar_url FROM users u JOIN login_identities li ON li.user_id = u.id WHERE li.provider = 'mobile' AND li.country_code = $1 AND li.mobile = $2 AND li.status = 'active' LIMIT 1 `, countryCode, mobile) return scanUser(row) } func (s *Store) CreateUser(ctx context.Context, tx Tx, params CreateUserParams) (*User, error) { row := tx.QueryRow(ctx, ` INSERT INTO users (user_public_id, status) VALUES ($1, $2) RETURNING id, user_public_id, status, nickname, avatar_url `, params.PublicID, params.Status) return scanUser(row) } func (s *Store) TouchUserLogin(ctx context.Context, tx Tx, userID string) error { _, err := tx.Exec(ctx, ` UPDATE users SET last_login_at = NOW() WHERE id = $1 `, userID) if err != nil { return fmt.Errorf("touch user last login: %w", err) } return nil } func (s *Store) DeactivateUser(ctx context.Context, tx Tx, userID string) error { _, err := tx.Exec(ctx, ` UPDATE users SET status = 'deleted', updated_at = NOW() WHERE id = $1 `, userID) if err != nil { return fmt.Errorf("deactivate user: %w", err) } return nil } func (s *Store) GetUserByID(ctx context.Context, db queryRower, userID string) (*User, error) { row := db.QueryRow(ctx, ` SELECT id, user_public_id, status, nickname, avatar_url FROM users WHERE id = $1 `, userID) return scanUser(row) } func scanUser(row pgx.Row) (*User, error) { var user User err := row.Scan(&user.ID, &user.PublicID, &user.Status, &user.Nickname, &user.AvatarURL) if errors.Is(err, pgx.ErrNoRows) { return nil, nil } if err != nil { return nil, fmt.Errorf("scan user: %w", err) } return &user, nil }