update apply diff

This commit is contained in:
duanfuxiang
2025-03-23 09:34:44 +08:00
parent 570e8d9564
commit 635db9babd
34 changed files with 3161 additions and 410 deletions

View File

@@ -1,4 +1,5 @@
import { App } from 'obsidian'
import { Transaction } from '@electric-sql/pglite'
import { editorStateToPlainText } from '../../../components/chat-view/chat-input/utils/editor-state-to-plain-text'
import { ChatAssistantMessage, ChatConversationMeta, ChatMessage, ChatUserMessage } from '../../../types/chat'
@@ -22,42 +23,44 @@ export class ConversationManager {
this.repository = new ConversationRepository(app, db)
}
async createConversation(id: string, title = 'New chat'): Promise<void> {
async createConversation(id: string, title = 'New chat', tx?: Transaction): Promise<void> {
const conversation = {
id,
title,
createdAt: new Date(),
updatedAt: new Date(),
}
await this.repository.create(conversation)
await this.repository.create(conversation, tx)
}
async saveConversation(id: string, messages: ChatMessage[]): Promise<void> {
const conversation = await this.repository.findById(id)
if (!conversation) {
let title = 'New chat'
if (messages.length > 0 && messages[0].role === 'user') {
const query = editorStateToPlainText(messages[0].content)
if (query.length > 20) {
title = `${query.slice(0, 20)}...`
} else {
title = query
async txCreateOrUpdateConversation(id: string, messages: ChatMessage[]): Promise<void> {
await this.repository.tx(async (tx) => {
const conversation = await this.repository.findById(id, tx)
if (!conversation) {
let title = 'New chat'
if (messages.length > 0 && messages[0].role === 'user') {
const query = editorStateToPlainText(messages[0].content)
if (query.length > 20) {
title = `${query.slice(0, 20)}...`
} else {
title = query
}
}
await this.createConversation(id, title, tx)
}
await this.createConversation(id, title)
}
// Delete existing messages
await this.repository.deleteAllMessagesFromConversation(id)
// Delete existing messages
await this.repository.deleteAllMessagesFromConversation(id, tx)
// Insert new messages
for (const message of messages) {
const insertMessage = this.serializeMessage(message, id)
await this.repository.createMessage(insertMessage)
}
// Insert new messages
for (const message of messages) {
const insertMessage = this.serializeMessage(message, id)
await this.repository.createMessage(insertMessage, tx)
}
// Update conversation timestamp
await this.repository.update(id, { updatedAt: new Date() })
// Update conversation timestamp
await this.repository.update(id, { updatedAt: new Date() }, tx)
})
}
async findConversation(id: string): Promise<ChatMessage[] | null> {

View File

@@ -1,129 +1,139 @@
import { PGliteInterface } from '@electric-sql/pglite'
import { PGliteInterface, Transaction } from '@electric-sql/pglite'
import { App } from 'obsidian'
import {
InsertConversation,
InsertMessage,
SelectConversation,
SelectMessage,
InsertConversation,
InsertMessage,
SelectConversation,
SelectMessage,
} from '../../schema'
export class ConversationRepository {
private app: App
private db: PGliteInterface
private app: App
private db: PGliteInterface
constructor(app: App, db: PGliteInterface) {
this.app = app
this.db = db
}
constructor(app: App, db: PGliteInterface) {
this.app = app
this.db = db
}
async create(conversation: InsertConversation): Promise<SelectConversation> {
const result = await this.db.query<SelectConversation>(
`INSERT INTO conversations (id, title, created_at, updated_at)
async tx(callback: (tx: Transaction) => Promise<void>) {
await this.db.transaction(async (tx) => {
await callback(tx)
});
}
async create(conversation: InsertConversation, tx?: Transaction): Promise<SelectConversation> {
const result = await (tx ?? this.db).query<SelectConversation>(
`INSERT INTO conversations (id, title, created_at, updated_at)
VALUES ($1, $2, $3, $4)
RETURNING *`,
[
conversation.id,
conversation.title,
conversation.createdAt || new Date(),
conversation.updatedAt || new Date()
]
)
return result.rows[0]
}
[
conversation.id,
conversation.title,
conversation.createdAt || new Date(),
conversation.updatedAt || new Date()
]
)
return result.rows[0]
}
async createMessage(message: InsertMessage): Promise<SelectMessage> {
const result = await this.db.query<SelectMessage>(
`INSERT INTO messages (
async createMessage(message: InsertMessage, tx?: Transaction): Promise<SelectMessage> {
const result = await (tx ?? this.db).query<SelectMessage>(
`INSERT INTO messages (
id, conversation_id, apply_status, role, content, reasoning_content,
prompt_content, metadata, mentionables,
similarity_search_results, created_at
)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
RETURNING *`,
[
message.id,
message.conversationId,
message.apply_status,
message.role,
message.content,
message.reasoningContent,
message.promptContent,
message.metadata,
message.mentionables,
message.similaritySearchResults,
message.createdAt || new Date()
]
[
message.id,
message.conversationId,
message.apply_status,
message.role,
message.content,
message.reasoningContent,
message.promptContent,
message.metadata,
message.mentionables,
message.similaritySearchResults,
message.createdAt || new Date()
]
)
return result.rows[0]
}
console.log('createMessage: ', message.id, result)
return result.rows[0]
}
async findById(id: string): Promise<SelectConversation | undefined> {
const result = await this.db.query<SelectConversation>(
`SELECT * FROM conversations WHERE id = $1 LIMIT 1`,
[id]
)
return result.rows[0]
}
async findById(id: string, tx?: Transaction): Promise<SelectConversation | undefined> {
const result = await (tx ?? this.db).query<SelectConversation>(
`SELECT * FROM conversations WHERE id = $1 LIMIT 1`,
[id]
)
return result.rows[0]
}
async findMessagesByConversationId(conversationId: string): Promise<SelectMessage[]> {
const result = await this.db.query<SelectMessage>(
`SELECT * FROM messages
async findMessagesByConversationId(conversationId: string, tx?: Transaction): Promise<SelectMessage[]> {
const result = await (tx ?? this.db).query<SelectMessage>(
`SELECT * FROM messages
WHERE conversation_id = $1
ORDER BY created_at`,
[conversationId]
[conversationId]
)
return result.rows
}
return result.rows
}
async findAll(): Promise<SelectConversation[]> {
const result = await this.db.query<SelectConversation>(
`SELECT * FROM conversations ORDER BY created_at DESC`
)
return result.rows
}
async findAll(tx?: Transaction): Promise<SelectConversation[]> {
const result = await (tx ?? this.db).query<SelectConversation>(
`SELECT * FROM conversations ORDER BY created_at DESC`
)
return result.rows
}
async update(id: string, data: Partial<InsertConversation>): Promise<SelectConversation> {
const setClauses: string[] = []
const values: (string | Date)[] = []
let paramIndex = 1
async update(id: string, data: Partial<InsertConversation>, tx?: Transaction): Promise<SelectConversation> {
const setClauses: string[] = []
const values: (string | Date)[] = []
let paramIndex = 1
if (data.title !== undefined) {
setClauses.push(`title = $${paramIndex}`)
values.push(data.title)
paramIndex++
}
if (data.title !== undefined) {
setClauses.push(`title = $${paramIndex}`)
values.push(data.title)
paramIndex++
}
// Always update updated_at
setClauses.push(`updated_at = $${paramIndex}`)
values.push(new Date())
paramIndex++
// Always update updated_at
setClauses.push(`updated_at = $${paramIndex}`)
values.push(new Date())
paramIndex++
// Add id as the last parameter
values.push(id)
// Add id as the last parameter
values.push(id)
const result = await this.db.query<SelectConversation>(
`UPDATE conversations
const result = await (tx ?? this.db).query<SelectConversation>(
`UPDATE conversations
SET ${setClauses.join(', ')}
WHERE id = $${paramIndex}
RETURNING *`,
values
)
return result.rows[0]
}
values
)
return result.rows[0]
}
async delete(id: string): Promise<boolean> {
const result = await this.db.query<SelectConversation>(
`DELETE FROM conversations WHERE id = $1 RETURNING *`,
[id]
)
return result.rows.length > 0
}
async delete(id: string, tx?: Transaction): Promise<boolean> {
const result = await (tx ?? this.db).query<SelectConversation>(
`DELETE FROM conversations WHERE id = $1 RETURNING *`,
[id]
)
return result.rows.length > 0
}
async deleteAllMessagesFromConversation(conversationId: string): Promise<void> {
await this.db.query(
`DELETE FROM messages WHERE conversation_id = $1`,
[conversationId]
)
}
async deleteAllMessagesFromConversation(conversationId: string, tx?: Transaction): Promise<void> {
const result = await (tx ?? this.db).query(
`DELETE FROM messages WHERE conversation_id = $1`,
[conversationId]
)
console.log('deleteAllMessagesFromConversation', conversationId, result)
return
}
}