Files
dkala-api/src/modules/cart/repositories/cart.repository.ts
T
2026-06-28 16:18:45 +03:30

94 lines
2.7 KiB
TypeScript

import { Injectable } from '@nestjs/common';
import { CacheService } from 'src/modules/utils/cache.service';
import { roundQuantity } from 'src/modules/products/utils/quantity.utils';
import { Cart } from '../interfaces/cart.interface';
@Injectable()
export class CartRepository {
private readonly CART_TTL = 3600; // 1 hour in seconds
private readonly CART_KEY_PREFIX = 'cart';
constructor(private readonly cacheService: CacheService) { }
/**
* Get cart by user and shop
*/
async findByUserAndShop(userId: string, shopId: string): Promise<Cart | null> {
const cacheKey = this.getCacheKey(userId, shopId);
const cachedCart = await this.cacheService.get<string>(cacheKey);
if (cachedCart) {
try {
const parsed: unknown = JSON.parse(cachedCart);
if (this.isCart(parsed) && parsed.userId === userId && parsed.shopId === shopId) {
return this.normalizeCartQuantities(parsed);
}
} catch {
// If parsing fails, return null
}
}
return null;
}
/**
* Save cart to cache
*/
async save(cart: Cart): Promise<void> {
const cacheKey = this.getCacheKey(cart.userId, cart.shopId);
await this.cacheService.set(cacheKey, JSON.stringify(cart), this.CART_TTL);
}
/**
* Delete cart from cache
*/
async delete(userId: string, shopId: string): Promise<void> {
const cacheKey = this.getCacheKey(userId, shopId);
await this.cacheService.del(cacheKey);
}
/**
* Generate cache key for cart
*/
private getCacheKey(userId: string, shopId: string): string {
return `${this.CART_KEY_PREFIX}:${userId}:${shopId}`;
}
/**
* Coerce cached item quantities to numbers (guards against string concat bugs).
*/
private normalizeCartQuantities(cart: Cart): Cart {
for (const item of cart.items) {
item.quantity = roundQuantity(item.quantity);
}
cart.totalItems = roundQuantity(cart.totalItems);
return cart;
}
/**
* Type guard to check if an object is a Cart
*/
private isCart(obj: unknown): obj is Cart {
if (typeof obj !== 'object' || obj === null) {
return false;
}
const cart = obj as Record<string, unknown>;
return (
typeof cart.userId === 'string' &&
typeof cart.shopId === 'string' &&
Array.isArray(cart.items) &&
typeof cart.subTotal === 'number' &&
typeof cart.itemsDiscount === 'number' &&
typeof cart.couponDiscount === 'number' &&
typeof cart.totalDiscount === 'number' &&
typeof cart.tax === 'number' &&
typeof cart.deliveryFee === 'number' &&
typeof cart.total === 'number' &&
typeof cart.totalItems === 'number' &&
typeof cart.createdAt === 'string' &&
typeof cart.updatedAt === 'string'
);
}
}