Files
domain-wall/packages/logic/domains/product/repository.ts
2025-10-21 13:11:31 +03:00

295 lines
8.2 KiB
TypeScript

import { desc, eq, type Database } from "@pkg/db";
import { product } from "@pkg/db/schema";
import { getError, Logger } from "@pkg/logger";
import { ERROR_CODES, type Result } from "@pkg/result";
import { nanoid } from "nanoid";
import {
productModel,
type CreateProductPayload,
type ProductModel,
type UpdateProductPayload,
} from "./data";
export class ProductRepository {
private db: Database;
constructor(db: Database) {
this.db = db;
}
async listAllProducts(): Promise<Result<ProductModel[]>> {
try {
const results = await this.db.query.product.findMany({
orderBy: [desc(product.createdAt)],
});
const out = [] as ProductModel[];
for (const result of results) {
const parsed = productModel.safeParse(result);
if (!parsed.success) {
Logger.error("Failed to parse product");
Logger.error(parsed.error);
continue;
}
out.push(parsed.data);
}
return { data: out };
} catch (e) {
return {
error: getError(
{
code: ERROR_CODES.DATABASE_ERROR,
message: "Failed to fetch products",
detail:
"An error occurred while retrieving products from the database",
userHint: "Please try refreshing the page",
actionable: false,
},
e,
),
};
}
}
async getProductById(id: number | string): Promise<Result<ProductModel>> {
try {
const result = await this.db.query.product.findFirst({
where:
typeof id === "number" ? eq(product.id, id) : eq(product.linkId, id),
});
if (!result) {
return {
error: getError({
code: ERROR_CODES.NOT_FOUND_ERROR,
message: "Product not found",
detail: "No product exists with the provided ID",
userHint: "Please check the product ID and try again",
actionable: true,
}),
};
}
const parsed = productModel.safeParse(result);
if (!parsed.success) {
Logger.error("Failed to parse product", result);
return {
error: getError({
code: ERROR_CODES.INTERNAL_SERVER_ERROR,
message: "Failed to parse product",
userHint: "Please try again",
detail: "Failed to parse product",
}),
};
}
return { data: parsed.data };
} catch (e) {
return {
error: getError(
{
code: ERROR_CODES.DATABASE_ERROR,
message: "Failed to fetch product",
detail:
"An error occurred while retrieving the product from the database",
userHint: "Please try refreshing the page",
actionable: false,
},
e,
),
};
}
}
async createProduct(payload: CreateProductPayload): Promise<Result<number>> {
try {
// Generate a unique linkId
const linkId = nanoid(16);
const result = await this.db
.insert(product)
.values({
linkId,
title: payload.title,
description: payload.description,
longDescription: payload.longDescription,
price: payload.price.toString(),
discountPrice: payload.discountPrice.toString(),
})
.returning({ id: product.id })
.execute();
if (!result || result.length === 0) {
throw new Error("Failed to create product record");
}
return { data: result[0].id };
} catch (e) {
return {
error: getError(
{
code: ERROR_CODES.DATABASE_ERROR,
message: "Failed to create product",
detail: "An error occurred while creating the product",
userHint: "Please try again",
actionable: false,
},
e,
),
};
}
}
async updateProduct(payload: UpdateProductPayload): Promise<Result<boolean>> {
try {
if (!payload.id) {
return {
error: getError({
code: ERROR_CODES.VALIDATION_ERROR,
message: "Invalid product ID",
detail: "No product ID was provided for the update operation",
userHint: "Please provide a valid product ID",
actionable: true,
}),
};
}
// Check if product exists
const existing = await this.db.query.product.findFirst({
where: eq(product.id, payload.id),
});
if (!existing) {
return {
error: getError({
code: ERROR_CODES.NOT_FOUND_ERROR,
message: "Product not found",
detail: "No product exists with the provided ID",
userHint: "Please check the product ID and try again",
actionable: true,
}),
};
}
// Build the update object with only the fields that are provided
const updateValues: Record<string, any> = {};
if (payload.title !== undefined) updateValues.title = payload.title;
if (payload.description !== undefined)
updateValues.description = payload.description;
if (payload.longDescription !== undefined)
updateValues.longDescription = payload.longDescription;
if (payload.price !== undefined)
updateValues.price = payload.price.toString();
if (payload.discountPrice !== undefined)
updateValues.discountPrice = payload.discountPrice.toString();
updateValues.updatedAt = new Date();
await this.db
.update(product)
.set(updateValues)
.where(eq(product.id, payload.id))
.execute();
return { data: true };
} catch (e) {
return {
error: getError(
{
code: ERROR_CODES.DATABASE_ERROR,
message: "Failed to update product",
detail: "An error occurred while updating the product",
userHint: "Please try again",
actionable: false,
},
e,
),
};
}
}
async deleteProduct(id: number): Promise<Result<boolean>> {
try {
// Check if product exists
const existing = await this.db.query.product.findFirst({
where: eq(product.id, id),
});
if (!existing) {
return {
error: getError({
code: ERROR_CODES.NOT_FOUND_ERROR,
message: "Product not found",
detail: "No product exists with the provided ID",
userHint: "Please check the product ID and try again",
actionable: true,
}),
};
}
await this.db.delete(product).where(eq(product.id, id)).execute();
return { data: true };
} catch (e) {
return {
error: getError(
{
code: ERROR_CODES.DATABASE_ERROR,
message: "Failed to delete product",
detail: "An error occurred while deleting the product",
userHint: "Please try again",
actionable: false,
},
e,
),
};
}
}
async refreshProductLinkId(id: number): Promise<Result<string>> {
try {
// Check if product exists
const existing = await this.db.query.product.findFirst({
where: eq(product.id, id),
});
if (!existing) {
return {
error: getError({
code: ERROR_CODES.NOT_FOUND_ERROR,
message: "Product not found",
detail: "No product exists with the provided ID",
userHint: "Please check the product ID and try again",
actionable: true,
}),
};
}
// Generate a new unique linkId
const newLinkId = nanoid(16);
await this.db
.update(product)
.set({
linkId: newLinkId,
updatedAt: new Date(),
})
.where(eq(product.id, id))
.execute();
return { data: newLinkId };
} catch (e) {
return {
error: getError(
{
code: ERROR_CODES.DATABASE_ERROR,
message: "Failed to refresh product link ID",
detail: "An error occurred while refreshing the product's link ID",
userHint: "Please try again",
actionable: false,
},
e,
),
};
}
}
}