// ===================================================================== // Database Seed Script // Reads mock data from the existing frontend JS files and inserts // into PostgreSQL via Prisma. // Run with: npm run db:seed // ===================================================================== const fs = require('fs'); const path = require('path'); const prisma = require('../config/db'); // Load the mock data files by evaluating them in a controlled context function loadMockData(filename) { const filepath = path.join(__dirname, '..', '..', '..', 'public', 'js', filename); const code = fs.readFileSync(filepath, 'utf-8'); const context = {}; // Execute the JS to populate the const variables const fn = new Function(code + '\nreturn { ' + 'MOCK_STATE_REGULATIONS: typeof MOCK_STATE_REGULATIONS !== "undefined" ? MOCK_STATE_REGULATIONS : undefined,' + 'MOCK_LOAD_BOARD: typeof MOCK_LOAD_BOARD !== "undefined" ? MOCK_LOAD_BOARD : undefined,' + 'MOCK_ESCORT_OPERATORS: typeof MOCK_ESCORT_OPERATORS !== "undefined" ? MOCK_ESCORT_OPERATORS : undefined,' + 'MOCK_STATE_CONTACTS: typeof MOCK_STATE_CONTACTS !== "undefined" ? MOCK_STATE_CONTACTS : undefined,' + 'MOCK_STATE_EQUIPMENT: typeof MOCK_STATE_EQUIPMENT !== "undefined" ? MOCK_STATE_EQUIPMENT : undefined,' + 'MOCK_TRUCK_STOPS: typeof MOCK_TRUCK_STOPS !== "undefined" ? MOCK_TRUCK_STOPS : undefined,' + 'MOCK_BRIDGE_CLEARANCES: typeof MOCK_BRIDGE_CLEARANCES !== "undefined" ? MOCK_BRIDGE_CLEARANCES : undefined,' + 'MOCK_WEIGH_STATIONS: typeof MOCK_WEIGH_STATIONS !== "undefined" ? MOCK_WEIGH_STATIONS : undefined,' + 'MOCK_ROUTE_CONDITIONS: typeof MOCK_ROUTE_CONDITIONS !== "undefined" ? MOCK_ROUTE_CONDITIONS : undefined,' + 'MOCK_WEATHER_ALERTS: typeof MOCK_WEATHER_ALERTS !== "undefined" ? MOCK_WEATHER_ALERTS : undefined,' + 'MOCK_SEASONAL_RESTRICTIONS: typeof MOCK_SEASONAL_RESTRICTIONS !== "undefined" ? MOCK_SEASONAL_RESTRICTIONS : undefined,' + 'MOCK_DOCUMENTS: typeof MOCK_DOCUMENTS !== "undefined" ? MOCK_DOCUMENTS : undefined' + ' };'); return fn(); } async function seed() { console.log('🌱 Seeding database...\n'); // Load mock data from both files const data1 = loadMockData('mock-data.js'); const data2 = loadMockData('mock-data-extended.js'); // Clear existing data in reverse dependency order console.log(' šŸ—‘ļø Clearing existing data...'); await prisma.contribution.deleteMany(); await prisma.document.deleteMany(); await prisma.order.deleteMany(); await prisma.load.deleteMany(); await prisma.escortProfile.deleteMany(); await prisma.user.deleteMany(); await prisma.alert.deleteMany(); await prisma.weighStation.deleteMany(); await prisma.bridge.deleteMany(); await prisma.truckStop.deleteMany(); await prisma.seasonalRestriction.deleteMany(); await prisma.contact.deleteMany(); await prisma.equipmentRequirement.deleteMany(); await prisma.regulation.deleteMany(); await prisma.state.deleteMany(); // --------------------------------------------------------------- // 1. States + Regulations (from MOCK_STATE_REGULATIONS) // --------------------------------------------------------------- console.log(' šŸ“ Seeding states and regulations...'); const stateMap = {}; // abbr -> state.id for (const reg of data1.MOCK_STATE_REGULATIONS) { const state = await prisma.state.create({ data: { name: reg.name, abbr: reg.abbr, lat: reg.lat, lng: reg.lng, regulation: { create: { permitWidth: reg.permitWidth, permitHeight: reg.permitHeight, permitLength: reg.permitLength, permitWeight: reg.permitWeight, escortWidth: reg.escortWidth, escortHeight: reg.escortHeight, escortLength: reg.escortLength, escortWeight: reg.escortWeight, travelRestrictions: reg.travel, holidays: reg.holidays, agency: reg.agency, url: reg.url, notes: reg.notes, }, }, }, }); stateMap[reg.abbr] = state.id; } console.log(` āœ… ${Object.keys(stateMap).length} states with regulations`); // --------------------------------------------------------------- // 2. Contacts (from MOCK_STATE_CONTACTS) // --------------------------------------------------------------- console.log(' šŸ“ž Seeding contacts...'); let contactCount = 0; if (data2.MOCK_STATE_CONTACTS) { for (const [abbr, contact] of Object.entries(data2.MOCK_STATE_CONTACTS)) { if (!stateMap[abbr]) continue; await prisma.contact.create({ data: { stateId: stateMap[abbr], permitPhone: contact.permit, policePhone: contact.police, email: contact.email, hours: contact.hours, portalUrl: contact.portal, }, }); contactCount++; } } console.log(` āœ… ${contactCount} state contacts`); // --------------------------------------------------------------- // 3. Equipment Requirements (from MOCK_STATE_EQUIPMENT) // --------------------------------------------------------------- console.log(' šŸ”§ Seeding equipment requirements...'); let equipCount = 0; if (data2.MOCK_STATE_EQUIPMENT) { for (const [abbr, equip] of Object.entries(data2.MOCK_STATE_EQUIPMENT)) { if (!stateMap[abbr]) continue; if (equip.escort) { await prisma.equipmentRequirement.create({ data: { stateId: stateMap[abbr], type: 'escort', certification: equip.escort.certification || '', vehicle: equip.escort.vehicle || '', signs: equip.escort.signs || '', lights: equip.escort.lights || '', heightPole: equip.escort.heightPole || '', flags: equip.escort.flags || '', safetyGear: equip.escort.safety || '', communication: equip.escort.communication || '', }, }); equipCount++; } if (equip.carrier) { await prisma.equipmentRequirement.create({ data: { stateId: stateMap[abbr], type: 'carrier', signs: equip.carrier.signs || '', flags: equip.carrier.flags || '', lights: equip.carrier.lights || '', safetyGear: [ equip.carrier.cones ? `Cones: ${equip.carrier.cones}` : '', equip.carrier.fireExtinguisher ? `Fire ext: ${equip.carrier.fireExtinguisher}` : '', equip.carrier.triangles ? `Triangles: ${equip.carrier.triangles}` : '', equip.carrier.flares ? `Flares: ${equip.carrier.flares}` : '', equip.carrier.firstAid ? `First aid: ${equip.carrier.firstAid}` : '', ].filter(Boolean).join('; '), }, }); equipCount++; } } } console.log(` āœ… ${equipCount} equipment requirements`); // --------------------------------------------------------------- // 4. Truck Stops (from MOCK_TRUCK_STOPS) // --------------------------------------------------------------- console.log(' ⛽ Seeding truck stops...'); let tsCount = 0; if (data2.MOCK_TRUCK_STOPS) { for (const ts of data2.MOCK_TRUCK_STOPS) { const stateAbbr = ts.location?.state; const stateId = stateMap[stateAbbr]; if (!stateId) continue; await prisma.truckStop.create({ data: { stateId, name: ts.name, lat: ts.location.lat, lng: ts.location.lng, address: `${ts.location.city}, ${ts.location.state}`, hasOversizeParking: ts.oversizeFriendly || false, entranceHeight: ts.entranceHeight || '', entranceWidth: ts.entranceWidth || '', lotSqFt: ts.lotSize ? parseInt(String(ts.lotSize).replace(/[^0-9]/g, '')) || null : null, facilities: ts.facilities || [], phone: '', }, }); tsCount++; } } console.log(` āœ… ${tsCount} truck stops`); // --------------------------------------------------------------- // 5. Bridge Clearances (from MOCK_BRIDGE_CLEARANCES) // --------------------------------------------------------------- console.log(' šŸŒ‰ Seeding bridges...'); let bridgeCount = 0; if (data2.MOCK_BRIDGE_CLEARANCES) { for (const b of data2.MOCK_BRIDGE_CLEARANCES) { const stateAbbr = b.location?.state; const stateId = stateMap[stateAbbr]; if (!stateId) continue; await prisma.bridge.create({ data: { stateId, name: `${b.type || 'Bridge'} at ${b.location.desc || b.route}`, lat: b.location.lat, lng: b.location.lng, route: b.route, heightClearance: parseFloat(String(b.clearanceHeight).replace(/[^0-9.]/g, '')) || 0, widthClearance: b.clearanceWidth ? parseFloat(String(b.clearanceWidth).replace(/[^0-9.]/g, '')) : null, weightLimit: b.weightLimit ? parseFloat(String(b.weightLimit).replace(/[^0-9.]/g, '')) : null, }, }); bridgeCount++; } } console.log(` āœ… ${bridgeCount} bridges`); // --------------------------------------------------------------- // 6. Weigh Stations (from MOCK_WEIGH_STATIONS) // --------------------------------------------------------------- console.log(' āš–ļø Seeding weigh stations...'); let wsCount = 0; if (data2.MOCK_WEIGH_STATIONS) { for (const ws of data2.MOCK_WEIGH_STATIONS) { const stateAbbr = ws.location?.state; const stateId = stateMap[stateAbbr]; if (!stateId) continue; await prisma.weighStation.create({ data: { stateId, name: ws.name, lat: ws.location.lat, lng: ws.location.lng, direction: ws.direction || '', route: ws.route || '', prePass: ws.prePass || false, hours: ws.hours || '', currentStatus: ws.currentStatus || 'unknown', }, }); wsCount++; } } console.log(` āœ… ${wsCount} weigh stations`); // --------------------------------------------------------------- // 7. Alerts — Route Conditions + Weather (from MOCK_ROUTE_CONDITIONS + MOCK_WEATHER_ALERTS) // --------------------------------------------------------------- console.log(' 🚨 Seeding alerts...'); let alertCount = 0; if (data2.MOCK_ROUTE_CONDITIONS) { for (const rc of data2.MOCK_ROUTE_CONDITIONS) { const stateAbbr = rc.location?.state; const stateId = stateMap[stateAbbr]; if (!stateId) continue; await prisma.alert.create({ data: { stateId, type: rc.type || 'construction', route: rc.route || '', description: rc.description || '', severity: rc.severity || 'info', startsAt: rc.startDate ? new Date(rc.startDate) : new Date(), endsAt: rc.endDate ? new Date(rc.endDate) : null, }, }); alertCount++; } } if (data2.MOCK_WEATHER_ALERTS) { for (const wa of data2.MOCK_WEATHER_ALERTS) { // Weather alerts may not have a state directly, try to match from region const stateAbbr = wa.state || (wa.routes?.[0] ? 'TX' : null); // fallback const stateId = stateAbbr ? stateMap[stateAbbr] : Object.values(stateMap)[0]; if (!stateId) continue; await prisma.alert.create({ data: { stateId, type: wa.type || 'weather', route: (wa.routes || []).join(', '), description: wa.description || '', severity: wa.severity || 'info', startsAt: wa.validFrom ? new Date(wa.validFrom) : new Date(), endsAt: wa.validTo ? new Date(wa.validTo) : null, }, }); alertCount++; } } console.log(` āœ… ${alertCount} alerts`); // --------------------------------------------------------------- // 8. Seasonal Restrictions (from MOCK_SEASONAL_RESTRICTIONS) // --------------------------------------------------------------- console.log(' šŸ“… Seeding seasonal restrictions...'); let seasonCount = 0; if (data2.MOCK_SEASONAL_RESTRICTIONS) { for (const sr of data2.MOCK_SEASONAL_RESTRICTIONS) { const stateAbbr = sr.state; const stateId = stateMap[stateAbbr]; if (!stateId) continue; await prisma.seasonalRestriction.create({ data: { stateId, name: sr.title || sr.type, type: sr.type || 'other', startMonth: sr.startMonth || 1, endMonth: sr.endMonth || 12, description: sr.description || '', }, }); seasonCount++; } } console.log(` āœ… ${seasonCount} seasonal restrictions`); // --------------------------------------------------------------- // Summary // --------------------------------------------------------------- console.log('\nšŸŽ‰ Seed complete!\n'); } seed() .catch((err) => { console.error('āŒ Seed failed:', err); process.exit(1); }) .finally(async () => { await prisma.$disconnect(); });