Files
runners-calendar/backend/src/seed.ts
Anton 698ae37553 feat(backend): implement REST API for races calendar
Express + TypeScript backend with PostgreSQL: CRUD endpoints for /races (GET list with year/month filters, GET by id, POST, PATCH, DELETE), health/readiness probes, SQL migration runner, seed script with upsert from CSV, camelCase/snake_case mapper, CORS, env validation, docker-compose, and API docs for frontend.

Made-with: Cursor
2026-04-01 14:47:53 +03:00

75 lines
1.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import fs from "fs";
import path from "path";
import { parse } from "csv-parse/sync";
import { pool } from "./db";
interface CsvRow {
date: string;
month: string;
day: string;
event: string;
distance_km: string;
}
function slugify(text: string): string {
return text
.toLowerCase()
.replace(/[«»"]/g, "")
.replace(/[^a-zа-яё0-9]+/gi, "-")
.replace(/(^-|-$)/g, "")
.substring(0, 60);
}
function makeId(date: string, title: string): string {
return `${date}-${slugify(title)}`;
}
async function seed() {
const csvPath = path.resolve(__dirname, "../../import/races_2026_calendar.csv");
if (!fs.existsSync(csvPath)) {
console.error(`[seed] CSV not found: ${csvPath}`);
process.exit(1);
}
const raw = fs.readFileSync(csvPath, "utf-8");
const records: CsvRow[] = parse(raw, {
columns: true,
skip_empty_lines: true,
trim: true,
});
console.log(`[seed] Parsed ${records.length} rows from CSV`);
const client = await pool.connect();
try {
for (const row of records) {
const id = makeId(row.date, row.event);
const distanceKm = parseFloat(row.distance_km);
await client.query(
`INSERT INTO races (id, race_date, title, distance_km, status)
VALUES ($1, $2, $3, $4, $5)
ON CONFLICT (id) DO UPDATE SET
race_date = EXCLUDED.race_date,
title = EXCLUDED.title,
distance_km = EXCLUDED.distance_km,
status = EXCLUDED.status,
updated_at = NOW()`,
[id, row.date, row.event, distanceKm, "planned"],
);
console.log(`[seed] Upserted: ${id}`);
}
console.log("[seed] Done.");
} finally {
client.release();
await pool.end();
}
}
seed().catch((err) => {
console.error("[seed] FAILED:", err.message);
process.exit(1);
});