mirror of
https://github.com/EthanMarti/infio-copilot.git
synced 2026-05-08 16:10:09 +00:00
update apply diff
This commit is contained in:
@@ -12,7 +12,7 @@ import { VectorManager } from './modules/vector/vector-manager'
|
||||
// import { migrations } from './sql'
|
||||
|
||||
export class DBManager {
|
||||
// private app: App
|
||||
private app: App
|
||||
// private dbPath: string
|
||||
private db: PGliteWithLive | null = null
|
||||
// private db: PgliteDatabase | null = null
|
||||
@@ -65,34 +65,34 @@ export class DBManager {
|
||||
// })
|
||||
// }
|
||||
|
||||
// private async loadExistingDatabase() {
|
||||
// try {
|
||||
// const databaseFileExists = await this.app.vault.adapter.exists(
|
||||
// this.dbPath,
|
||||
// )
|
||||
// if (!databaseFileExists) {
|
||||
// return null
|
||||
// }
|
||||
// const fileBuffer = await this.app.vault.adapter.readBinary(this.dbPath)
|
||||
// const fileBlob = new Blob([fileBuffer], { type: 'application/x-gzip' })
|
||||
// const { fsBundle, wasmModule, vectorExtensionBundlePath } =
|
||||
// await this.loadPGliteResources()
|
||||
// this.db = await PGlite.create({
|
||||
// loadDataDir: fileBlob,
|
||||
// fsBundle: fsBundle,
|
||||
// wasmModule: wasmModule,
|
||||
// extensions: {
|
||||
// vector: vectorExtensionBundlePath,
|
||||
// live
|
||||
// },
|
||||
// })
|
||||
// // return drizzle(this.pgClient)
|
||||
// } catch (error) {
|
||||
// console.error('Error loading database:', error)
|
||||
// console.log(this.dbPath)
|
||||
// return null
|
||||
// }
|
||||
// }
|
||||
private async loadExistingDatabase() {
|
||||
try {
|
||||
const databaseFileExists = await this.app.vault.adapter.exists(
|
||||
this.dbPath,
|
||||
)
|
||||
if (!databaseFileExists) {
|
||||
return null
|
||||
}
|
||||
const fileBuffer = await this.app.vault.adapter.readBinary(this.dbPath)
|
||||
const fileBlob = new Blob([fileBuffer], { type: 'application/x-gzip' })
|
||||
const { fsBundle, wasmModule, vectorExtensionBundlePath } =
|
||||
await this.loadPGliteResources()
|
||||
this.db = await PGlite.create({
|
||||
loadDataDir: fileBlob,
|
||||
fsBundle: fsBundle,
|
||||
wasmModule: wasmModule,
|
||||
extensions: {
|
||||
vector: vectorExtensionBundlePath,
|
||||
live
|
||||
},
|
||||
})
|
||||
// return drizzle(this.pgClient)
|
||||
} catch (error) {
|
||||
console.error('Error loading database:', error)
|
||||
console.log(this.dbPath)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
// private async migrateDatabase(): Promise<void> {
|
||||
// if (!this.db) {
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user