Files
Novault-backend/internal/repository/piggy_bank_repository.go
2026-01-25 21:59:00 +08:00

147 lines
5.7 KiB
Go

package repository
import (
"errors"
"fmt"
"time"
"accounting-app/internal/models"
"gorm.io/gorm"
)
// Common repository errors
var (
ErrPiggyBankNotFound = errors.New("piggy bank not found")
ErrPiggyBankInUse = errors.New("piggy bank is in use and cannot be deleted")
)
// PiggyBankRepository handles database operations for piggy banks
type PiggyBankRepository struct {
db *gorm.DB
}
// NewPiggyBankRepository creates a new PiggyBankRepository instance
func NewPiggyBankRepository(db *gorm.DB) *PiggyBankRepository {
return &PiggyBankRepository{db: db}
}
// Create creates a new piggy bank in the database
func (r *PiggyBankRepository) Create(piggyBank *models.PiggyBank) error {
if err := r.db.Create(piggyBank).Error; err != nil {
return fmt.Errorf("failed to create piggy bank: %w", err)
}
return nil
}
// GetByID retrieves a piggy bank by its ID
func (r *PiggyBankRepository) GetByID(userID uint, id uint) (*models.PiggyBank, error) {
var piggyBank models.PiggyBank
if err := r.db.Preload("LinkedAccount").Where("user_id = ?", userID).First(&piggyBank, id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, ErrPiggyBankNotFound
}
return nil, fmt.Errorf("failed to get piggy bank: %w", err)
}
return &piggyBank, nil
}
// GetAll retrieves all piggy banks for a user
func (r *PiggyBankRepository) GetAll(userID uint) ([]models.PiggyBank, error) {
var piggyBanks []models.PiggyBank
if err := r.db.Preload("LinkedAccount").Where("user_id = ?", userID).Order("created_at DESC").Find(&piggyBanks).Error; err != nil {
return nil, fmt.Errorf("failed to get piggy banks: %w", err)
}
return piggyBanks, nil
}
// Update updates an existing piggy bank in the database
func (r *PiggyBankRepository) Update(piggyBank *models.PiggyBank) error {
// First check if the piggy bank exists
var existing models.PiggyBank
if err := r.db.Where("user_id = ?", piggyBank.UserID).First(&existing, piggyBank.ID).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return ErrPiggyBankNotFound
}
return fmt.Errorf("failed to check piggy bank existence: %w", err)
}
// Update the piggy bank
if err := r.db.Save(piggyBank).Error; err != nil {
return fmt.Errorf("failed to update piggy bank: %w", err)
}
return nil
}
// Delete deletes a piggy bank by its ID
func (r *PiggyBankRepository) Delete(userID uint, id uint) error {
// First check if the piggy bank exists
var piggyBank models.PiggyBank
if err := r.db.Where("user_id = ?", userID).First(&piggyBank, id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return ErrPiggyBankNotFound
}
return fmt.Errorf("failed to check piggy bank existence: %w", err)
}
// Delete the piggy bank (soft delete due to gorm.DeletedAt field)
if err := r.db.Delete(&piggyBank).Error; err != nil {
return fmt.Errorf("failed to delete piggy bank: %w", err)
}
return nil
}
// GetByType retrieves all piggy banks of a specific type for a user
func (r *PiggyBankRepository) GetByType(userID uint, piggyBankType models.PiggyBankType) ([]models.PiggyBank, error) {
var piggyBanks []models.PiggyBank
if err := r.db.Preload("LinkedAccount").Where("user_id = ? AND type = ?", userID, piggyBankType).Order("created_at DESC").Find(&piggyBanks).Error; err != nil {
return nil, fmt.Errorf("failed to get piggy banks by type: %w", err)
}
return piggyBanks, nil
}
// GetByLinkedAccountID retrieves all piggy banks linked to a specific account for a user
func (r *PiggyBankRepository) GetByLinkedAccountID(userID, accountID uint) ([]models.PiggyBank, error) {
var piggyBanks []models.PiggyBank
if err := r.db.Preload("LinkedAccount").Where("user_id = ? AND linked_account_id = ?", userID, accountID).Order("created_at DESC").Find(&piggyBanks).Error; err != nil {
return nil, fmt.Errorf("failed to get piggy banks by linked account: %w", err)
}
return piggyBanks, nil
}
// GetActiveGoals retrieves all piggy banks that haven't reached their target yet for a user
func (r *PiggyBankRepository) GetActiveGoals(userID uint) ([]models.PiggyBank, error) {
var piggyBanks []models.PiggyBank
if err := r.db.Preload("LinkedAccount").Where("user_id = ? AND current_amount < target_amount", userID).Order("created_at DESC").Find(&piggyBanks).Error; err != nil {
return nil, fmt.Errorf("failed to get active piggy banks: %w", err)
}
return piggyBanks, nil
}
// GetCompletedGoals retrieves all piggy banks that have reached their target for a user
func (r *PiggyBankRepository) GetCompletedGoals(userID uint) ([]models.PiggyBank, error) {
var piggyBanks []models.PiggyBank
if err := r.db.Preload("LinkedAccount").Where("user_id = ? AND current_amount >= target_amount", userID).Order("created_at DESC").Find(&piggyBanks).Error; err != nil {
return nil, fmt.Errorf("failed to get completed piggy banks: %w", err)
}
return piggyBanks, nil
}
// GetGoalsDueBy retrieves all piggy banks with target dates on or before the specified date for a user
func (r *PiggyBankRepository) GetGoalsDueBy(userID uint, date time.Time) ([]models.PiggyBank, error) {
var piggyBanks []models.PiggyBank
if err := r.db.Preload("LinkedAccount").Where("user_id = ? AND target_date IS NOT NULL AND target_date <= ?", userID, date).Order("target_date ASC").Find(&piggyBanks).Error; err != nil {
return nil, fmt.Errorf("failed to get piggy banks due by date: %w", err)
}
return piggyBanks, nil
}
// ExistsByID checks if a piggy bank with the given ID exists for a user
func (r *PiggyBankRepository) ExistsByID(userID, id uint) (bool, error) {
var count int64
if err := r.db.Model(&models.PiggyBank{}).Where("user_id = ? AND id = ?", userID, id).Count(&count).Error; err != nil {
return false, fmt.Errorf("failed to check piggy bank existence: %w", err)
}
return count > 0, nil
}