Refactor test database setup and add migrations

- Updated test files to use a separate test database configuration.
- Introduced a new helper module for managing test database operations.
- Added a setup file to configure the environment for tests.
- Created new database migration scripts to optimize message indexing.
- Added a sample environment file for test database configuration.
This commit is contained in:
MythEclipse
2026-05-31 16:32:38 +07:00
parent 8a712cff9b
commit f224be2a66
16 changed files with 1639 additions and 70 deletions
+5 -3
View File
@@ -56,12 +56,14 @@ export async function buildConversationContext(
0,
);
const contextLines = await Promise.all(
contextBefore.map((msg) => formatMessageForPrompt(msg, "context")),
);
const selectedContextLines: string[] = [];
// Go backwards through context, taking most recent first
for (let i = contextBefore.length - 1; i >= 0; i--) {
const msg = contextBefore[i];
const line = await formatMessageForPrompt(msg, "context");
for (let i = contextLines.length - 1; i >= 0; i--) {
const line = contextLines[i];
const lineTokens = estimateTokens(line);
if (usedTokens + lineTokens <= maxTokens) {
+15 -2
View File
@@ -178,14 +178,27 @@ export async function captureMessage(
// Queue analysis after attachment uploads settle so AI uses stable tele URLs.
if (!isBacklog) {
if (attachmentUploadTasks.length > 0) {
setTimeout(() => queueMessageAnalysis(message.id), 30000);
let analysisQueued = false;
let fallbackTimer: NodeJS.Timeout | null = null;
const queueAnalysisOnce = () => {
if (analysisQueued) return;
analysisQueued = true;
if (fallbackTimer) {
clearTimeout(fallbackTimer);
fallbackTimer = null;
}
queueMessageAnalysis(message.id);
};
fallbackTimer = setTimeout(queueAnalysisOnce, 30000);
Promise.allSettled(attachmentUploadTasks)
.then(() => queueMessageAnalysis(message.id))
.then(queueAnalysisOnce)
.catch((err) => {
logger.error(
{ messageId: message.id, error: err },
"Failed to queue message analysis after attachment upload",
);
queueAnalysisOnce();
});
} else {
queueMessageAnalysis(message.id);
+20 -19
View File
@@ -48,6 +48,7 @@ interface MessageDatabase {
selectDistinct<T = unknown[]>(...args: unknown[]): QueryBuilder<T>;
insert<T = unknown>(...args: unknown[]): QueryBuilder<T>;
update(...args: unknown[]): QueryBuilder<unknown>;
transaction<T>(callback: (tx: MessageDatabase) => Promise<T>): Promise<T>;
}
function db(): MessageDatabase {
@@ -457,28 +458,28 @@ export async function updateMessagesAIAnalysisBulk(
): Promise<MessageRecord[]> {
if (updates.length === 0) return [];
try {
// Use raw SQL batch UPDATE instead of Promise.all per-message queries
// (P2: reduce N*2 queries → 2 queries total)
const database = db();
const now = Date.now();
for (const { messageId, result } of updates) {
await database
.update(messagesTable)
.set({
ai_status: result.status,
ai_moderation_flags: result.flags ?? null,
ai_moderation_score: result.score ?? null,
ai_analysis: result.analysis ?? null,
ai_categories: stringifyAIList(result.categories),
ai_severity: result.severity ?? null,
ai_confidence: result.confidence ?? result.score ?? null,
ai_recommended_action: result.recommendedAction ?? null,
ai_analyzed_at: result.analyzedAt ?? now,
ai_error: result.error ?? null,
})
.where(eq(messagesTable.id, messageId));
}
await database.transaction(async (tx) => {
for (const { messageId, result } of updates) {
await tx
.update(messagesTable)
.set({
ai_status: result.status,
ai_moderation_flags: result.flags ?? null,
ai_moderation_score: result.score ?? null,
ai_analysis: result.analysis ?? null,
ai_categories: stringifyAIList(result.categories),
ai_severity: result.severity ?? null,
ai_confidence: result.confidence ?? result.score ?? null,
ai_recommended_action: result.recommendedAction ?? null,
ai_analyzed_at: result.analyzedAt ?? now,
ai_error: result.error ?? null,
})
.where(eq(messagesTable.id, messageId));
}
});
// Fetch all updated messages in a single query
const ids = updates.map(({ messageId }) => messageId);