github.com/shoshinnikita/budget-manager@v0.7.1-0.20220131195411-8c46ff1c6778/internal/db/base/spend_type.go (about)

     1  package base
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	common "github.com/ShoshinNikita/budget-manager/internal/db"
     8  	"github.com/ShoshinNikita/budget-manager/internal/db/base/internal/sqlx"
     9  	"github.com/ShoshinNikita/budget-manager/internal/db/base/types"
    10  	"github.com/ShoshinNikita/budget-manager/internal/pkg/errors"
    11  )
    12  
    13  type SpendType struct {
    14  	ID       types.Uint   `db:"id"`
    15  	Name     types.String `db:"name"`
    16  	ParentID types.Uint   `db:"parent_id"`
    17  }
    18  
    19  // ToCommon converts SpendType to common SpendType structure from
    20  // "github.com/ShoshinNikita/budget-manager/internal/db" package
    21  //
    22  // We return a pointer instead of a value unlike other 'ToCommon' methods because Spend Type can be optional
    23  func (s *SpendType) ToCommon() *common.SpendType {
    24  	if s == nil {
    25  		return nil
    26  	}
    27  	if s.ID == 0 {
    28  		// Valid Spend Type must have id != 0
    29  		return nil
    30  	}
    31  
    32  	return &common.SpendType{
    33  		ID:       uint(s.ID),
    34  		Name:     string(s.Name),
    35  		ParentID: uint(s.ParentID),
    36  	}
    37  }
    38  
    39  // GetSpendTypes returns all Spend Types
    40  func (db DB) GetSpendTypes(ctx context.Context) ([]common.SpendType, error) {
    41  	var spendTypes []SpendType
    42  	err := db.db.RunInTransaction(ctx, func(tx *sqlx.Tx) error {
    43  		return tx.Select(&spendTypes, `SELECT * from spend_types ORDER BY id ASC`)
    44  	})
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  
    49  	res := make([]common.SpendType, 0, len(spendTypes))
    50  	for i := range spendTypes {
    51  		res = append(res, *spendTypes[i].ToCommon())
    52  	}
    53  	return res, nil
    54  }
    55  
    56  // AddSpendType adds new Spend Type
    57  func (db DB) AddSpendType(ctx context.Context, args common.AddSpendTypeArgs) (id uint, err error) {
    58  	err = db.db.RunInTransaction(ctx, func(tx *sqlx.Tx) error {
    59  		return tx.Get(
    60  			&id,
    61  			`INSERT INTO spend_types(name, parent_id) VALUES(?, ?) RETURNING id`,
    62  			args.Name, types.Uint(args.ParentID),
    63  		)
    64  	})
    65  	if err != nil {
    66  		return 0, err
    67  	}
    68  
    69  	return id, nil
    70  }
    71  
    72  // EditSpendType modifies existing Spend Type
    73  func (db DB) EditSpendType(ctx context.Context, args common.EditSpendTypeArgs) error {
    74  	return db.db.RunInTransaction(ctx, func(tx *sqlx.Tx) error {
    75  		if !checkSpendType(tx, args.ID) {
    76  			return common.ErrSpendTypeNotExist
    77  		}
    78  
    79  		query := newUpdateQueryBuilder("spend_types", args.ID)
    80  		if args.Name != nil {
    81  			query.Set("name", *args.Name)
    82  		}
    83  		if args.ParentID != nil {
    84  			if *args.ParentID == 0 {
    85  				query.Set("parent_id", nil)
    86  			} else {
    87  				query.Set("parent_id", *args.ParentID)
    88  			}
    89  		}
    90  		_, err := tx.ExecQuery(query)
    91  		return err
    92  	})
    93  }
    94  
    95  // RemoveSpendType removes Spend Type with passed id
    96  func (db DB) RemoveSpendType(ctx context.Context, id uint) error {
    97  	return db.db.RunInTransaction(ctx, func(tx *sqlx.Tx) error {
    98  		if !checkSpendType(tx, id) {
    99  			return common.ErrSpendTypeNotExist
   100  		}
   101  
   102  		// Don't remove Spend Type if it is used by Monthly Payment or Spend
   103  		for _, table := range []string{"monthly_payments", "spends"} {
   104  			var c int
   105  			err := tx.Get(&c, fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE type_id = ?", table), id)
   106  			if err != nil {
   107  				return errors.Wrapf(err, "couldn't count records in table %q", table)
   108  			}
   109  			if c != 0 {
   110  				return common.ErrSpendTypeIsUsed
   111  			}
   112  		}
   113  
   114  		// Remove Spend Type
   115  		_, err := tx.Exec(`DELETE FROM spend_types WHERE id = ?`, id)
   116  		if err != nil {
   117  			return err
   118  		}
   119  
   120  		return nil
   121  	})
   122  }