package repository import ( "context" "strings" "github.com/jackc/pgx/v5/pgxpool" "financeiro-carvalho/internal/middleware" "financeiro-carvalho/internal/model" ) type TransactionRepository interface { IsDuplicate(ctx context.Context, date, description string, amount float64) (bool, error) IsExternalIDKnown(ctx context.Context, externalID string) (bool, error) BulkInsert(ctx context.Context, rows []model.ImportRow) (int, error) SaveImportLog(ctx context.Context, filename, format string, imported, duplicates, errors int) error } type transactionRepo struct{ db *pgxpool.Pool } func NewTransactionRepository(db *pgxpool.Pool) TransactionRepository { return &transactionRepo{db: db} } func normalizeDesc(s string) string { return strings.ToLower(strings.Join(strings.Fields(s), " ")) } func (r *transactionRepo) IsDuplicate(ctx context.Context, date, description string, amount float64) (bool, error) { pid := middleware.ProfileIDFromCtx(ctx) var count int err := r.db.QueryRow(ctx, ` SELECT COUNT(*) FROM transactions WHERE date = $1 AND amount = $2 AND LOWER(description) = $3 AND profile_id = $4`, date, amount, normalizeDesc(description), pid).Scan(&count) return count > 0, err } func (r *transactionRepo) IsExternalIDKnown(ctx context.Context, externalID string) (bool, error) { if externalID == "" { return false, nil } pid := middleware.ProfileIDFromCtx(ctx) var count int err := r.db.QueryRow(ctx, ` SELECT COUNT(*) FROM transactions WHERE external_id = $1 AND profile_id = $2`, externalID, pid).Scan(&count) return count > 0, err } func (r *transactionRepo) BulkInsert(ctx context.Context, rows []model.ImportRow) (int, error) { pid := middleware.ProfileIDFromCtx(ctx) tx, err := r.db.Begin(ctx) if err != nil { return 0, err } defer tx.Rollback(ctx) count := 0 for _, row := range rows { if row.IsDuplicate { continue } var extID *string if row.ExternalID != "" { extID = &row.ExternalID } var origDate *string if row.OriginalDate != "" { origDate = &row.OriginalDate } _, err := tx.Exec(ctx, ` INSERT INTO transactions (date, original_date, amount, description, type, source, external_id, category_id, profile_id) VALUES ($1, $2, $3, $4, $5, 'import', $6, $7, $8)`, row.Date, origDate, row.Amount, row.Description, row.Type, extID, row.CategoryID, pid) if err != nil { return count, err } count++ } return count, tx.Commit(ctx) } func (r *transactionRepo) SaveImportLog(ctx context.Context, filename, format string, imported, duplicates, errors int) error { _, err := r.db.Exec(ctx, ` INSERT INTO import_logs (filename, format, imported_count, duplicate_count, error_count) VALUES ($1, $2, $3, $4, $5)`, filename, format, imported, duplicates, errors) return err }