- PostgreSQL 17 + TimescaleDB schema with 12 tables - 48 standards (IEEE, SFF, ITU-T, OIF, MSA) - 33 form factors (SFP through OSFP-XD/CPO) - 85+ vendors (OEM, compatible, manufacturers, marketplaces) - 80+ seed transceivers (1G-1.6T, CWDM, BiDi, DAC, AOC, FC, PON) - 60+ network devices (Cisco, Juniper, Arista, HPE, Dell, etc.) - Crawler framework with fs.com and eBay crawlers - REST API (15 endpoints) on port 3200 - MCP server (12 tools) on port 3201 - PM2 ecosystem for production deployment on Erik (.82)
143 lines
6.0 KiB
TypeScript
143 lines
6.0 KiB
TypeScript
import 'dotenv/config';
|
|
import { query, transaction } from '../src/utils/db.js';
|
|
import { standards } from '../seed/standards.js';
|
|
import { formFactors } from '../seed/form-factors.js';
|
|
import { vendors } from '../seed/vendors.js';
|
|
import { transceivers } from '../seed/transceivers.js';
|
|
import { networkDevices } from '../seed/network-devices.js';
|
|
import { pino } from 'pino';
|
|
|
|
const log = pino({ name: 'seed' });
|
|
|
|
async function seedStandards() {
|
|
log.info(`Seeding ${standards.length} standards...`);
|
|
for (const s of standards) {
|
|
await query(
|
|
`INSERT INTO standards (name, body, version, year, url, description)
|
|
VALUES ($1, $2, $3, $4, $5, $6)
|
|
ON CONFLICT (name) DO UPDATE SET version = $3, year = $4, url = $5, description = $6, updated_at = NOW()`,
|
|
[s.name, s.body, s.version ?? null, s.year ?? null, s.url ?? null, s.description ?? null]
|
|
);
|
|
}
|
|
log.info('Standards seeded');
|
|
}
|
|
|
|
async function seedFormFactors() {
|
|
log.info(`Seeding ${formFactors.length} form factors...`);
|
|
for (const ff of formFactors) {
|
|
await query(
|
|
`INSERT INTO form_factors (name, full_name, lanes, max_data_rate, data_rate_unit, width_mm, height_mm, depth_mm, power_max_w, generation, release_year, eol_year, description, image_url)
|
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)
|
|
ON CONFLICT (name) DO UPDATE SET full_name = $2, lanes = $3, max_data_rate = $4, power_max_w = $9, updated_at = NOW()`,
|
|
[ff.name, ff.full_name ?? null, ff.lanes ?? null, ff.max_data_rate ?? null, ff.data_rate_unit ?? 'Gbps',
|
|
ff.width_mm ?? null, ff.height_mm ?? null, ff.depth_mm ?? null, ff.power_max_w ?? null,
|
|
ff.generation ?? null, ff.release_year ?? null, ff.eol_year ?? null, ff.description ?? null, ff.image_url ?? null]
|
|
);
|
|
}
|
|
log.info('Form factors seeded');
|
|
}
|
|
|
|
async function seedVendors() {
|
|
log.info(`Seeding ${vendors.length} vendors...`);
|
|
for (const v of vendors) {
|
|
await query(
|
|
`INSERT INTO vendors (name, slug, vendor_type, website, logo_url, country, founded_year, description, is_oem, is_factory, aliases, scrape_url, scrape_enabled)
|
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
|
|
ON CONFLICT (slug) DO UPDATE SET name = $1, website = $4, description = $8, scrape_url = $12, scrape_enabled = $13, updated_at = NOW()`,
|
|
[v.name, v.slug, v.vendor_type, v.website ?? null, v.logo_url ?? null,
|
|
v.country ?? null, v.founded_year ?? null, v.description ?? null,
|
|
v.is_oem ?? false, v.is_factory ?? false, v.aliases ?? null,
|
|
v.scrape_url ?? null, v.scrape_enabled ?? false]
|
|
);
|
|
}
|
|
log.info('Vendors seeded');
|
|
}
|
|
|
|
async function seedTransceivers() {
|
|
log.info(`Seeding ${transceivers.length} transceivers...`);
|
|
|
|
// Build lookup maps
|
|
const vendorRows = await query('SELECT id, slug FROM vendors');
|
|
const vendorMap = new Map(vendorRows.rows.map(r => [r.slug, r.id]));
|
|
|
|
const ffRows = await query('SELECT id, name FROM form_factors');
|
|
const ffMap = new Map(ffRows.rows.map(r => [r.name, r.id]));
|
|
|
|
for (const t of transceivers) {
|
|
const vendorId = vendorMap.get(t.vendor_slug);
|
|
if (!vendorId) { log.warn(`Vendor not found: ${t.vendor_slug}`); continue; }
|
|
|
|
const ffId = ffMap.get(t.form_factor) ?? null;
|
|
const oemVendorId = t.oem_vendor_slug ? vendorMap.get(t.oem_vendor_slug) ?? null : null;
|
|
|
|
await query(
|
|
`INSERT INTO transceivers (part_number, vendor_id, form_factor_id, name, category, subcategory,
|
|
data_rate, data_rate_unit, max_reach, reach_unit, wavelength_nm, wavelength_rx,
|
|
connector, fiber_type, duplex, temp_range, dom_support,
|
|
oem_part_number, oem_vendor_id, description, tags, status, source)
|
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, 'seed')
|
|
ON CONFLICT (part_number, vendor_id) DO UPDATE SET
|
|
name = $4, category = $5, subcategory = $6, data_rate = $7, max_reach = $9,
|
|
wavelength_nm = $11, tags = $21, updated_at = NOW()`,
|
|
[
|
|
t.part_number, vendorId, ffId, t.name, t.category, t.subcategory,
|
|
t.data_rate, t.data_rate_unit, t.max_reach, t.reach_unit,
|
|
t.wavelength_nm, t.wavelength_rx ?? null,
|
|
t.connector, t.fiber_type, t.duplex, t.temp_range, t.dom_support,
|
|
t.oem_part_number ?? null, oemVendorId, t.description ?? null,
|
|
t.tags, t.status
|
|
]
|
|
);
|
|
}
|
|
log.info('Transceivers seeded');
|
|
}
|
|
|
|
async function seedNetworkDevices() {
|
|
log.info(`Seeding ${networkDevices.length} network devices...`);
|
|
|
|
const vendorRows = await query('SELECT id, slug FROM vendors');
|
|
const vendorMap = new Map(vendorRows.rows.map(r => [r.slug, r.id]));
|
|
|
|
for (const d of networkDevices) {
|
|
const vendorId = vendorMap.get(d.vendor_slug);
|
|
if (!vendorId) { log.warn(`Vendor not found: ${d.vendor_slug}`); continue; }
|
|
|
|
await query(
|
|
`INSERT INTO network_devices (vendor_id, model, series, device_type,
|
|
ports_sfp, ports_sfp_plus, ports_sfp28, ports_qsfp_plus, ports_qsfp28, ports_qsfp_dd, ports_osfp, ports_rj45,
|
|
max_throughput, release_year, status)
|
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)
|
|
ON CONFLICT (vendor_id, model) DO UPDATE SET
|
|
series = $3, max_throughput = $13, updated_at = NOW()`,
|
|
[
|
|
vendorId, d.model, d.series, d.device_type,
|
|
d.ports_sfp ?? 0, d.ports_sfp_plus ?? 0, d.ports_sfp28 ?? 0,
|
|
d.ports_qsfp_plus ?? 0, d.ports_qsfp28 ?? 0, d.ports_qsfp_dd ?? 0,
|
|
d.ports_osfp ?? 0, d.ports_rj45 ?? 0,
|
|
d.max_throughput ?? null, d.release_year ?? null, d.status
|
|
]
|
|
);
|
|
}
|
|
log.info('Network devices seeded');
|
|
}
|
|
|
|
async function main() {
|
|
log.info('Starting TIP seed...');
|
|
const start = Date.now();
|
|
|
|
await seedStandards();
|
|
await seedFormFactors();
|
|
await seedVendors();
|
|
await seedTransceivers();
|
|
await seedNetworkDevices();
|
|
|
|
const duration = ((Date.now() - start) / 1000).toFixed(1);
|
|
log.info(`Seed complete in ${duration}s`);
|
|
process.exit(0);
|
|
}
|
|
|
|
main().catch(err => {
|
|
log.error({ err }, 'Seed failed');
|
|
process.exit(1);
|
|
});
|