293 lines
8.2 KiB
TypeScript

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];
}