// Store Helpers - Database operations for cache initialization // These are used by stores in apps/backend/src/stores/ import { db } from '../db/db_index' import { homeBanners, productInfo, units, productSlots, deliverySlotInfo, specialDeals, storeInfo, productTags, productTagInfo, userIncidents, } from '../db/schema' import { eq, and, gt, sql, isNotNull, asc } from 'drizzle-orm' // ============================================================================ // BANNER STORE HELPERS // ============================================================================ export interface BannerData { id: number name: string imageUrl: string | null serialNum: number | null productIds: number[] | null createdAt: Date } export async function getAllBannersForCache(): Promise { return db.query.homeBanners.findMany({ where: isNotNull(homeBanners.serialNum), orderBy: asc(homeBanners.serialNum), }) } // ============================================================================ // PRODUCT STORE HELPERS // ============================================================================ export interface ProductBasicData { id: number name: string shortDescription: string | null longDescription: string | null price: string marketPrice: string | null images: unknown isOutOfStock: boolean storeId: number | null unitShortNotation: string incrementStep: number productQuantity: number isFlashAvailable: boolean flashPrice: string | null } export interface StoreBasicData { id: number name: string description: string | null } export interface DeliverySlotData { productId: number id: number deliveryTime: Date freezeTime: Date isCapacityFull: boolean } export interface SpecialDealData { productId: number quantity: string price: string validTill: Date } export interface ProductTagData { productId: number tagName: string } export async function getAllProductsForCache(): Promise { const results = await db .select({ id: productInfo.id, name: productInfo.name, shortDescription: productInfo.shortDescription, longDescription: productInfo.longDescription, price: productInfo.price, marketPrice: productInfo.marketPrice, images: productInfo.images, isOutOfStock: productInfo.isOutOfStock, storeId: productInfo.storeId, unitShortNotation: units.shortNotation, incrementStep: productInfo.incrementStep, productQuantity: productInfo.productQuantity, isFlashAvailable: productInfo.isFlashAvailable, flashPrice: productInfo.flashPrice, }) .from(productInfo) .innerJoin(units, eq(productInfo.unitId, units.id)) return results.map((product) => ({ ...product, price: String(product.price ?? '0'), marketPrice: product.marketPrice ? String(product.marketPrice) : null, flashPrice: product.flashPrice ? String(product.flashPrice) : null, })) } export async function getAllStoresForCache(): Promise { return db.query.storeInfo.findMany({ columns: { id: true, name: true, description: true }, }) } export async function getAllDeliverySlotsForCache(): Promise { return db .select({ productId: productSlots.productId, id: deliverySlotInfo.id, deliveryTime: deliverySlotInfo.deliveryTime, freezeTime: deliverySlotInfo.freezeTime, isCapacityFull: deliverySlotInfo.isCapacityFull, }) .from(productSlots) .innerJoin(deliverySlotInfo, eq(productSlots.slotId, deliverySlotInfo.id)) .where( and( eq(deliverySlotInfo.isActive, true), eq(deliverySlotInfo.isCapacityFull, false), gt(deliverySlotInfo.deliveryTime, sql`CURRENT_TIMESTAMP`) ) ) } export async function getAllSpecialDealsForCache(): Promise { const results = await db .select({ productId: specialDeals.productId, quantity: specialDeals.quantity, price: specialDeals.price, validTill: specialDeals.validTill, }) .from(specialDeals) .where(gt(specialDeals.validTill, sql`CURRENT_TIMESTAMP`)) return results.map((deal) => ({ ...deal, quantity: String(deal.quantity ?? '0'), price: String(deal.price ?? '0'), })) } export async function getAllProductTagsForCache(): Promise { return db .select({ productId: productTags.productId, tagName: productTagInfo.tagName, }) .from(productTags) .innerJoin(productTagInfo, eq(productTags.tagId, productTagInfo.id)) } // ============================================================================ // PRODUCT TAG STORE HELPERS // ============================================================================ export interface TagBasicData { id: number tagName: string tagDescription: string | null imageUrl: string | null isDashboardTag: boolean relatedStores: unknown } export interface TagProductMapping { tagId: number productId: number } export async function getAllTagsForCache(): Promise { return db .select({ id: productTagInfo.id, tagName: productTagInfo.tagName, tagDescription: productTagInfo.tagDescription, imageUrl: productTagInfo.imageUrl, isDashboardTag: productTagInfo.isDashboardTag, relatedStores: productTagInfo.relatedStores, }) .from(productTagInfo) } export async function getAllTagProductMappings(): Promise { return db .select({ tagId: productTags.tagId, productId: productTags.productId, }) .from(productTags) } // ============================================================================ // SLOT STORE HELPERS // ============================================================================ export interface SlotWithProductsData { id: number deliveryTime: Date freezeTime: Date isActive: boolean isCapacityFull: boolean productSlots: Array<{ product: { id: number name: string productQuantity: number shortDescription: string | null price: string marketPrice: string | null unit: { shortNotation: string } | null store: { id: number; name: string; description: string | null } | null images: unknown isOutOfStock: boolean storeId: number | null } }> } export async function getAllSlotsWithProductsForCache(): Promise { const now = new Date() return db.query.deliverySlotInfo.findMany({ where: and( eq(deliverySlotInfo.isActive, true), gt(deliverySlotInfo.deliveryTime, now) ), with: { productSlots: { with: { product: { with: { unit: true, store: true, }, }, }, }, }, orderBy: asc(deliverySlotInfo.deliveryTime), }) as Promise } // ============================================================================ // USER NEGATIVITY STORE HELPERS // ============================================================================ export interface UserNegativityData { userId: number totalNegativityScore: number } export async function getAllUserNegativityScores(): Promise { const results = await db .select({ userId: userIncidents.userId, totalNegativityScore: sql`sum(${userIncidents.negativityScore})`, }) .from(userIncidents) .groupBy(userIncidents.userId) return results.map((result) => ({ userId: result.userId, totalNegativityScore: Number(result.totalNegativityScore ?? 0), })) } export async function getUserNegativityScore(userId: number): Promise { const [result] = await db .select({ totalNegativityScore: sql`sum(${userIncidents.negativityScore})`, }) .from(userIncidents) .where(eq(userIncidents.userId, userId)) .limit(1) return Number(result?.totalNegativityScore ?? 0) }