// import redisClient from '@/src/lib/redis-client' import { getAllSlotsWithProductsForCache, type SlotWithProductsData, } from '@/src/dbService' import { scaffoldAssetUrl } from '@/src/lib/s3-client' import dayjs from 'dayjs' // Define the structure for slot with products interface SlotWithProducts { id: number deliveryTime: Date freezeTime: Date isActive: boolean isCapacityFull: boolean products: Array<{ id: number name: string shortDescription: string | null productQuantity: number price: string marketPrice: string | null unit: string | null images: string[] isOutOfStock: boolean storeId: number | null nextDeliveryDate: Date }> } interface SlotInfo { id: number deliveryTime: Date freezeTime: Date isCapacityFull: boolean } async function transformSlotToStoreSlot(slot: SlotWithProductsData): Promise { return { id: slot.id, deliveryTime: slot.deliveryTime, freezeTime: slot.freezeTime, isActive: slot.isActive, isCapacityFull: slot.isCapacityFull, products: slot.products.map((product) => ({ id: product.id, name: product.name, productQuantity: product.productQuantity, shortDescription: product.shortDescription, price: product.price.toString(), marketPrice: product.marketPrice?.toString() || null, unit: product.unit?.shortNotation || null, images: scaffoldAssetUrl( (product.images as string[]) || [] ), isOutOfStock: product.isOutOfStock, storeId: product.storeId, nextDeliveryDate: slot.deliveryTime, })), } } function extractSlotInfo(slot: SlotWithProductsData): SlotInfo { return { id: slot.id, deliveryTime: slot.deliveryTime, freezeTime: slot.freezeTime, isCapacityFull: slot.isCapacityFull, } } async function fetchAllTransformedSlots(): Promise { const slots = await getAllSlotsWithProductsForCache() return Promise.all(slots.map(transformSlotToStoreSlot)) } export async function initializeSlotStore(): Promise { try { console.log('Initializing slot store in Redis...') // Fetch active delivery slots with future delivery times const slots = await getAllSlotsWithProductsForCache() /* // Old implementation - direct DB queries: import { db } from '@/src/db/db_index' import { deliverySlotInfo } from '@/src/db/schema' import { eq, gt, and, asc } from 'drizzle-orm' const now = new Date(); const slots = await 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), }); */ // Transform data for storage const slotsWithProducts = await Promise.all( slots.map(async (slot) => ({ id: slot.id, deliveryTime: slot.deliveryTime, freezeTime: slot.freezeTime, isActive: slot.isActive, isCapacityFull: slot.isCapacityFull, products: await Promise.all( slot.products.map(async (product) => ({ id: product.id, name: product.name, productQuantity: product.productQuantity, shortDescription: product.shortDescription, price: product.price.toString(), marketPrice: product.marketPrice?.toString() || null, unit: product.unit?.shortNotation || null, images: scaffoldAssetUrl( (product.images as string[]) || [] ), isOutOfStock: product.isOutOfStock, storeId: product.storeId, nextDeliveryDate: slot.deliveryTime, })) ), })) ) // Store each slot in Redis with key pattern "slot:{id}" // for (const slot of slotsWithProducts) { // await redisClient.set(`slot:${slot.id}`, JSON.stringify(slot)) // } // Build and store product-slots map // Group slots by productId const productSlotsMap: Record = {} for (const slot of slotsWithProducts) { for (const product of slot.products) { if (!productSlotsMap[product.id]) { productSlotsMap[product.id] = [] } productSlotsMap[product.id].push({ id: slot.id, deliveryTime: slot.deliveryTime, freezeTime: slot.freezeTime, isCapacityFull: slot.isCapacityFull, }) } } // Store each product's slots in Redis with key pattern "product:{id}:slots" // for (const [productId, slotInfos] of Object.entries(productSlotsMap)) { // await redisClient.set( // `product:${productId}:slots`, // JSON.stringify(slotInfos) // ) // } console.log('Slot store initialized successfully') } catch (error) { console.error('Error initializing slot store:', error) } } export async function getSlotById(slotId: number): Promise { try { // const key = `slot:${slotId}` // const data = await redisClient.get(key) // if (!data) return null // return JSON.parse(data) as SlotWithProducts const slots = await getAllSlotsWithProductsForCache() const slot = slots.find(s => s.id === slotId) if (!slot) return null return transformSlotToStoreSlot(slot) } catch (error) { console.error(`Error getting slot ${slotId}:`, error) return null } } export async function getAllSlots(): Promise { try { // Get all keys matching the pattern "slot:*" // const keys = await redisClient.KEYS('slot:*') // // if (keys.length === 0) return [] // // // Get all slots using MGET for better performance // const slotsData = await redisClient.MGET(keys) // // const slots: SlotWithProducts[] = [] // for (const slotData of slotsData) { // if (slotData) { // slots.push(JSON.parse(slotData) as SlotWithProducts) // } // } // // return slots return fetchAllTransformedSlots() } catch (error) { console.error('Error getting all slots:', error) return [] } } export async function getProductSlots(productId: number): Promise { try { // const key = `product:${productId}:slots` // const data = await redisClient.get(key) // if (!data) return [] // return JSON.parse(data) as SlotInfo[] const slots = await getAllSlotsWithProductsForCache() const productSlots: SlotInfo[] = [] for (const slot of slots) { const hasProduct = slot.products.some(p => p.id === productId) if (hasProduct) { productSlots.push(extractSlotInfo(slot)) } } return productSlots } catch (error) { console.error(`Error getting slots for product ${productId}:`, error) return [] } } export async function getAllProductsSlots(): Promise> { try { // Get all keys matching the pattern "product:*:slots" // const keys = await redisClient.KEYS('product:*:slots') // // if (keys.length === 0) return {} // // // Get all product slots using MGET for better performance // const productsData = await redisClient.MGET(keys) // // const result: Record = {} // for (const key of keys) { // // Extract productId from key "product:{id}:slots" // const match = key.match(/product:(\d+):slots/) // if (match) { // const productId = parseInt(match[1], 10) // const dataIndex = keys.indexOf(key) // if (productsData[dataIndex]) { // result[productId] = JSON.parse(productsData[dataIndex]) as SlotInfo[] // } // } // } // // return result const slots = await getAllSlotsWithProductsForCache() const result: Record = {} for (const slot of slots) { const slotInfo = extractSlotInfo(slot) for (const product of slot.products) { const productId = product.id if (!result[productId]) { result[productId] = [] } result[productId].push(slotInfo) } } return result } catch (error) { console.error('Error getting all products slots:', error) return {} } } export async function getMultipleProductsSlots( productIds: number[] ): Promise> { try { if (productIds.length === 0) return {} // Build keys for all productIds // const keys = productIds.map((id) => `product:${id}:slots`) // // // Use MGET for batch retrieval // const productsData = await redisClient.MGET(keys) // // const result: Record = {} // for (let i = 0; i < productIds.length; i++) { // const data = productsData[i] // if (data) { // const slots = JSON.parse(data) as SlotInfo[] // // Filter out slots that are at full capacity // result[productIds[i]] = slots.filter((slot) => !slot.isCapacityFull) // } // } // // return result const slots = await getAllSlotsWithProductsForCache() const productIdSet = new Set(productIds) const result: Record = {} for (const productId of productIds) { result[productId] = [] } for (const slot of slots) { const slotInfo = extractSlotInfo(slot) for (const product of slot.products) { const pid = product.id if (productIdSet.has(pid) && !slot.isCapacityFull) { result[pid].push(slotInfo) } } } return result } catch (error) { console.error('Error getting products slots:', error) return {} } }