feat(conversations): add search endpoint — M1-006 (#299)
Some checks failed
ci/woodpecker/push/ci Pipeline failed
Some checks failed
ci/woodpecker/push/ci Pipeline failed
Co-authored-by: Jason Woltje <jason@diversecanvas.com> Co-committed-by: Jason Woltje <jason@diversecanvas.com>
This commit was merged in pull request #299.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { eq, and, asc, desc, type Db, conversations, messages } from '@mosaic/db';
|
||||
import { eq, and, asc, desc, ilike, type Db, conversations, messages } from '@mosaic/db';
|
||||
|
||||
/** Maximum number of conversations returned per list query. */
|
||||
const MAX_CONVERSATIONS = 200;
|
||||
@@ -10,6 +10,15 @@ export type NewConversation = typeof conversations.$inferInsert;
|
||||
export type Message = typeof messages.$inferSelect;
|
||||
export type NewMessage = typeof messages.$inferInsert;
|
||||
|
||||
export interface MessageSearchResult {
|
||||
messageId: string;
|
||||
conversationId: string;
|
||||
conversationTitle: string | null;
|
||||
role: 'user' | 'assistant' | 'system';
|
||||
content: string;
|
||||
createdAt: Date;
|
||||
}
|
||||
|
||||
export function createConversationsRepo(db: Db) {
|
||||
return {
|
||||
async findAll(userId: string): Promise<Conversation[]> {
|
||||
@@ -87,6 +96,35 @@ export function createConversationsRepo(db: Db) {
|
||||
.limit(MAX_MESSAGES);
|
||||
},
|
||||
|
||||
/**
|
||||
* Search messages by content across all conversations belonging to the user.
|
||||
* Uses ILIKE for case-insensitive substring matching.
|
||||
*/
|
||||
async searchMessages(
|
||||
userId: string,
|
||||
query: string,
|
||||
limit: number,
|
||||
offset: number,
|
||||
): Promise<MessageSearchResult[]> {
|
||||
const rows = await db
|
||||
.select({
|
||||
messageId: messages.id,
|
||||
conversationId: conversations.id,
|
||||
conversationTitle: conversations.title,
|
||||
role: messages.role,
|
||||
content: messages.content,
|
||||
createdAt: messages.createdAt,
|
||||
})
|
||||
.from(messages)
|
||||
.innerJoin(conversations, eq(messages.conversationId, conversations.id))
|
||||
.where(and(eq(conversations.userId, userId), ilike(messages.content, `%${query}%`)))
|
||||
.orderBy(desc(messages.createdAt))
|
||||
.limit(limit)
|
||||
.offset(offset);
|
||||
|
||||
return rows;
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a message to a conversation, scoped to the given user.
|
||||
* Verifies the parent conversation belongs to the user before inserting.
|
||||
|
||||
@@ -25,6 +25,7 @@ export {
|
||||
type NewConversation,
|
||||
type Message,
|
||||
type NewMessage,
|
||||
type MessageSearchResult,
|
||||
} from './conversations.js';
|
||||
export {
|
||||
createAgentsRepo,
|
||||
|
||||
@@ -15,4 +15,5 @@ export {
|
||||
lt,
|
||||
gte,
|
||||
lte,
|
||||
ilike,
|
||||
} from 'drizzle-orm';
|
||||
|
||||
Reference in New Issue
Block a user