143 lines
3.8 KiB
Go
143 lines
3.8 KiB
Go
package sqlite_repositories
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/theorift/white-zone-bot/database"
|
|
"github.com/theorift/white-zone-bot/models"
|
|
"github.com/theorift/white-zone-bot/repositories"
|
|
)
|
|
|
|
type SQLiteUserRepository struct {
|
|
ctx context.Context
|
|
db *sql.DB // Main database connection
|
|
executor database.DBTX // Current executor (db or tx)
|
|
}
|
|
|
|
func NewUserRepository(ctx context.Context, db *sql.DB) *SQLiteUserRepository {
|
|
return &SQLiteUserRepository{
|
|
ctx: ctx,
|
|
db: db,
|
|
executor: db, // Use db as default executor
|
|
}
|
|
}
|
|
|
|
func (r *SQLiteUserRepository) queries() *database.Queries {
|
|
return database.New(r.executor)
|
|
}
|
|
|
|
// Core operations
|
|
func (r *SQLiteUserRepository) GetUser(id int64) (models.User, error) {
|
|
dbUser, err := r.queries().GetUser(r.ctx, id)
|
|
if err != nil {
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
return models.User{ID: 0}, repositories.ErrRecordNotFound
|
|
}
|
|
return models.User{ID: 0}, fmt.Errorf("failed to get user: %w", err)
|
|
}
|
|
|
|
return models.User{
|
|
ID: dbUser.ID,
|
|
Points: dbUser.Points,
|
|
ReferrerID: dbUser.ReferrerID.Int64,
|
|
}, nil
|
|
}
|
|
|
|
func (r *SQLiteUserRepository) CreateUser(id int64, referrerID int64) error {
|
|
params := database.CreateUserParams{
|
|
ID: id,
|
|
ReferrerID: sql.NullInt64{Int64: referrerID, Valid: referrerID != 0},
|
|
}
|
|
|
|
err := r.queries().CreateUser(r.ctx, params)
|
|
if err != nil {
|
|
if strings.Contains(err.Error(), "UNIQUE constraint failed") {
|
|
return repositories.ErrDuplicateEntry
|
|
}
|
|
if strings.Contains(err.Error(), "FOREIGN KEY constraint failed") {
|
|
return repositories.ErrForeignKeyViolation
|
|
}
|
|
return fmt.Errorf("failed to create user: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *SQLiteUserRepository) UpsertReferrer(id int64, referrerID int64) error {
|
|
params := database.UpsertReferrerParams{
|
|
ID: id,
|
|
ReferrerID: sql.NullInt64{Int64: referrerID, Valid: referrerID != 0},
|
|
}
|
|
|
|
err := r.queries().UpsertReferrer(r.ctx, params)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to upsert referrer: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Points operations
|
|
func (r *SQLiteUserRepository) AddPointsToUser(id int64, points int64) error {
|
|
params := database.AddPointsToUserParams{
|
|
ID: id,
|
|
Points: points,
|
|
}
|
|
|
|
if err := r.queries().AddPointsToUser(r.ctx, params); err != nil {
|
|
return fmt.Errorf("failed to add points: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *SQLiteUserRepository) ReducePointsFromUser(id int64, points int64) (int64, error) {
|
|
params := database.ReducePointsFromUserParams{
|
|
ID: id,
|
|
Points: points,
|
|
}
|
|
|
|
newPoints, err := r.queries().ReducePointsFromUser(r.ctx, params)
|
|
if err != nil {
|
|
if strings.Contains(err.Error(), "CHECK constraint failed: points >= 0") {
|
|
return 0, repositories.ErrInsufficientUserPoints
|
|
}
|
|
return 0, fmt.Errorf("failed to reduce points: %w", err)
|
|
}
|
|
return newPoints, nil
|
|
}
|
|
|
|
// Transaction management
|
|
func (r *SQLiteUserRepository) BeginTx() (*sql.Tx, error) {
|
|
tx, err := r.db.BeginTx(r.ctx, &sql.TxOptions{
|
|
Isolation: sql.LevelSerializable,
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to begin transaction: %w", err)
|
|
}
|
|
return tx, nil
|
|
}
|
|
|
|
func (r *SQLiteUserRepository) WithTx(tx *sql.Tx) repositories.UserRepository {
|
|
return &SQLiteUserRepository{
|
|
ctx: r.ctx,
|
|
db: r.db, // Retain original DB connection
|
|
executor: tx, // Use transaction for queries
|
|
}
|
|
}
|
|
|
|
func (r *SQLiteUserRepository) Commit(tx *sql.Tx) error {
|
|
if err := tx.Commit(); err != nil {
|
|
return fmt.Errorf("failed to commit transaction: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *SQLiteUserRepository) Rollback(tx *sql.Tx) error {
|
|
if err := tx.Rollback(); err != nil && !errors.Is(err, sql.ErrTxDone) {
|
|
return fmt.Errorf("failed to rollback transaction: %w", err)
|
|
}
|
|
return nil
|
|
}
|