candle-annotator/src/app/api/export/route.ts
Marko Djordjevic 5f70f13da3 feat: migrate from SQLite to PostgreSQL - complete schema and API updates
- Remove better-sqlite3, add pg driver
- Convert schema to PostgreSQL types (serial, timestamp, boolean, jsonb)
- Generate fresh PostgreSQL migrations
- Update database connection layer with pg.Pool
- Fix all API routes: remove JSON.parse/stringify, use native timestamps and booleans
- Update drizzle.config.ts and .env.example for PostgreSQL
2026-02-17 13:43:06 +01:00

71 lines
2.2 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server';
import { db } from '@/lib/db';
import { annotations, candles, charts } from '@/lib/db/schema';
import { eq, and, desc } from 'drizzle-orm';
export async function GET(request: NextRequest) {
try {
const { searchParams } = request.nextUrl;
let chartId = searchParams.get('chartId');
// Fall back to most recent chart if no chartId provided
if (!chartId) {
const latest = await db.select({ id: charts.id }).from(charts).orderBy(desc(charts.created_at)).limit(1);
if (latest.length === 0) {
return new NextResponse('timestamp,label_type,price\n', {
headers: {
'Content-Type': 'text/csv',
'Content-Disposition': 'attachment; filename="annotations.csv"',
},
});
}
chartId = String(latest[0].id);
}
const chartIdNum = parseInt(chartId, 10);
const allAnnotations = await db
.select()
.from(annotations)
.where(eq(annotations.chart_id, chartIdNum));
// Build CSV content
const csvRows = ['timestamp,label_type,price'];
for (const annotation of allAnnotations) {
let price: number | null = null;
if (annotation.label_type === 'break_up' || annotation.label_type === 'break_down') {
const candleResult = await db
.select()
.from(candles)
.where(and(eq(candles.chart_id, chartIdNum), eq(candles.time, annotation.timestamp)))
.limit(1);
if (candleResult.length > 0) {
price = candleResult[0].close;
}
} else if (annotation.label_type === 'line' && annotation.geometry) {
const geometry = annotation.geometry as any;
price = geometry.startPrice || null;
}
csvRows.push(
`${annotation.timestamp},${annotation.label_type},${price !== null ? price : ''}`
);
}
const csvContent = csvRows.join('\n');
return new NextResponse(csvContent, {
headers: {
'Content-Type': 'text/csv',
'Content-Disposition': 'attachment; filename="annotations.csv"',
},
});
} catch (error: any) {
return NextResponse.json(
{ error: error.message || 'Failed to export annotations' },
{ status: 500 }
);
}
}