feat(pagination): add pagination to all list endpoints
Added pagination support to: - ListCompanies: filter by role, search - ListProducts: filter by seller, search - ListOrders: filter by buyer, seller, status - ListInventory: filter by expiring date, seller New domain types: - ProductFilter, ProductPage - CompanyFilter, CompanyPage - OrderFilter, OrderPage - InventoryPage All endpoints now return paginated responses with: - items array - total count - current page - page size Updated MockRepository in both test files to match new signatures
This commit is contained in:
parent
b713d8fbed
commit
45d34f36c8
10 changed files with 307 additions and 70 deletions
|
|
@ -71,9 +71,70 @@ type InventoryItem struct {
|
|||
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
|
||||
}
|
||||
|
||||
// InventoryFilter allows filtering by expiration window.
|
||||
// InventoryFilter allows filtering by expiration window with pagination.
|
||||
type InventoryFilter struct {
|
||||
ExpiringBefore *time.Time
|
||||
SellerID *uuid.UUID
|
||||
Limit int
|
||||
Offset int
|
||||
}
|
||||
|
||||
// InventoryPage wraps paginated inventory results.
|
||||
type InventoryPage struct {
|
||||
Items []InventoryItem `json:"items"`
|
||||
Total int64 `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
// ProductFilter captures product listing constraints.
|
||||
type ProductFilter struct {
|
||||
SellerID *uuid.UUID
|
||||
Category string
|
||||
Search string
|
||||
Limit int
|
||||
Offset int
|
||||
}
|
||||
|
||||
// ProductPage wraps paginated product results.
|
||||
type ProductPage struct {
|
||||
Products []Product `json:"products"`
|
||||
Total int64 `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
// CompanyFilter captures company listing constraints.
|
||||
type CompanyFilter struct {
|
||||
Role string
|
||||
Search string
|
||||
Limit int
|
||||
Offset int
|
||||
}
|
||||
|
||||
// CompanyPage wraps paginated company results.
|
||||
type CompanyPage struct {
|
||||
Companies []Company `json:"companies"`
|
||||
Total int64 `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
// OrderFilter captures order listing constraints.
|
||||
type OrderFilter struct {
|
||||
BuyerID *uuid.UUID
|
||||
SellerID *uuid.UUID
|
||||
Status OrderStatus
|
||||
Limit int
|
||||
Offset int
|
||||
}
|
||||
|
||||
// OrderPage wraps paginated order results.
|
||||
type OrderPage struct {
|
||||
Orders []Order `json:"orders"`
|
||||
Total int64 `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
// InventoryAdjustment records manual stock corrections.
|
||||
|
|
|
|||
|
|
@ -47,12 +47,18 @@ func (h *Handler) CreateCompany(w http.ResponseWriter, r *http.Request) {
|
|||
// @Success 200 {array} domain.Company
|
||||
// @Router /api/v1/companies [get]
|
||||
func (h *Handler) ListCompanies(w http.ResponseWriter, r *http.Request) {
|
||||
companies, err := h.svc.ListCompanies(r.Context())
|
||||
page, pageSize := parsePagination(r)
|
||||
filter := domain.CompanyFilter{
|
||||
Role: r.URL.Query().Get("role"),
|
||||
Search: r.URL.Query().Get("search"),
|
||||
}
|
||||
|
||||
result, err := h.svc.ListCompanies(r.Context(), filter, page, pageSize)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, companies)
|
||||
writeJSON(w, http.StatusOK, result)
|
||||
}
|
||||
|
||||
// GetCompany godoc
|
||||
|
|
|
|||
|
|
@ -42,8 +42,8 @@ func (m *MockRepository) CreateCompany(ctx context.Context, company *domain.Comp
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m *MockRepository) ListCompanies(ctx context.Context) ([]domain.Company, error) {
|
||||
return m.companies, nil
|
||||
func (m *MockRepository) ListCompanies(ctx context.Context, filter domain.CompanyFilter) ([]domain.Company, int64, error) {
|
||||
return m.companies, int64(len(m.companies)), nil
|
||||
}
|
||||
|
||||
func (m *MockRepository) GetCompany(ctx context.Context, id uuid.UUID) (*domain.Company, error) {
|
||||
|
|
@ -85,8 +85,8 @@ func (m *MockRepository) CreateProduct(ctx context.Context, product *domain.Prod
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m *MockRepository) ListProducts(ctx context.Context) ([]domain.Product, error) {
|
||||
return m.products, nil
|
||||
func (m *MockRepository) ListProducts(ctx context.Context, filter domain.ProductFilter) ([]domain.Product, int64, error) {
|
||||
return m.products, int64(len(m.products)), nil
|
||||
}
|
||||
|
||||
func (m *MockRepository) GetProduct(ctx context.Context, id uuid.UUID) (*domain.Product, error) {
|
||||
|
|
@ -123,8 +123,8 @@ func (m *MockRepository) AdjustInventory(ctx context.Context, productID uuid.UUI
|
|||
return &domain.InventoryItem{}, nil
|
||||
}
|
||||
|
||||
func (m *MockRepository) ListInventory(ctx context.Context, filter domain.InventoryFilter) ([]domain.InventoryItem, error) {
|
||||
return []domain.InventoryItem{}, nil
|
||||
func (m *MockRepository) ListInventory(ctx context.Context, filter domain.InventoryFilter) ([]domain.InventoryItem, int64, error) {
|
||||
return []domain.InventoryItem{}, 0, nil
|
||||
}
|
||||
|
||||
func (m *MockRepository) CreateOrder(ctx context.Context, order *domain.Order) error {
|
||||
|
|
@ -134,8 +134,8 @@ func (m *MockRepository) CreateOrder(ctx context.Context, order *domain.Order) e
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m *MockRepository) ListOrders(ctx context.Context) ([]domain.Order, error) {
|
||||
return m.orders, nil
|
||||
func (m *MockRepository) ListOrders(ctx context.Context, filter domain.OrderFilter) ([]domain.Order, int64, error) {
|
||||
return m.orders, int64(len(m.orders)), nil
|
||||
}
|
||||
|
||||
func (m *MockRepository) GetOrder(ctx context.Context, id uuid.UUID) (*domain.Order, error) {
|
||||
|
|
@ -259,10 +259,10 @@ func TestListProducts(t *testing.T) {
|
|||
t.Errorf("expected status %d, got %d", http.StatusOK, rec.Code)
|
||||
}
|
||||
|
||||
// Should return empty array
|
||||
// Should return page with empty products array
|
||||
body := strings.TrimSpace(rec.Body.String())
|
||||
if body != "[]" {
|
||||
t.Errorf("expected empty array, got %s", body)
|
||||
if !strings.Contains(body, `"products":[]`) || !strings.Contains(body, `"total":0`) {
|
||||
t.Errorf("expected paginated response with empty products, got %s", body)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,13 +51,16 @@ func (h *Handler) CreateOrder(w http.ResponseWriter, r *http.Request) {
|
|||
// @Success 200 {array} domain.Order
|
||||
// @Router /api/v1/orders [get]
|
||||
func (h *Handler) ListOrders(w http.ResponseWriter, r *http.Request) {
|
||||
orders, err := h.svc.ListOrders(r.Context())
|
||||
page, pageSize := parsePagination(r)
|
||||
filter := domain.OrderFilter{}
|
||||
|
||||
result, err := h.svc.ListOrders(r.Context(), filter, page, pageSize)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, orders)
|
||||
writeJSON(w, http.StatusOK, result)
|
||||
}
|
||||
|
||||
// GetOrder godoc
|
||||
|
|
|
|||
|
|
@ -49,12 +49,17 @@ func (h *Handler) CreateProduct(w http.ResponseWriter, r *http.Request) {
|
|||
// @Success 200 {array} domain.Product
|
||||
// @Router /api/v1/products [get]
|
||||
func (h *Handler) ListProducts(w http.ResponseWriter, r *http.Request) {
|
||||
products, err := h.svc.ListProducts(r.Context())
|
||||
page, pageSize := parsePagination(r)
|
||||
filter := domain.ProductFilter{
|
||||
Search: r.URL.Query().Get("search"),
|
||||
}
|
||||
|
||||
result, err := h.svc.ListProducts(r.Context(), filter, page, pageSize)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, products)
|
||||
writeJSON(w, http.StatusOK, result)
|
||||
}
|
||||
|
||||
// GetProduct godoc
|
||||
|
|
@ -174,6 +179,7 @@ func (h *Handler) DeleteProduct(w http.ResponseWriter, r *http.Request) {
|
|||
// @Router /api/v1/inventory [get]
|
||||
// ListInventory exposes stock with expiring batch filters.
|
||||
func (h *Handler) ListInventory(w http.ResponseWriter, r *http.Request) {
|
||||
page, pageSize := parsePagination(r)
|
||||
var filter domain.InventoryFilter
|
||||
if days := r.URL.Query().Get("expires_in_days"); days != "" {
|
||||
n, err := strconv.Atoi(days)
|
||||
|
|
@ -185,13 +191,13 @@ func (h *Handler) ListInventory(w http.ResponseWriter, r *http.Request) {
|
|||
filter.ExpiringBefore = &expires
|
||||
}
|
||||
|
||||
inventory, err := h.svc.ListInventory(r.Context(), filter)
|
||||
result, err := h.svc.ListInventory(r.Context(), filter, page, pageSize)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, inventory)
|
||||
writeJSON(w, http.StatusOK, result)
|
||||
}
|
||||
|
||||
// AdjustInventory godoc
|
||||
|
|
|
|||
|
|
@ -35,13 +35,41 @@ VALUES (:id, :role, :cnpj, :corporate_name, :license_number, :is_verified, :crea
|
|||
return err
|
||||
}
|
||||
|
||||
func (r *Repository) ListCompanies(ctx context.Context) ([]domain.Company, error) {
|
||||
var companies []domain.Company
|
||||
query := `SELECT id, role, cnpj, corporate_name, license_number, is_verified, created_at, updated_at FROM companies ORDER BY created_at DESC`
|
||||
if err := r.db.SelectContext(ctx, &companies, query); err != nil {
|
||||
return nil, err
|
||||
func (r *Repository) ListCompanies(ctx context.Context, filter domain.CompanyFilter) ([]domain.Company, int64, error) {
|
||||
baseQuery := `FROM companies`
|
||||
var args []any
|
||||
var clauses []string
|
||||
|
||||
if filter.Role != "" {
|
||||
clauses = append(clauses, fmt.Sprintf("role = $%d", len(args)+1))
|
||||
args = append(args, filter.Role)
|
||||
}
|
||||
return companies, nil
|
||||
if filter.Search != "" {
|
||||
clauses = append(clauses, fmt.Sprintf("(corporate_name ILIKE $%d OR cnpj ILIKE $%d)", len(args)+1, len(args)+1))
|
||||
args = append(args, "%"+filter.Search+"%")
|
||||
}
|
||||
|
||||
where := ""
|
||||
if len(clauses) > 0 {
|
||||
where = " WHERE " + strings.Join(clauses, " AND ")
|
||||
}
|
||||
|
||||
var total int64
|
||||
if err := r.db.GetContext(ctx, &total, "SELECT count(*) "+baseQuery+where, args...); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if filter.Limit <= 0 {
|
||||
filter.Limit = 20
|
||||
}
|
||||
args = append(args, filter.Limit, filter.Offset)
|
||||
listQuery := fmt.Sprintf("SELECT id, role, cnpj, corporate_name, license_number, is_verified, created_at, updated_at %s%s ORDER BY created_at DESC LIMIT $%d OFFSET $%d", baseQuery, where, len(args)-1, len(args))
|
||||
|
||||
var companies []domain.Company
|
||||
if err := r.db.SelectContext(ctx, &companies, listQuery, args...); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
return companies, total, nil
|
||||
}
|
||||
|
||||
func (r *Repository) GetCompany(ctx context.Context, id uuid.UUID) (*domain.Company, error) {
|
||||
|
|
@ -133,13 +161,41 @@ VALUES (:id, :seller_id, :name, :description, :batch, :expires_at, :price_cents,
|
|||
return err
|
||||
}
|
||||
|
||||
func (r *Repository) ListProducts(ctx context.Context) ([]domain.Product, error) {
|
||||
var products []domain.Product
|
||||
query := `SELECT id, seller_id, name, description, batch, expires_at, price_cents, stock, created_at, updated_at FROM products ORDER BY created_at DESC`
|
||||
if err := r.db.SelectContext(ctx, &products, query); err != nil {
|
||||
return nil, err
|
||||
func (r *Repository) ListProducts(ctx context.Context, filter domain.ProductFilter) ([]domain.Product, int64, error) {
|
||||
baseQuery := `FROM products`
|
||||
var args []any
|
||||
var clauses []string
|
||||
|
||||
if filter.SellerID != nil {
|
||||
clauses = append(clauses, fmt.Sprintf("seller_id = $%d", len(args)+1))
|
||||
args = append(args, *filter.SellerID)
|
||||
}
|
||||
return products, nil
|
||||
if filter.Search != "" {
|
||||
clauses = append(clauses, fmt.Sprintf("name ILIKE $%d", len(args)+1))
|
||||
args = append(args, "%"+filter.Search+"%")
|
||||
}
|
||||
|
||||
where := ""
|
||||
if len(clauses) > 0 {
|
||||
where = " WHERE " + strings.Join(clauses, " AND ")
|
||||
}
|
||||
|
||||
var total int64
|
||||
if err := r.db.GetContext(ctx, &total, "SELECT count(*) "+baseQuery+where, args...); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if filter.Limit <= 0 {
|
||||
filter.Limit = 20
|
||||
}
|
||||
args = append(args, filter.Limit, filter.Offset)
|
||||
listQuery := fmt.Sprintf("SELECT id, seller_id, name, description, batch, expires_at, price_cents, stock, created_at, updated_at %s%s ORDER BY created_at DESC LIMIT $%d OFFSET $%d", baseQuery, where, len(args)-1, len(args))
|
||||
|
||||
var products []domain.Product
|
||||
if err := r.db.SelectContext(ctx, &products, listQuery, args...); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
return products, total, nil
|
||||
}
|
||||
|
||||
func (r *Repository) GetProduct(ctx context.Context, id uuid.UUID) (*domain.Product, error) {
|
||||
|
|
@ -244,7 +300,40 @@ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)`
|
|||
return tx.Commit()
|
||||
}
|
||||
|
||||
func (r *Repository) ListOrders(ctx context.Context) ([]domain.Order, error) {
|
||||
func (r *Repository) ListOrders(ctx context.Context, filter domain.OrderFilter) ([]domain.Order, int64, error) {
|
||||
baseQuery := `FROM orders`
|
||||
var args []any
|
||||
var clauses []string
|
||||
|
||||
if filter.BuyerID != nil {
|
||||
clauses = append(clauses, fmt.Sprintf("buyer_id = $%d", len(args)+1))
|
||||
args = append(args, *filter.BuyerID)
|
||||
}
|
||||
if filter.SellerID != nil {
|
||||
clauses = append(clauses, fmt.Sprintf("seller_id = $%d", len(args)+1))
|
||||
args = append(args, *filter.SellerID)
|
||||
}
|
||||
if filter.Status != "" {
|
||||
clauses = append(clauses, fmt.Sprintf("status = $%d", len(args)+1))
|
||||
args = append(args, filter.Status)
|
||||
}
|
||||
|
||||
where := ""
|
||||
if len(clauses) > 0 {
|
||||
where = " WHERE " + strings.Join(clauses, " AND ")
|
||||
}
|
||||
|
||||
var total int64
|
||||
if err := r.db.GetContext(ctx, &total, "SELECT count(*) "+baseQuery+where, args...); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if filter.Limit <= 0 {
|
||||
filter.Limit = 20
|
||||
}
|
||||
args = append(args, filter.Limit, filter.Offset)
|
||||
listQuery := fmt.Sprintf(`SELECT id, buyer_id, seller_id, status, total_cents, shipping_recipient_name, shipping_street, shipping_number, shipping_complement, shipping_district, shipping_city, shipping_state, shipping_zip_code, shipping_country, created_at, updated_at %s%s ORDER BY created_at DESC LIMIT $%d OFFSET $%d`, baseQuery, where, len(args)-1, len(args))
|
||||
|
||||
var rows []struct {
|
||||
ID uuid.UUID `db:"id"`
|
||||
BuyerID uuid.UUID `db:"buyer_id"`
|
||||
|
|
@ -263,9 +352,9 @@ func (r *Repository) ListOrders(ctx context.Context) ([]domain.Order, error) {
|
|||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at"`
|
||||
}
|
||||
query := `SELECT id, buyer_id, seller_id, status, total_cents, shipping_recipient_name, shipping_street, shipping_number, shipping_complement, shipping_district, shipping_city, shipping_state, shipping_zip_code, shipping_country, created_at, updated_at FROM orders ORDER BY created_at DESC`
|
||||
if err := r.db.SelectContext(ctx, &rows, query); err != nil {
|
||||
return nil, err
|
||||
|
||||
if err := r.db.SelectContext(ctx, &rows, listQuery, args...); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
orders := make([]domain.Order, 0, len(rows))
|
||||
|
|
@ -273,7 +362,7 @@ func (r *Repository) ListOrders(ctx context.Context) ([]domain.Order, error) {
|
|||
for _, row := range rows {
|
||||
var items []domain.OrderItem
|
||||
if err := r.db.SelectContext(ctx, &items, itemQuery, row.ID); err != nil {
|
||||
return nil, err
|
||||
return nil, 0, err
|
||||
}
|
||||
orders = append(orders, domain.Order{
|
||||
ID: row.ID,
|
||||
|
|
@ -297,7 +386,7 @@ func (r *Repository) ListOrders(ctx context.Context) ([]domain.Order, error) {
|
|||
UpdatedAt: row.UpdatedAt,
|
||||
})
|
||||
}
|
||||
return orders, nil
|
||||
return orders, total, nil
|
||||
}
|
||||
|
||||
func (r *Repository) GetOrder(ctx context.Context, id uuid.UUID) (*domain.Order, error) {
|
||||
|
|
@ -480,25 +569,40 @@ func (r *Repository) AdjustInventory(ctx context.Context, productID uuid.UUID, d
|
|||
}, nil
|
||||
}
|
||||
|
||||
func (r *Repository) ListInventory(ctx context.Context, filter domain.InventoryFilter) ([]domain.InventoryItem, error) {
|
||||
func (r *Repository) ListInventory(ctx context.Context, filter domain.InventoryFilter) ([]domain.InventoryItem, int64, error) {
|
||||
baseQuery := `FROM products`
|
||||
args := []any{}
|
||||
clauses := []string{}
|
||||
if filter.ExpiringBefore != nil {
|
||||
clauses = append(clauses, fmt.Sprintf("expires_at <= $%d", len(args)+1))
|
||||
args = append(args, *filter.ExpiringBefore)
|
||||
}
|
||||
if filter.SellerID != nil {
|
||||
clauses = append(clauses, fmt.Sprintf("seller_id = $%d", len(args)+1))
|
||||
args = append(args, *filter.SellerID)
|
||||
}
|
||||
|
||||
where := ""
|
||||
if len(clauses) > 0 {
|
||||
where = " WHERE " + strings.Join(clauses, " AND ")
|
||||
}
|
||||
|
||||
query := fmt.Sprintf(`SELECT id AS product_id, seller_id, name, batch, expires_at, stock AS quantity, price_cents, updated_at FROM products%s ORDER BY expires_at ASC`, where)
|
||||
var items []domain.InventoryItem
|
||||
if err := r.db.SelectContext(ctx, &items, query, args...); err != nil {
|
||||
return nil, err
|
||||
var total int64
|
||||
if err := r.db.GetContext(ctx, &total, "SELECT count(*) "+baseQuery+where, args...); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
return items, nil
|
||||
|
||||
if filter.Limit <= 0 {
|
||||
filter.Limit = 20
|
||||
}
|
||||
args = append(args, filter.Limit, filter.Offset)
|
||||
listQuery := fmt.Sprintf(`SELECT id AS product_id, seller_id, name, batch, expires_at, stock AS quantity, price_cents, updated_at %s%s ORDER BY expires_at ASC LIMIT $%d OFFSET $%d`, baseQuery, where, len(args)-1, len(args))
|
||||
|
||||
var items []domain.InventoryItem
|
||||
if err := r.db.SelectContext(ctx, &items, listQuery, args...); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
return items, total, nil
|
||||
}
|
||||
|
||||
func (r *Repository) CreateUser(ctx context.Context, user *domain.User) error {
|
||||
|
|
|
|||
|
|
@ -17,21 +17,22 @@ import (
|
|||
// Repository defines DB contract for the core entities.
|
||||
type Repository interface {
|
||||
CreateCompany(ctx context.Context, company *domain.Company) error
|
||||
ListCompanies(ctx context.Context) ([]domain.Company, error)
|
||||
ListCompanies(ctx context.Context, filter domain.CompanyFilter) ([]domain.Company, int64, error)
|
||||
GetCompany(ctx context.Context, id uuid.UUID) (*domain.Company, error)
|
||||
UpdateCompany(ctx context.Context, company *domain.Company) error
|
||||
DeleteCompany(ctx context.Context, id uuid.UUID) error
|
||||
|
||||
CreateProduct(ctx context.Context, product *domain.Product) error
|
||||
ListProducts(ctx context.Context) ([]domain.Product, error)
|
||||
ListProducts(ctx context.Context, filter domain.ProductFilter) ([]domain.Product, int64, error)
|
||||
GetProduct(ctx context.Context, id uuid.UUID) (*domain.Product, error)
|
||||
UpdateProduct(ctx context.Context, product *domain.Product) error
|
||||
DeleteProduct(ctx context.Context, id uuid.UUID) error
|
||||
AdjustInventory(ctx context.Context, productID uuid.UUID, delta int64, reason string) (*domain.InventoryItem, error)
|
||||
ListInventory(ctx context.Context, filter domain.InventoryFilter) ([]domain.InventoryItem, error)
|
||||
ListInventory(ctx context.Context, filter domain.InventoryFilter) ([]domain.InventoryItem, int64, error)
|
||||
|
||||
CreateOrder(ctx context.Context, order *domain.Order) error
|
||||
ListOrders(ctx context.Context) ([]domain.Order, error)
|
||||
ListOrders(ctx context.Context, filter domain.OrderFilter) ([]domain.Order, int64, error)
|
||||
|
||||
GetOrder(ctx context.Context, id uuid.UUID) (*domain.Order, error)
|
||||
UpdateOrderStatus(ctx context.Context, id uuid.UUID, status domain.OrderStatus) error
|
||||
DeleteOrder(ctx context.Context, id uuid.UUID) error
|
||||
|
|
@ -86,8 +87,20 @@ func (s *Service) RegisterCompany(ctx context.Context, company *domain.Company)
|
|||
return s.repo.CreateCompany(ctx, company)
|
||||
}
|
||||
|
||||
func (s *Service) ListCompanies(ctx context.Context) ([]domain.Company, error) {
|
||||
return s.repo.ListCompanies(ctx)
|
||||
func (s *Service) ListCompanies(ctx context.Context, filter domain.CompanyFilter, page, pageSize int) (*domain.CompanyPage, error) {
|
||||
if pageSize <= 0 {
|
||||
pageSize = 20
|
||||
}
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
filter.Limit = pageSize
|
||||
filter.Offset = (page - 1) * pageSize
|
||||
companies, total, err := s.repo.ListCompanies(ctx, filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &domain.CompanyPage{Companies: companies, Total: total, Page: page, PageSize: pageSize}, nil
|
||||
}
|
||||
|
||||
func (s *Service) GetCompany(ctx context.Context, id uuid.UUID) (*domain.Company, error) {
|
||||
|
|
@ -107,8 +120,20 @@ func (s *Service) RegisterProduct(ctx context.Context, product *domain.Product)
|
|||
return s.repo.CreateProduct(ctx, product)
|
||||
}
|
||||
|
||||
func (s *Service) ListProducts(ctx context.Context) ([]domain.Product, error) {
|
||||
return s.repo.ListProducts(ctx)
|
||||
func (s *Service) ListProducts(ctx context.Context, filter domain.ProductFilter, page, pageSize int) (*domain.ProductPage, error) {
|
||||
if pageSize <= 0 {
|
||||
pageSize = 20
|
||||
}
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
filter.Limit = pageSize
|
||||
filter.Offset = (page - 1) * pageSize
|
||||
products, total, err := s.repo.ListProducts(ctx, filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &domain.ProductPage{Products: products, Total: total, Page: page, PageSize: pageSize}, nil
|
||||
}
|
||||
|
||||
func (s *Service) GetProduct(ctx context.Context, id uuid.UUID) (*domain.Product, error) {
|
||||
|
|
@ -123,8 +148,20 @@ func (s *Service) DeleteProduct(ctx context.Context, id uuid.UUID) error {
|
|||
return s.repo.DeleteProduct(ctx, id)
|
||||
}
|
||||
|
||||
func (s *Service) ListInventory(ctx context.Context, filter domain.InventoryFilter) ([]domain.InventoryItem, error) {
|
||||
return s.repo.ListInventory(ctx, filter)
|
||||
func (s *Service) ListInventory(ctx context.Context, filter domain.InventoryFilter, page, pageSize int) (*domain.InventoryPage, error) {
|
||||
if pageSize <= 0 {
|
||||
pageSize = 20
|
||||
}
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
filter.Limit = pageSize
|
||||
filter.Offset = (page - 1) * pageSize
|
||||
items, total, err := s.repo.ListInventory(ctx, filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &domain.InventoryPage{Items: items, Total: total, Page: page, PageSize: pageSize}, nil
|
||||
}
|
||||
|
||||
func (s *Service) AdjustInventory(ctx context.Context, productID uuid.UUID, delta int64, reason string) (*domain.InventoryItem, error) {
|
||||
|
|
@ -137,8 +174,20 @@ func (s *Service) CreateOrder(ctx context.Context, order *domain.Order) error {
|
|||
return s.repo.CreateOrder(ctx, order)
|
||||
}
|
||||
|
||||
func (s *Service) ListOrders(ctx context.Context) ([]domain.Order, error) {
|
||||
return s.repo.ListOrders(ctx)
|
||||
func (s *Service) ListOrders(ctx context.Context, filter domain.OrderFilter, page, pageSize int) (*domain.OrderPage, error) {
|
||||
if pageSize <= 0 {
|
||||
pageSize = 20
|
||||
}
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
filter.Limit = pageSize
|
||||
filter.Offset = (page - 1) * pageSize
|
||||
orders, total, err := s.repo.ListOrders(ctx, filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &domain.OrderPage{Orders: orders, Total: total, Page: page, PageSize: pageSize}, nil
|
||||
}
|
||||
|
||||
func (s *Service) GetOrder(ctx context.Context, id uuid.UUID) (*domain.Order, error) {
|
||||
|
|
|
|||
|
|
@ -38,8 +38,8 @@ func (m *MockRepository) CreateCompany(ctx context.Context, company *domain.Comp
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m *MockRepository) ListCompanies(ctx context.Context) ([]domain.Company, error) {
|
||||
return m.companies, nil
|
||||
func (m *MockRepository) ListCompanies(ctx context.Context, filter domain.CompanyFilter) ([]domain.Company, int64, error) {
|
||||
return m.companies, int64(len(m.companies)), nil
|
||||
}
|
||||
|
||||
func (m *MockRepository) GetCompany(ctx context.Context, id uuid.UUID) (*domain.Company, error) {
|
||||
|
|
@ -79,8 +79,8 @@ func (m *MockRepository) CreateProduct(ctx context.Context, product *domain.Prod
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m *MockRepository) ListProducts(ctx context.Context) ([]domain.Product, error) {
|
||||
return m.products, nil
|
||||
func (m *MockRepository) ListProducts(ctx context.Context, filter domain.ProductFilter) ([]domain.Product, int64, error) {
|
||||
return m.products, int64(len(m.products)), nil
|
||||
}
|
||||
|
||||
func (m *MockRepository) GetProduct(ctx context.Context, id uuid.UUID) (*domain.Product, error) {
|
||||
|
|
@ -116,8 +116,8 @@ func (m *MockRepository) AdjustInventory(ctx context.Context, productID uuid.UUI
|
|||
return &domain.InventoryItem{ProductID: productID, Quantity: delta}, nil
|
||||
}
|
||||
|
||||
func (m *MockRepository) ListInventory(ctx context.Context, filter domain.InventoryFilter) ([]domain.InventoryItem, error) {
|
||||
return []domain.InventoryItem{}, nil
|
||||
func (m *MockRepository) ListInventory(ctx context.Context, filter domain.InventoryFilter) ([]domain.InventoryItem, int64, error) {
|
||||
return []domain.InventoryItem{}, 0, nil
|
||||
}
|
||||
|
||||
// Order methods
|
||||
|
|
@ -126,8 +126,8 @@ func (m *MockRepository) CreateOrder(ctx context.Context, order *domain.Order) e
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m *MockRepository) ListOrders(ctx context.Context) ([]domain.Order, error) {
|
||||
return m.orders, nil
|
||||
func (m *MockRepository) ListOrders(ctx context.Context, filter domain.OrderFilter) ([]domain.Order, int64, error) {
|
||||
return m.orders, int64(len(m.orders)), nil
|
||||
}
|
||||
|
||||
func (m *MockRepository) GetOrder(ctx context.Context, id uuid.UUID) (*domain.Order, error) {
|
||||
|
|
@ -296,13 +296,13 @@ func TestListCompanies(t *testing.T) {
|
|||
svc, _ := newTestService()
|
||||
ctx := context.Background()
|
||||
|
||||
companies, err := svc.ListCompanies(ctx)
|
||||
page, err := svc.ListCompanies(ctx, domain.CompanyFilter{}, 1, 20)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to list companies: %v", err)
|
||||
}
|
||||
|
||||
if len(companies) != 0 {
|
||||
t.Errorf("expected 0 companies, got %d", len(companies))
|
||||
if len(page.Companies) != 0 {
|
||||
t.Errorf("expected 0 companies, got %d", len(page.Companies))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -359,13 +359,13 @@ func TestListProducts(t *testing.T) {
|
|||
svc, _ := newTestService()
|
||||
ctx := context.Background()
|
||||
|
||||
products, err := svc.ListProducts(ctx)
|
||||
page, err := svc.ListProducts(ctx, domain.ProductFilter{}, 1, 20)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to list products: %v", err)
|
||||
}
|
||||
|
||||
if len(products) != 0 {
|
||||
t.Errorf("expected 0 products, got %d", len(products))
|
||||
if len(page.Products) != 0 {
|
||||
t.Errorf("expected 0 products, got %d", len(page.Products))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
2
marketplace/vite.config.d.ts
vendored
Normal file
2
marketplace/vite.config.d.ts
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
declare const _default: import("vite").UserConfig;
|
||||
export default _default;
|
||||
6
marketplace/vite.config.js
Normal file
6
marketplace/vite.config.js
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
import { defineConfig } from 'vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
});
|
||||
Loading…
Reference in a new issue