From b79f3f69f37be6e5606190c7d02f3ce735f9cb98 Mon Sep 17 00:00:00 2001 From: Natthapol SERMSARAN Date: Tue, 1 Apr 2025 15:16:51 +0700 Subject: [PATCH] feat: implement inventory repository with status and category relations --- .../internal/repository/postgres_inventory.go | 210 +++++++++++++----- 1 file changed, 156 insertions(+), 54 deletions(-) diff --git a/backend/internal/repository/postgres_inventory.go b/backend/internal/repository/postgres_inventory.go index 5dd0319..1bd5d98 100644 --- a/backend/internal/repository/postgres_inventory.go +++ b/backend/internal/repository/postgres_inventory.go @@ -31,12 +31,11 @@ func (p *postgresInventoryRepository) fetch(ctx context.Context, query string, a &i.ID, &i.UserID, &i.Name, - &i.Category, - &i.Type, + &i.CategoryID, &i.Quantity, - &i.Unit, + &i.UnitID, &i.DateAdded, - &i.Status, + &i.StatusID, &i.CreatedAt, &i.UpdatedAt, ); err != nil { @@ -49,18 +48,49 @@ func (p *postgresInventoryRepository) fetch(ctx context.Context, query string, a func (p *postgresInventoryRepository) GetByID(ctx context.Context, id, userID string) (domain.InventoryItem, error) { query := ` - SELECT id, user_id, name, category, type, quantity, unit, date_added, status, created_at, updated_at - FROM inventory_items - WHERE id = $1 AND user_id = $2` + SELECT + i.id, i.user_id, i.name, i.category_id, i.quantity, i.unit_id, + i.date_added, i.status_id, i.created_at, i.updated_at, + c.name as category_name, + s.name as status_name, + u.name as unit_name + FROM inventory_items i + LEFT JOIN inventory_category c ON i.category_id = c.id + LEFT JOIN inventory_status s ON i.status_id = s.id + LEFT JOIN harvest_units u ON i.unit_id = u.id + WHERE i.id = $1 AND i.user_id = $2` - items, err := p.fetch(ctx, query, id, userID) + rows, err := p.conn.Query(ctx, query, id, userID) if err != nil { return domain.InventoryItem{}, err } - if len(items) == 0 { + defer rows.Close() + + if !rows.Next() { return domain.InventoryItem{}, domain.ErrNotFound } - return items[0], nil + + var item domain.InventoryItem + err = rows.Scan( + &item.ID, + &item.UserID, + &item.Name, + &item.CategoryID, + &item.Quantity, + &item.UnitID, + &item.DateAdded, + &item.StatusID, + &item.CreatedAt, + &item.UpdatedAt, + &item.Category.Name, + &item.Status.Name, + &item.Unit.Name, + ) + if err != nil { + return domain.InventoryItem{}, err + } + + return item, nil } func (p *postgresInventoryRepository) GetByUserID( @@ -74,58 +104,57 @@ func (p *postgresInventoryRepository) GetByUserID( argPos := 2 query.WriteString(` - SELECT id, user_id, name, category, type, quantity, unit, date_added, status, created_at, updated_at - FROM inventory_items - WHERE user_id = $1`) + SELECT + i.id, i.user_id, i.name, i.category_id, i.quantity, i.unit_id, + i.date_added, i.status_id, i.created_at, i.updated_at, + c.name as category_name, + s.name as status_name, + u.name as unit_name + FROM inventory_items i + LEFT JOIN inventory_category c ON i.category_id = c.id + LEFT JOIN inventory_status s ON i.status_id = s.id + LEFT JOIN harvest_units u ON i.unit_id = u.id + WHERE i.user_id = $1`) - if filter.Category != "" { - query.WriteString(fmt.Sprintf(" AND category = $%d", argPos)) - args = append(args, filter.Category) + if filter.CategoryID != 0 { + query.WriteString(fmt.Sprintf(" AND i.category_id = $%d", argPos)) + args = append(args, filter.CategoryID) argPos++ } - if filter.Type != "" { - query.WriteString(fmt.Sprintf(" AND type = $%d", argPos)) - args = append(args, filter.Type) - argPos++ - } - - if filter.Status != "" { - query.WriteString(fmt.Sprintf(" AND status = $%d", argPos)) - args = append(args, filter.Status) + if filter.StatusID != 0 { + query.WriteString(fmt.Sprintf(" AND i.status_id = $%d", argPos)) + args = append(args, filter.StatusID) argPos++ } if !filter.StartDate.IsZero() { - query.WriteString(fmt.Sprintf(" AND date_added >= $%d", argPos)) + query.WriteString(fmt.Sprintf(" AND i.date_added >= $%d", argPos)) args = append(args, filter.StartDate) argPos++ } if !filter.EndDate.IsZero() { - query.WriteString(fmt.Sprintf(" AND date_added <= $%d", argPos)) + query.WriteString(fmt.Sprintf(" AND i.date_added <= $%d", argPos)) args = append(args, filter.EndDate) argPos++ } if filter.SearchQuery != "" { - query.WriteString(fmt.Sprintf(" AND name ILIKE $%d", argPos)) + query.WriteString(fmt.Sprintf(" AND i.name ILIKE $%d", argPos)) args = append(args, "%"+filter.SearchQuery+"%") argPos++ } if sort.Field == "" { - sort.Field = "date_added" + sort.Field = "i.date_added" sort.Direction = "desc" } validSortFields := map[string]bool{ "name": true, - "category": true, - "type": true, "quantity": true, "date_added": true, - "status": true, "created_at": true, } @@ -138,14 +167,52 @@ func (p *postgresInventoryRepository) GetByUserID( } } - return p.fetch(ctx, query.String(), args...) + rows, err := p.conn.Query(ctx, query.String(), args...) + if err != nil { + return nil, err + } + defer rows.Close() + + var items []domain.InventoryItem + for rows.Next() { + var item domain.InventoryItem + err := rows.Scan( + &item.ID, + &item.UserID, + &item.Name, + &item.CategoryID, + &item.Quantity, + &item.UnitID, + &item.DateAdded, + &item.StatusID, + &item.CreatedAt, + &item.UpdatedAt, + &item.Category.Name, + &item.Status.Name, + &item.Unit.Name, + ) + if err != nil { + return nil, err + } + items = append(items, item) + } + + return items, nil } func (p *postgresInventoryRepository) GetAll(ctx context.Context) ([]domain.InventoryItem, error) { query := ` - SELECT id, user_id, name, category, type, quantity, unit, date_added, status, created_at, updated_at - FROM inventory_items - ORDER BY created_at DESC` + SELECT + i.id, i.user_id, i.name, i.category_id, i.quantity, i.unit_id, + i.date_added, i.status_id, i.created_at, i.updated_at, + c.name as category_name, + s.name as status_name, + u.name as unit_name + FROM inventory_items i + LEFT JOIN inventory_category c ON i.category_id = c.id + LEFT JOIN inventory_status s ON i.status_id = s.id + LEFT JOIN harvest_units u ON i.unit_id = u.id + ORDER BY i.created_at DESC` return p.fetch(ctx, query) } @@ -157,20 +224,19 @@ func (p *postgresInventoryRepository) CreateOrUpdate(ctx context.Context, item * item.CreatedAt = now query := ` INSERT INTO inventory_items - (id, user_id, name, category, type, quantity, unit, date_added, status, created_at, updated_at) - VALUES (gen_random_uuid(), $1, $2, $3, $4, $5, $6, $7, $8, $9, $10) + (id, user_id, name, category_id, quantity, unit_id, date_added, status_id, created_at, updated_at) + VALUES (gen_random_uuid(), $1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING id` return p.conn.QueryRow( ctx, query, item.UserID, item.Name, - item.Category, - item.Type, + item.CategoryID, item.Quantity, - item.Unit, + item.UnitID, item.DateAdded, - item.Status, + item.StatusID, item.CreatedAt, item.UpdatedAt, ).Scan(&item.ID) @@ -179,26 +245,24 @@ func (p *postgresInventoryRepository) CreateOrUpdate(ctx context.Context, item * query := ` UPDATE inventory_items SET name = $1, - category = $2, - type = $3, - quantity = $4, - unit = $5, - date_added = $6, - status = $7, - updated_at = $8 - WHERE id = $9 AND user_id = $10 + category_id = $2, + quantity = $3, + unit_id = $4, + date_added = $5, + status_id = $6, + updated_at = $7 + WHERE id = $8 AND user_id = $9 RETURNING id` return p.conn.QueryRow( ctx, query, item.Name, - item.Category, - item.Type, + item.CategoryID, item.Quantity, - item.Unit, + item.UnitID, item.DateAdded, - item.Status, + item.StatusID, item.UpdatedAt, item.ID, item.UserID, @@ -210,3 +274,41 @@ func (p *postgresInventoryRepository) Delete(ctx context.Context, id, userID str _, err := p.conn.Exec(ctx, query, id, userID) return err } + +func (p *postgresInventoryRepository) GetStatuses(ctx context.Context) ([]domain.InventoryStatus, error) { + query := `SELECT id, name FROM inventory_status ORDER BY id` + rows, err := p.conn.Query(ctx, query) + if err != nil { + return nil, err + } + defer rows.Close() + + var statuses []domain.InventoryStatus + for rows.Next() { + var s domain.InventoryStatus + if err := rows.Scan(&s.ID, &s.Name); err != nil { + return nil, err + } + statuses = append(statuses, s) + } + return statuses, nil +} + +func (p *postgresInventoryRepository) GetCategories(ctx context.Context) ([]domain.InventoryCategory, error) { + query := `SELECT id, name FROM inventory_category ORDER BY id` + rows, err := p.conn.Query(ctx, query) + if err != nil { + return nil, err + } + defer rows.Close() + + var categories []domain.InventoryCategory + for rows.Next() { + var c domain.InventoryCategory + if err := rows.Scan(&c.ID, &c.Name); err != nil { + return nil, err + } + categories = append(categories, c) + } + return categories, nil +}