vibeStonk/server/repository/sqliteUsers.go
2025-06-12 16:57:42 -04:00

153 lines
3.1 KiB
Go

package repository
import (
"database/sql"
"errors"
"fmt"
models "vibeStonk/server/models/v1"
)
var (
ErrUserNotFound = errors.New("user not found")
)
func newSqliteUsersRepo(db *sql.DB) (UserRepo, error) {
repo := &sqliteUsersRepo{db: db}
if err := repo.initialize(); err != nil {
return nil, err
}
return repo, nil
}
type sqliteUsersRepo struct {
db *sql.DB
}
// initialize creates the users table if it doesn't exist
func (s *sqliteUsersRepo) initialize() error {
query := `
CREATE TABLE IF NOT EXISTS users (
id TEXT PRIMARY KEY,
username TEXT UNIQUE NOT NULL,
pref_name TEXT,
hash TEXT
);
`
_, err := s.db.Exec(query)
if err != nil {
return fmt.Errorf("failed to create user table: %w", err)
}
query = `
CREATE INDEX IF NOT EXISTS users_usernames
ON users(id, username);
`
_, err = s.db.Exec(query)
if err != nil {
return fmt.Errorf("failed to create username index for users table: %w", err)
}
return err
}
func (s *sqliteUsersRepo) Create(user *models.User) (*models.User, error) {
// Note: The hash field is in the proto definition but not in the generated struct
// In a real implementation, we would need to handle this differently
query := `
INSERT INTO users (id, username, pref_name, hash)
VALUES (?, ?, ?, ?)
`
_, err := s.db.Exec(query, user.Id, user.UserName, user.PrefName, user.Hash)
if err != nil {
return nil, err
}
return user, nil
}
func (s *sqliteUsersRepo) Get(id string) (*models.User, error) {
query := `
SELECT id, username, pref_name, hash
FROM users
WHERE id = ?
`
row := s.db.QueryRow(query, id)
user := &models.User{}
err := row.Scan(&user.Id, &user.UserName, &user.PrefName, &user.Hash)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, ErrUserNotFound
}
return nil, err
}
return user, nil
}
func (s *sqliteUsersRepo) GetByUsername(username string) (*models.User, error) {
query := `
SELECT id, username, pref_name, hash
FROM users
WHERE username = ?
`
row := s.db.QueryRow(query, username)
user := &models.User{}
err := row.Scan(&user.Id, &user.UserName, &user.PrefName, &user.Hash)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, ErrUserNotFound
}
return nil, err
}
return user, nil
}
func (s *sqliteUsersRepo) Update(user *models.User) error {
// Note: The hash field is in the proto definition but not in the generated struct
// In a real implementation, we would need to handle this differently
query := `
UPDATE users
SET username = ?, pref_name = ?
WHERE id = ?
`
result, err := s.db.Exec(query, user.UserName, user.PrefName, user.Id)
if err != nil {
return err
}
rowsAffected, err := result.RowsAffected()
if err != nil {
return err
}
if rowsAffected == 0 {
return ErrUserNotFound
}
return nil
}
func (s *sqliteUsersRepo) Delete(user *models.User) error {
query := `
DELETE FROM users
WHERE id = ?
`
result, err := s.db.Exec(query, user.Id)
if err != nil {
return err
}
rowsAffected, err := result.RowsAffected()
if err != nil {
return err
}
if rowsAffected == 0 {
return ErrUserNotFound
}
return nil
}