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 }