import { pool } from "./client"; export interface SearchParams { q?: string; form_factor?: string; speed?: string; speed_gbps?: number; category?: string; fiber_type?: string; reach_min?: number; reach_max?: number; wdm_type?: string; coherent?: boolean; market_status?: string; vendor?: string; limit?: number; offset?: number; } export async function searchTransceivers(params: SearchParams) { const conditions: string[] = []; const values: any[] = []; let idx = 1; if (params.q) { conditions.push(`search_vector @@ plainto_tsquery('english', $${idx})`); values.push(params.q); idx++; } if (params.form_factor) { conditions.push(`form_factor = $${idx}`); values.push(params.form_factor); idx++; } if (params.speed) { conditions.push(`speed = $${idx}`); values.push(params.speed); idx++; } if (params.speed_gbps) { conditions.push(`speed_gbps = $${idx}`); values.push(params.speed_gbps); idx++; } if (params.category) { conditions.push(`category = $${idx}`); values.push(params.category); idx++; } if (params.fiber_type) { conditions.push(`fiber_type = $${idx}`); values.push(params.fiber_type); idx++; } if (params.reach_min) { conditions.push(`reach_meters >= $${idx}`); values.push(params.reach_min); idx++; } if (params.reach_max) { conditions.push(`reach_meters <= $${idx}`); values.push(params.reach_max); idx++; } if (params.wdm_type) { conditions.push(`wdm_type = $${idx}`); values.push(params.wdm_type); idx++; } if (params.coherent !== undefined) { conditions.push(`coherent = $${idx}`); values.push(params.coherent); idx++; } if (params.market_status) { conditions.push(`market_status = $${idx}`); values.push(params.market_status); idx++; } if (params.vendor) { conditions.push(`v.name ILIKE $${idx}`); values.push(`%${params.vendor}%`); idx++; } const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : ""; const limit = params.limit || 50; const offset = params.offset || 0; // Add relevance ranking when full-text search is used const orderBy = params.q ? `ORDER BY ts_rank(search_vector, plainto_tsquery('english', $1)) DESC` : `ORDER BY speed_gbps DESC, reach_meters ASC`; const query = ` SELECT t.*, v.name as vendor_name FROM transceivers t LEFT JOIN vendors v ON t.vendor_id = v.id ${where} ${orderBy} LIMIT ${limit} OFFSET ${offset} `; const countQuery = `SELECT COUNT(*) FROM transceivers t LEFT JOIN vendors v ON t.vendor_id = v.id ${where}`; const [dataResult, countResult] = await Promise.all([ pool.query(query, values), pool.query(countQuery, values), ]); return { data: dataResult.rows, total: parseInt(countResult.rows[0].count), limit, offset, }; } export async function getTransceiverById(id: string) { const result = await pool.query( `SELECT t.*, v.name as vendor_name, s.name as standard_full_name FROM transceivers t LEFT JOIN vendors v ON t.vendor_id = v.id LEFT JOIN standards s ON t.standard_id = s.id WHERE t.id::text = $1::text OR t.slug = $1::text`, [id] ); return result.rows[0] || null; } export interface SwitchSearchParams extends SearchParams { whitebox?: boolean; sonic_compatible?: boolean; asic_vendor?: string; nos?: string; ocp?: boolean; max_speed_gbps?: number; } export async function searchSwitches(params: SwitchSearchParams) { const conditions: string[] = []; const values: any[] = []; let idx = 1; if (params.q) { conditions.push(`sw.search_vector @@ plainto_tsquery('english', $${idx})`); values.push(params.q); idx++; } if (params.category) { conditions.push(`sw.category = $${idx}`); values.push(params.category); idx++; } if (params.whitebox !== undefined) { conditions.push(`sw.is_whitebox = $${idx}`); values.push(params.whitebox); idx++; } if (params.sonic_compatible !== undefined) { conditions.push(`sw.sonic_compatible = $${idx}`); values.push(params.sonic_compatible); idx++; } if (params.asic_vendor) { conditions.push(`sw.asic_vendor ILIKE $${idx}`); values.push(`%${params.asic_vendor}%`); idx++; } if (params.nos) { conditions.push(`$${idx} = ANY(sw.supported_nos)`); values.push(params.nos); idx++; } if (params.ocp !== undefined) { conditions.push(`sw.is_ocp_accepted = $${idx}`); values.push(params.ocp); idx++; } if (params.max_speed_gbps) { conditions.push(`sw.max_speed_gbps = $${idx}`); values.push(params.max_speed_gbps); idx++; } const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : ""; const limit = params.limit || 50; const offset = params.offset || 0; const orderBy = params.q ? `ORDER BY ts_rank(sw.search_vector, plainto_tsquery('english', $1)) DESC` : `ORDER BY sw.max_speed_gbps DESC NULLS LAST`; const query = ` SELECT sw.*, v.name as vendor_name FROM switches sw LEFT JOIN vendors v ON sw.vendor_id = v.id ${where} ${orderBy} LIMIT ${limit} OFFSET ${offset} `; const countQuery = `SELECT COUNT(*) FROM switches sw ${where}`; const [dataResult, countResult] = await Promise.all([ pool.query(query, values), pool.query(countQuery, values), ]); return { data: dataResult.rows, total: parseInt(countResult.rows[0].count), limit, offset, }; } export async function getSwitchById(id: string) { const result = await pool.query( `SELECT sw.*, v.name as vendor_name, v.website as vendor_website FROM switches sw LEFT JOIN vendors v ON sw.vendor_id = v.id WHERE sw.id = $1`, [id] ); return result.rows[0] || null; } export async function getSwitchDocuments(switchId: string) { const result = await pool.query( `SELECT pd.*, v.name as vendor_name FROM product_documents pd LEFT JOIN vendors v ON pd.vendor_id = v.id WHERE pd.switch_id = $1 ORDER BY pd.doc_type, pd.title`, [switchId] ); return result.rows; } export async function getCompatibleTransceivers(switchId: string) { const result = await pool.query( `SELECT t.*, c.status, c.verified_by, c.notes as compat_notes FROM compatibility c JOIN transceivers t ON c.transceiver_id = t.id WHERE c.switch_id = $1 AND c.status = 'compatible' ORDER BY t.speed_gbps DESC`, [switchId] ); return result.rows; } export async function listVendors(type?: string) { const query = type ? `SELECT v.*, (SELECT COUNT(*) FROM transceivers t WHERE t.vendor_id = v.id) as transceiver_count, (SELECT COUNT(*) FROM switches s WHERE s.vendor_id = v.id) as switch_count FROM vendors v WHERE v.type = $1 ORDER BY v.name` : `SELECT v.*, (SELECT COUNT(*) FROM transceivers t WHERE t.vendor_id = v.id) as transceiver_count, (SELECT COUNT(*) FROM switches s WHERE s.vendor_id = v.id) as switch_count FROM vendors v ORDER BY v.name`; const result = await pool.query(query, type ? [type] : []); return result.rows; } export async function listStandards(speed?: string) { const query = speed ? `SELECT * FROM standards WHERE speed = $1 ORDER BY year_ratified DESC` : `SELECT * FROM standards ORDER BY year_ratified DESC`; const result = await pool.query(query, speed ? [speed] : []); return result.rows; } export async function getDbStats() { const result = await pool.query(` SELECT (SELECT COUNT(*) FROM vendors) as vendor_count, (SELECT COUNT(*) FROM standards) as standard_count, (SELECT COUNT(*) FROM transceivers) as transceiver_count, (SELECT COUNT(*) FROM switches) as switch_count, (SELECT COUNT(*) FROM compatibility) as compatibility_count, (SELECT COUNT(*) FROM breakouts) as breakout_count, (SELECT COUNT(*) FROM knowledge_base) as kb_count, (SELECT COUNT(*) FROM documents) as document_count, (SELECT COUNT(*) FROM news_articles) as news_count, (SELECT COUNT(*) FROM product_documents) as product_document_count, (SELECT COUNT(*) FROM switches WHERE image_url IS NOT NULL) as switches_with_images, (SELECT COUNT(*) FROM switches WHERE datasheet_r2_key IS NOT NULL) as switches_with_datasheets `); return result.rows[0]; }