From b85e67541b5d48ec79eddfea2c122da80c022925 Mon Sep 17 00:00:00 2001 From: Jokul Date: Tue, 7 Jul 2026 21:58:17 +0800 Subject: [PATCH] feat: ReJson/TairJson support - string.ts: rejsonGet, rejsonSet, rejsonDel using JSON.GET/SET/DEL - IPC + preload for rejsonGet/rejsonSet - New ReJsonEditor.vue: Monaco JSON editor with JSON.GET/SET - KeyDetail: dispatch ReJSON-RL/json/tair-json types to ReJsonEditor --- ROADMAP.md | 2 +- electron/main/ipc-handlers.ts | 8 +++ electron/main/redis/string.ts | 21 +++++++- electron/preload/index.d.ts | 2 + electron/preload/index.ts | 5 ++ src/components/KeyDetail.vue | 2 + src/components/ReJsonEditor.vue | 90 +++++++++++++++++++++++++++++++++ 7 files changed, 128 insertions(+), 2 deletions(-) create mode 100644 src/components/ReJsonEditor.vue diff --git a/ROADMAP.md b/ROADMAP.md index cdf3ad7..850df36 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -29,7 +29,7 @@ - [x] **多格式查看器** — Text / Hex / Json / Binary / Msgpack / PHP Serialize / Java Serialize / Pickle / Brotli / Gzip / Deflate / DeflateRaw / Protobuf(13 种格式) - [x] **自动格式检测** — 检查内容 magic bytes 自动选择查看器 - [x] **自定义格式化器** — 外部可执行文件 + 模板参数 {KEY} {VALUE} {HEX} {HEX_FILE} -- [ ] **ReJson / TairJson 支持** — JSON.GET / JSON.SET / JSON.DEL 编辑 +- [x] **ReJson / TairJson 支持** — JSON.GET / JSON.SET / JSON.DEL 编辑 - [ ] **二进制 key 支持** — [Hex] 前缀输入,hex ↔ buffer 双向转换 - [ ] **虚拟化滚动** — 大 key 集合(200k+)的性能优化,KeyList 树形视图虚拟化 - [ ] **批量删除预览** — 先扫描预览,再确认删除,显示 key 数量和总大小 diff --git a/electron/main/ipc-handlers.ts b/electron/main/ipc-handlers.ts index 7d4d451..27326ee 100644 --- a/electron/main/ipc-handlers.ts +++ b/electron/main/ipc-handlers.ts @@ -159,6 +159,14 @@ export function registerIpcHandlers(): void { await redis.setStringValue(id, key, value) })) + // ReJson + ipcMain.handle('redis:rejsonGet', async (_e, id: string, key: string, path: string) => { + return redis.rejsonGet(id, key, path) + }) + ipcMain.handle('redis:rejsonSet', withLog('JSON.SET', async (_e, id: string, key: string, path: string, value: string) => { + await redis.rejsonSet(id, key, path, value) + })) + // Redis - Hash ipcMain.handle('redis:hashScan', async (_e, id: string, key: string, cursor: string, count: number) => { return redis.getHashFields(id, key, cursor, count) diff --git a/electron/main/redis/string.ts b/electron/main/redis/string.ts index 16d3d7b..bd38eb2 100644 --- a/electron/main/redis/string.ts +++ b/electron/main/redis/string.ts @@ -1,5 +1,5 @@ // src/main/redis/string.ts -// String 操作 +// String + ReJson 操作 import { getClient } from './connection' export async function getStringValue(id: string, key: string): Promise { @@ -13,3 +13,22 @@ export async function setStringValue(id: string, key: string, value: string): Pr if (!client) throw new Error(`Client ${id} not found`) await client.set(key, value) } + +// ReJson operations +export async function rejsonGet(id: string, key: string, path: string = '.'): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + return (client as any).call('JSON.GET', key, path) +} + +export async function rejsonSet(id: string, key: string, path: string, value: string): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + await (client as any).call('JSON.SET', key, path, value) +} + +export async function rejsonDel(id: string, key: string, path: string = '.'): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + return (client as any).call('JSON.DEL', key, path) +} diff --git a/electron/preload/index.d.ts b/electron/preload/index.d.ts index 0ee4531..831ed79 100644 --- a/electron/preload/index.d.ts +++ b/electron/preload/index.d.ts @@ -68,6 +68,8 @@ export interface ElectronAPI { getKeyTTL: (id: string, key: string) => Promise getString: (id: string, key: string) => Promise setString: (id: string, key: string, value: string) => Promise + rejsonGet: (id: string, key: string, path: string) => Promise + rejsonSet: (id: string, key: string, path: string, value: string) => Promise deleteKey: (id: string, key: string) => Promise hashScan: (id: string, key: string, cursor: string, count: number) => Promise<{ cursor: string; fields: [string, string][] }> diff --git a/electron/preload/index.ts b/electron/preload/index.ts index a281643..b9539d4 100644 --- a/electron/preload/index.ts +++ b/electron/preload/index.ts @@ -43,6 +43,11 @@ const electronAPI = { getString: (id: string, key: string): Promise => ipcRenderer.invoke('redis:getString', id, key), setString: (id: string, key: string, value: string): Promise => ipcRenderer.invoke('redis:setString', id, key, value), + // ReJson + rejsonGet: (id: string, key: string, path: string): Promise => + ipcRenderer.invoke('redis:rejsonGet', id, key, path), + rejsonSet: (id: string, key: string, path: string, value: string): Promise => + ipcRenderer.invoke('redis:rejsonSet', id, key, path, value), deleteKey: (id: string, key: string): Promise => ipcRenderer.invoke('redis:deleteKey', id, key), hashScan: (id: string, key: string, cursor: string, count: number): Promise => ipcRenderer.invoke('redis:hashScan', id, key, cursor, count), diff --git a/src/components/KeyDetail.vue b/src/components/KeyDetail.vue index ec2cb5c..d1d1f77 100644 --- a/src/components/KeyDetail.vue +++ b/src/components/KeyDetail.vue @@ -11,6 +11,7 @@ import ListEditor from './ListEditor.vue' import SetEditor from './SetEditor.vue' import ZsetEditor from './ZsetEditor.vue' import StreamEditor from './StreamEditor.vue' +import ReJsonEditor from './ReJsonEditor.vue' const keyStore = useKeyStore() const connStore = useConnectionStore() @@ -148,6 +149,7 @@ async function refreshKey() { +

{{ t('key.unsupported', { type: keyStore.selectedType }) }}

diff --git a/src/components/ReJsonEditor.vue b/src/components/ReJsonEditor.vue new file mode 100644 index 0000000..2ede9a9 --- /dev/null +++ b/src/components/ReJsonEditor.vue @@ -0,0 +1,90 @@ + + + + +