fix: correct timestamp/boolean types for PostgreSQL schema (Date not int, bool not 0/1)

This commit is contained in:
Marko Djordjevic 2026-02-17 22:50:31 +01:00
parent e00bd4d804
commit 69634909d1
9 changed files with 75 additions and 131 deletions

View file

@ -1,7 +1,11 @@
import { NextRequest, NextResponse } from 'next/server';
import { db } from '@/lib/db';
import { spanAnnotations, candles } from '@/lib/db/schema';
import { eq, and } from 'drizzle-orm';
import { eq } from 'drizzle-orm';
function toUnix(d: Date): number {
return Math.floor(d.getTime() / 1000);
}
export async function GET(request: NextRequest) {
try {
@ -38,15 +42,15 @@ export async function GET(request: NextRequest) {
total_spans: spans.length,
spans: spans.map((span) => ({
id: span.id,
start_time: span.start_time,
end_time: span.end_time,
start_time: toUnix(span.start_time),
end_time: toUnix(span.end_time),
label: span.label,
confidence: span.confidence,
outcome: span.outcome,
notes: span.notes,
sub_spans: span.sub_spans,
color: span.color,
created_at: span.created_at,
created_at: toUnix(span.created_at),
})),
summary: {
labels: spans.reduce((acc, span) => {
@ -69,25 +73,23 @@ export async function GET(request: NextRequest) {
];
for (const span of spans) {
// Find candles in the span range
const spanCandles = chartCandles.filter(
(c) => c.time >= span.start_time && c.time <= span.end_time
);
const spanStart = toUnix(span.start_time);
const spanEnd = toUnix(span.end_time);
// Add context padding
const contextStart = span.start_time - contextPadding * 60; // Assuming 1-minute candles
const contextEnd = span.end_time + contextPadding * 60;
// Add context padding (assuming 1-minute candles)
const contextStart = spanStart - contextPadding * 60;
const contextEnd = spanEnd + contextPadding * 60;
const contextCandles = chartCandles.filter(
(c) => c.time >= contextStart && c.time <= contextEnd
);
const contextCandles = chartCandles.filter((c) => {
const t = toUnix(c.time);
return t >= contextStart && t <= contextEnd;
});
// Create one row per candle in the context window
contextCandles.forEach((candle, idx) => {
let position = 'context';
if (candle.time >= span.start_time && candle.time <= span.end_time) {
position = 'span';
}
contextCandles.forEach((candle) => {
const candleTime = toUnix(candle.time);
const position =
candleTime >= spanStart && candleTime <= spanEnd ? 'span' : 'context';
csvRows.push(
[
@ -95,11 +97,11 @@ export async function GET(request: NextRequest) {
span.label,
span.confidence || '',
span.outcome || '',
span.start_time,
span.end_time,
spanStart,
spanEnd,
contextStart,
contextEnd,
candle.time,
candleTime,
candle.open,
candle.high,
candle.low,
@ -119,24 +121,29 @@ export async function GET(request: NextRequest) {
},
});
} else if (format === 'bio') {
// BIO-tagged CSV
// One row per candle, with BIO tags for each label type
// BIO-tagged CSV — one row per candle, with BIO tags for each label type
// Get all unique labels
const labelTypes = Array.from(new Set(spans.map((s) => s.label)));
// Pre-compute unix times for spans
const spansUnix = spans.map((s) => ({
...s,
startUnix: toUnix(s.start_time),
endUnix: toUnix(s.end_time),
}));
// Create header
const header = ['time', 'open', 'high', 'low', 'close'];
labelTypes.forEach((label) => {
header.push(`bio_${label}`);
});
labelTypes.forEach((label) => header.push(`bio_${label}`));
const csvRows: string[] = [header.join(',')];
// Process each candle
chartCandles.forEach((candle) => {
const candleTime = toUnix(candle.time);
const row = [
candle.time.toString(),
candleTime.toString(),
candle.open.toString(),
candle.high.toString(),
candle.low.toString(),
@ -145,16 +152,14 @@ export async function GET(request: NextRequest) {
// For each label type, determine BIO tag
labelTypes.forEach((label) => {
const spansWithLabel = spans.filter((s) => s.label === label);
const spansWithLabel = spansUnix.filter((s) => s.label === label);
let bioTag = 'O'; // Outside by default
for (const span of spansWithLabel) {
if (candle.time >= span.start_time && candle.time <= span.end_time) {
// Check if this is the first candle in the span
const isFirst = candle.time === span.start_time;
bioTag = isFirst ? `B-${label}` : `I-${label}`;
break; // Use first matching span
if (candleTime >= span.startUnix && candleTime <= span.endUnix) {
bioTag = candleTime === span.startUnix ? `B-${label}` : `I-${label}`;
break;
}
}

View file

@ -89,7 +89,7 @@ export async function POST(request: NextRequest): Promise<NextResponse> {
// Parse and prepare candle data
const candleData = rows.map((row) => {
let timestamp: number;
let timestamp: Date;
// Handle both date strings and Unix timestamps
if (typeof row.time === 'string') {
@ -98,7 +98,7 @@ export async function POST(request: NextRequest): Promise<NextResponse> {
if (isNaN(date.getTime())) {
throw new Error(`Invalid date format: ${row.time}`);
}
timestamp = date; // PostgreSQL timestamp type expects Date object or ISO string
timestamp = date;
} else if (typeof row.time === 'number') {
// If Unix timestamp (seconds), convert to Date
timestamp = new Date(row.time * 1000);