(
chatId: string,
messages: PersistedMessage[],
options?: { chatModel?: string | null },
executor?: DbOrTx
)
| 84 | * transaction; otherwise it runs in its own. |
| 85 | */ |
| 86 | export async function replaceCopilotChatMessages( |
| 87 | chatId: string, |
| 88 | messages: PersistedMessage[], |
| 89 | options?: { chatModel?: string | null }, |
| 90 | executor?: DbOrTx |
| 91 | ): Promise<void> { |
| 92 | const deduped = dedupeById(messages) |
| 93 | const newMessageIds = deduped.map((m) => m.id) |
| 94 | const run = async (tx: DbOrTx) => { |
| 95 | await tx |
| 96 | .delete(copilotMessages) |
| 97 | .where( |
| 98 | newMessageIds.length > 0 |
| 99 | ? and( |
| 100 | eq(copilotMessages.chatId, chatId), |
| 101 | notInArray(copilotMessages.messageId, newMessageIds) |
| 102 | ) |
| 103 | : eq(copilotMessages.chatId, chatId) |
| 104 | ) |
| 105 | if (deduped.length === 0) return |
| 106 | await tx |
| 107 | .insert(copilotMessages) |
| 108 | .values(deduped.map((m, i) => toRow(chatId, m, i, options))) |
| 109 | .onConflictDoUpdate({ |
| 110 | target: [copilotMessages.chatId, copilotMessages.messageId], |
| 111 | set: { |
| 112 | content: sql`excluded.content`, |
| 113 | role: sql`excluded.role`, |
| 114 | model: sql`COALESCE(excluded.model, ${copilotMessages.model})`, |
| 115 | streamId: sql`COALESCE(excluded.stream_id, ${copilotMessages.streamId})`, |
| 116 | seq: sql`excluded.seq`, |
| 117 | updatedAt: sql`now()`, |
| 118 | }, |
| 119 | }) |
| 120 | } |
| 121 | await (executor ? run(executor) : db.transaction(run)) |
| 122 | } |
no test coverage detected