You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
190 lines
5.5 KiB
190 lines
5.5 KiB
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<Product> { |
|
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<Product> { |
|
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<string, any> = {}; |
|
|
|
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<Product> { |
|
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); |
|
} |
|
} |
|
}
|
|
|