import { Injectable } from "@nestjs/common"; import { InjectModel } from "@nestjs/sequelize"; import { Product } from "./entities/product.entity"; import { CreateProductDto } from "./dto/create-product.dto"; import { UpdateProductDto } from "./dto/update-product.dto"; import { Op } from "sequelize"; import { HttpException, HttpStatus } from "@nestjs/common"; @Injectable() export class ProductsService { constructor(@InjectModel(Product) private readonly productModel: typeof Product) {} // create a new product async create(createProductDto: CreateProductDto): Promise { try { const existingProduct = await this.productModel.findOne({ where: { name: createProductDto.name }, }); if (existingProduct) { existingProduct.quantity += createProductDto.quantity || 0; await existingProduct.save(); return existingProduct; } const newProduct = await this.productModel.create(createProductDto); return newProduct; } catch (error) { if(error instanceof HttpException){ throw error } throw new HttpException("An error occurred while creating or updating the product.", HttpStatus.INTERNAL_SERVER_ERROR); } } // find a product by id async findOne(id: string): Promise { try { const product = await this.productModel.findByPk(id); if (!product) { throw new HttpException("Product not found with the given ID.", HttpStatus.NOT_FOUND); } return product; } catch (error) { if (error instanceof HttpException) { throw error; } throw new HttpException("An unexpected error occurred while fetching the product.", HttpStatus.INTERNAL_SERVER_ERROR); } } // list of all product async findAll( search?: string, priceMin?: number, priceMax?: number, page: number = 1, limit: number = 10, ): Promise<{ products: Product[]; total: number; totalPages: number; currentPage: number }> { try { const where: Record = {}; if (search) { where.name = { [Op.iLike]: `%${search}%` }; } if (priceMin !== undefined || priceMax !== undefined) { where.price = {}; if (priceMin !== undefined) { where.price[Op.gte] = priceMin; } if (priceMax !== undefined) { where.price[Op.lte] = priceMax; } } const offset = (page - 1) * limit; const { rows: products, count: total } = await this.productModel.findAndCountAll({ where, limit, offset, attributes: { exclude: ["description", "quantity", "createdAt", "updatedAt", "tags"] }, }); const totalPages = Math.ceil(total / limit); return { products, total, totalPages, currentPage: page, }; } catch (error) { console.error("Error retrieving products:", error.message); if (error instanceof HttpException) { throw error; } throw new HttpException("An unexpected error occurred while retrieving products.", HttpStatus.INTERNAL_SERVER_ERROR); } } // update a product info async update(id: string, updateProductDto: UpdateProductDto): Promise { const product = await this.productModel.findByPk(id); if (!product) { throw new HttpException("Product not found.", HttpStatus.NOT_FOUND); } try { const { name, description, price, imageUrl, tags, quantity, brand, color, category } = updateProductDto; let updated = false; if (name && name !== product.name) { product.name = name; updated = true; } if (description && description !== product.description) { product.description = description; updated = true; } if (price !== undefined && price !== product.price) { product.price = price; updated = true; } if (imageUrl && imageUrl !== product.imageUrl) { product.imageUrl = imageUrl; updated = true; } if (tags && tags !== product.tags) { product.tags = tags; updated = true; } if (quantity !== undefined && quantity !== product.quantity) { product.quantity = quantity; updated = true; } if (brand && brand !== product.brand) { product.brand = brand; updated = true; } if (color && color !== product.color) { product.color = color; updated = true; } if (category && category !== product.category) { product.category = category; updated = true; } if (updated) { await product.save(); } return product; } catch (error) { if(error instanceof HttpException){ throw error } throw new HttpException("An error occurred while updating the product.", HttpStatus.INTERNAL_SERVER_ERROR); } } // delete a product async remove(id: string): Promise<{ message: string }> { try { const product = await this.productModel.findByPk(id); if (!product) { throw new HttpException(`Product with id ${id} not found.`, HttpStatus.NOT_FOUND); } await product.destroy(); return { message: "Product deleted successfully." }; } catch (error) { console.error("Error during product deletion:", error.message); if (error instanceof HttpException) { throw error; } throw new HttpException("An unexpected error occurred while deleting the product.", HttpStatus.INTERNAL_SERVER_ERROR); } } }