package repository import ( "database/sql" "fmt" "time" "fncConvertGui/internal/crypto" "fncConvertGui/internal/models" ) // CustomerRepository handles customer CRUD with field-level encryption. type CustomerRepository struct { db *sql.DB enc *crypto.Encryptor } // NewCustomerRepository creates a new repository. func NewCustomerRepository(db *sql.DB, enc *crypto.Encryptor) *CustomerRepository { return &CustomerRepository{db: db, enc: enc} } // Create inserts a new customer, encrypting sensitive fields. func (r *CustomerRepository) Create(c *models.Customer) (int64, error) { encName, err := r.enc.Encrypt([]byte(c.Name)) if err != nil { return 0, fmt.Errorf("encrypt name: %w", err) } encEmail, err := r.enc.Encrypt([]byte(c.Email)) if err != nil { return 0, fmt.Errorf("encrypt email: %w", err) } encPhone, err := r.enc.Encrypt([]byte(c.Phone)) if err != nil { return 0, fmt.Errorf("encrypt phone: %w", err) } now := time.Now() res, err := r.db.Exec( `INSERT INTO customers (name, email, phone, company, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)`, encName, encEmail, encPhone, c.Company, now, now, ) if err != nil { return 0, fmt.Errorf("insert: %w", err) } return res.LastInsertId() } // GetByID fetches a customer by ID, decrypting sensitive fields. func (r *CustomerRepository) GetByID(id int64) (*models.Customer, error) { var c models.Customer var encName, encEmail, encPhone []byte err := r.db.QueryRow( `SELECT id, name, email, phone, company, created_at, updated_at FROM customers WHERE id = ?`, id, ).Scan(&c.ID, &encName, &encEmail, &encPhone, &c.Company, &c.CreatedAt, &c.UpdatedAt) if err != nil { return nil, fmt.Errorf("query: %w", err) } name, err := r.enc.Decrypt(encName) if err != nil { return nil, fmt.Errorf("decrypt name: %w", err) } email, err := r.enc.Decrypt(encEmail) if err != nil { return nil, fmt.Errorf("decrypt email: %w", err) } phone, err := r.enc.Decrypt(encPhone) if err != nil { return nil, fmt.Errorf("decrypt phone: %w", err) } c.Name = string(name) c.Email = string(email) c.Phone = string(phone) return &c, nil } // List returns all customers with decrypted fields for list views. func (r *CustomerRepository) List() ([]models.CustomerListItem, error) { rows, err := r.db.Query( `SELECT id, name, email, company FROM customers ORDER BY id DESC`) if err != nil { return nil, fmt.Errorf("query: %w", err) } defer rows.Close() var items []models.CustomerListItem for rows.Next() { var item models.CustomerListItem var encName, encEmail []byte if err := rows.Scan(&item.ID, &encName, &encEmail, &item.Company); err != nil { return nil, fmt.Errorf("scan: %w", err) } name, err := r.enc.Decrypt(encName) if err != nil { return nil, fmt.Errorf("decrypt name: %w", err) } email, err := r.enc.Decrypt(encEmail) if err != nil { return nil, fmt.Errorf("decrypt email: %w", err) } item.Name = string(name) item.Email = string(email) items = append(items, item) } return items, rows.Err() } // Update modifies an existing customer, re-encrypting sensitive fields. func (r *CustomerRepository) Update(c *models.Customer) error { encName, err := r.enc.Encrypt([]byte(c.Name)) if err != nil { return fmt.Errorf("encrypt name: %w", err) } encEmail, err := r.enc.Encrypt([]byte(c.Email)) if err != nil { return fmt.Errorf("encrypt email: %w", err) } encPhone, err := r.enc.Encrypt([]byte(c.Phone)) if err != nil { return fmt.Errorf("encrypt phone: %w", err) } _, err = r.db.Exec( `UPDATE customers SET name=?, email=?, phone=?, company=?, updated_at=? WHERE id=?`, encName, encEmail, encPhone, c.Company, time.Now(), c.ID, ) if err != nil { return fmt.Errorf("update: %w", err) } return nil } // Delete removes a customer by ID. func (r *CustomerRepository) Delete(id int64) error { _, err := r.db.Exec(`DELETE FROM customers WHERE id = ?`, id) if err != nil { return fmt.Errorf("delete: %w", err) } return nil }