2023-11-05 11:57:52 +08:00
|
|
|
import { defineStore } from 'pinia'
|
2024-05-14 10:09:50 +08:00
|
|
|
import { endsWith, get, isEmpty, join, map, now, size, slice, split } from 'lodash'
|
2023-11-05 11:57:52 +08:00
|
|
|
import {
|
|
|
|
AddHashField,
|
|
|
|
AddListItem,
|
|
|
|
AddStreamValue,
|
|
|
|
AddZSetValue,
|
2024-01-05 00:36:48 +08:00
|
|
|
BatchSetTTL,
|
2023-11-05 11:57:52 +08:00
|
|
|
CleanCmdHistory,
|
|
|
|
CloseConnection,
|
2023-11-13 15:28:13 +08:00
|
|
|
ConvertValue,
|
2023-11-05 11:57:52 +08:00
|
|
|
DeleteKey,
|
2023-12-19 20:10:01 +08:00
|
|
|
DeleteKeys,
|
2024-06-17 18:29:56 +08:00
|
|
|
DeleteKeysByPattern,
|
2023-12-18 00:58:20 +08:00
|
|
|
ExportKey,
|
2023-11-05 11:57:52 +08:00
|
|
|
FlushDB,
|
2024-01-25 00:29:15 +08:00
|
|
|
GetClientList,
|
2023-11-05 11:57:52 +08:00
|
|
|
GetCmdHistory,
|
2024-05-22 17:10:58 +08:00
|
|
|
GetHashValue,
|
2023-11-08 23:45:33 +08:00
|
|
|
GetKeyDetail,
|
|
|
|
GetKeySummary,
|
2023-12-04 15:43:25 +08:00
|
|
|
GetKeyType,
|
2023-11-05 11:57:52 +08:00
|
|
|
GetSlowLogs,
|
2023-12-27 15:44:08 +08:00
|
|
|
ImportCSV,
|
2023-11-05 11:57:52 +08:00
|
|
|
LoadAllKeys,
|
2023-12-26 01:13:21 +08:00
|
|
|
LoadNextAllKeys,
|
2023-11-05 11:57:52 +08:00
|
|
|
LoadNextKeys,
|
|
|
|
OpenConnection,
|
|
|
|
OpenDatabase,
|
|
|
|
RemoveStreamValues,
|
|
|
|
RenameKey,
|
|
|
|
ServerInfo,
|
|
|
|
SetHashValue,
|
|
|
|
SetKeyTTL,
|
|
|
|
SetKeyValue,
|
|
|
|
SetListItem,
|
|
|
|
SetSetItem,
|
|
|
|
UpdateSetItem,
|
|
|
|
UpdateZSetValue,
|
|
|
|
} from 'wailsjs/go/services/browserService.js'
|
|
|
|
import useTabStore from 'stores/tab.js'
|
2024-01-23 17:37:00 +08:00
|
|
|
import { nativeRedisKey } from '@/utils/key_convert.js'
|
2023-11-05 11:57:52 +08:00
|
|
|
import { BrowserTabType } from '@/consts/browser_tab_type.js'
|
|
|
|
import { KeyViewType } from '@/consts/key_view_type.js'
|
|
|
|
import { ConnectionType } from '@/consts/connection_type.js'
|
|
|
|
import useConnectionStore from 'stores/connections.js'
|
2023-11-13 15:28:13 +08:00
|
|
|
import { decodeTypes, formatTypes } from '@/consts/value_view_type.js'
|
2023-12-01 17:59:04 +08:00
|
|
|
import { isRedisGlob } from '@/utils/glob_pattern.js'
|
2023-12-03 12:27:05 +08:00
|
|
|
import { i18nGlobal } from '@/utils/i18n.js'
|
2024-01-23 11:26:15 +08:00
|
|
|
import { EventsEmit, EventsOn } from 'wailsjs/runtime/runtime.js'
|
2023-12-25 16:22:29 +08:00
|
|
|
import { RedisNodeItem } from '@/objects/redisNodeItem.js'
|
|
|
|
import { RedisServerState } from '@/objects/redisServerState.js'
|
|
|
|
import { RedisDatabaseItem } from '@/objects/redisDatabaseItem.js'
|
2023-12-26 12:04:46 +08:00
|
|
|
import { timeout } from '@/utils/promise.js'
|
2023-11-05 11:57:52 +08:00
|
|
|
|
|
|
|
const useBrowserStore = defineStore('browser', {
|
2023-12-01 17:59:04 +08:00
|
|
|
/**
|
|
|
|
* @typedef {Object} FilterItem
|
|
|
|
* @property {string} pattern key pattern filter
|
|
|
|
* @property {string} type type filter
|
|
|
|
*/
|
|
|
|
|
2023-11-05 11:57:52 +08:00
|
|
|
/**
|
|
|
|
* @typedef {Object} HistoryItem
|
|
|
|
* @property {string} time
|
|
|
|
* @property {string} server
|
|
|
|
* @property {string} cmd
|
|
|
|
* @property {number} cost
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @typedef {Object} BrowserState
|
2023-12-25 16:22:29 +08:00
|
|
|
* @property {Object.<string, RedisServerState>} servers
|
2023-11-05 11:57:52 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @returns {BrowserState}
|
|
|
|
*/
|
|
|
|
state: () => ({
|
2023-12-25 16:22:29 +08:00
|
|
|
servers: {},
|
2023-11-05 11:57:52 +08:00
|
|
|
}),
|
|
|
|
getters: {
|
|
|
|
anyConnectionOpened() {
|
2023-12-25 16:22:29 +08:00
|
|
|
return !isEmpty(this.servers)
|
2023-12-01 17:59:04 +08:00
|
|
|
},
|
2023-11-05 11:57:52 +08:00
|
|
|
},
|
|
|
|
actions: {
|
|
|
|
/**
|
|
|
|
* check if connection is connected
|
|
|
|
* @param name
|
|
|
|
* @returns {boolean}
|
|
|
|
*/
|
|
|
|
isConnected(name) {
|
2023-12-25 16:22:29 +08:00
|
|
|
return this.servers.hasOwnProperty(name)
|
2023-11-05 11:57:52 +08:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* close all connections
|
|
|
|
* @returns {Promise<void>}
|
|
|
|
*/
|
|
|
|
async closeAllConnection() {
|
2023-12-25 16:22:29 +08:00
|
|
|
for (const serverName in this.servers) {
|
|
|
|
await CloseConnection(serverName)
|
|
|
|
this.servers[serverName].dispose()
|
2023-11-05 11:57:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
const tabStore = useTabStore()
|
|
|
|
tabStore.removeAllTab()
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
2023-12-01 17:59:04 +08:00
|
|
|
* get database info list
|
2024-07-01 17:28:35 +08:00
|
|
|
* @param {string} server
|
2023-12-25 16:22:29 +08:00
|
|
|
* @return {RedisDatabaseItem[]}
|
2023-12-01 17:59:04 +08:00
|
|
|
*/
|
|
|
|
getDBList(server) {
|
2023-12-25 16:22:29 +08:00
|
|
|
const serverInst = this.servers[server]
|
|
|
|
if (serverInst != null) {
|
|
|
|
return serverInst.getDatabase()
|
|
|
|
}
|
|
|
|
return []
|
2023-12-01 17:59:04 +08:00
|
|
|
},
|
|
|
|
|
2024-07-01 17:28:35 +08:00
|
|
|
/**
|
|
|
|
* get server version
|
|
|
|
* @param {string} server
|
|
|
|
*/
|
|
|
|
getServerVersion(server) {
|
|
|
|
const serverInst = this.servers[server]
|
|
|
|
if (serverInst != null) {
|
|
|
|
return serverInst.version
|
|
|
|
}
|
|
|
|
return '1.0.0'
|
|
|
|
},
|
|
|
|
|
2023-12-01 17:59:04 +08:00
|
|
|
/**
|
|
|
|
* get database by server name and database index
|
|
|
|
* @param {string} server
|
2023-11-05 11:57:52 +08:00
|
|
|
* @param {number} db
|
2023-12-25 16:22:29 +08:00
|
|
|
* @return {RedisDatabaseItem|null}
|
2023-11-05 11:57:52 +08:00
|
|
|
*/
|
2023-12-01 17:59:04 +08:00
|
|
|
getDatabase(server, db) {
|
2023-12-25 16:22:29 +08:00
|
|
|
/** @type {RedisServerState} **/
|
|
|
|
const serverInst = this.servers[server]
|
|
|
|
if (serverInst != null) {
|
|
|
|
return serverInst.databases[db] || null
|
2023-11-05 11:57:52 +08:00
|
|
|
}
|
|
|
|
return null
|
|
|
|
},
|
|
|
|
|
2023-11-10 11:52:54 +08:00
|
|
|
/**
|
2023-12-01 17:59:04 +08:00
|
|
|
* get current selection database by server
|
|
|
|
* @param server
|
|
|
|
* @return {number}
|
2023-11-10 11:52:54 +08:00
|
|
|
*/
|
2023-12-01 17:59:04 +08:00
|
|
|
getSelectedDB(server) {
|
2023-12-25 16:22:29 +08:00
|
|
|
/** @type {RedisServerState} **/
|
|
|
|
const serverInst = this.servers[server]
|
|
|
|
if (serverInst != null) {
|
|
|
|
return serverInst.db
|
|
|
|
}
|
|
|
|
return 0
|
2023-12-01 17:59:04 +08:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
2023-12-27 18:23:40 +08:00
|
|
|
* get key struct in current database
|
|
|
|
* @param {string} server
|
|
|
|
* @param {boolean} [includeRoot]
|
2023-12-25 16:22:29 +08:00
|
|
|
* @return {RedisNodeItem[]}
|
2023-12-01 17:59:04 +08:00
|
|
|
*/
|
2023-12-27 18:23:40 +08:00
|
|
|
getKeyStruct(server, includeRoot) {
|
2023-12-25 16:22:29 +08:00
|
|
|
/** @type {RedisServerState} **/
|
|
|
|
const serverInst = this.servers[server]
|
|
|
|
let rootNode = null
|
|
|
|
if (serverInst != null) {
|
|
|
|
rootNode = serverInst.getRoot()
|
|
|
|
}
|
2023-12-27 18:23:40 +08:00
|
|
|
if (includeRoot === true) {
|
|
|
|
return [rootNode]
|
|
|
|
}
|
2023-12-25 16:22:29 +08:00
|
|
|
return get(rootNode, 'children', [])
|
2023-11-10 11:52:54 +08:00
|
|
|
},
|
|
|
|
|
2024-01-03 18:44:51 +08:00
|
|
|
getReloadKey(server) {
|
|
|
|
/** @type {RedisServerState} **/
|
|
|
|
const serverInst = this.servers[server]
|
|
|
|
return serverInst != null ? serverInst.reloadKey : 0
|
|
|
|
},
|
|
|
|
|
|
|
|
reloadServer(server) {
|
|
|
|
/** @type {RedisServerState} **/
|
|
|
|
const serverInst = this.servers[server]
|
|
|
|
if (serverInst != null) {
|
|
|
|
serverInst.reloadKey = Date.now()
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2023-11-05 11:57:52 +08:00
|
|
|
/**
|
|
|
|
* switch key view
|
|
|
|
* @param {string} connName
|
|
|
|
* @param {number} viewType
|
|
|
|
*/
|
2023-12-19 20:19:41 +08:00
|
|
|
// async switchKeyView(connName, viewType) {
|
|
|
|
// if (viewType !== KeyViewType.Tree && viewType !== KeyViewType.List) {
|
|
|
|
// return
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// const t = get(this.viewType, connName, KeyViewType.Tree)
|
|
|
|
// if (t === viewType) {
|
|
|
|
// return
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// this.viewType[connName] = viewType
|
|
|
|
// const dbs = get(this.databases, connName, [])
|
|
|
|
// for (const dbItem of dbs) {
|
|
|
|
// if (!dbItem.opened) {
|
|
|
|
// continue
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// dbItem.children = undefined
|
2023-12-25 16:22:29 +08:00
|
|
|
// dbItem.keyCount = 0
|
2023-12-19 20:19:41 +08:00
|
|
|
// const { db = 0 } = dbItem
|
|
|
|
// this._getNodeMap(connName, db).clear()
|
|
|
|
// this._addKeyNodes(connName, db, keys)
|
|
|
|
// this._tidyNode(connName, db, '')
|
|
|
|
// }
|
|
|
|
// },
|
2023-11-05 11:57:52 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* open connection
|
|
|
|
* @param {string} name
|
|
|
|
* @param {boolean} [reload]
|
|
|
|
* @returns {Promise<void>}
|
|
|
|
*/
|
|
|
|
async openConnection(name, reload) {
|
|
|
|
if (this.isConnected(name)) {
|
|
|
|
if (reload !== true) {
|
|
|
|
return
|
|
|
|
} else {
|
|
|
|
// reload mode, try close connection first
|
|
|
|
await CloseConnection(name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const { data, success, msg } = await OpenConnection(name)
|
|
|
|
if (!success) {
|
|
|
|
throw new Error(msg)
|
|
|
|
}
|
|
|
|
// append to db node to current connection
|
|
|
|
// const connNode = this.getConnection(name)
|
|
|
|
// if (connNode == null) {
|
|
|
|
// throw new Error('no such connection')
|
|
|
|
// }
|
2024-07-01 17:28:35 +08:00
|
|
|
const { db, view = KeyViewType.Tree, lastDB, version } = data
|
2023-11-05 11:57:52 +08:00
|
|
|
if (isEmpty(db)) {
|
|
|
|
throw new Error('no db loaded')
|
|
|
|
}
|
2023-12-25 16:22:29 +08:00
|
|
|
const serverInst = new RedisServerState({
|
|
|
|
name,
|
|
|
|
separator: this.getSeparator(name),
|
2023-12-29 00:14:56 +08:00
|
|
|
db: -1,
|
2024-01-06 01:25:20 +08:00
|
|
|
viewType: view,
|
2024-07-01 17:28:35 +08:00
|
|
|
version,
|
2023-12-25 16:22:29 +08:00
|
|
|
})
|
2023-12-29 00:14:56 +08:00
|
|
|
/** @type {Object.<number,RedisDatabaseItem>} **/
|
|
|
|
const databases = {}
|
|
|
|
for (const dbItem of db) {
|
|
|
|
databases[dbItem.index] = new RedisDatabaseItem({
|
|
|
|
db: dbItem.index,
|
2024-01-18 17:15:34 +08:00
|
|
|
alias: dbItem.alias,
|
2023-12-29 00:14:56 +08:00
|
|
|
maxKeys: dbItem.maxKeys,
|
|
|
|
})
|
|
|
|
if (dbItem.index === lastDB) {
|
|
|
|
// set last opened database as default
|
|
|
|
serverInst.db = dbItem.index
|
|
|
|
} else if (serverInst.db === -1) {
|
|
|
|
// set the first database as default
|
|
|
|
serverInst.db = dbItem.index
|
2023-12-02 02:03:29 +08:00
|
|
|
}
|
2023-11-05 11:57:52 +08:00
|
|
|
}
|
2023-12-25 16:22:29 +08:00
|
|
|
serverInst.databases = databases
|
|
|
|
this.servers[name] = serverInst
|
2023-11-05 11:57:52 +08:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* close connection
|
|
|
|
* @param {string} name
|
|
|
|
* @returns {Promise<boolean>}
|
|
|
|
*/
|
|
|
|
async closeConnection(name) {
|
|
|
|
const { success, msg } = await CloseConnection(name)
|
|
|
|
if (!success) {
|
|
|
|
// throw new Error(msg)
|
|
|
|
return false
|
|
|
|
}
|
2023-12-25 16:22:29 +08:00
|
|
|
delete this.servers[name]
|
2023-11-05 11:57:52 +08:00
|
|
|
|
|
|
|
const tabStore = useTabStore()
|
|
|
|
tabStore.removeTabByName(name)
|
|
|
|
return true
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* open database and load all keys
|
2023-12-01 17:59:04 +08:00
|
|
|
* @param server
|
2023-11-05 11:57:52 +08:00
|
|
|
* @param db
|
|
|
|
* @returns {Promise<void>}
|
|
|
|
*/
|
2023-12-01 17:59:04 +08:00
|
|
|
async openDatabase(server, db) {
|
2024-03-08 16:52:26 +08:00
|
|
|
const { data, success, msg } = await OpenDatabase(server, db)
|
2023-11-05 11:57:52 +08:00
|
|
|
if (!success) {
|
|
|
|
throw new Error(msg)
|
|
|
|
}
|
2023-11-05 13:00:03 +08:00
|
|
|
const { keys = [], end = false, maxKeys = 0 } = data
|
2023-11-05 11:57:52 +08:00
|
|
|
|
2023-12-25 16:22:29 +08:00
|
|
|
/** @type {RedisServerState} **/
|
|
|
|
const serverInst = this.servers[server]
|
|
|
|
if (serverInst == null) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
serverInst.db = db
|
|
|
|
serverInst.setDatabaseKeyCount(db, maxKeys)
|
|
|
|
serverInst.loadingState.fullLoaded = end
|
|
|
|
|
2023-11-05 11:57:52 +08:00
|
|
|
if (isEmpty(keys)) {
|
2023-12-25 16:22:29 +08:00
|
|
|
serverInst.nodeMap.clear()
|
2023-11-05 11:57:52 +08:00
|
|
|
} else {
|
|
|
|
// append db node to current connection's children
|
2023-12-25 16:22:29 +08:00
|
|
|
serverInst.addKeyNodes(keys)
|
2023-11-05 11:57:52 +08:00
|
|
|
}
|
2023-12-26 15:40:31 +08:00
|
|
|
serverInst.tidyNode('', false)
|
2023-11-05 11:57:52 +08:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* close database
|
2023-12-01 17:59:04 +08:00
|
|
|
* @param server
|
2023-11-05 11:57:52 +08:00
|
|
|
* @param db
|
|
|
|
*/
|
2023-12-01 17:59:04 +08:00
|
|
|
closeDatabase(server, db) {
|
2023-12-25 16:22:29 +08:00
|
|
|
/** @type {RedisServerState} **/
|
|
|
|
const serverInst = this.servers[server]
|
|
|
|
if (serverInst == null) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if (serverInst.db !== db) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
serverInst.closeDatabase()
|
|
|
|
|
|
|
|
/** @type {RedisDatabaseItem} **/
|
2023-12-01 17:59:04 +08:00
|
|
|
const selDB = this.getDatabase(server, db)
|
2023-11-05 11:57:52 +08:00
|
|
|
if (selDB == null) {
|
|
|
|
return
|
|
|
|
}
|
2023-12-25 16:22:29 +08:00
|
|
|
selDB.keyCount = 0
|
2023-11-05 11:57:52 +08:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
2024-05-17 14:43:43 +08:00
|
|
|
* @param {string} server
|
|
|
|
* @param {boolean} mute
|
2023-11-05 11:57:52 +08:00
|
|
|
* @returns {Promise<{}>}
|
|
|
|
*/
|
2024-05-17 14:43:43 +08:00
|
|
|
async getServerInfo(server, mute) {
|
2023-11-05 11:57:52 +08:00
|
|
|
try {
|
2024-01-12 11:18:41 +08:00
|
|
|
const { success, data, msg } = await ServerInfo(server)
|
2023-11-05 11:57:52 +08:00
|
|
|
if (success) {
|
2023-12-25 16:22:29 +08:00
|
|
|
/** @type {RedisServerState} **/
|
|
|
|
const serverInst = this.servers[server]
|
|
|
|
if (serverInst != null) {
|
|
|
|
serverInst.stats = data
|
|
|
|
}
|
2023-11-05 11:57:52 +08:00
|
|
|
return data
|
2024-05-17 14:43:43 +08:00
|
|
|
} else if (!isEmpty(msg) && mute !== true) {
|
2024-01-12 11:18:41 +08:00
|
|
|
$message.warning(msg)
|
2023-11-05 11:57:52 +08:00
|
|
|
}
|
|
|
|
} finally {
|
|
|
|
}
|
|
|
|
return {}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
2023-11-08 23:45:33 +08:00
|
|
|
* load key summary info
|
2023-11-05 11:57:52 +08:00
|
|
|
* @param {string} server
|
|
|
|
* @param {number} db
|
2023-11-08 23:45:33 +08:00
|
|
|
* @param {string|number[]} [key] null or blank indicate that update tab to display normal content (blank content or server status)
|
2023-12-14 16:35:37 +08:00
|
|
|
* @param {boolean} [clearValue]
|
2023-11-08 23:45:33 +08:00
|
|
|
* @return {Promise<void>}
|
2023-11-05 11:57:52 +08:00
|
|
|
*/
|
2023-12-14 16:35:37 +08:00
|
|
|
async loadKeySummary({ server, db, key, clearValue }) {
|
2023-11-05 11:57:52 +08:00
|
|
|
try {
|
|
|
|
const tab = useTabStore()
|
|
|
|
if (!isEmpty(key)) {
|
2023-11-08 23:45:33 +08:00
|
|
|
const { data, success, msg } = await GetKeySummary({
|
|
|
|
server,
|
|
|
|
db,
|
|
|
|
key,
|
|
|
|
})
|
2023-11-05 11:57:52 +08:00
|
|
|
if (success) {
|
2023-11-08 23:45:33 +08:00
|
|
|
const { type, ttl, size, length } = data
|
2024-01-06 01:25:20 +08:00
|
|
|
const k = nativeRedisKey(key)
|
2023-11-05 11:57:52 +08:00
|
|
|
const binaryKey = k !== key
|
|
|
|
tab.upsertTab({
|
|
|
|
subTab: BrowserTabType.KeyDetail,
|
|
|
|
server,
|
|
|
|
db,
|
|
|
|
type,
|
|
|
|
ttl,
|
|
|
|
keyCode: binaryKey ? key : undefined,
|
|
|
|
key: k,
|
|
|
|
size,
|
|
|
|
length,
|
2023-12-14 16:35:37 +08:00
|
|
|
clearValue,
|
2023-11-05 11:57:52 +08:00
|
|
|
})
|
|
|
|
return
|
|
|
|
} else {
|
|
|
|
if (!isEmpty(msg)) {
|
2023-11-08 23:45:33 +08:00
|
|
|
$message.error('load key summary fail: ' + msg)
|
2023-11-05 11:57:52 +08:00
|
|
|
}
|
|
|
|
// its danger to delete "non-exists" key, just remove from tree view
|
2024-01-11 13:06:46 +08:00
|
|
|
// await this.deleteKey(server, db, key, true)
|
2023-11-05 11:57:52 +08:00
|
|
|
// TODO: show key not found page or check exists on server first?
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
tab.upsertTab({
|
|
|
|
subTab: BrowserTabType.Status,
|
|
|
|
server,
|
|
|
|
db,
|
|
|
|
type: 'none',
|
|
|
|
ttl: -1,
|
|
|
|
key: null,
|
|
|
|
keyCode: null,
|
|
|
|
size: 0,
|
|
|
|
length: 0,
|
2023-12-14 16:35:37 +08:00
|
|
|
clearValue,
|
2023-11-05 11:57:52 +08:00
|
|
|
})
|
2023-11-08 23:45:33 +08:00
|
|
|
} catch (e) {
|
2024-03-05 11:48:55 +08:00
|
|
|
$message.error(e.message || 'unknown error')
|
2023-11-08 23:45:33 +08:00
|
|
|
} finally {
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2023-12-04 15:43:25 +08:00
|
|
|
/**
|
|
|
|
* load key type
|
|
|
|
* @param {string} server
|
|
|
|
* @param {number} db
|
2024-01-06 01:25:20 +08:00
|
|
|
* @param {string|number[]} key
|
2023-12-04 15:43:25 +08:00
|
|
|
* @param {number[]} keyCode
|
|
|
|
* @return {Promise<void>}
|
|
|
|
*/
|
2024-01-06 01:25:20 +08:00
|
|
|
async loadKeyType({ server, db, key }) {
|
2023-12-25 16:22:29 +08:00
|
|
|
/** @type {RedisServerState} **/
|
|
|
|
const serverInst = this.servers[server]
|
|
|
|
if (serverInst == null) {
|
|
|
|
return
|
|
|
|
}
|
2024-01-06 01:25:20 +08:00
|
|
|
const node = serverInst.getNode(ConnectionType.RedisValue, nativeRedisKey(key))
|
2023-12-06 18:25:51 +08:00
|
|
|
if (node == null || !isEmpty(node.redisType)) {
|
|
|
|
return
|
|
|
|
}
|
2023-12-04 15:43:25 +08:00
|
|
|
try {
|
|
|
|
node.redisType = 'loading'
|
2024-01-06 01:25:20 +08:00
|
|
|
const { data, success, msg } = await GetKeyType({ server, db, key })
|
2023-12-06 18:25:51 +08:00
|
|
|
if (success) {
|
|
|
|
const { type } = data || {}
|
|
|
|
node.redisType = type
|
|
|
|
} else {
|
|
|
|
node.redisType = 'NONE'
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
node.redisType = 'NONE'
|
2023-12-04 15:43:25 +08:00
|
|
|
} finally {
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2023-11-08 23:45:33 +08:00
|
|
|
/**
|
|
|
|
* reload key
|
2023-11-13 22:31:18 +08:00
|
|
|
* @param {string} server
|
|
|
|
* @param {number} db
|
|
|
|
* @param {string|number[]} key
|
|
|
|
* @param {string} [decode]
|
|
|
|
* @param {string} [format]
|
2023-11-20 16:23:27 +08:00
|
|
|
* @param {string} [matchPattern]
|
2024-03-14 17:12:46 +08:00
|
|
|
* @param {boolean} [showLoading]
|
2023-11-08 23:45:33 +08:00
|
|
|
* @return {Promise<void>}
|
|
|
|
*/
|
2024-03-14 17:12:46 +08:00
|
|
|
async reloadKey({ server, db, key, decode, format, matchPattern, showLoading = true }) {
|
2023-11-08 23:45:33 +08:00
|
|
|
const tab = useTabStore()
|
|
|
|
try {
|
2024-03-14 17:12:46 +08:00
|
|
|
if (showLoading) {
|
|
|
|
tab.updateLoading({ server, db, loading: true })
|
|
|
|
}
|
2023-12-14 16:35:37 +08:00
|
|
|
await this.loadKeySummary({ server, db, key, clearValue: true })
|
2024-03-14 17:12:46 +08:00
|
|
|
await this.loadKeyDetail({
|
|
|
|
server,
|
|
|
|
db,
|
|
|
|
key,
|
|
|
|
decode,
|
|
|
|
format,
|
|
|
|
matchPattern,
|
|
|
|
reset: true,
|
|
|
|
showLoading: false,
|
|
|
|
})
|
2023-11-08 23:45:33 +08:00
|
|
|
} finally {
|
2024-03-14 17:12:46 +08:00
|
|
|
if (showLoading) {
|
|
|
|
tab.updateLoading({ server, db, loading: false })
|
|
|
|
}
|
2023-11-08 23:45:33 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* load key content
|
|
|
|
* @param {string} server
|
|
|
|
* @param {number} db
|
|
|
|
* @param {string|number[]} key
|
2023-11-13 22:31:18 +08:00
|
|
|
* @param {string} [format]
|
|
|
|
* @param {string} [decode]
|
2023-11-08 23:45:33 +08:00
|
|
|
* @param {string} [matchPattern]
|
|
|
|
* @param {boolean} [reset]
|
|
|
|
* @param {boolean} [full]
|
2024-03-14 17:12:46 +08:00
|
|
|
* @param {boolean} [showLoading]
|
2023-11-08 23:45:33 +08:00
|
|
|
* @return {Promise<void>}
|
|
|
|
*/
|
2024-03-14 17:12:46 +08:00
|
|
|
async loadKeyDetail({ server, db, key, format, decode, matchPattern, reset, full, showLoading = true }) {
|
2023-11-08 23:45:33 +08:00
|
|
|
const tab = useTabStore()
|
2024-03-05 11:48:55 +08:00
|
|
|
const serverInst = this.servers[server]
|
|
|
|
if (serverInst == null) {
|
|
|
|
return
|
|
|
|
}
|
2023-11-08 23:45:33 +08:00
|
|
|
try {
|
2024-03-14 17:12:46 +08:00
|
|
|
if (showLoading) {
|
|
|
|
tab.updateLoading({ server, db, loading: true })
|
|
|
|
}
|
2024-03-05 11:48:55 +08:00
|
|
|
const [storeFormat, storeDecode] = serverInst.getDecodeHistory(key, db)
|
2023-11-08 23:45:33 +08:00
|
|
|
const { data, success, msg } = await GetKeyDetail({
|
|
|
|
server,
|
|
|
|
db,
|
|
|
|
key,
|
2024-03-05 11:48:55 +08:00
|
|
|
format: isEmpty(format) ? storeFormat : format,
|
|
|
|
decode: isEmpty(decode) ? storeDecode : decode,
|
2023-11-08 23:45:33 +08:00
|
|
|
matchPattern,
|
|
|
|
full: full === true,
|
|
|
|
reset,
|
|
|
|
lite: true,
|
|
|
|
})
|
|
|
|
if (success) {
|
2024-01-06 22:13:26 +08:00
|
|
|
const {
|
|
|
|
value,
|
|
|
|
keyType,
|
|
|
|
decode: retDecode,
|
|
|
|
format: retFormat,
|
|
|
|
match: retMatch,
|
|
|
|
reset: retReset,
|
|
|
|
end,
|
|
|
|
} = data
|
2023-11-08 23:45:33 +08:00
|
|
|
tab.updateValue({
|
|
|
|
server,
|
|
|
|
db,
|
2024-01-06 01:25:20 +08:00
|
|
|
key: nativeRedisKey(key),
|
2023-11-08 23:45:33 +08:00
|
|
|
value,
|
2024-03-05 11:48:55 +08:00
|
|
|
decode: retDecode || storeDecode,
|
|
|
|
format: retFormat || storeFormat,
|
2023-11-20 16:23:27 +08:00
|
|
|
reset: retReset,
|
|
|
|
matchPattern: retMatch || '',
|
2023-11-08 23:45:33 +08:00
|
|
|
end,
|
|
|
|
})
|
2023-11-13 22:31:18 +08:00
|
|
|
} else {
|
|
|
|
$message.error('load key detail fail:' + msg)
|
2023-11-08 23:45:33 +08:00
|
|
|
}
|
2023-11-05 11:57:52 +08:00
|
|
|
} finally {
|
2024-03-14 17:12:46 +08:00
|
|
|
if (showLoading) {
|
|
|
|
tab.updateLoading({ server, db, loading: false })
|
|
|
|
}
|
2023-11-05 11:57:52 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2023-11-13 15:28:13 +08:00
|
|
|
/**
|
|
|
|
* convert value by decode type or format
|
|
|
|
* @param {string|number[]} value
|
|
|
|
* @param {string} [decode]
|
|
|
|
* @param {string} [format]
|
|
|
|
* @return {Promise<{[format]: string, [decode]: string, value: string}>}
|
|
|
|
*/
|
|
|
|
async convertValue({ value, decode, format }) {
|
|
|
|
try {
|
|
|
|
const { data, success } = await ConvertValue(value, decode, format)
|
|
|
|
if (success) {
|
|
|
|
const { value: retVal, decode: retDecode, format: retFormat } = data
|
|
|
|
return { value: retVal, decode: retDecode, format: retFormat }
|
|
|
|
}
|
|
|
|
} catch (e) {}
|
|
|
|
return { value, decode, format }
|
|
|
|
},
|
|
|
|
|
2023-11-05 11:57:52 +08:00
|
|
|
/**
|
|
|
|
* scan keys with prefix
|
2023-12-25 16:22:29 +08:00
|
|
|
* @param {string} server
|
2023-11-05 11:57:52 +08:00
|
|
|
* @param {number} db
|
|
|
|
* @param {string} match
|
2024-03-08 16:52:26 +08:00
|
|
|
* @param {boolean} exact
|
2023-11-10 11:52:54 +08:00
|
|
|
* @param {string} [matchType]
|
2023-12-26 01:13:21 +08:00
|
|
|
* @param {number} [loadType] 0.load next; 1.load next full; 2.reload load all
|
2023-11-10 11:52:54 +08:00
|
|
|
* @returns {Promise<{keys: string[], maxKeys: number, end: boolean}>}
|
2023-11-05 11:57:52 +08:00
|
|
|
*/
|
2024-03-08 16:52:26 +08:00
|
|
|
async scanKeys({ server, db, match = '*', exact = false, matchType = '', loadType = 0 }) {
|
2023-11-05 11:57:52 +08:00
|
|
|
let resp
|
2023-12-26 01:13:21 +08:00
|
|
|
switch (loadType) {
|
|
|
|
case 0:
|
|
|
|
default:
|
2024-03-08 16:52:26 +08:00
|
|
|
resp = await LoadNextKeys(server, db, match, matchType, exact)
|
2023-12-26 01:13:21 +08:00
|
|
|
break
|
|
|
|
case 1:
|
2024-03-08 16:52:26 +08:00
|
|
|
resp = await LoadNextAllKeys(server, db, match, matchType, exact)
|
2023-12-26 01:13:21 +08:00
|
|
|
break
|
|
|
|
case 2:
|
2024-03-08 16:52:26 +08:00
|
|
|
resp = await LoadAllKeys(server, db, match, matchType, exact)
|
2023-12-26 01:13:21 +08:00
|
|
|
break
|
2023-11-05 11:57:52 +08:00
|
|
|
}
|
|
|
|
const { data, success, msg } = resp || {}
|
|
|
|
if (!success) {
|
|
|
|
throw new Error(msg)
|
|
|
|
}
|
2023-11-10 11:52:54 +08:00
|
|
|
const { keys = [], maxKeys, end } = data
|
|
|
|
return { keys, end, maxKeys, success }
|
2023-11-05 11:57:52 +08:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
2023-12-25 16:22:29 +08:00
|
|
|
* @param {string} server
|
2023-11-05 11:57:52 +08:00
|
|
|
* @param {number} db
|
2024-03-08 16:52:26 +08:00
|
|
|
* @param {string|null} match
|
|
|
|
* @param {boolean} exact
|
2023-11-05 11:57:52 +08:00
|
|
|
* @param {string|null} matchType
|
|
|
|
* @param {boolean} [all]
|
2023-11-10 11:52:54 +08:00
|
|
|
* @return {Promise<{keys: Array<string|number[]>, maxKeys: number, end: boolean}>}
|
2023-11-05 11:57:52 +08:00
|
|
|
* @private
|
|
|
|
*/
|
2024-03-08 16:52:26 +08:00
|
|
|
async _loadKeys({ server, db, match, exact, matchType, all }) {
|
2023-11-05 11:57:52 +08:00
|
|
|
if (isEmpty(match)) {
|
|
|
|
match = '*'
|
2024-03-08 16:52:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!isRedisGlob(match) && !exact) {
|
|
|
|
if (!endsWith(match, '*')) {
|
|
|
|
match = match + '*'
|
2023-11-05 11:57:52 +08:00
|
|
|
}
|
|
|
|
}
|
2024-03-08 16:52:26 +08:00
|
|
|
return this.scanKeys({ server, db, match, exact, matchType, loadType: all ? 1 : 0 })
|
2023-11-05 11:57:52 +08:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* load more keys within the database
|
2023-12-25 16:22:29 +08:00
|
|
|
* @param {string} server
|
2023-11-05 11:57:52 +08:00
|
|
|
* @param {number} db
|
|
|
|
* @return {Promise<boolean>}
|
|
|
|
*/
|
2023-12-25 16:22:29 +08:00
|
|
|
async loadMoreKeys(server, db) {
|
2024-03-08 16:52:26 +08:00
|
|
|
const { match, type: keyType, exact } = this.getKeyFilter(server)
|
|
|
|
const { keys, maxKeys, end } = await this._loadKeys({
|
|
|
|
server,
|
|
|
|
db,
|
|
|
|
match,
|
|
|
|
exact,
|
|
|
|
matchType: keyType,
|
|
|
|
all: false,
|
|
|
|
})
|
2023-12-25 16:22:29 +08:00
|
|
|
/** @type RedisServerState **/
|
|
|
|
const serverInst = this.servers[server]
|
|
|
|
if (serverInst != null) {
|
|
|
|
serverInst.setDBKeyCount(db, maxKeys)
|
|
|
|
// remove current keys below prefix
|
|
|
|
serverInst.addKeyNodes(keys)
|
|
|
|
serverInst.tidyNode('')
|
|
|
|
}
|
2023-11-05 11:57:52 +08:00
|
|
|
return end
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* load all left keys within the database
|
2023-12-25 16:22:29 +08:00
|
|
|
* @param {string} server
|
2023-11-05 11:57:52 +08:00
|
|
|
* @param {number} db
|
|
|
|
* @return {Promise<void>}
|
|
|
|
*/
|
2023-12-25 16:22:29 +08:00
|
|
|
async loadAllKeys(server, db) {
|
2024-03-08 16:52:26 +08:00
|
|
|
const { match, type: keyType, exact } = this.getKeyFilter(server)
|
|
|
|
const { keys, maxKeys } = await this._loadKeys({ server, db, match, exact, matchType: keyType, all: true })
|
2023-12-25 16:22:29 +08:00
|
|
|
/** @type RedisServerState **/
|
|
|
|
const serverInst = this.servers[server]
|
|
|
|
if (serverInst != null) {
|
|
|
|
serverInst.setDBKeyCount(db, maxKeys)
|
|
|
|
serverInst.addKeyNodes(keys)
|
|
|
|
serverInst.tidyNode('')
|
|
|
|
}
|
2023-11-05 11:57:52 +08:00
|
|
|
},
|
|
|
|
|
2023-11-10 11:52:54 +08:00
|
|
|
/**
|
|
|
|
* reload keys under layer
|
2023-12-19 20:19:41 +08:00
|
|
|
* @param {string} server
|
2023-11-10 11:52:54 +08:00
|
|
|
* @param {number} db
|
|
|
|
* @param {string} prefix
|
|
|
|
* @return {Promise<void>}
|
|
|
|
*/
|
2023-12-19 20:19:41 +08:00
|
|
|
async reloadLayer(server, db, prefix) {
|
2023-11-10 11:52:54 +08:00
|
|
|
if (isEmpty(prefix)) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
let match = prefix
|
2023-12-25 16:22:29 +08:00
|
|
|
const separator = this.getSeparator(server)
|
2023-11-10 11:52:54 +08:00
|
|
|
if (!endsWith(match, separator)) {
|
|
|
|
match += separator + '*'
|
|
|
|
} else {
|
|
|
|
match += '*'
|
|
|
|
}
|
|
|
|
// FIXME: ignore original match pattern due to redis not support combination matching
|
2024-03-08 16:52:26 +08:00
|
|
|
const { match: originMatch, type: keyType, exact } = this.getKeyFilter(server)
|
|
|
|
const { keys, maxKeys, success } = await this._loadKeys({
|
|
|
|
server,
|
|
|
|
db,
|
|
|
|
match: originMatch,
|
|
|
|
exact: false,
|
|
|
|
matchType: keyType,
|
|
|
|
all: true,
|
|
|
|
})
|
2023-11-10 11:52:54 +08:00
|
|
|
if (!success) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-12-25 16:22:29 +08:00
|
|
|
/** @type RedisServerState **/
|
|
|
|
const serverInst = this.servers[server]
|
|
|
|
if (serverInst != null) {
|
|
|
|
serverInst.setDBKeyCount(db, maxKeys)
|
|
|
|
// remove current keys below prefix
|
|
|
|
serverInst.removeKeyNode(prefix, true)
|
|
|
|
serverInst.addKeyNodes(keys)
|
|
|
|
serverInst.tidyNode(prefix)
|
|
|
|
}
|
2023-11-10 11:52:54 +08:00
|
|
|
},
|
|
|
|
|
2023-11-05 11:57:52 +08:00
|
|
|
/**
|
|
|
|
* get custom separator of connection
|
|
|
|
* @param server
|
|
|
|
* @returns {string}
|
|
|
|
* @private
|
|
|
|
*/
|
2023-12-25 16:22:29 +08:00
|
|
|
getSeparator(server) {
|
2023-11-05 11:57:52 +08:00
|
|
|
const connStore = useConnectionStore()
|
|
|
|
const { keySeparator } = connStore.getDefaultSeparator(server)
|
|
|
|
if (isEmpty(keySeparator)) {
|
|
|
|
return ':'
|
|
|
|
}
|
|
|
|
return keySeparator
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* get tree node by key name
|
|
|
|
* @param key
|
2023-12-25 16:22:29 +08:00
|
|
|
* @return {RedisNodeItem|null}
|
2023-11-05 11:57:52 +08:00
|
|
|
*/
|
|
|
|
getNode(key) {
|
|
|
|
let idx = key.indexOf('#')
|
|
|
|
if (idx < 0) {
|
|
|
|
idx = size(key)
|
|
|
|
}
|
|
|
|
const dbPart = key.substring(0, idx)
|
|
|
|
// parse server and db index
|
|
|
|
const idx2 = dbPart.lastIndexOf('/db')
|
|
|
|
if (idx2 < 0) {
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
const server = dbPart.substring(0, idx2)
|
2023-12-25 16:22:29 +08:00
|
|
|
/** @type {RedisServerState} **/
|
|
|
|
const serverInst = this.servers[server]
|
|
|
|
if (serverInst == null) {
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
|
2023-11-05 11:57:52 +08:00
|
|
|
const db = parseInt(dbPart.substring(idx2 + 3))
|
|
|
|
if (isNaN(db)) {
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
|
2023-12-25 16:22:29 +08:00
|
|
|
if (size(key) <= idx + 1) {
|
|
|
|
return null
|
2023-11-05 11:57:52 +08:00
|
|
|
}
|
2023-12-25 16:22:29 +08:00
|
|
|
// contains redis key
|
|
|
|
const keyPart = key.substring(idx + 1)
|
|
|
|
return serverInst.nodeMap.get(keyPart)
|
2023-11-05 11:57:52 +08:00
|
|
|
},
|
|
|
|
|
2024-05-14 10:09:50 +08:00
|
|
|
/**
|
|
|
|
* get parent tree node by key name
|
|
|
|
* @param key
|
|
|
|
* @return {RedisNodeItem|null}
|
|
|
|
*/
|
|
|
|
getParentNode(key) {
|
|
|
|
const i = key.indexOf('#')
|
|
|
|
if (i < 0) {
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
const [server, db] = split(key.substring(0, i), '/')
|
|
|
|
if (isEmpty(server) || isEmpty(db)) {
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
/** @type {RedisServerState} **/
|
|
|
|
const serverInst = this.servers[server]
|
|
|
|
if (serverInst == null) {
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
const separator = this.getSeparator(server)
|
|
|
|
const keyPart = key.substring(i)
|
|
|
|
const keyStartIdx = keyPart.indexOf('/')
|
|
|
|
const redisKey = keyPart.substring(keyStartIdx + 1)
|
|
|
|
const redisKeyParts = split(redisKey, separator)
|
|
|
|
const parentKey = slice(redisKeyParts, 0, size(redisKeyParts) - 1)
|
|
|
|
if (isEmpty(parentKey)) {
|
|
|
|
return serverInst.getRoot()
|
|
|
|
}
|
|
|
|
return serverInst.nodeMap.get(`${ConnectionType.RedisKey}/${join(parentKey, separator)}`)
|
|
|
|
},
|
|
|
|
|
2023-11-05 11:57:52 +08:00
|
|
|
/**
|
|
|
|
* set redis key
|
2023-11-13 15:28:13 +08:00
|
|
|
* @param {string} server
|
2023-11-05 11:57:52 +08:00
|
|
|
* @param {number} db
|
|
|
|
* @param {string|number[]} key
|
|
|
|
* @param {string} keyType
|
|
|
|
* @param {any} value
|
|
|
|
* @param {number} ttl
|
2023-11-13 15:28:13 +08:00
|
|
|
* @param {string} [format]
|
2023-11-05 11:57:52 +08:00
|
|
|
* @param {string} [decode]
|
|
|
|
* @returns {Promise<{[msg]: string, success: boolean, [nodeKey]: {string}}>}
|
|
|
|
*/
|
2023-11-13 22:41:33 +08:00
|
|
|
async setKey({ server, db, key, keyType, value, ttl, format = formatTypes.RAW, decode = decodeTypes.NONE }) {
|
2023-11-05 11:57:52 +08:00
|
|
|
try {
|
2023-11-13 15:28:13 +08:00
|
|
|
const { data, success, msg } = await SetKeyValue({
|
|
|
|
server,
|
|
|
|
db,
|
|
|
|
key,
|
|
|
|
keyType,
|
|
|
|
value,
|
|
|
|
ttl,
|
|
|
|
format,
|
|
|
|
decode,
|
|
|
|
})
|
2023-11-05 11:57:52 +08:00
|
|
|
if (success) {
|
2023-12-25 16:22:29 +08:00
|
|
|
/** @type RedisServerState **/
|
|
|
|
const serverInst = this.servers[server]
|
2024-05-21 15:55:02 +08:00
|
|
|
if (serverInst != null && serverInst.db === db) {
|
2023-12-25 16:22:29 +08:00
|
|
|
// const { value } = data
|
|
|
|
// update tree view data
|
|
|
|
const { newKey = 0 } = serverInst.addKeyNodes([key], true)
|
|
|
|
if (newKey > 0) {
|
|
|
|
serverInst.tidyNode(key)
|
|
|
|
serverInst.updateDBKeyCount(db, newKey)
|
|
|
|
}
|
2024-05-21 15:55:02 +08:00
|
|
|
|
|
|
|
const { value: updatedValue } = data
|
|
|
|
if (updatedValue != null) {
|
|
|
|
const tab = useTabStore()
|
|
|
|
tab.updateValue({ server, db, key, value: updatedValue })
|
|
|
|
}
|
2024-02-28 18:27:39 +08:00
|
|
|
}
|
2024-01-06 22:13:26 +08:00
|
|
|
// this.loadKeySummary({ server, db, key })
|
2023-11-13 15:28:13 +08:00
|
|
|
return {
|
|
|
|
success,
|
|
|
|
nodeKey: `${server}/db${db}#${ConnectionType.RedisValue}/${key}`,
|
|
|
|
updatedValue: value,
|
2023-11-05 11:57:52 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return { success, msg }
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
return { success: false, msg: e.message }
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
2023-11-13 15:28:13 +08:00
|
|
|
* update hash entry
|
2023-11-05 11:57:52 +08:00
|
|
|
* when field is set, newField is null, delete field
|
|
|
|
* when field is null, newField is set, add new field
|
|
|
|
* when both field and newField are set, and field === newField, update field
|
|
|
|
* when both field and newField are set, and field !== newField, delete field and add newField
|
2023-11-13 15:28:13 +08:00
|
|
|
* @param {string} server
|
2023-11-05 11:57:52 +08:00
|
|
|
* @param {number} db
|
|
|
|
* @param {string|number[]} key
|
|
|
|
* @param {string} field
|
2023-11-13 15:28:13 +08:00
|
|
|
* @param {string} [newField]
|
|
|
|
* @param {string} [value]
|
2023-11-17 17:20:32 +08:00
|
|
|
* @param {decodeTypes} [decode]
|
|
|
|
* @param {formatTypes} [format]
|
|
|
|
* @param {decodeTypes} [retDecode]
|
|
|
|
* @param {formatTypes} [retFormat]
|
2023-11-13 15:28:13 +08:00
|
|
|
* @param {boolean} [refresh]
|
2023-11-17 16:26:03 +08:00
|
|
|
* @param {number} [index] index for retrieve affect entries quickly
|
2023-12-14 16:35:37 +08:00
|
|
|
* @param {boolean} [reload]
|
2023-11-05 11:57:52 +08:00
|
|
|
* @returns {Promise<{[msg]: string, success: boolean, [updated]: {}}>}
|
|
|
|
*/
|
2023-11-13 15:28:13 +08:00
|
|
|
async setHash({
|
|
|
|
server,
|
|
|
|
db,
|
|
|
|
key,
|
|
|
|
field,
|
|
|
|
newField = '',
|
|
|
|
value = '',
|
|
|
|
decode = decodeTypes.NONE,
|
2023-11-13 22:41:33 +08:00
|
|
|
format = formatTypes.RAW,
|
2023-11-17 16:26:03 +08:00
|
|
|
retDecode,
|
|
|
|
retFormat,
|
|
|
|
index,
|
2023-12-14 16:35:37 +08:00
|
|
|
reload,
|
2023-11-13 15:28:13 +08:00
|
|
|
}) {
|
2023-11-05 11:57:52 +08:00
|
|
|
try {
|
2023-11-13 15:28:13 +08:00
|
|
|
const { data, success, msg } = await SetHashValue({
|
|
|
|
server,
|
|
|
|
db,
|
|
|
|
key,
|
|
|
|
field,
|
|
|
|
newField,
|
|
|
|
value,
|
|
|
|
decode,
|
|
|
|
format,
|
2023-11-17 18:41:15 +08:00
|
|
|
retDecode,
|
|
|
|
retFormat,
|
2023-11-13 15:28:13 +08:00
|
|
|
})
|
2023-11-05 11:57:52 +08:00
|
|
|
if (success) {
|
2023-11-17 16:26:03 +08:00
|
|
|
/**
|
|
|
|
* @type {{updated: HashEntryItem[], removed: HashEntryItem[], updated: HashEntryItem[], replaced: HashReplaceItem[]}}
|
|
|
|
*/
|
|
|
|
const { updated = [], removed = [], added = [], replaced = [] } = data
|
|
|
|
const tab = useTabStore()
|
|
|
|
if (!isEmpty(removed)) {
|
2023-11-17 18:41:15 +08:00
|
|
|
const removedKeys = map(removed, 'k')
|
2023-11-17 16:26:03 +08:00
|
|
|
tab.removeValueEntries({ server, db, key, type: 'hash', entries: removedKeys })
|
|
|
|
}
|
|
|
|
if (!isEmpty(updated)) {
|
|
|
|
tab.updateValueEntries({ server, db, key, type: 'hash', entries: updated })
|
|
|
|
}
|
|
|
|
if (!isEmpty(added)) {
|
|
|
|
tab.insertValueEntries({ server, db, key, type: 'hash', entries: added })
|
|
|
|
}
|
|
|
|
if (!isEmpty(replaced)) {
|
|
|
|
tab.replaceValueEntries({
|
|
|
|
server,
|
|
|
|
db,
|
|
|
|
key,
|
|
|
|
type: 'hash',
|
|
|
|
entries: replaced,
|
|
|
|
index: [index],
|
|
|
|
})
|
2023-11-08 23:45:33 +08:00
|
|
|
}
|
2023-12-14 16:35:37 +08:00
|
|
|
if (reload === true) {
|
|
|
|
this.reloadKey({ server, db, key })
|
|
|
|
} else {
|
|
|
|
// reload summary only
|
|
|
|
this.loadKeySummary({ server, db, key })
|
|
|
|
}
|
2023-11-05 11:57:52 +08:00
|
|
|
return { success, updated }
|
|
|
|
} else {
|
|
|
|
return { success, msg }
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
return { success: false, msg: e.message }
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* insert or update hash field item
|
2023-11-17 01:24:04 +08:00
|
|
|
* @param {string} server
|
2023-11-05 11:57:52 +08:00
|
|
|
* @param {number} db
|
|
|
|
* @param {string|number[]} key
|
|
|
|
* @param {number }action 0:ignore duplicated fields 1:overwrite duplicated fields
|
|
|
|
* @param {string[]} fieldItems field1, value1, filed2, value2...
|
2023-12-14 16:35:37 +08:00
|
|
|
* @param {boolean} [reload]
|
2023-11-17 01:24:04 +08:00
|
|
|
* @returns {Promise<{[msg]: string, success: boolean, [updated]: [], [added]: []}>}
|
2023-11-05 11:57:52 +08:00
|
|
|
*/
|
2023-12-14 16:35:37 +08:00
|
|
|
async addHashField({ server, db, key, action, fieldItems, reload }) {
|
2023-11-05 11:57:52 +08:00
|
|
|
try {
|
2023-11-17 01:24:04 +08:00
|
|
|
const { data, success, msg } = await AddHashField(server, db, key, action, fieldItems)
|
2023-11-05 11:57:52 +08:00
|
|
|
if (success) {
|
2023-11-17 01:24:04 +08:00
|
|
|
const { updated = [], added = [] } = data
|
2023-11-08 23:45:33 +08:00
|
|
|
const tab = useTabStore()
|
2023-11-17 01:24:04 +08:00
|
|
|
if (!isEmpty(updated)) {
|
2023-11-17 16:26:03 +08:00
|
|
|
tab.updateValueEntries({ server, db, key, type: 'hash', entries: updated })
|
2023-11-17 01:24:04 +08:00
|
|
|
}
|
|
|
|
if (!isEmpty(added)) {
|
|
|
|
tab.insertValueEntries({ server, db, key, type: 'hash', entries: added })
|
|
|
|
}
|
2023-12-14 16:35:37 +08:00
|
|
|
if (reload === true) {
|
|
|
|
this.reloadKey({ server, db, key })
|
|
|
|
} else {
|
|
|
|
// reload summary only
|
|
|
|
this.loadKeySummary({ server, db, key })
|
|
|
|
}
|
2023-11-17 01:24:04 +08:00
|
|
|
return { success, updated, added }
|
2023-11-05 11:57:52 +08:00
|
|
|
} else {
|
|
|
|
return { success: false, msg }
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
return { success: false, msg: e.message }
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2024-05-22 17:10:58 +08:00
|
|
|
/**
|
|
|
|
* get hash field
|
|
|
|
* @param {string} server
|
|
|
|
* @param {number} db
|
|
|
|
* @param {string} key
|
|
|
|
* @param {string} field
|
|
|
|
* @param {decodeTypes} [decode]
|
|
|
|
* @param {formatTypes} [format]
|
|
|
|
* @return {Promise<{{msg: string, success: boolean, updated: HashEntryItem[]}>}
|
|
|
|
*/
|
|
|
|
async getHashField({ server, db, key, field, decode = decodeTypes.NONE, format = formatTypes.RAW }) {
|
|
|
|
try {
|
|
|
|
const { data, success, msg } = await GetHashValue({ server, db, key, field, decode, format })
|
|
|
|
if (success && !isEmpty(data)) {
|
|
|
|
const tab = useTabStore()
|
|
|
|
tab.updateValueEntries({ server, db, key, type: 'hash', entries: [data] })
|
|
|
|
return { success, updated: data }
|
|
|
|
} else {
|
|
|
|
return { success: false, msg }
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
return { success: false, msg: e.message }
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2023-11-05 11:57:52 +08:00
|
|
|
/**
|
|
|
|
* remove hash field
|
2023-11-15 23:41:53 +08:00
|
|
|
* @param {string} server
|
2023-11-05 11:57:52 +08:00
|
|
|
* @param {number} db
|
2023-11-15 23:41:53 +08:00
|
|
|
* @param {string|number[]} key
|
2023-11-05 11:57:52 +08:00
|
|
|
* @param {string} field
|
2023-12-14 16:35:37 +08:00
|
|
|
* @param {boolean} reload
|
2023-11-05 11:57:52 +08:00
|
|
|
* @returns {Promise<{[msg]: {}, success: boolean, [removed]: string[]}>}
|
|
|
|
*/
|
2023-12-14 16:35:37 +08:00
|
|
|
async removeHashField({ server, db, key, field, reload }) {
|
2023-11-05 11:57:52 +08:00
|
|
|
try {
|
2023-11-15 23:41:53 +08:00
|
|
|
const { data, success, msg } = await SetHashValue({ server, db, key, field, newField: '' })
|
2023-11-05 11:57:52 +08:00
|
|
|
if (success) {
|
|
|
|
const { removed = [] } = data
|
2023-11-15 23:41:53 +08:00
|
|
|
// if (!isEmpty(removed)) {
|
|
|
|
// const tab = useTabStore()
|
|
|
|
// tab.removeValueEntries({ server, db, key, type: 'hash', entries: removed })
|
|
|
|
// }
|
2023-12-14 16:35:37 +08:00
|
|
|
if (reload === true) {
|
|
|
|
this.reloadKey({ server, db, key })
|
|
|
|
} else {
|
|
|
|
// reload summary only
|
|
|
|
this.loadKeySummary({ server, db, key })
|
|
|
|
}
|
2023-11-05 11:57:52 +08:00
|
|
|
return { success, removed }
|
|
|
|
} else {
|
|
|
|
return { success, msg }
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
return { success: false, msg: e.message }
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* prepend item to head of list
|
2023-11-15 23:41:53 +08:00
|
|
|
* @param {string} server
|
|
|
|
* @param {number} db
|
|
|
|
* @param {string|number[]} key
|
|
|
|
* @param {string[]} values
|
2023-12-14 16:35:37 +08:00
|
|
|
* @param {boolean} reload
|
2023-11-08 23:45:33 +08:00
|
|
|
* @returns {Promise<{[msg]: string, success: boolean, [item]: []}>}
|
2023-11-05 11:57:52 +08:00
|
|
|
*/
|
2023-12-14 16:35:37 +08:00
|
|
|
async prependListItem({ server, db, key, values, reload }) {
|
2023-11-05 11:57:52 +08:00
|
|
|
try {
|
2023-11-15 23:41:53 +08:00
|
|
|
const { data, success, msg } = await AddListItem(server, db, key, 0, values)
|
2023-11-05 11:57:52 +08:00
|
|
|
if (success) {
|
|
|
|
const { left = [] } = data
|
2023-11-08 23:45:33 +08:00
|
|
|
if (!isEmpty(left)) {
|
|
|
|
const tab = useTabStore()
|
2023-11-17 01:24:04 +08:00
|
|
|
tab.insertValueEntries({
|
2023-11-15 23:41:53 +08:00
|
|
|
server: server,
|
2023-11-08 23:45:33 +08:00
|
|
|
db,
|
|
|
|
key,
|
|
|
|
type: 'list',
|
2023-11-17 01:24:04 +08:00
|
|
|
entries: left,
|
2023-11-08 23:45:33 +08:00
|
|
|
prepend: true,
|
|
|
|
})
|
2023-12-14 16:35:37 +08:00
|
|
|
if (reload === true) {
|
|
|
|
this.reloadKey({ server, db, key })
|
|
|
|
} else {
|
|
|
|
// reload summary only
|
|
|
|
this.loadKeySummary({ server, db, key })
|
|
|
|
}
|
2023-11-08 23:45:33 +08:00
|
|
|
}
|
2023-11-05 11:57:52 +08:00
|
|
|
return { success, item: left }
|
|
|
|
} else {
|
|
|
|
return { success: false, msg }
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
return { success: false, msg: e.message }
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* append item to tail of list
|
2023-11-15 23:41:53 +08:00
|
|
|
* @param {string} server
|
|
|
|
* @param {number} db
|
|
|
|
* @param {string|number[]} key
|
|
|
|
* @param {string[]} values
|
2023-12-14 16:35:37 +08:00
|
|
|
* @param {boolean} [reload]
|
2023-11-08 23:45:33 +08:00
|
|
|
* @returns {Promise<{[msg]: string, success: boolean, [item]: any[]}>}
|
2023-11-05 11:57:52 +08:00
|
|
|
*/
|
2023-12-14 16:35:37 +08:00
|
|
|
async appendListItem({ server, db, key, values, reload }) {
|
2023-11-05 11:57:52 +08:00
|
|
|
try {
|
2023-11-15 23:41:53 +08:00
|
|
|
const { data, success, msg } = await AddListItem(server, db, key, 1, values)
|
2023-11-05 11:57:52 +08:00
|
|
|
if (success) {
|
|
|
|
const { right = [] } = data
|
2023-11-17 01:24:04 +08:00
|
|
|
// FIXME: do not append items if not all items loaded
|
2023-11-08 23:45:33 +08:00
|
|
|
if (!isEmpty(right)) {
|
|
|
|
const tab = useTabStore()
|
2023-11-17 01:24:04 +08:00
|
|
|
tab.insertValueEntries({
|
2023-11-15 23:41:53 +08:00
|
|
|
server: server,
|
2023-11-08 23:45:33 +08:00
|
|
|
db,
|
|
|
|
key,
|
|
|
|
type: 'list',
|
2023-11-17 01:24:04 +08:00
|
|
|
entries: right,
|
2023-11-08 23:45:33 +08:00
|
|
|
prepend: false,
|
|
|
|
})
|
2023-12-14 16:35:37 +08:00
|
|
|
if (reload === true) {
|
|
|
|
this.reloadKey({ server, db, key })
|
|
|
|
} else {
|
|
|
|
// reload summary only
|
|
|
|
this.loadKeySummary({ server, db, key })
|
|
|
|
}
|
2023-11-08 23:45:33 +08:00
|
|
|
}
|
2023-11-05 11:57:52 +08:00
|
|
|
return { success, item: right }
|
|
|
|
} else {
|
|
|
|
return { success: false, msg }
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
return { success: false, msg: e.message }
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* update value of list item by index
|
2023-11-14 14:49:16 +08:00
|
|
|
* @param {string} server
|
2023-11-05 11:57:52 +08:00
|
|
|
* @param {number} db
|
|
|
|
* @param {string|number[]} key
|
|
|
|
* @param {number} index
|
2023-11-14 14:49:16 +08:00
|
|
|
* @param {string|number[]} value
|
2023-11-15 23:41:53 +08:00
|
|
|
* @param {decodeTypes} decode
|
|
|
|
* @param {formatTypes} format
|
2023-11-17 17:20:32 +08:00
|
|
|
* @param {decodeTypes} [retDecode]
|
|
|
|
* @param {formatTypes} [retFormat]
|
2023-12-14 16:35:37 +08:00
|
|
|
* @param {boolean} [reload]
|
2023-11-17 17:20:32 +08:00
|
|
|
* @returns {Promise<{[msg]: string, success: boolean}>}
|
2023-11-05 11:57:52 +08:00
|
|
|
*/
|
2023-11-17 17:20:32 +08:00
|
|
|
async updateListItem({
|
|
|
|
server,
|
|
|
|
db,
|
|
|
|
key,
|
|
|
|
index,
|
|
|
|
value,
|
|
|
|
decode = decodeTypes.NONE,
|
|
|
|
format = formatTypes.RAW,
|
|
|
|
retDecode,
|
|
|
|
retFormat,
|
2023-12-14 16:35:37 +08:00
|
|
|
reload,
|
2023-11-17 17:20:32 +08:00
|
|
|
}) {
|
2023-11-05 11:57:52 +08:00
|
|
|
try {
|
2023-11-17 17:20:32 +08:00
|
|
|
const { data, success, msg } = await SetListItem({
|
|
|
|
server,
|
|
|
|
db,
|
|
|
|
key,
|
|
|
|
index,
|
|
|
|
value,
|
|
|
|
decode,
|
|
|
|
format,
|
|
|
|
retDecode,
|
|
|
|
retFormat,
|
|
|
|
})
|
2023-11-05 11:57:52 +08:00
|
|
|
if (success) {
|
2023-11-17 17:20:32 +08:00
|
|
|
/** @type {{replaced: ListReplaceItem[]}} **/
|
|
|
|
const { replaced = [], removed = [] } = data
|
|
|
|
const tab = useTabStore()
|
|
|
|
if (!isEmpty(replaced)) {
|
|
|
|
tab.replaceValueEntries({
|
|
|
|
server,
|
|
|
|
db,
|
|
|
|
key,
|
|
|
|
type: 'list',
|
|
|
|
entries: replaced,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
if (!isEmpty(removed)) {
|
|
|
|
const removedIndex = map(removed, 'index')
|
|
|
|
tab.removeValueEntries({
|
|
|
|
server,
|
|
|
|
db,
|
|
|
|
key,
|
|
|
|
type: 'list',
|
|
|
|
entries: removedIndex,
|
|
|
|
})
|
|
|
|
}
|
2023-12-14 16:35:37 +08:00
|
|
|
if (reload === true) {
|
|
|
|
this.reloadKey({ server, db, key })
|
|
|
|
} else {
|
|
|
|
// reload summary only
|
|
|
|
this.loadKeySummary({ server, db, key })
|
|
|
|
}
|
2023-11-17 17:20:32 +08:00
|
|
|
return { success }
|
2023-11-05 11:57:52 +08:00
|
|
|
} else {
|
|
|
|
return { success, msg }
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
return { success: false, msg: e.message }
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* remove list item
|
2023-11-14 14:49:16 +08:00
|
|
|
* @param {string} server
|
2023-11-05 11:57:52 +08:00
|
|
|
* @param {number} db
|
|
|
|
* @param {string|number[]} key
|
|
|
|
* @param {number} index
|
2023-12-14 16:35:37 +08:00
|
|
|
* @param {boolean} [reload]
|
2023-11-05 11:57:52 +08:00
|
|
|
* @returns {Promise<{[msg]: string, success: boolean, [removed]: string[]}>}
|
|
|
|
*/
|
2023-12-14 16:35:37 +08:00
|
|
|
async removeListItem({ server, db, key, index, reload }) {
|
2023-11-05 11:57:52 +08:00
|
|
|
try {
|
2023-11-14 14:49:16 +08:00
|
|
|
const { data, success, msg } = await SetListItem({ server, db, key, index })
|
2023-11-05 11:57:52 +08:00
|
|
|
if (success) {
|
|
|
|
const { removed = [] } = data
|
2023-11-17 17:20:32 +08:00
|
|
|
const tab = useTabStore()
|
|
|
|
if (!isEmpty(removed)) {
|
|
|
|
const removedIndexes = map(removed, 'index')
|
|
|
|
tab.removeValueEntries({
|
|
|
|
server,
|
|
|
|
db,
|
|
|
|
key,
|
|
|
|
type: 'list',
|
|
|
|
entries: removedIndexes,
|
|
|
|
})
|
2023-12-14 16:35:37 +08:00
|
|
|
if (reload === true) {
|
|
|
|
this.reloadKey({ server, db, key })
|
|
|
|
} else {
|
|
|
|
// reload summary only
|
|
|
|
this.loadKeySummary({ server, db, key })
|
|
|
|
}
|
2023-11-17 17:20:32 +08:00
|
|
|
}
|
2023-11-05 11:57:52 +08:00
|
|
|
return { success, removed }
|
|
|
|
} else {
|
|
|
|
return { success, msg }
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
return { success: false, msg: e.message }
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* add item to set
|
2023-11-17 01:24:04 +08:00
|
|
|
* @param {string} server
|
2023-11-05 11:57:52 +08:00
|
|
|
* @param {number} db
|
|
|
|
* @param {string|number} key
|
2023-11-08 23:45:33 +08:00
|
|
|
* @param {string|string[]} value
|
2023-12-14 16:35:37 +08:00
|
|
|
* @param {boolean} [reload]
|
2023-11-05 11:57:52 +08:00
|
|
|
* @returns {Promise<{[msg]: string, success: boolean}>}
|
|
|
|
*/
|
2023-12-14 16:35:37 +08:00
|
|
|
async addSetItem({ server, db, key, value, reload }) {
|
2023-11-05 11:57:52 +08:00
|
|
|
try {
|
2023-11-14 17:15:02 +08:00
|
|
|
if ((!value) instanceof Array) {
|
2023-11-08 23:45:33 +08:00
|
|
|
value = [value]
|
|
|
|
}
|
2023-11-17 01:24:04 +08:00
|
|
|
const { data, success, msg } = await SetSetItem(server, db, key, false, value)
|
2023-11-05 11:57:52 +08:00
|
|
|
if (success) {
|
2023-11-17 01:24:04 +08:00
|
|
|
const { added } = data
|
|
|
|
if (!isEmpty(added)) {
|
|
|
|
const tab = useTabStore()
|
|
|
|
tab.insertValueEntries({ server, db, key, type: 'set', entries: added })
|
|
|
|
}
|
2023-12-14 16:35:37 +08:00
|
|
|
if (reload === true) {
|
|
|
|
this.reloadKey({ server, db, key })
|
|
|
|
} else {
|
|
|
|
// reload summary only
|
|
|
|
this.loadKeySummary({ server, db, key })
|
|
|
|
}
|
2023-11-05 11:57:52 +08:00
|
|
|
return { success }
|
|
|
|
} else {
|
|
|
|
return { success, msg }
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
return { success: false, msg: e.message }
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* update value of set item
|
2023-11-14 17:15:02 +08:00
|
|
|
* @param {string} server
|
2023-11-05 11:57:52 +08:00
|
|
|
* @param {number} db
|
|
|
|
* @param {string|number[]} key
|
2023-11-14 17:15:02 +08:00
|
|
|
* @param {string|number[]} value
|
|
|
|
* @param {string|number[]} newValue
|
2023-11-17 18:41:15 +08:00
|
|
|
* @param {decodeTypes} [decode]
|
|
|
|
* @param {formatTypes} [format]
|
|
|
|
* @param {decodeTypes} [retDecode]
|
|
|
|
* @param {formatTypes} [retFormat]
|
2023-12-14 16:35:37 +08:00
|
|
|
* @param {boolean} [reload]
|
2023-11-17 18:41:15 +08:00
|
|
|
* @returns {Promise<{[msg]: string, success: boolean}>}
|
2023-11-05 11:57:52 +08:00
|
|
|
*/
|
2023-11-17 18:41:15 +08:00
|
|
|
async updateSetItem({
|
|
|
|
server,
|
|
|
|
db,
|
|
|
|
key,
|
|
|
|
value,
|
|
|
|
newValue,
|
|
|
|
decode = decodeTypes.NONE,
|
|
|
|
format = formatTypes.RAW,
|
|
|
|
retDecode,
|
|
|
|
retFormat,
|
2023-12-14 16:35:37 +08:00
|
|
|
reload,
|
2023-11-17 18:41:15 +08:00
|
|
|
}) {
|
2023-11-05 11:57:52 +08:00
|
|
|
try {
|
2023-11-17 18:41:15 +08:00
|
|
|
const { data, success, msg } = await UpdateSetItem({
|
|
|
|
server,
|
|
|
|
db,
|
|
|
|
key,
|
|
|
|
value,
|
|
|
|
newValue,
|
|
|
|
decode,
|
|
|
|
format,
|
|
|
|
retDecode,
|
|
|
|
retFormat,
|
|
|
|
})
|
2023-11-05 11:57:52 +08:00
|
|
|
if (success) {
|
2023-11-17 18:41:15 +08:00
|
|
|
const { added, removed } = data
|
|
|
|
const tab = useTabStore()
|
|
|
|
if (!isEmpty(removed)) {
|
|
|
|
const removedValues = map(removed, 'v')
|
|
|
|
tab.removeValueEntries({ server, db, key, type: 'set', entries: removedValues })
|
|
|
|
}
|
|
|
|
if (!isEmpty(added)) {
|
|
|
|
tab.insertValueEntries({ server, db, key, type: 'set', entries: added })
|
|
|
|
}
|
2023-12-14 16:35:37 +08:00
|
|
|
if (reload === true) {
|
|
|
|
this.reloadKey({ server, db, key })
|
|
|
|
} else {
|
|
|
|
// reload summary only
|
|
|
|
this.loadKeySummary({ server, db, key })
|
|
|
|
}
|
2023-11-17 18:41:15 +08:00
|
|
|
return { success }
|
2023-11-05 11:57:52 +08:00
|
|
|
} else {
|
2023-11-17 18:41:15 +08:00
|
|
|
return { success: false, msg }
|
2023-11-05 11:57:52 +08:00
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
return { success: false, msg: e.message }
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* remove item from set
|
2023-11-15 23:41:53 +08:00
|
|
|
* @param {string} server
|
2023-11-05 11:57:52 +08:00
|
|
|
* @param {number} db
|
|
|
|
* @param {string|number[]} key
|
|
|
|
* @param {string} value
|
2023-12-14 16:35:37 +08:00
|
|
|
* @param {boolean} [reload]
|
2023-11-05 11:57:52 +08:00
|
|
|
* @returns {Promise<{[msg]: string, success: boolean}>}
|
|
|
|
*/
|
2023-12-14 16:35:37 +08:00
|
|
|
async removeSetItem({ server, db, key, value, reload }) {
|
2023-11-05 11:57:52 +08:00
|
|
|
try {
|
2023-11-17 18:41:15 +08:00
|
|
|
const { data, success, msg } = await SetSetItem(server, db, key, true, [value])
|
2023-11-05 11:57:52 +08:00
|
|
|
if (success) {
|
2023-11-17 18:41:15 +08:00
|
|
|
const { removed } = data
|
|
|
|
const tab = useTabStore()
|
|
|
|
if (!isEmpty(removed)) {
|
|
|
|
const removedValues = map(removed, 'v')
|
|
|
|
tab.removeValueEntries({ server, db, key, type: 'set', entries: removedValues })
|
|
|
|
}
|
2023-12-14 16:35:37 +08:00
|
|
|
if (reload === true) {
|
|
|
|
this.reloadKey({ server, db, key })
|
|
|
|
} else {
|
|
|
|
// reload summary only
|
|
|
|
this.loadKeySummary({ server, db, key })
|
|
|
|
}
|
2023-11-05 11:57:52 +08:00
|
|
|
return { success }
|
|
|
|
} else {
|
|
|
|
return { success, msg }
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
return { success: false, msg: e.message }
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* add item to sorted set
|
2023-11-17 01:24:04 +08:00
|
|
|
* @param {string} server
|
2023-11-05 11:57:52 +08:00
|
|
|
* @param {number} db
|
|
|
|
* @param {string|number[]} key
|
|
|
|
* @param {number} action
|
|
|
|
* @param {Object.<string, number>} vs value: score
|
2023-12-14 16:35:37 +08:00
|
|
|
* @param {boolean} [reload]
|
2023-11-05 11:57:52 +08:00
|
|
|
* @returns {Promise<{[msg]: string, success: boolean}>}
|
|
|
|
*/
|
2023-12-14 16:35:37 +08:00
|
|
|
async addZSetItem({ server, db, key, action, vs, reload }) {
|
2023-11-05 11:57:52 +08:00
|
|
|
try {
|
2023-11-17 01:24:04 +08:00
|
|
|
const { data, success, msg } = await AddZSetValue(server, db, key, action, vs)
|
2023-11-05 11:57:52 +08:00
|
|
|
if (success) {
|
2023-11-17 01:24:04 +08:00
|
|
|
const { added, updated } = data
|
|
|
|
const tab = useTabStore()
|
|
|
|
if (!isEmpty(added)) {
|
|
|
|
tab.insertValueEntries({ server, db, key, type: 'zset', entries: added })
|
|
|
|
}
|
|
|
|
if (!isEmpty(updated)) {
|
2023-11-17 16:26:03 +08:00
|
|
|
tab.updateValueEntries({ server, db, key, type: 'zset', entries: updated })
|
2023-11-17 01:24:04 +08:00
|
|
|
}
|
2023-12-14 16:35:37 +08:00
|
|
|
if (reload === true) {
|
|
|
|
this.reloadKey({ server, db, key })
|
|
|
|
} else {
|
|
|
|
// reload summary only
|
|
|
|
this.loadKeySummary({ server, db, key })
|
|
|
|
}
|
2023-11-05 11:57:52 +08:00
|
|
|
return { success }
|
|
|
|
} else {
|
|
|
|
return { success, msg }
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
return { success: false, msg: e.message }
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* update item of sorted set
|
2023-11-15 23:41:53 +08:00
|
|
|
* @param {string} server
|
2023-11-05 11:57:52 +08:00
|
|
|
* @param {number} db
|
|
|
|
* @param {string|number[]} key
|
|
|
|
* @param {string} value
|
|
|
|
* @param {string} newValue
|
|
|
|
* @param {number} score
|
2023-11-15 23:41:53 +08:00
|
|
|
* @param {decodeTypes} decode
|
|
|
|
* @param {formatTypes} format
|
2023-11-17 18:41:15 +08:00
|
|
|
* @param {decodeTypes} [retDecode]
|
|
|
|
* @param {formatTypes} [retFormat]
|
|
|
|
* @param {number} [index] index for retrieve affect entries quickly
|
2023-12-14 16:35:37 +08:00
|
|
|
* @param {boolean} [reload]
|
2023-11-17 18:41:15 +08:00
|
|
|
* @returns {Promise<{[msg]: string, success: boolean}>}
|
2023-11-05 11:57:52 +08:00
|
|
|
*/
|
2023-11-15 23:41:53 +08:00
|
|
|
async updateZSetItem({
|
|
|
|
server,
|
|
|
|
db,
|
|
|
|
key,
|
|
|
|
value = '',
|
|
|
|
newValue,
|
|
|
|
score,
|
|
|
|
decode = decodeTypes.NONE,
|
|
|
|
format = formatTypes.RAW,
|
2023-11-17 18:41:15 +08:00
|
|
|
retDecode,
|
|
|
|
retFormat,
|
|
|
|
index,
|
2023-12-14 16:35:37 +08:00
|
|
|
reload,
|
2023-11-15 23:41:53 +08:00
|
|
|
}) {
|
2023-11-05 11:57:52 +08:00
|
|
|
try {
|
2023-11-15 23:41:53 +08:00
|
|
|
const { data, success, msg } = await UpdateZSetValue({
|
|
|
|
server,
|
|
|
|
db,
|
|
|
|
key,
|
|
|
|
value,
|
|
|
|
newValue,
|
|
|
|
score,
|
|
|
|
decode,
|
|
|
|
format,
|
2023-11-17 18:41:15 +08:00
|
|
|
retDecode,
|
|
|
|
retFormat,
|
2023-11-15 23:41:53 +08:00
|
|
|
})
|
2023-11-05 11:57:52 +08:00
|
|
|
if (success) {
|
2023-11-17 18:41:15 +08:00
|
|
|
const { updated = [], added = [], removed = [], replaced = [] } = data
|
|
|
|
const tab = useTabStore()
|
|
|
|
if (!isEmpty(removed)) {
|
|
|
|
const removedValues = map(removed, 'v')
|
|
|
|
tab.removeValueEntries({ server, db, key, type: 'zset', entries: removedValues })
|
|
|
|
}
|
|
|
|
if (!isEmpty(updated)) {
|
|
|
|
tab.updateValueEntries({ server, db, key, type: 'zset', entries: updated })
|
|
|
|
}
|
|
|
|
if (!isEmpty(added)) {
|
|
|
|
tab.insertValueEntries({ server, db, key, type: 'zset', entries: added })
|
|
|
|
}
|
|
|
|
if (!isEmpty(replaced)) {
|
|
|
|
tab.replaceValueEntries({ server, db, key, type: 'zset', entries: replaced, index: [index] })
|
|
|
|
}
|
2023-12-14 16:35:37 +08:00
|
|
|
if (reload === true) {
|
|
|
|
this.reloadKey({ server, db, key })
|
|
|
|
} else {
|
|
|
|
// reload summary only
|
|
|
|
this.loadKeySummary({ server, db, key })
|
|
|
|
}
|
2023-11-05 11:57:52 +08:00
|
|
|
return { success, updated, removed }
|
|
|
|
} else {
|
|
|
|
return { success, msg }
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
return { success: false, msg: e.message }
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* remove item from sorted set
|
2023-11-15 23:41:53 +08:00
|
|
|
* @param {string} server
|
2023-11-05 11:57:52 +08:00
|
|
|
* @param {number} db
|
|
|
|
* @param {string|number[]} key
|
|
|
|
* @param {string} value
|
2023-12-14 16:35:37 +08:00
|
|
|
* @param {boolean} [reload]
|
2023-11-05 11:57:52 +08:00
|
|
|
* @returns {Promise<{[msg]: string, success: boolean, [removed]: []}>}
|
|
|
|
*/
|
2023-12-14 16:35:37 +08:00
|
|
|
async removeZSetItem({ server, db, key, value, reload }) {
|
2023-11-05 11:57:52 +08:00
|
|
|
try {
|
2023-11-15 23:41:53 +08:00
|
|
|
const { data, success, msg } = await UpdateZSetValue({ server, db, key, value, newValue: '', score: 0 })
|
2023-11-05 11:57:52 +08:00
|
|
|
if (success) {
|
|
|
|
const { removed } = data
|
2023-11-17 18:41:15 +08:00
|
|
|
const tab = useTabStore()
|
|
|
|
if (!isEmpty(removed)) {
|
|
|
|
const removeValues = map(removed, 'v')
|
|
|
|
tab.removeValueEntries({ server, db, key, type: 'zset', entries: removeValues })
|
|
|
|
}
|
2023-12-14 16:35:37 +08:00
|
|
|
if (reload === true) {
|
|
|
|
this.reloadKey({ server, db, key })
|
|
|
|
} else {
|
|
|
|
// reload summary only
|
|
|
|
this.loadKeySummary({ server, db, key })
|
|
|
|
}
|
2023-11-15 23:41:53 +08:00
|
|
|
return { success, removed }
|
2023-11-05 11:57:52 +08:00
|
|
|
} else {
|
|
|
|
return { success, msg }
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
return { success: false, msg: e.message }
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* insert new stream field item
|
2023-11-17 01:24:04 +08:00
|
|
|
* @param {string} server
|
2023-11-05 11:57:52 +08:00
|
|
|
* @param {number} db
|
|
|
|
* @param {string|number[]} key
|
|
|
|
* @param {string} id
|
|
|
|
* @param {string[]} values field1, value1, filed2, value2...
|
2023-12-14 16:35:37 +08:00
|
|
|
* @param {boolean} [reload]
|
2023-11-08 23:45:33 +08:00
|
|
|
* @returns {Promise<{[msg]: string, success: boolean}>}
|
2023-11-05 11:57:52 +08:00
|
|
|
*/
|
2023-12-14 16:35:37 +08:00
|
|
|
async addStreamValue({ server, db, key, id, values, reload }) {
|
2023-11-05 11:57:52 +08:00
|
|
|
try {
|
2023-11-17 01:24:04 +08:00
|
|
|
const { data = {}, success, msg } = await AddStreamValue(server, db, key, id, values)
|
2023-11-05 11:57:52 +08:00
|
|
|
if (success) {
|
2023-11-17 01:24:04 +08:00
|
|
|
const { added = [] } = data
|
|
|
|
if (!isEmpty(added)) {
|
|
|
|
const tab = useTabStore()
|
|
|
|
tab.insertValueEntries({
|
|
|
|
server,
|
|
|
|
db,
|
|
|
|
key,
|
|
|
|
type: 'stream',
|
|
|
|
entries: added,
|
|
|
|
})
|
2023-12-14 16:35:37 +08:00
|
|
|
if (reload === true) {
|
|
|
|
this.reloadKey({ server, db, key })
|
|
|
|
} else {
|
|
|
|
// reload summary only
|
|
|
|
this.loadKeySummary({ server, db, key })
|
|
|
|
}
|
2023-11-17 01:24:04 +08:00
|
|
|
}
|
2023-11-08 23:45:33 +08:00
|
|
|
return { success }
|
2023-11-05 11:57:52 +08:00
|
|
|
} else {
|
|
|
|
return { success: false, msg }
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
return { success: false, msg: e.message }
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* remove stream field
|
2023-12-14 16:35:37 +08:00
|
|
|
* @param {string} server
|
2023-11-05 11:57:52 +08:00
|
|
|
* @param {number} db
|
|
|
|
* @param {string|number[]} key
|
|
|
|
* @param {string[]|string} ids
|
2023-12-14 16:35:37 +08:00
|
|
|
* @param {boolean} [reload]
|
2023-11-08 23:45:33 +08:00
|
|
|
* @returns {Promise<{[msg]: {}, success: boolean}>}
|
2023-11-05 11:57:52 +08:00
|
|
|
*/
|
2023-12-14 16:35:37 +08:00
|
|
|
async removeStreamValues({ server, db, key, ids, reload }) {
|
2023-11-05 11:57:52 +08:00
|
|
|
if (typeof ids === 'string') {
|
|
|
|
ids = [ids]
|
|
|
|
}
|
|
|
|
try {
|
2023-12-14 16:35:37 +08:00
|
|
|
const { data = {}, success, msg } = await RemoveStreamValues(server, db, key, ids)
|
2023-11-05 11:57:52 +08:00
|
|
|
if (success) {
|
2023-11-18 00:51:40 +08:00
|
|
|
const tab = useTabStore()
|
2023-12-14 16:35:37 +08:00
|
|
|
tab.removeValueEntries({ server, db, key, type: 'stream', entries: ids })
|
|
|
|
if (reload === true) {
|
|
|
|
this.reloadKey({ server, db, key })
|
|
|
|
} else {
|
|
|
|
// reload summary only
|
|
|
|
this.loadKeySummary({ server, db, key })
|
|
|
|
}
|
2023-11-08 23:45:33 +08:00
|
|
|
return { success }
|
2023-11-05 11:57:52 +08:00
|
|
|
} else {
|
|
|
|
return { success, msg }
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
return { success: false, msg: e.message }
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* reset key's ttl
|
2023-12-25 16:22:29 +08:00
|
|
|
* @param {string} server
|
2023-11-05 11:57:52 +08:00
|
|
|
* @param {number} db
|
2024-01-05 00:36:48 +08:00
|
|
|
* @param {string|number[]} key
|
2023-11-05 11:57:52 +08:00
|
|
|
* @param {number} ttl
|
|
|
|
* @returns {Promise<boolean>}
|
|
|
|
*/
|
2023-12-25 16:22:29 +08:00
|
|
|
async setTTL(server, db, key, ttl) {
|
2023-11-05 11:57:52 +08:00
|
|
|
try {
|
2023-12-25 16:22:29 +08:00
|
|
|
const { success, msg } = await SetKeyTTL(server, db, key, ttl)
|
2024-01-05 00:36:48 +08:00
|
|
|
if (success) {
|
|
|
|
const tabStore = useTabStore()
|
|
|
|
tabStore.updateTTL({
|
|
|
|
server,
|
|
|
|
db,
|
2024-01-06 01:25:20 +08:00
|
|
|
key: nativeRedisKey(key),
|
2024-01-05 00:36:48 +08:00
|
|
|
ttl,
|
|
|
|
})
|
|
|
|
}
|
2023-11-05 11:57:52 +08:00
|
|
|
return success === true
|
|
|
|
} catch (e) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2024-01-05 00:36:48 +08:00
|
|
|
async setTTLs(server, db, keys, ttl) {
|
|
|
|
// const msgRef = $message.loading('', { duration: 0, closable: true })
|
|
|
|
// let updated = []
|
|
|
|
// let failCount = 0
|
|
|
|
// let canceled = false
|
|
|
|
const serialNo = Date.now().valueOf().toString()
|
|
|
|
// const eventName = 'ttling:' + serialNo
|
|
|
|
// const cancelEvent = 'ttling:stop:' + serialNo
|
|
|
|
try {
|
|
|
|
// let maxProgress = 0
|
|
|
|
// EventsOn(eventName, ({ total, progress, processing }) => {
|
|
|
|
// // update delete progress
|
|
|
|
// if (progress > maxProgress) {
|
|
|
|
// maxProgress = progress
|
|
|
|
// }
|
|
|
|
// const k = decodeRedisKey(processing)
|
|
|
|
// msgRef.content = i18nGlobal.t('dialogue.delete.doing', {
|
|
|
|
// key: k,
|
|
|
|
// index: maxProgress,
|
|
|
|
// count: total,
|
|
|
|
// })
|
|
|
|
// })
|
|
|
|
// msgRef.onClose = () => {
|
|
|
|
// EventsEmit(cancelEvent)
|
|
|
|
// }
|
|
|
|
const { data, success, msg } = await BatchSetTTL(server, db, keys, ttl, serialNo)
|
|
|
|
if (success) {
|
|
|
|
// canceled = get(data, 'canceled', false)
|
|
|
|
// updated = get(data, 'updated', [])
|
|
|
|
// failCount = get(data, 'failed', 0)
|
|
|
|
} else {
|
|
|
|
$message.error(msg)
|
|
|
|
}
|
|
|
|
} finally {
|
|
|
|
// msgRef.destroy()
|
|
|
|
// EventsOff(eventName)
|
|
|
|
}
|
|
|
|
$message.success(i18nGlobal.t('dialogue.ttl.success'))
|
|
|
|
// const deletedCount = size(updated)
|
|
|
|
// if (canceled) {
|
|
|
|
// $message.info(i18nGlobal.t('dialogue.handle_cancel'))
|
|
|
|
// } else if (failCount <= 0) {
|
|
|
|
// // no fail
|
|
|
|
// $message.success(i18nGlobal.t('dialogue.delete.completed', { success: deletedCount, fail: failCount }))
|
|
|
|
// } else if (failCount >= deletedCount) {
|
|
|
|
// // all fail
|
|
|
|
// $message.error(i18nGlobal.t('dialogue.delete.completed', { success: deletedCount, fail: failCount }))
|
|
|
|
// } else {
|
|
|
|
// // some fail
|
2024-01-23 17:37:00 +08:00
|
|
|
// $message.warning(i18nGlobal.t('dialogue.delete.completed', { success: deletedCount, fail: failCount }))
|
2024-01-05 00:36:48 +08:00
|
|
|
// }
|
|
|
|
},
|
|
|
|
|
2023-11-05 11:57:52 +08:00
|
|
|
/**
|
|
|
|
* delete redis key
|
2023-12-25 16:22:29 +08:00
|
|
|
* @param {string} server
|
2023-11-05 11:57:52 +08:00
|
|
|
* @param {number} db
|
|
|
|
* @param {string|number[]} key
|
|
|
|
* @param {boolean} [soft] do not try to remove from redis if true, just remove from tree data
|
|
|
|
* @returns {Promise<boolean>}
|
|
|
|
*/
|
2023-12-25 16:22:29 +08:00
|
|
|
async deleteKey(server, db, key, soft) {
|
2023-11-05 11:57:52 +08:00
|
|
|
try {
|
2024-01-03 17:58:21 +08:00
|
|
|
let deleteCount = 1
|
2023-11-05 11:57:52 +08:00
|
|
|
if (soft !== true) {
|
2023-12-25 16:22:29 +08:00
|
|
|
const { data } = await DeleteKey(server, db, key)
|
2023-11-05 13:00:03 +08:00
|
|
|
deleteCount = get(data, 'deleteCount', 0)
|
2023-11-05 11:57:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
const k = nativeRedisKey(key)
|
|
|
|
// update tree view data
|
2023-12-25 16:22:29 +08:00
|
|
|
/** @type RedisServerState **/
|
|
|
|
const serverInst = this.servers[server]
|
|
|
|
if (serverInst != null) {
|
|
|
|
serverInst.removeKeyNode(k)
|
|
|
|
serverInst.tidyNode(k, true)
|
|
|
|
serverInst.updateDBKeyCount(db, -deleteCount)
|
|
|
|
}
|
2023-11-05 11:57:52 +08:00
|
|
|
|
|
|
|
// set tab content empty
|
|
|
|
const tab = useTabStore()
|
2023-12-25 16:22:29 +08:00
|
|
|
tab.emptyTab(server)
|
2024-01-04 00:44:27 +08:00
|
|
|
tab.setSelectedKeys(server)
|
|
|
|
tab.setCheckedKeys(server)
|
2023-11-05 11:57:52 +08:00
|
|
|
return true
|
|
|
|
} finally {
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
2023-12-03 12:27:05 +08:00
|
|
|
* delete multiple keys
|
|
|
|
* @param {string} server
|
2023-11-05 11:57:52 +08:00
|
|
|
* @param {number} db
|
2023-12-03 12:27:05 +08:00
|
|
|
* @param {string[]|number[][]} keys
|
|
|
|
* @return {Promise<void>}
|
2023-11-05 11:57:52 +08:00
|
|
|
*/
|
2024-01-23 17:37:00 +08:00
|
|
|
async deleteKeys(server, db, keys) {
|
2024-01-23 11:26:15 +08:00
|
|
|
const msgRef = $message.loading(i18nGlobal.t('dialogue.delete.deleting'), { duration: 0, closable: true })
|
2023-12-19 20:10:01 +08:00
|
|
|
let deleted = []
|
2023-12-13 11:48:27 +08:00
|
|
|
let failCount = 0
|
2023-12-19 20:10:01 +08:00
|
|
|
let canceled = false
|
|
|
|
const serialNo = Date.now().valueOf().toString()
|
2024-01-23 11:26:15 +08:00
|
|
|
msgRef.onClose = () => {
|
|
|
|
EventsEmit('delete:stop:' + serialNo)
|
|
|
|
}
|
|
|
|
try {
|
2024-01-23 17:37:00 +08:00
|
|
|
const { success, msg, data } = await DeleteKeys(server, db, keys, serialNo)
|
2023-12-19 20:10:01 +08:00
|
|
|
if (success) {
|
|
|
|
canceled = get(data, 'canceled', false)
|
|
|
|
deleted = get(data, 'deleted', [])
|
|
|
|
failCount = get(data, 'failed', 0)
|
|
|
|
} else {
|
|
|
|
$message.error(msg)
|
2023-11-05 11:57:52 +08:00
|
|
|
}
|
2023-12-13 11:48:27 +08:00
|
|
|
} finally {
|
2023-12-27 15:44:08 +08:00
|
|
|
msgRef.destroy()
|
2023-12-13 11:48:27 +08:00
|
|
|
// clear checked keys
|
|
|
|
const tab = useTabStore()
|
|
|
|
tab.setCheckedKeys(server)
|
2024-06-17 18:29:56 +08:00
|
|
|
}
|
|
|
|
// refresh model data
|
|
|
|
const deletedCount = size(deleted)
|
|
|
|
if (canceled) {
|
|
|
|
$message.info(i18nGlobal.t('dialogue.handle_cancel'))
|
|
|
|
} else if (failCount <= 0) {
|
|
|
|
// no fail
|
|
|
|
$message.success(i18nGlobal.t('dialogue.delete.completed', { success: deletedCount, fail: failCount }))
|
|
|
|
} else if (failCount >= deletedCount) {
|
|
|
|
// all fail
|
|
|
|
$message.error(i18nGlobal.t('dialogue.delete.completed', { success: deletedCount, fail: failCount }))
|
|
|
|
} else {
|
|
|
|
// some fail
|
|
|
|
$message.warning(i18nGlobal.t('dialogue.delete.completed', { success: deletedCount, fail: failCount }))
|
|
|
|
}
|
|
|
|
// update ui
|
|
|
|
timeout(100).then(async () => {
|
|
|
|
/** @type RedisServerState **/
|
|
|
|
const serverInst = this.servers[server]
|
|
|
|
if (serverInst != null) {
|
|
|
|
let start = now()
|
|
|
|
for (let i = 0; i < deleted.length; i++) {
|
|
|
|
serverInst.removeKeyNode(deleted[i], false)
|
|
|
|
if (now() - start > 300) {
|
|
|
|
await timeout(100)
|
|
|
|
start = now()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
serverInst.tidyNode('', true)
|
|
|
|
serverInst.updateDBKeyCount(db, -deletedCount)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* delete multiple keys by pattern
|
|
|
|
* @param server
|
|
|
|
* @param db
|
|
|
|
* @param pattern
|
|
|
|
* @return {Promise<void>}
|
|
|
|
*/
|
|
|
|
async deleteByPattern(server, db, pattern) {
|
|
|
|
const msgRef = $message.loading(i18nGlobal.t('dialogue.delete.deleting'), { duration: 0, closable: true })
|
|
|
|
let deleted = []
|
|
|
|
let failCount = 0
|
|
|
|
let canceled = false
|
|
|
|
try {
|
|
|
|
const { success, msg, data } = await DeleteKeysByPattern(server, db, pattern)
|
|
|
|
if (success) {
|
|
|
|
canceled = get(data, 'canceled', false)
|
|
|
|
deleted = get(data, 'deleted', [])
|
|
|
|
failCount = get(data, 'failed', 0)
|
|
|
|
} else {
|
|
|
|
$message.error(msg)
|
|
|
|
}
|
|
|
|
} finally {
|
|
|
|
msgRef.destroy()
|
|
|
|
// clear checked keys
|
|
|
|
const tab = useTabStore()
|
|
|
|
tab.setCheckedKeys(server)
|
2023-11-05 11:57:52 +08:00
|
|
|
}
|
2023-12-03 12:27:05 +08:00
|
|
|
// refresh model data
|
2023-12-19 20:10:01 +08:00
|
|
|
const deletedCount = size(deleted)
|
|
|
|
if (canceled) {
|
|
|
|
$message.info(i18nGlobal.t('dialogue.handle_cancel'))
|
|
|
|
} else if (failCount <= 0) {
|
2023-12-03 12:27:05 +08:00
|
|
|
// no fail
|
2024-01-23 17:37:00 +08:00
|
|
|
$message.success(i18nGlobal.t('dialogue.delete.completed', { success: deletedCount, fail: failCount }))
|
2023-12-03 12:27:05 +08:00
|
|
|
} else if (failCount >= deletedCount) {
|
|
|
|
// all fail
|
2024-01-23 17:37:00 +08:00
|
|
|
$message.error(i18nGlobal.t('dialogue.delete.completed', { success: deletedCount, fail: failCount }))
|
2023-12-03 12:27:05 +08:00
|
|
|
} else {
|
|
|
|
// some fail
|
2024-01-23 17:37:00 +08:00
|
|
|
$message.warning(i18nGlobal.t('dialogue.delete.completed', { success: deletedCount, fail: failCount }))
|
2023-12-03 12:27:05 +08:00
|
|
|
}
|
2023-12-26 12:04:46 +08:00
|
|
|
// update ui
|
|
|
|
timeout(100).then(async () => {
|
|
|
|
/** @type RedisServerState **/
|
|
|
|
const serverInst = this.servers[server]
|
|
|
|
if (serverInst != null) {
|
|
|
|
let start = now()
|
|
|
|
for (let i = 0; i < deleted.length; i++) {
|
|
|
|
serverInst.removeKeyNode(deleted[i], false)
|
|
|
|
if (now() - start > 300) {
|
|
|
|
await timeout(100)
|
|
|
|
start = now()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
serverInst.tidyNode('', true)
|
|
|
|
serverInst.updateDBKeyCount(db, -deletedCount)
|
|
|
|
}
|
|
|
|
})
|
2023-11-05 11:57:52 +08:00
|
|
|
},
|
|
|
|
|
2023-12-18 00:58:20 +08:00
|
|
|
/**
|
|
|
|
* export multiple keys
|
|
|
|
* @param {string} server
|
|
|
|
* @param {number} db
|
|
|
|
* @param {string[]|number[][]} keys
|
|
|
|
* @param {string} path
|
2023-12-27 17:41:51 +08:00
|
|
|
* @param {boolean} [expire]
|
2023-12-18 00:58:20 +08:00
|
|
|
* @returns {Promise<void>}
|
|
|
|
*/
|
2023-12-27 17:41:51 +08:00
|
|
|
async exportKeys(server, db, keys, path, expire) {
|
2023-12-27 15:44:08 +08:00
|
|
|
const msgRef = $message.loading('', { duration: 0, closable: true })
|
2023-12-18 00:58:20 +08:00
|
|
|
let exported = 0
|
|
|
|
let failCount = 0
|
|
|
|
let canceled = false
|
2024-01-23 11:26:15 +08:00
|
|
|
const cancelEventFn = EventsOn('exporting:' + path, ({ total, progress, processing }) => {
|
|
|
|
// update export progress
|
|
|
|
msgRef.content = i18nGlobal.t('dialogue.export.exporting', {
|
|
|
|
// key: decodeRedisKey(processing),
|
|
|
|
index: progress,
|
|
|
|
count: total,
|
2023-12-18 00:58:20 +08:00
|
|
|
})
|
2024-01-23 11:26:15 +08:00
|
|
|
})
|
|
|
|
msgRef.onClose = () => {
|
|
|
|
EventsEmit('export:stop:' + path)
|
|
|
|
}
|
|
|
|
try {
|
2023-12-27 17:41:51 +08:00
|
|
|
const { data, success, msg } = await ExportKey(server, db, keys, path, expire)
|
2023-12-18 00:58:20 +08:00
|
|
|
if (success) {
|
|
|
|
canceled = get(data, 'canceled', false)
|
|
|
|
exported = get(data, 'exported', 0)
|
|
|
|
failCount = get(data, 'failed', 0)
|
|
|
|
} else {
|
|
|
|
$message.error(msg)
|
|
|
|
}
|
|
|
|
} finally {
|
2023-12-27 15:44:08 +08:00
|
|
|
msgRef.destroy()
|
2024-01-23 11:26:15 +08:00
|
|
|
cancelEventFn()
|
2023-12-18 00:58:20 +08:00
|
|
|
}
|
|
|
|
if (canceled) {
|
|
|
|
$message.info(i18nGlobal.t('dialogue.handle_cancel'))
|
|
|
|
} else if (failCount <= 0) {
|
|
|
|
// no fail
|
|
|
|
$message.success(
|
|
|
|
i18nGlobal.t('dialogue.export.export_completed', { success: exported, fail: failCount }),
|
|
|
|
)
|
|
|
|
} else if (failCount >= exported) {
|
|
|
|
// all fail
|
|
|
|
$message.error(i18nGlobal.t('dialogue.export.export_completed', { success: exported, fail: failCount }))
|
|
|
|
} else {
|
|
|
|
// some fail
|
2024-01-23 17:37:00 +08:00
|
|
|
$message.warning(
|
|
|
|
i18nGlobal.t('dialogue.export.export_completed', {
|
|
|
|
success: exported,
|
|
|
|
fail: failCount,
|
|
|
|
}),
|
|
|
|
)
|
2023-12-18 00:58:20 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2023-12-27 15:44:08 +08:00
|
|
|
/**
|
|
|
|
* import multiple keys from csv file
|
|
|
|
* @param {string} server
|
|
|
|
* @param {number} db
|
|
|
|
* @param {string} path
|
2023-12-27 17:41:51 +08:00
|
|
|
* @param {number} conflict
|
2024-01-05 17:46:12 +08:00
|
|
|
* @param {number} [ttl] <0:use previous; ==0: persist; >0: custom ttl
|
2024-01-03 18:44:51 +08:00
|
|
|
* @param {boolean} [reload]
|
2023-12-27 15:44:08 +08:00
|
|
|
* @return {Promise<void>}
|
|
|
|
*/
|
2024-01-05 17:46:12 +08:00
|
|
|
async importKeysFromCSVFile(server, db, path, conflict, ttl, reload) {
|
2023-12-27 15:44:08 +08:00
|
|
|
const msgRef = $message.loading('', { duration: 0, closable: true })
|
|
|
|
let imported = 0
|
|
|
|
let ignored = 0
|
|
|
|
let canceled = false
|
2024-01-23 11:26:15 +08:00
|
|
|
const cancelEventFn = EventsOn('importing:' + path, ({ imported = 0, ignored = 0 }) => {
|
|
|
|
// update export progress
|
|
|
|
msgRef.content = i18nGlobal.t('dialogue.import.importing', {
|
|
|
|
// key: decodeRedisKey(processing),
|
|
|
|
imported,
|
|
|
|
conflict: ignored,
|
2023-12-27 15:44:08 +08:00
|
|
|
})
|
2024-01-23 11:26:15 +08:00
|
|
|
})
|
|
|
|
msgRef.onClose = () => {
|
|
|
|
EventsEmit('import:stop:' + path)
|
|
|
|
}
|
|
|
|
try {
|
2024-01-05 17:46:12 +08:00
|
|
|
const { data, success, msg } = await ImportCSV(server, db, path, conflict, ttl)
|
2023-12-27 15:44:08 +08:00
|
|
|
if (success) {
|
|
|
|
canceled = get(data, 'canceled', false)
|
|
|
|
imported = get(data, 'imported', 0)
|
|
|
|
ignored = get(data, 'ignored', 0)
|
|
|
|
} else {
|
|
|
|
$message.error(msg)
|
|
|
|
}
|
|
|
|
} finally {
|
2024-01-23 11:26:15 +08:00
|
|
|
cancelEventFn()
|
2023-12-27 15:44:08 +08:00
|
|
|
msgRef.destroy()
|
|
|
|
}
|
|
|
|
if (canceled) {
|
|
|
|
$message.info(i18nGlobal.t('dialogue.handle_cancel'))
|
|
|
|
} else {
|
2024-01-03 18:44:51 +08:00
|
|
|
// finish
|
2023-12-27 15:44:08 +08:00
|
|
|
$message.success(i18nGlobal.t('dialogue.import.import_completed', { success: imported, ignored }))
|
2024-01-03 18:44:51 +08:00
|
|
|
if (reload) {
|
|
|
|
this.reloadServer(server)
|
|
|
|
}
|
2023-12-27 15:44:08 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2023-11-05 11:57:52 +08:00
|
|
|
/**
|
|
|
|
* flush database
|
2024-01-05 18:24:38 +08:00
|
|
|
* @param {string} server
|
|
|
|
* @param {number} db
|
|
|
|
* @param {boolean} async
|
2023-11-05 11:57:52 +08:00
|
|
|
* @return {Promise<boolean>}
|
|
|
|
*/
|
2023-12-25 16:22:29 +08:00
|
|
|
async flushDatabase(server, db, async) {
|
2023-11-05 11:57:52 +08:00
|
|
|
try {
|
2023-12-25 16:22:29 +08:00
|
|
|
const { success = false } = await FlushDB(server, db, async)
|
2023-11-05 11:57:52 +08:00
|
|
|
|
|
|
|
if (success === true) {
|
2023-12-25 16:22:29 +08:00
|
|
|
/** @type RedisServerState **/
|
|
|
|
const serverInst = this.servers[server]
|
|
|
|
if (serverInst != null) {
|
|
|
|
// update tree view data
|
|
|
|
serverInst.removeKeyNode()
|
|
|
|
}
|
2023-11-05 11:57:52 +08:00
|
|
|
// set tab content empty
|
|
|
|
const tab = useTabStore()
|
2023-12-25 16:22:29 +08:00
|
|
|
tab.emptyTab(server)
|
2023-12-27 18:02:35 +08:00
|
|
|
tab.setSelectedKeys(server)
|
|
|
|
tab.setCheckedKeys(server)
|
2024-01-05 20:48:57 +08:00
|
|
|
tab.setExpandedKeys(server)
|
2023-11-05 11:57:52 +08:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
} finally {
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* rename key
|
2023-12-07 10:39:50 +08:00
|
|
|
* @param {string} server
|
2023-11-05 11:57:52 +08:00
|
|
|
* @param {number} db
|
|
|
|
* @param {string} key
|
|
|
|
* @param {string} newKey
|
2023-11-08 23:45:33 +08:00
|
|
|
* @returns {Promise<{[msg]: string, success: boolean, [nodeKey]: string}>}
|
2023-11-05 11:57:52 +08:00
|
|
|
*/
|
2023-12-07 10:39:50 +08:00
|
|
|
async renameKey(server, db, key, newKey) {
|
|
|
|
const { success = false, msg } = await RenameKey(server, db, key, newKey)
|
2023-11-05 11:57:52 +08:00
|
|
|
if (success) {
|
|
|
|
// delete old key and add new key struct
|
2023-12-25 16:22:29 +08:00
|
|
|
/** @type RedisServerState **/
|
|
|
|
const serverInst = this.servers[server]
|
|
|
|
if (serverInst != null) {
|
|
|
|
serverInst.renameKey(key, newKey)
|
|
|
|
}
|
2023-12-07 10:39:50 +08:00
|
|
|
return { success: true, nodeKey: `${server}/db${db}#${ConnectionType.RedisValue}/${newKey}` }
|
2023-11-05 11:57:52 +08:00
|
|
|
} else {
|
|
|
|
return { success: false, msg }
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* get command history
|
|
|
|
* @param {number} [pageNo]
|
|
|
|
* @param {number} [pageSize]
|
|
|
|
* @returns {Promise<HistoryItem[]>}
|
|
|
|
*/
|
|
|
|
async getCmdHistory(pageNo, pageSize) {
|
|
|
|
if (pageNo === undefined || pageSize === undefined) {
|
|
|
|
pageNo = -1
|
|
|
|
pageSize = -1
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
const { success, data = { list: [] } } = await GetCmdHistory(pageNo, pageSize)
|
|
|
|
const { list } = data
|
|
|
|
return list
|
|
|
|
} catch {
|
|
|
|
return []
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* clean cmd history
|
|
|
|
* @return {Promise<boolean>}
|
|
|
|
*/
|
|
|
|
async cleanCmdHistory() {
|
|
|
|
try {
|
|
|
|
const { success } = await CleanCmdHistory()
|
|
|
|
return success === true
|
|
|
|
} catch {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2024-01-25 00:29:15 +08:00
|
|
|
/**
|
|
|
|
* get client list info
|
|
|
|
* @param {string} server
|
|
|
|
* @return {Promise<{idle: number, name: string, addr: string, age: number, db: number}[]>}
|
|
|
|
*/
|
|
|
|
async getClientList(server) {
|
|
|
|
const { success, msg, data } = await GetClientList(server)
|
|
|
|
if (success) {
|
|
|
|
const { list = [] } = data
|
|
|
|
return map(list, (item) => ({
|
|
|
|
addr: item['addr'],
|
|
|
|
name: item['name'],
|
|
|
|
age: item['age'] || 0,
|
|
|
|
idle: item['idle'] || 0,
|
|
|
|
db: item['db'] || 0,
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
return []
|
|
|
|
},
|
|
|
|
|
2023-11-05 11:57:52 +08:00
|
|
|
/**
|
|
|
|
* get slow log list
|
|
|
|
* @param {string} server
|
|
|
|
* @param {number} num
|
|
|
|
* @return {Promise<[]>}
|
|
|
|
*/
|
2024-01-17 15:48:23 +08:00
|
|
|
async getSlowLog(server, num) {
|
2023-11-05 11:57:52 +08:00
|
|
|
try {
|
2024-01-17 15:48:23 +08:00
|
|
|
const { success, data = { list: [] } } = await GetSlowLogs(server, num)
|
2023-11-05 11:57:52 +08:00
|
|
|
const { list } = data
|
|
|
|
return list
|
|
|
|
} catch {
|
|
|
|
return []
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* get key filter pattern and filter type
|
|
|
|
* @param {string} server
|
2024-03-08 16:52:26 +08:00
|
|
|
* @returns {{match: string, type: string, exact: boolean}}
|
2023-11-05 11:57:52 +08:00
|
|
|
*/
|
2023-12-01 17:59:04 +08:00
|
|
|
getKeyFilter(server) {
|
2023-12-25 16:22:29 +08:00
|
|
|
let serverInst = this.servers[server]
|
|
|
|
if (serverInst == null) {
|
|
|
|
serverInst = new RedisServerState({
|
|
|
|
name: server,
|
|
|
|
separator: this.getSeparator(name),
|
|
|
|
})
|
2023-11-05 11:57:52 +08:00
|
|
|
}
|
2023-12-25 16:22:29 +08:00
|
|
|
return serverInst.getFilter()
|
2023-11-05 11:57:52 +08:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
2023-12-01 17:59:04 +08:00
|
|
|
*
|
2023-11-05 11:57:52 +08:00
|
|
|
* @param {string} server
|
2023-12-01 17:59:04 +08:00
|
|
|
* @param {string} [pattern]
|
2023-12-25 16:22:29 +08:00
|
|
|
* @param {string} [type]
|
2024-03-08 16:52:26 +08:00
|
|
|
* @param {boolean} [exact]
|
2023-11-05 11:57:52 +08:00
|
|
|
*/
|
2024-03-08 16:52:26 +08:00
|
|
|
setKeyFilter(server, { pattern, type, exact = false }) {
|
2023-12-25 16:22:29 +08:00
|
|
|
const serverInst = this.servers[server]
|
|
|
|
if (serverInst != null) {
|
2024-03-08 16:52:26 +08:00
|
|
|
serverInst.setFilter({ pattern, type, exact })
|
2023-12-25 16:22:29 +08:00
|
|
|
}
|
2023-11-05 11:57:52 +08:00
|
|
|
},
|
2024-03-05 11:48:55 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param {string} server
|
|
|
|
* @param {string} key
|
|
|
|
* @param {number} db
|
|
|
|
* @param {string} format
|
|
|
|
* @param {string} decode
|
|
|
|
*/
|
|
|
|
setSelectedFormat(server, key, db, format, decode) {
|
|
|
|
const serverInst = this.servers[server]
|
|
|
|
if (serverInst == null) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
serverInst.addDecodeHistory(key, db, format, decode)
|
|
|
|
},
|
2023-11-05 11:57:52 +08:00
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
export default useBrowserStore
|