package repository import ( "context" "database/sql" "fmt" "erp-mvp/core-service/internal/models" "github.com/google/uuid" ) type ItemRepository interface { Create(ctx context.Context, item *models.Item) error GetByID(ctx context.Context, id uuid.UUID, orgID uuid.UUID) (*models.Item, error) GetByOrganization(ctx context.Context, orgID uuid.UUID) ([]*models.Item, error) Update(ctx context.Context, item *models.Item) error Delete(ctx context.Context, id uuid.UUID, orgID uuid.UUID) error Search(ctx context.Context, orgID uuid.UUID, query string, category string) ([]*models.Item, error) } type itemRepository struct { db *sql.DB } func NewItemRepository(db *sql.DB) ItemRepository { return &itemRepository{db: db} } func (r *itemRepository) Create(ctx context.Context, item *models.Item) error { query := ` INSERT INTO items (id, organization_id, name, description, category, created_at) VALUES ($1, $2, $3, $4, $5, $6) ` _, err := r.db.ExecContext(ctx, query, item.ID, item.OrganizationID, item.Name, item.Description, item.Category, item.CreatedAt, ) if err != nil { return fmt.Errorf("failed to create item: %w", err) } return nil } func (r *itemRepository) GetByID(ctx context.Context, id uuid.UUID, orgID uuid.UUID) (*models.Item, error) { query := ` SELECT id, organization_id, name, description, category, created_at FROM items WHERE id = $1 AND organization_id = $2 ` item := &models.Item{} err := r.db.QueryRowContext(ctx, query, id, orgID).Scan( &item.ID, &item.OrganizationID, &item.Name, &item.Description, &item.Category, &item.CreatedAt, ) if err != nil { if err == sql.ErrNoRows { return nil, fmt.Errorf("item not found") } return nil, fmt.Errorf("failed to get item: %w", err) } return item, nil } func (r *itemRepository) GetByOrganization(ctx context.Context, orgID uuid.UUID) ([]*models.Item, error) { query := ` SELECT id, organization_id, name, description, category, created_at FROM items WHERE organization_id = $1 ORDER BY name ` rows, err := r.db.QueryContext(ctx, query, orgID) if err != nil { return nil, fmt.Errorf("failed to query items: %w", err) } defer rows.Close() var items []*models.Item for rows.Next() { item := &models.Item{} err := rows.Scan( &item.ID, &item.OrganizationID, &item.Name, &item.Description, &item.Category, &item.CreatedAt, ) if err != nil { return nil, fmt.Errorf("failed to scan item: %w", err) } items = append(items, item) } if err = rows.Err(); err != nil { return nil, fmt.Errorf("error iterating items: %w", err) } return items, nil } func (r *itemRepository) Update(ctx context.Context, item *models.Item) error { query := ` UPDATE items SET name = $3, description = $4, category = $5 WHERE id = $1 AND organization_id = $2 ` result, err := r.db.ExecContext(ctx, query, item.ID, item.OrganizationID, item.Name, item.Description, item.Category, ) if err != nil { return fmt.Errorf("failed to update item: %w", err) } rowsAffected, err := result.RowsAffected() if err != nil { return fmt.Errorf("failed to get rows affected: %w", err) } if rowsAffected == 0 { return fmt.Errorf("item not found") } return nil } func (r *itemRepository) Delete(ctx context.Context, id uuid.UUID, orgID uuid.UUID) error { query := ` DELETE FROM items WHERE id = $1 AND organization_id = $2 ` result, err := r.db.ExecContext(ctx, query, id, orgID) if err != nil { return fmt.Errorf("failed to delete item: %w", err) } rowsAffected, err := result.RowsAffected() if err != nil { return fmt.Errorf("failed to get rows affected: %w", err) } if rowsAffected == 0 { return fmt.Errorf("item not found") } return nil } func (r *itemRepository) Search(ctx context.Context, orgID uuid.UUID, query string, category string) ([]*models.Item, error) { baseQuery := ` SELECT id, organization_id, name, description, category, created_at FROM items WHERE organization_id = $1 ` var args []interface{} args = append(args, orgID) argIndex := 2 if query != "" { baseQuery += fmt.Sprintf(" AND (name ILIKE $%d OR description ILIKE $%d)", argIndex, argIndex) args = append(args, "%"+query+"%") argIndex++ } if category != "" { baseQuery += fmt.Sprintf(" AND category = $%d", argIndex) args = append(args, category) argIndex++ } baseQuery += " ORDER BY name" rows, err := r.db.QueryContext(ctx, baseQuery, args...) if err != nil { return nil, fmt.Errorf("failed to search items: %w", err) } defer rows.Close() var items []*models.Item for rows.Next() { item := &models.Item{} err := rows.Scan( &item.ID, &item.OrganizationID, &item.Name, &item.Description, &item.Category, &item.CreatedAt, ) if err != nil { return nil, fmt.Errorf("failed to scan item: %w", err) } items = append(items, item) } if err = rows.Err(); err != nil { return nil, fmt.Errorf("error iterating search results: %w", err) } return items, nil }