codeweaver 1.1.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.vscode/settings.json +3 -0
- package/README.md +114 -181
- package/package.json +12 -7
- package/src/app.ts +2 -112
- package/src/config.ts +33 -64
- package/src/constants.ts +7 -0
- package/src/db.ts +183 -0
- package/src/entities/order.entity.ts +68 -0
- package/src/entities/product.entity.ts +75 -0
- package/src/entities/user.entity.ts +38 -0
- package/src/main.ts +85 -0
- package/src/routers/orders/dto/order.dto.ts +54 -29
- package/src/routers/orders/{index.ts → index.router.ts} +13 -13
- package/src/routers/orders/order.controller.ts +118 -120
- package/src/routers/products/dto/product.dto.ts +86 -30
- package/src/routers/products/{index.ts → index.router.ts} +14 -15
- package/src/routers/products/product.controller.ts +136 -161
- package/src/routers/users/dto/user.dto.ts +14 -18
- package/src/routers/users/{index.ts → index.router.ts} +6 -7
- package/src/routers/users/user.controller.ts +87 -118
- package/src/swagger-options.ts +39 -0
- package/src/utilities/assign.ts +66 -0
- package/src/utilities/cache/memory-cache.ts +74 -0
- package/src/utilities/cache/redis-cache.ts +111 -0
- package/src/utilities/conversion.ts +158 -0
- package/src/utilities/error-handling.ts +156 -0
- package/src/utilities/router.ts +0 -0
- package/tsconfig.json +1 -4
- package/tsconfig.paths.json +8 -10
- package/src/packages/ts-zod-decorators/index.ts +0 -3
- package/src/packages/ts-zod-decorators/validate.decorator.ts +0 -20
- package/src/packages/ts-zod-decorators/validator.class.ts +0 -72
- package/src/packages/ts-zod-decorators/zod-input.decorator.ts +0 -12
- package/src/packages/ts-zod-decorators/zod-output.decorator.ts +0 -11
- package/src/types.ts +0 -16
- package/src/utilities.ts +0 -47
- /package/src/routers/{index.ts → index.router.ts} +0 -0
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Router, Request, Response } from "express";
|
|
2
2
|
import asyncHandler from "express-async-handler";
|
|
3
3
|
import OrderController from "./order.controller";
|
|
4
|
-
import { sendError } from "@/utilities";
|
|
5
4
|
|
|
6
5
|
const router = Router();
|
|
7
6
|
const orderController = new OrderController();
|
|
@@ -11,7 +10,7 @@ const orderController = new OrderController();
|
|
|
11
10
|
* /orders:
|
|
12
11
|
* post:
|
|
13
12
|
* summary: Create a new order
|
|
14
|
-
* description: Creates an order with
|
|
13
|
+
* description: Creates an order with order details and products.
|
|
15
14
|
* consumes:
|
|
16
15
|
* - application/json
|
|
17
16
|
* produces:
|
|
@@ -59,8 +58,9 @@ const orderController = new OrderController();
|
|
|
59
58
|
router.post(
|
|
60
59
|
"/",
|
|
61
60
|
asyncHandler(async (req: Request, res: Response) => {
|
|
62
|
-
const order = await orderController.
|
|
63
|
-
|
|
61
|
+
const order = await orderController.validateOrderCreationDto(req.body);
|
|
62
|
+
await orderController.create(order);
|
|
63
|
+
res.status(201).send();;
|
|
64
64
|
})
|
|
65
65
|
);
|
|
66
66
|
|
|
@@ -100,9 +100,9 @@ router.get(
|
|
|
100
100
|
router.get(
|
|
101
101
|
"/:id",
|
|
102
102
|
asyncHandler(async (req: Request, res: Response) => {
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
103
|
+
const id = await orderController.validateId(req.params.id);
|
|
104
|
+
const order = await orderController.get(id);
|
|
105
|
+
res.json(order);
|
|
106
106
|
})
|
|
107
107
|
);
|
|
108
108
|
|
|
@@ -125,9 +125,9 @@ router.get(
|
|
|
125
125
|
router.patch(
|
|
126
126
|
"/:id/cancel",
|
|
127
127
|
asyncHandler(async (req: Request, res: Response) => {
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
128
|
+
const id = await orderController.validateId(req.params.id);
|
|
129
|
+
const order = await orderController.cancel(id);
|
|
130
|
+
res.json(order);
|
|
131
131
|
})
|
|
132
132
|
);
|
|
133
133
|
|
|
@@ -152,9 +152,9 @@ router.patch(
|
|
|
152
152
|
router.patch(
|
|
153
153
|
"/:id/deliver",
|
|
154
154
|
asyncHandler(async (req: Request, res: Response) => {
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
|
|
155
|
+
const id = await orderController.validateId(req.params.id);
|
|
156
|
+
const order = await orderController.deliver(id);
|
|
157
|
+
res.json(order);
|
|
158
158
|
})
|
|
159
159
|
);
|
|
160
160
|
|
|
@@ -1,191 +1,189 @@
|
|
|
1
|
-
import { onError, rateLimit, timeout } from "utils-decorators";
|
|
1
|
+
import { memoizeAsync, onError, rateLimit, timeout } from "utils-decorators";
|
|
2
2
|
import {
|
|
3
|
-
|
|
3
|
+
OrderDto,
|
|
4
4
|
OrderCreationDto,
|
|
5
5
|
ZodOrderCreationDto,
|
|
6
6
|
} from "./dto/order.dto";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
{
|
|
14
|
-
id: 1,
|
|
15
|
-
userId: 1,
|
|
16
|
-
products: [
|
|
17
|
-
{ productId: 2, quantity: 1 },
|
|
18
|
-
{ productId: 6, quantity: 2 },
|
|
19
|
-
],
|
|
20
|
-
status: "Delivered",
|
|
21
|
-
total: 14400,
|
|
22
|
-
createdAt: new Date("2024-01-15"),
|
|
23
|
-
deliveredAt: new Date("2024-02-10"),
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
id: 2,
|
|
27
|
-
userId: 3,
|
|
28
|
-
products: [
|
|
29
|
-
{ productId: 9, quantity: 1 },
|
|
30
|
-
{ productId: 7, quantity: 1 },
|
|
31
|
-
],
|
|
32
|
-
status: "Processing",
|
|
33
|
-
total: 36500,
|
|
34
|
-
createdAt: new Date("2024-03-20"),
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
id: 3,
|
|
38
|
-
userId: 2,
|
|
39
|
-
products: [
|
|
40
|
-
{ productId: 1, quantity: 1 },
|
|
41
|
-
{ productId: 4, quantity: 2 },
|
|
42
|
-
],
|
|
43
|
-
status: "Canceled",
|
|
44
|
-
total: 81000,
|
|
45
|
-
createdAt: new Date("2024-05-01"),
|
|
46
|
-
canceledAt: new Date("2024-05-03"),
|
|
47
|
-
},
|
|
48
|
-
];
|
|
7
|
+
import { ResponseError } from "@/utilities/error-handling";
|
|
8
|
+
import { convert, stringToInteger } from "@/utilities/conversion";
|
|
9
|
+
import config from "@/config";
|
|
10
|
+
import { orders } from "@/db";
|
|
11
|
+
import { Order, ZodOrder } from "@/entities/order.entity";
|
|
12
|
+
import { MapAsyncCache } from "@/utilities/cache/memory-cache";
|
|
49
13
|
|
|
50
14
|
function exceedHandler() {
|
|
51
15
|
const message = "Too much call in allowed window";
|
|
52
|
-
|
|
53
|
-
throw new Error(message, {
|
|
54
|
-
cause: { status: 500, message } satisfies ResponseError,
|
|
55
|
-
});
|
|
16
|
+
throw new ResponseError(message, 429);
|
|
56
17
|
}
|
|
57
18
|
|
|
58
|
-
function
|
|
19
|
+
function orderNotFoundHandler(e: ResponseError) {
|
|
59
20
|
const message = "Order not found.";
|
|
21
|
+
throw new ResponseError(message, 404, e.message);
|
|
22
|
+
}
|
|
60
23
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
24
|
+
function invalidInputHandler(e: ResponseError) {
|
|
25
|
+
const message = "Invalid input";
|
|
26
|
+
throw new ResponseError(message, 400, e.message);
|
|
64
27
|
}
|
|
65
28
|
|
|
29
|
+
const ordersCache = new MapAsyncCache<OrderDto[]>(config.cacheSize);
|
|
30
|
+
const orderCache = new MapAsyncCache<OrderDto>(config.cacheSize);
|
|
31
|
+
|
|
66
32
|
/**
|
|
67
33
|
* Controller for handling order-related operations
|
|
68
34
|
* @class OrderController
|
|
69
35
|
* @desc Provides methods for order management including creation, status updates and retrieval
|
|
70
36
|
*/
|
|
71
37
|
export default class OrderController {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
38
|
+
// constructor(private readonly orderService: OrderService) { }
|
|
39
|
+
|
|
40
|
+
@onError({
|
|
41
|
+
func: orderNotFoundHandler,
|
|
76
42
|
})
|
|
77
|
-
@Validate
|
|
78
43
|
/**
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
* @
|
|
44
|
+
* Validates a string ID and converts it to a number.
|
|
45
|
+
*
|
|
46
|
+
* @param {string} id - The ID to validate and convert.
|
|
47
|
+
* @returns {number} The numeric value of the provided ID.
|
|
82
48
|
*/
|
|
83
|
-
public async
|
|
84
|
-
|
|
85
|
-
|
|
49
|
+
public async validateId(id: string): Promise<number> {
|
|
50
|
+
return stringToInteger(id);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@onError({
|
|
54
|
+
func: invalidInputHandler,
|
|
55
|
+
})
|
|
56
|
+
/**
|
|
57
|
+
* Validates and creates a new Order from the given DTO.
|
|
58
|
+
*
|
|
59
|
+
* @param {OrderCreationDto} order - The incoming OrderCreationDto to validate and transform.
|
|
60
|
+
* @returns {Order} A fully formed Order object ready for persistence.
|
|
61
|
+
*/
|
|
62
|
+
public async validateOrderCreationDto(
|
|
63
|
+
order: OrderCreationDto
|
|
64
|
+
): Promise<Order> {
|
|
65
|
+
const newOrder = await ZodOrderCreationDto.parseAsync(order);
|
|
66
|
+
return {
|
|
67
|
+
...newOrder,
|
|
86
68
|
id: orders.length + 1,
|
|
87
|
-
createdAt: new Date(),
|
|
88
69
|
status: "Processing",
|
|
89
|
-
|
|
70
|
+
createdAt: new Date(),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
90
73
|
|
|
91
|
-
|
|
92
|
-
|
|
74
|
+
@rateLimit({
|
|
75
|
+
timeSpanMs: config.rateLimitTimeSpan,
|
|
76
|
+
allowedCalls: config.rateLimitAllowedCalls,
|
|
77
|
+
exceedHandler,
|
|
78
|
+
})
|
|
79
|
+
/**
|
|
80
|
+
* Create a new order
|
|
81
|
+
* @param {Order} order - Order creation data
|
|
82
|
+
* @returns {Promise<void>}
|
|
83
|
+
* @throws {ResponseError} 500 - When rate limit exceeded
|
|
84
|
+
* @throws {ResponseError} 400 - Invalid input data
|
|
85
|
+
*/
|
|
86
|
+
public async create(order: Order): Promise<void> {
|
|
87
|
+
orders.push(order);
|
|
88
|
+
await orderCache.set(order.id.toString(), order as OrderDto);
|
|
89
|
+
await ordersCache.delete("key");
|
|
93
90
|
}
|
|
94
91
|
|
|
95
|
-
@
|
|
92
|
+
@memoizeAsync({
|
|
93
|
+
cache: ordersCache,
|
|
94
|
+
keyResolver: () => "key",
|
|
95
|
+
expirationTimeMs: config.memoizeTime,
|
|
96
|
+
})
|
|
97
|
+
@timeout(config.timeout)
|
|
96
98
|
@rateLimit({
|
|
97
|
-
timeSpanMs:
|
|
98
|
-
allowedCalls:
|
|
99
|
+
timeSpanMs: config.rateLimitTimeSpan,
|
|
100
|
+
allowedCalls: config.rateLimitAllowedCalls,
|
|
99
101
|
exceedHandler,
|
|
100
102
|
})
|
|
101
103
|
/**
|
|
102
104
|
* Retrieves all orders
|
|
103
105
|
* @returns List of orders
|
|
104
106
|
*/
|
|
105
|
-
public async getAll(): Promise<
|
|
106
|
-
return orders;
|
|
107
|
+
public async getAll(): Promise<OrderDto[]> {
|
|
108
|
+
return orders as OrderDto[];
|
|
107
109
|
}
|
|
108
110
|
|
|
111
|
+
@memoizeAsync({
|
|
112
|
+
cache: orderCache,
|
|
113
|
+
keyResolver: (id: number) => id.toString(),
|
|
114
|
+
expirationTimeMs: config.memoizeTime,
|
|
115
|
+
})
|
|
109
116
|
@rateLimit({
|
|
110
|
-
timeSpanMs:
|
|
111
|
-
allowedCalls:
|
|
117
|
+
timeSpanMs: config.rateLimitTimeSpan,
|
|
118
|
+
allowedCalls: config.rateLimitAllowedCalls,
|
|
112
119
|
exceedHandler,
|
|
113
120
|
})
|
|
114
|
-
@onError({
|
|
115
|
-
func: getOrderErrorHandler,
|
|
116
|
-
})
|
|
117
121
|
/**
|
|
118
122
|
* Finds an order by its ID
|
|
119
|
-
* @param id - Order ID as string
|
|
123
|
+
* @param {number} id - Order ID as string
|
|
120
124
|
* @returns Order details or error object if not found
|
|
121
125
|
*/
|
|
122
|
-
public async get(id:
|
|
123
|
-
const
|
|
124
|
-
if (
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
return {
|
|
129
|
-
status: 404,
|
|
130
|
-
message: "Order dose not exist.",
|
|
131
|
-
} satisfies ResponseError;
|
|
132
|
-
|
|
133
|
-
return order satisfies Order;
|
|
126
|
+
public async get(id: number): Promise<OrderDto> {
|
|
127
|
+
const order = orders.find((order) => order.id === id);
|
|
128
|
+
if (order == null) {
|
|
129
|
+
throw new ResponseError("Order not found");
|
|
130
|
+
}
|
|
131
|
+
return convert(order!, ZodOrder);
|
|
134
132
|
}
|
|
135
133
|
|
|
136
134
|
@rateLimit({
|
|
137
|
-
timeSpanMs:
|
|
138
|
-
allowedCalls:
|
|
135
|
+
timeSpanMs: config.rateLimitTimeSpan,
|
|
136
|
+
allowedCalls: config.rateLimitAllowedCalls,
|
|
139
137
|
exceedHandler,
|
|
140
138
|
})
|
|
141
139
|
/**
|
|
142
140
|
* Cancel an existing order
|
|
143
|
-
* @param {
|
|
144
|
-
* @returns {Promise<Order
|
|
141
|
+
* @param {number} id - Order ID to cancel
|
|
142
|
+
* @returns {Promise<Order>} Updated order or error object
|
|
145
143
|
* @throws {ResponseError} 404 - Order not found
|
|
146
144
|
* @throws {ResponseError} 400 - Invalid ID format or invalid status for cancellation
|
|
147
145
|
*/
|
|
148
|
-
public async cancel(id:
|
|
146
|
+
public async cancel(id: number): Promise<OrderDto> {
|
|
149
147
|
let order = await this.get(id);
|
|
150
|
-
if (
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
"Cancellation is not available unless the order is in processing status.",
|
|
157
|
-
} satisfies ResponseError;
|
|
158
|
-
|
|
148
|
+
if (order.status != "Processing") {
|
|
149
|
+
throw new ResponseError(
|
|
150
|
+
"Cancellation is not available unless the order is in processing status.",
|
|
151
|
+
400
|
|
152
|
+
);
|
|
153
|
+
}
|
|
159
154
|
order.status = "Canceled";
|
|
160
155
|
order.deliveredAt = new Date();
|
|
161
|
-
|
|
156
|
+
|
|
157
|
+
await orderCache.set(id.toString(), order);
|
|
158
|
+
await ordersCache.delete("key");
|
|
159
|
+
return order;
|
|
162
160
|
}
|
|
163
161
|
|
|
164
162
|
@rateLimit({
|
|
165
|
-
timeSpanMs:
|
|
166
|
-
allowedCalls:
|
|
163
|
+
timeSpanMs: config.rateLimitTimeSpan,
|
|
164
|
+
allowedCalls: config.rateLimitAllowedCalls,
|
|
167
165
|
exceedHandler,
|
|
168
166
|
})
|
|
169
167
|
/**
|
|
170
168
|
* Mark an order as delivered
|
|
171
|
-
* @param {
|
|
172
|
-
* @returns {Promise<Order
|
|
169
|
+
* @param {number} id - Order ID to mark as delivered
|
|
170
|
+
* @returns {Promise<Order>} Updated order or error object
|
|
173
171
|
* @throws {ResponseError} 404 - Order not found
|
|
174
172
|
* @throws {ResponseError} 400 - Invalid ID format or invalid status for delivery
|
|
175
173
|
*/
|
|
176
|
-
public async deliver(id:
|
|
174
|
+
public async deliver(id: number): Promise<OrderDto> {
|
|
177
175
|
let order = await this.get(id);
|
|
178
|
-
if (
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
"Delivery is only available when the order is in processing status.",
|
|
185
|
-
} satisfies ResponseError;
|
|
186
|
-
|
|
176
|
+
if (order.status != "Processing") {
|
|
177
|
+
throw new ResponseError(
|
|
178
|
+
"Delivery is only available when the order is in processing status.",
|
|
179
|
+
400
|
|
180
|
+
);
|
|
181
|
+
}
|
|
187
182
|
order.status = "Delivered";
|
|
188
183
|
order.deliveredAt = new Date();
|
|
189
|
-
|
|
184
|
+
|
|
185
|
+
await orderCache.set(id.toString(), order);
|
|
186
|
+
await ordersCache.delete("key");
|
|
187
|
+
return order;
|
|
190
188
|
}
|
|
191
189
|
}
|
|
@@ -1,36 +1,92 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ZodProduct } from "@/entities/product.entity";
|
|
2
|
+
import z from "zod";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* @property {number} id - Unique identifier (min 1)
|
|
7
|
-
* @property {string} name - Product name (min 2 chars)
|
|
8
|
-
* @property {number} price - Product price (min 1000)
|
|
9
|
-
* @property {string} [description] - Optional description (min 10 chars)
|
|
10
|
-
* @property {string} category - Product category from predefined enum
|
|
11
|
-
* @property {number} stock - Available stock quantity (min 0)
|
|
5
|
+
* DTO for creating a Product.
|
|
6
|
+
* Derived from the full Product schema by omitting the system-generated id.
|
|
12
7
|
*/
|
|
13
|
-
export const ZodProduct = z.object({
|
|
14
|
-
id: z.number().min(1).int(),
|
|
15
|
-
name: z.string().min(2),
|
|
16
|
-
price: z.number().min(1000),
|
|
17
|
-
description: z.string().min(10).optional(),
|
|
18
|
-
category: z.enum([
|
|
19
|
-
"Electronics",
|
|
20
|
-
"Appliances",
|
|
21
|
-
"Sports",
|
|
22
|
-
"Kitchen",
|
|
23
|
-
"Mobile Accessories",
|
|
24
|
-
"Computer Accessories",
|
|
25
|
-
"Home Appliances",
|
|
26
|
-
"Books",
|
|
27
|
-
]),
|
|
28
|
-
stock: z.number().min(0).int(),
|
|
29
|
-
});
|
|
30
|
-
|
|
31
8
|
export const ZodProductCreationDto = ZodProduct.omit({ id: true });
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* DTO for updating a Product.
|
|
12
|
+
* All fields are optional to support partial updates (PATCH semantics).
|
|
13
|
+
*/
|
|
32
14
|
export const ZodProductUpdateDto = ZodProductCreationDto.partial();
|
|
33
15
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Product categories supported by the system.
|
|
18
|
+
* Centralized to avoid repeating the union type in multiple places.
|
|
19
|
+
*/
|
|
20
|
+
export type ProductCategory =
|
|
21
|
+
| "Electronics"
|
|
22
|
+
| "Appliances"
|
|
23
|
+
| "Sports"
|
|
24
|
+
| "Kitchen"
|
|
25
|
+
| "Mobile Accessories"
|
|
26
|
+
| "Computer Accessories"
|
|
27
|
+
| "Home Appliances"
|
|
28
|
+
| "Books";
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Data required to create a Product.
|
|
32
|
+
*/
|
|
33
|
+
export type ProductCreationDto = {
|
|
34
|
+
/** Product name. */
|
|
35
|
+
name: string;
|
|
36
|
+
|
|
37
|
+
/** Product price. */
|
|
38
|
+
price: number;
|
|
39
|
+
|
|
40
|
+
/** Category from the predefined list. */
|
|
41
|
+
category: ProductCategory;
|
|
42
|
+
|
|
43
|
+
/** Stock count in inventory. Non-negative. */
|
|
44
|
+
stock: number;
|
|
45
|
+
|
|
46
|
+
/** Optional product description. */
|
|
47
|
+
description?: string | undefined;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Data for updating a Product.
|
|
52
|
+
* All fields are optional to support partial updates.
|
|
53
|
+
*/
|
|
54
|
+
export type ProductUpdateDto = {
|
|
55
|
+
/** Optional product name. */
|
|
56
|
+
name?: string | undefined;
|
|
57
|
+
|
|
58
|
+
/** Optional product price. */
|
|
59
|
+
price?: number | undefined;
|
|
60
|
+
|
|
61
|
+
/** Optional product description. */
|
|
62
|
+
description?: string | undefined;
|
|
63
|
+
|
|
64
|
+
/** Optional product category. Must be one of the predefined categories if provided. */
|
|
65
|
+
category?: ProductCategory | undefined;
|
|
66
|
+
|
|
67
|
+
/** Optional stock count in inventory. */
|
|
68
|
+
stock?: number | undefined;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Data Transfer Object representing a full Product (as returned by APIs, etc.).
|
|
73
|
+
*/
|
|
74
|
+
export type ProductDto = {
|
|
75
|
+
/** Unique identifier for the product. */
|
|
76
|
+
id: number;
|
|
77
|
+
|
|
78
|
+
/** Product name. */
|
|
79
|
+
name: string;
|
|
80
|
+
|
|
81
|
+
/** Product price. */
|
|
82
|
+
price: number;
|
|
83
|
+
|
|
84
|
+
/** Category of the product. */
|
|
85
|
+
category: ProductCategory;
|
|
86
|
+
|
|
87
|
+
/** Stock count in inventory. */
|
|
88
|
+
stock: number;
|
|
89
|
+
|
|
90
|
+
/** Optional product description. */
|
|
91
|
+
description?: string | undefined;
|
|
92
|
+
};
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Router, Request, Response } from "express";
|
|
2
2
|
import asyncHandler from "express-async-handler";
|
|
3
3
|
import ProductController from "./product.controller";
|
|
4
|
-
import { sendError } from "@/utilities";
|
|
5
4
|
|
|
6
5
|
const router = Router();
|
|
7
6
|
const productController = new ProductController();
|
|
@@ -64,8 +63,11 @@ const productController = new ProductController();
|
|
|
64
63
|
router.post(
|
|
65
64
|
"/",
|
|
66
65
|
asyncHandler(async (req: Request, res: Response) => {
|
|
67
|
-
const product = await productController.
|
|
68
|
-
|
|
66
|
+
const product = await productController.validateProductCreationDto(
|
|
67
|
+
req.body
|
|
68
|
+
);
|
|
69
|
+
await productController.create(product);
|
|
70
|
+
res.status(201).send();
|
|
69
71
|
})
|
|
70
72
|
);
|
|
71
73
|
|
|
@@ -104,10 +106,9 @@ router.get(
|
|
|
104
106
|
router.get(
|
|
105
107
|
"/:id",
|
|
106
108
|
asyncHandler(async (req: Request, res: Response) => {
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
else res.json(product);
|
|
109
|
+
const id = await productController.validateId(req.params.id);
|
|
110
|
+
const product = await productController.get(id);
|
|
111
|
+
res.json(product);
|
|
111
112
|
})
|
|
112
113
|
);
|
|
113
114
|
|
|
@@ -167,10 +168,9 @@ router.get(
|
|
|
167
168
|
router.put(
|
|
168
169
|
"/:id",
|
|
169
170
|
asyncHandler(async (req: Request, res: Response) => {
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
else res.json(product);
|
|
171
|
+
const id = await productController.validateId(req.params.id);
|
|
172
|
+
const product = await productController.update(id, req.body);
|
|
173
|
+
res.json(product);
|
|
174
174
|
})
|
|
175
175
|
);
|
|
176
176
|
|
|
@@ -197,10 +197,9 @@ router.put(
|
|
|
197
197
|
router.delete(
|
|
198
198
|
"/:id",
|
|
199
199
|
asyncHandler(async (req: Request, res: Response) => {
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
else res.json(product);
|
|
200
|
+
const id = await productController.validateId(req.params.id);
|
|
201
|
+
const product = await productController.delete(id);
|
|
202
|
+
res.json(product);
|
|
204
203
|
})
|
|
205
204
|
);
|
|
206
205
|
|