Files
Neon-Desk/lib/server/repos/research-journal.ts
francy51 7a70545f09 Merge branch 't3code/expand-research-management-plan'
# Conflicts:
#	app/analysis/page.tsx
#	app/watchlist/page.tsx
#	components/shell/app-shell.tsx
#	lib/api.ts
#	lib/query/options.ts
#	lib/server/api/app.ts
#	lib/server/db/index.test.ts
#	lib/server/db/index.ts
#	lib/server/db/schema.ts
#	lib/server/repos/research-journal.ts
#	lib/types.ts
2026-03-07 20:39:49 -05:00

85 lines
2.5 KiB
TypeScript

import { and, desc, eq } from 'drizzle-orm';
import type {
ResearchArtifactKind,
ResearchJournalEntry,
ResearchJournalEntryType
} from '@/lib/types';
import { db } from '@/lib/server/db';
import { researchArtifact } from '@/lib/server/db/schema';
import {
createResearchJournalEntryCompat as createResearchJournalEntryRecord,
deleteResearchJournalEntryCompat as deleteResearchJournalEntryRecord,
listResearchJournalEntriesCompat as listResearchJournalEntries,
updateResearchJournalEntryCompat as updateResearchJournalEntryRecord
} from '@/lib/server/repos/research-library';
type ResearchArtifactRow = typeof researchArtifact.$inferSelect;
function toJournalType(kind: ResearchArtifactKind, accessionNumber: string | null): ResearchJournalEntryType | null {
if (kind === 'status_change') {
return 'status_change';
}
if (kind === 'note') {
return accessionNumber ? 'filing_note' : 'note';
}
if (kind === 'filing' || kind === 'ai_report') {
return 'filing_note';
}
return null;
}
function toResearchJournalEntry(row: ResearchArtifactRow): ResearchJournalEntry | null {
const entryType = toJournalType(row.kind, row.accession_number ?? null);
if (!entryType) {
return null;
}
return {
id: row.id,
user_id: row.user_id,
ticker: row.ticker,
accession_number: row.accession_number ?? null,
entry_type: entryType,
title: row.title ?? null,
body_markdown: row.body_markdown ?? row.summary ?? '',
metadata: row.metadata ?? null,
created_at: row.created_at,
updated_at: row.updated_at
};
}
export async function listResearchJournalEntriesForUser(userId: string, limit = 250) {
const safeLimit = Math.min(Math.max(Math.trunc(limit), 1), 500);
const rows = await db
.select()
.from(researchArtifact)
.where(eq(researchArtifact.user_id, userId))
.orderBy(desc(researchArtifact.updated_at), desc(researchArtifact.id))
.limit(safeLimit * 2);
return rows
.map(toResearchJournalEntry)
.filter((entry): entry is ResearchJournalEntry => Boolean(entry))
.slice(0, safeLimit);
}
export async function getResearchJournalEntryRecord(userId: string, id: number) {
const [row] = await db
.select()
.from(researchArtifact)
.where(and(eq(researchArtifact.user_id, userId), eq(researchArtifact.id, id)))
.limit(1);
return row ? toResearchJournalEntry(row) : null;
}
export {
createResearchJournalEntryRecord,
deleteResearchJournalEntryRecord,
listResearchJournalEntries,
updateResearchJournalEntryRecord
};