feat(products): implement CRUD operations and pagination
Added the implementation for Create, Read, Update, and Delete (CRUD) operations in the `ProductsService` and `ProductsController`. These include methods for adding, editing, deleting and listing all products with pagination. All these changes are reflected in the `ProductsModule` and related DTO file.
This commit is contained in:
parent
1618bee00d
commit
007cee5951
@ -1,12 +1,55 @@
|
|||||||
import { Controller } from '@nestjs/common';
|
import {
|
||||||
|
BadRequestException,
|
||||||
|
Body,
|
||||||
|
Controller, Delete, Get,
|
||||||
|
HttpCode,
|
||||||
|
HttpStatus,
|
||||||
|
Param,
|
||||||
|
Patch,
|
||||||
|
Post, Query,
|
||||||
|
UseGuards
|
||||||
|
} from "@nestjs/common";
|
||||||
|
import { CreateProductDto, EditProductDto } from "src/products/products.dto";
|
||||||
|
import { AdminGuard } from "src/auth/auth.guard";
|
||||||
|
import { ProductsService } from "src/products/products.service";
|
||||||
|
|
||||||
@Controller('products')
|
@Controller('products')
|
||||||
export class ProductsController {
|
export class ProductsController {
|
||||||
//TODO add a new product (admin)
|
constructor(
|
||||||
|
private readonly productsService: ProductsService
|
||||||
|
) {}
|
||||||
|
|
||||||
//TODO edit a product (admin)
|
@HttpCode(HttpStatus.CREATED)
|
||||||
|
@UseGuards(AdminGuard)
|
||||||
//TODO delete a product (admin)
|
@Post('new')
|
||||||
|
async newProduct(@Body() dto: CreateProductDto) {
|
||||||
|
const result = await this.productsService.add(dto)
|
||||||
|
if (result.count !== 1) {
|
||||||
|
throw new BadRequestException('Insertion failed');
|
||||||
|
}
|
||||||
|
return result.statement
|
||||||
|
}
|
||||||
|
|
||||||
//TODO list all product with pagination.
|
//TODO list all product with pagination.
|
||||||
|
@HttpCode(HttpStatus.OK)
|
||||||
|
@Get("all")
|
||||||
|
async getAllProducts(@Query('page') page: number) {
|
||||||
|
return this.productsService.findAll(page || 0, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO edit a product (admin)
|
||||||
|
@HttpCode(HttpStatus.OK)
|
||||||
|
@UseGuards(AdminGuard)
|
||||||
|
@Patch(':id')
|
||||||
|
async editProduct(@Param('id') id: string, @Body() dto: EditProductDto) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO delete a product (admin)
|
||||||
|
@HttpCode(HttpStatus.ACCEPTED)
|
||||||
|
@UseGuards(AdminGuard)
|
||||||
|
@Delete(':id')
|
||||||
|
async deleteProduct(@Param('id') id: string) {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
45
src/products/products.dto.ts
Normal file
45
src/products/products.dto.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import {
|
||||||
|
IsEmail, IsInt,
|
||||||
|
IsNotEmpty,
|
||||||
|
IsString,
|
||||||
|
IsStrongPassword,
|
||||||
|
MaxLength, Min,
|
||||||
|
MinLength
|
||||||
|
} from "class-validator";
|
||||||
|
import { optional } from "zod";
|
||||||
|
|
||||||
|
export class CreateProductDto {
|
||||||
|
@MinLength(1)
|
||||||
|
@MaxLength(32)
|
||||||
|
@IsNotEmpty()
|
||||||
|
@IsString()
|
||||||
|
slugName: string;
|
||||||
|
|
||||||
|
@MinLength(1)
|
||||||
|
@MaxLength(64)
|
||||||
|
@IsNotEmpty()
|
||||||
|
@IsString()
|
||||||
|
displayName: string;
|
||||||
|
|
||||||
|
@IsInt()
|
||||||
|
@Min(0)
|
||||||
|
price: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class EditProductDto {
|
||||||
|
@MinLength(1)
|
||||||
|
@MaxLength(32)
|
||||||
|
@IsNotEmpty()
|
||||||
|
@IsString()
|
||||||
|
slugName?: string;
|
||||||
|
|
||||||
|
@MinLength(1)
|
||||||
|
@MaxLength(64)
|
||||||
|
@IsNotEmpty()
|
||||||
|
@IsString()
|
||||||
|
displayName?: string;
|
||||||
|
|
||||||
|
@IsInt()
|
||||||
|
@Min(0)
|
||||||
|
price?: number;
|
||||||
|
}
|
@ -1,8 +1,10 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { ProductsController } from './products.controller';
|
import { ProductsController } from './products.controller';
|
||||||
import { ProductsService } from './products.service';
|
import { ProductsService } from './products.service';
|
||||||
|
import { DrizzleModule } from "src/drizzle/drizzle.module";
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
|
imports: [DrizzleModule],
|
||||||
controllers: [ProductsController],
|
controllers: [ProductsController],
|
||||||
providers: [ProductsService]
|
providers: [ProductsService]
|
||||||
})
|
})
|
||||||
|
@ -1,13 +1,97 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable, InternalServerErrorException } from "@nestjs/common";
|
||||||
|
import { DrizzleService } from "src/drizzle/drizzle.service";
|
||||||
|
import { ProductsTable } from "src/schema";
|
||||||
|
import { CreateProductDto, EditProductDto } from "src/products/products.dto";
|
||||||
|
import { countDistinct, eq } from "drizzle-orm";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ProductsService {
|
export class ProductsService {
|
||||||
//TODO add a new product (admin)
|
|
||||||
|
|
||||||
//TODO edit a product (admin)
|
constructor(
|
||||||
|
private db: DrizzleService,
|
||||||
|
) {}
|
||||||
|
|
||||||
//TODO delete a product (admin)
|
async add(data: CreateProductDto) {
|
||||||
|
try {
|
||||||
|
const res = await this.db.use()
|
||||||
|
.insert(ProductsTable)
|
||||||
|
.values({
|
||||||
|
slugName: data.slugName,
|
||||||
|
displayName: data.displayName,
|
||||||
|
price: String(data.price),
|
||||||
|
imagePath: "placeholder"
|
||||||
|
})
|
||||||
|
console.log(`Adding new product "${data.slugName}" ...\n`, res)
|
||||||
|
return res;
|
||||||
|
} catch (err) {
|
||||||
|
throw new InternalServerErrorException(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async edit(productId: string, data: EditProductDto) {
|
||||||
|
try {
|
||||||
|
const res = await this.db.use()
|
||||||
|
.update(ProductsTable)
|
||||||
|
.set({
|
||||||
|
slugName: data.slugName,
|
||||||
|
displayName: data.displayName,
|
||||||
|
price: String(data.price),
|
||||||
|
})
|
||||||
|
.where(eq(ProductsTable.uuid, productId))
|
||||||
|
.prepare("editProductById")
|
||||||
|
.execute();
|
||||||
|
console.log(`Editing product n°${productId} ...\n`, res)
|
||||||
|
return res;
|
||||||
|
} catch (err) {
|
||||||
|
throw new InternalServerErrorException(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async delete(productId: string) {
|
||||||
|
try {
|
||||||
|
const res = await this.db.use()
|
||||||
|
.delete(ProductsTable)
|
||||||
|
.where(eq(ProductsTable.uuid, productId))
|
||||||
|
.prepare("deleteProductById")
|
||||||
|
.execute();
|
||||||
|
console.log(`Deleting product n°${productId} ...\n`, res)
|
||||||
|
return res;
|
||||||
|
} catch (err) {
|
||||||
|
throw new InternalServerErrorException(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//TODO list all product with pagination.
|
//TODO list all product with pagination.
|
||||||
|
async findAll(page: number, limit: number) {
|
||||||
|
try {
|
||||||
|
//get the number of row first
|
||||||
|
const count = await this.db.use()
|
||||||
|
.select({
|
||||||
|
total: countDistinct(ProductsTable.uuid)
|
||||||
|
})
|
||||||
|
.from(ProductsTable)
|
||||||
|
.prepare("countProducts")
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
const res = await this.db.use()
|
||||||
|
.select()
|
||||||
|
.from(ProductsTable)
|
||||||
|
.limit(limit)
|
||||||
|
.offset((page - 1) * limit)
|
||||||
|
.prepare("findAllProducts")
|
||||||
|
.execute();
|
||||||
|
console.log(`Fetching products (page ${page}, limit ${limit}) ...\n`)
|
||||||
|
const response = {
|
||||||
|
total: count[0].total,
|
||||||
|
page: page,
|
||||||
|
productsPerPage: limit,
|
||||||
|
products: res
|
||||||
|
}
|
||||||
|
console.log(response)
|
||||||
|
return response;
|
||||||
|
} catch (err) {
|
||||||
|
throw new InternalServerErrorException(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user