# 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
85 lines
2.5 KiB
TypeScript
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
|
|
};
|