package repository import ( "database/sql" "errors" "fmt" models "vibeStonk/server/models/v1" ) var ( ErrTransactionNotFound = errors.New("transaction not found") ) func newSqliteTransactionRepo(db *sql.DB) (TransactionRepo, error) { repo := &sqliteTransactionRepo{db: db} if err := repo.initialize(); err != nil { return nil, err } return repo, nil } type sqliteTransactionRepo struct { db *sql.DB } // initialize creates the transactions table if it doesn't exist func (s *sqliteTransactionRepo) initialize() error { query := ` CREATE TABLE IF NOT EXISTS transactions ( id INTEGER PRIMARY KEY AUTOINCREMENT, purchase_id INTEGER NOT NULL, sale_id INTEGER NOT NULL, qty REAL NOT NULL, FOREIGN KEY (purchase_id) REFERENCES purchases(id), FOREIGN KEY (sale_id) REFERENCES sales(id) ); ` _, err := s.db.Exec(query) if err != nil { return fmt.Errorf("failed to create transactions table: %w", err) } query = ` CREATE INDEX IF NOT EXISTS transactions_foreign_id ON transactions(purchase_id, sale_id); ` _, err = s.db.Exec(query) if err != nil { return fmt.Errorf("failed to create purchase_id index for transactions table: %w", err) } return nil } func (s *sqliteTransactionRepo) Create(transaction *models.Transaction) (*models.Transaction, error) { query := ` INSERT INTO transactions (purchase_id, sale_id, qty) VALUES (?, ?, ?) ` result, err := s.db.Exec(query, transaction.PurchaseID, transaction.SaleID, transaction.Qty) if err != nil { return nil, fmt.Errorf("failed to create transaction: %w", err) } id, err := result.LastInsertId() if err != nil { return nil, fmt.Errorf("failed to get last insert ID: %w", err) } transaction.Id = id return transaction, nil } func (s *sqliteTransactionRepo) Get(id int64) (*models.Transaction, error) { query := ` SELECT id, purchase_id, sale_id, qty FROM transactions WHERE id = ? ` row := s.db.QueryRow(query, id) transaction := &models.Transaction{} err := row.Scan(&transaction.Id, &transaction.PurchaseID, &transaction.SaleID, &transaction.Qty) if err != nil { if errors.Is(err, sql.ErrNoRows) { return nil, ErrTransactionNotFound } return nil, fmt.Errorf("failed to get transaction: %w", err) } return transaction, nil } func (s *sqliteTransactionRepo) GetByPurchaseID(purchaseID int64) ([]*models.Transaction, error) { query := ` SELECT id, purchase_id, sale_id, qty FROM transactions WHERE purchase_id = ? ` rows, err := s.db.Query(query, purchaseID) if err != nil { return nil, fmt.Errorf("failed to get transactions by purchase ID: %w", err) } defer rows.Close() var transactions []*models.Transaction for rows.Next() { transaction := &models.Transaction{} err := rows.Scan(&transaction.Id, &transaction.PurchaseID, &transaction.SaleID, &transaction.Qty) if err != nil { return nil, fmt.Errorf("failed to scan transaction row: %w", err) } transactions = append(transactions, transaction) } if err := rows.Err(); err != nil { return nil, fmt.Errorf("error iterating transaction rows: %w", err) } return transactions, nil } func (s *sqliteTransactionRepo) GetBySaleID(saleID int64) ([]*models.Transaction, error) { query := ` SELECT id, purchase_id, sale_id, qty FROM transactions WHERE sale_id = ? ` rows, err := s.db.Query(query, saleID) if err != nil { return nil, fmt.Errorf("failed to get transactions by sale ID: %w", err) } defer rows.Close() var transactions []*models.Transaction for rows.Next() { transaction := &models.Transaction{} err := rows.Scan(&transaction.Id, &transaction.PurchaseID, &transaction.SaleID, &transaction.Qty) if err != nil { return nil, fmt.Errorf("failed to scan transaction row: %w", err) } transactions = append(transactions, transaction) } if err := rows.Err(); err != nil { return nil, fmt.Errorf("error iterating transaction rows: %w", err) } return transactions, nil } func (s *sqliteTransactionRepo) DeleteBySaleID(saleID int64) error { query := ` DELETE FROM transactions WHERE sale_id = ? ` result, err := s.db.Exec(query, saleID) if err != nil { return fmt.Errorf("failed to delete transaction: %w", err) } rowsAffected, err := result.RowsAffected() if err != nil { return fmt.Errorf("failed to get rows affected: %w", err) } if rowsAffected == 0 { return ErrTransactionNotFound } return nil } func (s *sqliteTransactionRepo) List() ([]*models.Transaction, error) { query := ` SELECT id, purchase_id, sale_id, qty FROM transactions ` rows, err := s.db.Query(query) if err != nil { return nil, fmt.Errorf("failed to list transactions: %w", err) } defer rows.Close() var transactions []*models.Transaction for rows.Next() { transaction := &models.Transaction{} err := rows.Scan(&transaction.Id, &transaction.PurchaseID, &transaction.SaleID, &transaction.Qty) if err != nil { return nil, fmt.Errorf("failed to scan transaction row: %w", err) } transactions = append(transactions, transaction) } if err := rows.Err(); err != nil { return nil, fmt.Errorf("error iterating transaction rows: %w", err) } return transactions, nil }