update commnad name
This commit is contained in:
parent
96b9fcef3b
commit
ecbe1725aa
@ -12,9 +12,9 @@ export class DatabaseNotInitializedException extends DatabaseException {
|
||||
}
|
||||
}
|
||||
|
||||
export class DuplicateTemplateException extends DatabaseException {
|
||||
constructor(templateName: string) {
|
||||
super(`Template with name "${templateName}" already exists`)
|
||||
this.name = 'DuplicateTemplateException'
|
||||
export class DuplicateCommandException extends DatabaseException {
|
||||
constructor(commandName: string) {
|
||||
super(`Command with name "${commandName}" already exists`)
|
||||
this.name = 'DuplicateCommandException'
|
||||
}
|
||||
}
|
||||
|
||||
148
src/database/json/command/CommandManager.ts
Executable file
148
src/database/json/command/CommandManager.ts
Executable file
@ -0,0 +1,148 @@
|
||||
import fuzzysort from 'fuzzysort'
|
||||
import { App } from 'obsidian'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
|
||||
import { AbstractJsonRepository } from '../base'
|
||||
import { COMMAND_DIR, ROOT_DIR } from '../constants'
|
||||
import {
|
||||
DuplicateCommandException,
|
||||
EmptyCommandNameException,
|
||||
} from '../exception'
|
||||
|
||||
import { COMMAND_SCHEMA_VERSION, Command, CommandMetadata } from './types'
|
||||
|
||||
export class CommandManager extends AbstractJsonRepository<
|
||||
Command,
|
||||
CommandMetadata
|
||||
> {
|
||||
constructor(app: App) {
|
||||
super(app, `${ROOT_DIR}/${COMMAND_DIR}`)
|
||||
}
|
||||
|
||||
protected generateFileName(template: Command): string {
|
||||
// Format: v{schemaVersion}_name_id.json (with name encoded)
|
||||
const encodedName = encodeURIComponent(template.name)
|
||||
return `v${COMMAND_SCHEMA_VERSION}_${encodedName}_${template.id}.json`
|
||||
}
|
||||
|
||||
protected parseFileName(fileName: string): CommandMetadata | null {
|
||||
const match = fileName.match(
|
||||
new RegExp(`^v${COMMAND_SCHEMA_VERSION}_(.+)_([0-9a-f-]+)\\.json$`),
|
||||
)
|
||||
if (!match) return null
|
||||
|
||||
const encodedName = match[1]
|
||||
const id = match[2]
|
||||
const name = decodeURIComponent(encodedName)
|
||||
|
||||
return { id, name, schemaVersion: COMMAND_SCHEMA_VERSION }
|
||||
}
|
||||
|
||||
public async createCommand(
|
||||
command: Omit<
|
||||
Command,
|
||||
'id' | 'createdAt' | 'updatedAt' | 'schemaVersion'
|
||||
>,
|
||||
): Promise<Command> {
|
||||
if (command.name !== undefined && command.name.length === 0) {
|
||||
throw new EmptyCommandNameException()
|
||||
}
|
||||
|
||||
const existingCommand = await this.findByName(command.name)
|
||||
if (existingCommand) {
|
||||
throw new DuplicateCommandException(command.name)
|
||||
}
|
||||
|
||||
const newCommand: Command = {
|
||||
id: uuidv4(),
|
||||
...command,
|
||||
createdAt: Date.now(),
|
||||
updatedAt: Date.now(),
|
||||
schemaVersion: COMMAND_SCHEMA_VERSION,
|
||||
}
|
||||
|
||||
await this.create(newCommand)
|
||||
return newCommand
|
||||
}
|
||||
|
||||
public async ListCommands(): Promise<Command[]> {
|
||||
const allMetadata = await this.listMetadata()
|
||||
const allCommands = await Promise.all(allMetadata.map(async (meta) => this.read(meta.fileName)))
|
||||
return allCommands.sort((a, b) => b.updatedAt - a.updatedAt)
|
||||
}
|
||||
|
||||
public async findById(id: string): Promise<Command | null> {
|
||||
const allMetadata = await this.listMetadata()
|
||||
const targetMetadata = allMetadata.find((meta) => meta.id === id)
|
||||
|
||||
if (!targetMetadata) return null
|
||||
|
||||
return this.read(targetMetadata.fileName)
|
||||
}
|
||||
|
||||
public async findByName(name: string): Promise<Command | null> {
|
||||
const allMetadata = await this.listMetadata()
|
||||
const targetMetadata = allMetadata.find((meta) => meta.name === name)
|
||||
|
||||
if (!targetMetadata) return null
|
||||
|
||||
return this.read(targetMetadata.fileName)
|
||||
}
|
||||
|
||||
public async updateCommand(
|
||||
id: string,
|
||||
updates: Partial<
|
||||
Omit<Command, 'id' | 'createdAt' | 'updatedAt' | 'schemaVersion'>
|
||||
>,
|
||||
): Promise<Command | null> {
|
||||
if (updates.name !== undefined && updates.name.length === 0) {
|
||||
throw new EmptyCommandNameException()
|
||||
}
|
||||
|
||||
const command = await this.findById(id)
|
||||
if (!command) return null
|
||||
|
||||
if (updates.name && updates.name !== command.name) {
|
||||
const existingCommand = await this.findByName(updates.name)
|
||||
if (existingCommand) {
|
||||
throw new DuplicateCommandException(updates.name)
|
||||
}
|
||||
}
|
||||
|
||||
const updatedCommand: Command = {
|
||||
...command,
|
||||
...updates,
|
||||
updatedAt: Date.now(),
|
||||
}
|
||||
|
||||
await this.update(command, updatedCommand)
|
||||
return updatedCommand
|
||||
}
|
||||
|
||||
public async deleteCommand(id: string): Promise<boolean> {
|
||||
const command = await this.findById(id)
|
||||
if (!command) return false
|
||||
|
||||
const fileName = this.generateFileName(command)
|
||||
await this.delete(fileName)
|
||||
return true
|
||||
}
|
||||
|
||||
public async searchCommands(query: string): Promise<Command[]> {
|
||||
const allMetadata = await this.listMetadata()
|
||||
const results = fuzzysort.go(query, allMetadata, {
|
||||
keys: ['name'],
|
||||
threshold: 0.2,
|
||||
limit: 20,
|
||||
all: true,
|
||||
})
|
||||
|
||||
const commands = (
|
||||
await Promise.all(
|
||||
results.map(async (result) => this.read(result.obj.fileName)),
|
||||
)
|
||||
).filter((command): command is Command => command !== null)
|
||||
|
||||
return commands
|
||||
}
|
||||
}
|
||||
@ -1,148 +0,0 @@
|
||||
import fuzzysort from 'fuzzysort'
|
||||
import { App } from 'obsidian'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
|
||||
import { AbstractJsonRepository } from '../base'
|
||||
import { ROOT_DIR, TEMPLATE_DIR } from '../constants'
|
||||
import {
|
||||
DuplicateTemplateException,
|
||||
EmptyTemplateNameException,
|
||||
} from '../exception'
|
||||
|
||||
import { TEMPLATE_SCHEMA_VERSION, Template, TemplateMetadata } from './types'
|
||||
|
||||
export class TemplateManager extends AbstractJsonRepository<
|
||||
Template,
|
||||
TemplateMetadata
|
||||
> {
|
||||
constructor(app: App) {
|
||||
super(app, `${ROOT_DIR}/${TEMPLATE_DIR}`)
|
||||
}
|
||||
|
||||
protected generateFileName(template: Template): string {
|
||||
// Format: v{schemaVersion}_name_id.json (with name encoded)
|
||||
const encodedName = encodeURIComponent(template.name)
|
||||
return `v${TEMPLATE_SCHEMA_VERSION}_${encodedName}_${template.id}.json`
|
||||
}
|
||||
|
||||
protected parseFileName(fileName: string): TemplateMetadata | null {
|
||||
const match = fileName.match(
|
||||
new RegExp(`^v${TEMPLATE_SCHEMA_VERSION}_(.+)_([0-9a-f-]+)\\.json$`),
|
||||
)
|
||||
if (!match) return null
|
||||
|
||||
const encodedName = match[1]
|
||||
const id = match[2]
|
||||
const name = decodeURIComponent(encodedName)
|
||||
|
||||
return { id, name, schemaVersion: TEMPLATE_SCHEMA_VERSION }
|
||||
}
|
||||
|
||||
public async createTemplate(
|
||||
template: Omit<
|
||||
Template,
|
||||
'id' | 'createdAt' | 'updatedAt' | 'schemaVersion'
|
||||
>,
|
||||
): Promise<Template> {
|
||||
if (template.name !== undefined && template.name.length === 0) {
|
||||
throw new EmptyTemplateNameException()
|
||||
}
|
||||
|
||||
const existingTemplate = await this.findByName(template.name)
|
||||
if (existingTemplate) {
|
||||
throw new DuplicateTemplateException(template.name)
|
||||
}
|
||||
|
||||
const newTemplate: Template = {
|
||||
id: uuidv4(),
|
||||
...template,
|
||||
createdAt: Date.now(),
|
||||
updatedAt: Date.now(),
|
||||
schemaVersion: TEMPLATE_SCHEMA_VERSION,
|
||||
}
|
||||
|
||||
await this.create(newTemplate)
|
||||
return newTemplate
|
||||
}
|
||||
|
||||
public async ListTemplates(): Promise<Template[]> {
|
||||
const allMetadata = await this.listMetadata()
|
||||
const allTemplates = await Promise.all(allMetadata.map(async (meta) => this.read(meta.fileName)))
|
||||
return allTemplates.sort((a, b) => b.updatedAt - a.updatedAt)
|
||||
}
|
||||
|
||||
public async findById(id: string): Promise<Template | null> {
|
||||
const allMetadata = await this.listMetadata()
|
||||
const targetMetadata = allMetadata.find((meta) => meta.id === id)
|
||||
|
||||
if (!targetMetadata) return null
|
||||
|
||||
return this.read(targetMetadata.fileName)
|
||||
}
|
||||
|
||||
public async findByName(name: string): Promise<Template | null> {
|
||||
const allMetadata = await this.listMetadata()
|
||||
const targetMetadata = allMetadata.find((meta) => meta.name === name)
|
||||
|
||||
if (!targetMetadata) return null
|
||||
|
||||
return this.read(targetMetadata.fileName)
|
||||
}
|
||||
|
||||
public async updateTemplate(
|
||||
id: string,
|
||||
updates: Partial<
|
||||
Omit<Template, 'id' | 'createdAt' | 'updatedAt' | 'schemaVersion'>
|
||||
>,
|
||||
): Promise<Template | null> {
|
||||
if (updates.name !== undefined && updates.name.length === 0) {
|
||||
throw new EmptyTemplateNameException()
|
||||
}
|
||||
|
||||
const template = await this.findById(id)
|
||||
if (!template) return null
|
||||
|
||||
if (updates.name && updates.name !== template.name) {
|
||||
const existingTemplate = await this.findByName(updates.name)
|
||||
if (existingTemplate) {
|
||||
throw new DuplicateTemplateException(updates.name)
|
||||
}
|
||||
}
|
||||
|
||||
const updatedTemplate: Template = {
|
||||
...template,
|
||||
...updates,
|
||||
updatedAt: Date.now(),
|
||||
}
|
||||
|
||||
await this.update(template, updatedTemplate)
|
||||
return updatedTemplate
|
||||
}
|
||||
|
||||
public async deleteTemplate(id: string): Promise<boolean> {
|
||||
const template = await this.findById(id)
|
||||
if (!template) return false
|
||||
|
||||
const fileName = this.generateFileName(template)
|
||||
await this.delete(fileName)
|
||||
return true
|
||||
}
|
||||
|
||||
public async searchTemplates(query: string): Promise<Template[]> {
|
||||
const allMetadata = await this.listMetadata()
|
||||
const results = fuzzysort.go(query, allMetadata, {
|
||||
keys: ['name'],
|
||||
threshold: 0.2,
|
||||
limit: 20,
|
||||
all: true,
|
||||
})
|
||||
|
||||
const templates = (
|
||||
await Promise.all(
|
||||
results.map(async (result) => this.read(result.obj.fileName)),
|
||||
)
|
||||
).filter((template): template is Template => template !== null)
|
||||
|
||||
return templates
|
||||
}
|
||||
}
|
||||
@ -1,8 +1,8 @@
|
||||
import { SerializedLexicalNode } from 'lexical'
|
||||
|
||||
export const TEMPLATE_SCHEMA_VERSION = 1
|
||||
export const COMMAND_SCHEMA_VERSION = 1
|
||||
|
||||
export type Template = {
|
||||
export type Command = {
|
||||
id: string
|
||||
name: string
|
||||
content: { nodes: SerializedLexicalNode[] }
|
||||
@ -11,7 +11,7 @@ export type Template = {
|
||||
schemaVersion: number
|
||||
}
|
||||
|
||||
export type TemplateMetadata = {
|
||||
export type CommandMetadata = {
|
||||
id: string
|
||||
name: string
|
||||
schemaVersion: number
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
export const ROOT_DIR = '.infio_json_db'
|
||||
export const TEMPLATE_DIR = 'templates'
|
||||
export const COMMAND_DIR = 'commands'
|
||||
export const CHAT_DIR = 'chats'
|
||||
export const INITIAL_MIGRATION_MARKER = '.initial_migration_completed'
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
export class DuplicateTemplateException extends Error {
|
||||
constructor(templateName: string) {
|
||||
super(`Template with name "${templateName}" already exists`)
|
||||
this.name = 'DuplicateTemplateException'
|
||||
export class DuplicateCommandException extends Error {
|
||||
constructor(commandName: string) {
|
||||
super(`Command with name "${commandName}" already exists`)
|
||||
this.name = 'DuplicateCommandException'
|
||||
}
|
||||
}
|
||||
|
||||
export class EmptyTemplateNameException extends Error {
|
||||
export class EmptyCommandNameException extends Error {
|
||||
constructor() {
|
||||
super('Template name cannot be empty')
|
||||
this.name = 'EmptyTemplateNameException'
|
||||
super('Command name cannot be empty')
|
||||
this.name = 'EmptyCommandNameException'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
import { App, normalizePath } from 'obsidian'
|
||||
|
||||
import { DBManager } from '../database-manager'
|
||||
import { DuplicateTemplateException } from '../exception'
|
||||
import { DuplicateCommandException } from '../exception'
|
||||
import { ConversationManager } from '../modules/conversation/conversation-manager'
|
||||
|
||||
import { ChatManager } from './chat/ChatManager'
|
||||
import { CommandManager } from './command/CommandManager'
|
||||
import { INITIAL_MIGRATION_MARKER, ROOT_DIR } from './constants'
|
||||
import { TemplateManager } from './command/TemplateManager'
|
||||
import { serializeChatMessage } from './utils'
|
||||
|
||||
async function hasMigrationCompleted(app: App): Promise<boolean> {
|
||||
@ -62,44 +62,44 @@ async function transferChatHistory(app: App, dbManager: DBManager): Promise<void
|
||||
console.log('Chat history migration to JSON database completed')
|
||||
}
|
||||
|
||||
async function transferTemplates(
|
||||
async function transferCommands(
|
||||
app: App,
|
||||
dbManager: DBManager,
|
||||
): Promise<void> {
|
||||
const jsonTemplateManager = new TemplateManager(app)
|
||||
const templateManager = dbManager.getCommandManager()
|
||||
const jsonCommandManager = new CommandManager(app)
|
||||
const commandManager = dbManager.getCommandManager()
|
||||
|
||||
const templates = await templateManager.findAllCommands()
|
||||
const commands = await commandManager.findAllCommands()
|
||||
|
||||
for (const template of templates) {
|
||||
for (const command of commands) {
|
||||
try {
|
||||
if (await jsonTemplateManager.findByName(template.name)) {
|
||||
if (await jsonCommandManager.findByName(command.name)) {
|
||||
// Template already exists, skip
|
||||
continue
|
||||
}
|
||||
await jsonTemplateManager.createTemplate({
|
||||
name: template.name,
|
||||
content: template.content,
|
||||
await jsonCommandManager.createCommand({
|
||||
name: command.name,
|
||||
content: command.content,
|
||||
})
|
||||
|
||||
const verifyTemplate = await jsonTemplateManager.findByName(template.name)
|
||||
if (!verifyTemplate) {
|
||||
const verifyCommand = await jsonCommandManager.findByName(command.name)
|
||||
if (!verifyCommand) {
|
||||
throw new Error(
|
||||
`Failed to verify migration of template ${template.name}`,
|
||||
`Failed to verify migration of command ${command.name}`,
|
||||
)
|
||||
}
|
||||
|
||||
await templateManager.deleteCommand(template.id)
|
||||
await commandManager.deleteCommand(command.id)
|
||||
} catch (error) {
|
||||
if (error instanceof DuplicateTemplateException) {
|
||||
console.log(`Duplicate template found: ${template.name}. Skipping...`)
|
||||
if (error instanceof DuplicateCommandException) {
|
||||
console.log(`Duplicate command found: ${command.name}. Skipping...`)
|
||||
} else {
|
||||
console.error(`Error migrating template ${template.name}:`, error)
|
||||
console.error(`Error migrating command ${command.name}:`, error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Templates migration to JSON database completed')
|
||||
console.log('Commands migration to JSON database completed')
|
||||
}
|
||||
|
||||
export async function migrateToJsonDatabase(
|
||||
@ -112,7 +112,7 @@ export async function migrateToJsonDatabase(
|
||||
}
|
||||
|
||||
await transferChatHistory(app, dbManager)
|
||||
await transferTemplates(app, dbManager)
|
||||
await transferCommands(app, dbManager)
|
||||
await markMigrationCompleted(app)
|
||||
onMigrationComplete?.()
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@ import fuzzysort from 'fuzzysort'
|
||||
import { App } from 'obsidian'
|
||||
|
||||
import { DBManager } from '../../database-manager'
|
||||
import { DuplicateTemplateException } from '../../exception'
|
||||
import { DuplicateCommandException } from '../../exception'
|
||||
import { InsertTemplate, SelectTemplate, UpdateTemplate } from '../../schema'
|
||||
|
||||
import { CommandRepository } from './command-repository'
|
||||
@ -21,7 +21,7 @@ export class CommandManager {
|
||||
async createCommand(command: InsertTemplate): Promise<SelectTemplate> {
|
||||
const existingTemplate = await this.repository.findByName(command.name)
|
||||
if (existingTemplate) {
|
||||
throw new DuplicateTemplateException(command.name)
|
||||
throw new DuplicateCommandException(command.name)
|
||||
}
|
||||
const created = await this.repository.create(command)
|
||||
return created
|
||||
|
||||
@ -2,7 +2,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
|
||||
import { lexicalNodeToPlainText } from '../components/chat-view/chat-input/utils/editor-state-to-plain-text'
|
||||
import { useApp } from '../contexts/AppContext'
|
||||
import { TemplateManager } from '../database/json/command/TemplateManager'
|
||||
import { CommandManager } from '../database/json/command/CommandManager'
|
||||
import { TemplateContent } from '../database/schema'
|
||||
|
||||
|
||||
@ -28,10 +28,10 @@ export function useCommands(): UseCommands {
|
||||
|
||||
|
||||
const app = useApp()
|
||||
const templateManager = useMemo(() => new TemplateManager(app), [app])
|
||||
const templateManager = useMemo(() => new CommandManager(app), [app])
|
||||
|
||||
const fetchCommandList = useCallback(async () => {
|
||||
templateManager.ListTemplates().then((rows) => {
|
||||
templateManager.ListCommands().then((rows) => {
|
||||
setCommandList(rows.map((row) => ({
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
@ -49,7 +49,7 @@ export function useCommands(): UseCommands {
|
||||
|
||||
const createCommand = useCallback(
|
||||
async (name: string, content: TemplateContent): Promise<void> => {
|
||||
await templateManager.createTemplate({
|
||||
await templateManager.createCommand({
|
||||
name,
|
||||
content,
|
||||
})
|
||||
@ -60,7 +60,7 @@ export function useCommands(): UseCommands {
|
||||
|
||||
const deleteCommand = useCallback(
|
||||
async (id: string): Promise<void> => {
|
||||
await templateManager.deleteTemplate(id)
|
||||
await templateManager.deleteCommand(id)
|
||||
fetchCommandList()
|
||||
},
|
||||
[templateManager, fetchCommandList],
|
||||
@ -68,7 +68,7 @@ export function useCommands(): UseCommands {
|
||||
|
||||
const updateCommand = useCallback(
|
||||
async (id: string, name: string, content: TemplateContent): Promise<void> => {
|
||||
await templateManager.updateTemplate(id, {
|
||||
await templateManager.updateCommand(id, {
|
||||
name,
|
||||
content,
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user