diff --git a/backend/services/connection_service.go b/backend/services/connection_service.go
index 651e4a9..8ac8dbd 100644
--- a/backend/services/connection_service.go
+++ b/backend/services/connection_service.go
@@ -545,7 +545,7 @@ func (c *connectionService) ScanKeys(connName string, db int, match, keyType str
filterType := len(keyType) > 0
- var keys []string
+ var keys []any
//keys := map[string]keyItem{}
var cursor uint64
for {
@@ -559,7 +559,9 @@ func (c *connectionService) ScanKeys(connName string, db int, match, keyType str
resp.Msg = err.Error()
return
}
- keys = append(keys, loadedKey...)
+ for _, k := range loadedKey {
+ keys = append(keys, strutil.EncodeRedisKey(k))
+ }
//for _, k := range loadedKey {
// //t, _ := rdb.Type(ctx, k).Result()
// keys[k] = keyItem{Type: "t"}
@@ -579,13 +581,14 @@ func (c *connectionService) ScanKeys(connName string, db int, match, keyType str
}
// GetKeyValue get value by key
-func (c *connectionService) GetKeyValue(connName string, db int, key, viewAs string) (resp types.JSResp) {
+func (c *connectionService) GetKeyValue(connName string, db int, k any, viewAs string) (resp types.JSResp) {
rdb, ctx, err := c.getRedisClient(connName, db)
if err != nil {
resp.Msg = err.Error()
return
}
+ key := strutil.DecodeRedisKey(k)
var keyType string
var dur time.Duration
keyType, err = rdb.Type(ctx, key).Result()
@@ -717,13 +720,14 @@ func (c *connectionService) GetKeyValue(connName string, db int, key, viewAs str
// SetKeyValue set value by key
// @param ttl <= 0 means keep current ttl
-func (c *connectionService) SetKeyValue(connName string, db int, key, keyType string, value any, ttl int64, viewAs string) (resp types.JSResp) {
+func (c *connectionService) SetKeyValue(connName string, db int, k any, keyType string, value any, ttl int64, viewAs string) (resp types.JSResp) {
rdb, ctx, err := c.getRedisClient(connName, db)
if err != nil {
resp.Msg = err.Error()
return
}
+ key := strutil.DecodeRedisKey(k)
var expiration time.Duration
if ttl < 0 {
if expiration, err = rdb.PTTL(ctx, key).Result(); err != nil {
@@ -839,13 +843,14 @@ func (c *connectionService) SetKeyValue(connName string, db int, key, keyType st
}
// SetHashValue set hash field
-func (c *connectionService) SetHashValue(connName string, db int, key, field, newField, value string) (resp types.JSResp) {
+func (c *connectionService) SetHashValue(connName string, db int, k any, field, newField, value string) (resp types.JSResp) {
rdb, ctx, err := c.getRedisClient(connName, db)
if err != nil {
resp.Msg = err.Error()
return
}
+ key := strutil.DecodeRedisKey(k)
var removedField []string
updatedField := map[string]string{}
if len(field) <= 0 {
@@ -884,13 +889,14 @@ func (c *connectionService) SetHashValue(connName string, db int, key, field, ne
}
// AddHashField add or update hash field
-func (c *connectionService) AddHashField(connName string, db int, key string, action int, fieldItems []any) (resp types.JSResp) {
+func (c *connectionService) AddHashField(connName string, db int, k any, action int, fieldItems []any) (resp types.JSResp) {
rdb, ctx, err := c.getRedisClient(connName, db)
if err != nil {
resp.Msg = err.Error()
return
}
+ key := strutil.DecodeRedisKey(k)
updated := map[string]any{}
switch action {
case 1:
@@ -929,13 +935,14 @@ func (c *connectionService) AddHashField(connName string, db int, key string, ac
}
// AddListItem add item to list or remove from it
-func (c *connectionService) AddListItem(connName string, db int, key string, action int, items []any) (resp types.JSResp) {
+func (c *connectionService) AddListItem(connName string, db int, k any, action int, items []any) (resp types.JSResp) {
rdb, ctx, err := c.getRedisClient(connName, db)
if err != nil {
resp.Msg = err.Error()
return
}
+ key := strutil.DecodeRedisKey(k)
var leftPush, rightPush []any
switch action {
case 0:
@@ -961,13 +968,14 @@ func (c *connectionService) AddListItem(connName string, db int, key string, act
}
// SetListItem update or remove list item by index
-func (c *connectionService) SetListItem(connName string, db int, key string, index int64, value string) (resp types.JSResp) {
+func (c *connectionService) SetListItem(connName string, db int, k any, index int64, value string) (resp types.JSResp) {
rdb, ctx, err := c.getRedisClient(connName, db)
if err != nil {
resp.Msg = err.Error()
return
}
+ key := strutil.DecodeRedisKey(k)
var removed []int64
updated := map[int64]string{}
if len(value) <= 0 {
@@ -1003,13 +1011,14 @@ func (c *connectionService) SetListItem(connName string, db int, key string, ind
}
// SetSetItem add members to set or remove from set
-func (c *connectionService) SetSetItem(connName string, db int, key string, remove bool, members []any) (resp types.JSResp) {
+func (c *connectionService) SetSetItem(connName string, db int, k any, remove bool, members []any) (resp types.JSResp) {
rdb, ctx, err := c.getRedisClient(connName, db)
if err != nil {
resp.Msg = err.Error()
return
}
+ key := strutil.DecodeRedisKey(k)
if remove {
_, err = rdb.SRem(ctx, key, members...).Result()
} else {
@@ -1025,13 +1034,14 @@ func (c *connectionService) SetSetItem(connName string, db int, key string, remo
}
// UpdateSetItem replace member of set
-func (c *connectionService) UpdateSetItem(connName string, db int, key, value, newValue string) (resp types.JSResp) {
+func (c *connectionService) UpdateSetItem(connName string, db int, k any, value, newValue string) (resp types.JSResp) {
rdb, ctx, err := c.getRedisClient(connName, db)
if err != nil {
resp.Msg = err.Error()
return
}
+ key := strutil.DecodeRedisKey(k)
_, _ = rdb.SRem(ctx, key, value).Result()
_, err = rdb.SAdd(ctx, key, newValue).Result()
if err != nil {
@@ -1044,13 +1054,14 @@ func (c *connectionService) UpdateSetItem(connName string, db int, key, value, n
}
// UpdateZSetValue update value of sorted set member
-func (c *connectionService) UpdateZSetValue(connName string, db int, key, value, newValue string, score float64) (resp types.JSResp) {
+func (c *connectionService) UpdateZSetValue(connName string, db int, k any, value, newValue string, score float64) (resp types.JSResp) {
rdb, ctx, err := c.getRedisClient(connName, db)
if err != nil {
resp.Msg = err.Error()
return
}
+ key := strutil.DecodeRedisKey(k)
updated := map[string]any{}
var removed []string
if len(newValue) <= 0 {
@@ -1094,13 +1105,14 @@ func (c *connectionService) UpdateZSetValue(connName string, db int, key, value,
}
// AddZSetValue add item to sorted set
-func (c *connectionService) AddZSetValue(connName string, db int, key string, action int, valueScore map[string]float64) (resp types.JSResp) {
+func (c *connectionService) AddZSetValue(connName string, db int, k any, action int, valueScore map[string]float64) (resp types.JSResp) {
rdb, ctx, err := c.getRedisClient(connName, db)
if err != nil {
resp.Msg = err.Error()
return
}
+ key := strutil.DecodeRedisKey(k)
members := maputil.ToSlice(valueScore, func(k string) redis.Z {
return redis.Z{
Score: valueScore[k],
@@ -1126,13 +1138,14 @@ func (c *connectionService) AddZSetValue(connName string, db int, key string, ac
}
// AddStreamValue add stream field
-func (c *connectionService) AddStreamValue(connName string, db int, key, ID string, fieldItems []any) (resp types.JSResp) {
+func (c *connectionService) AddStreamValue(connName string, db int, k any, ID string, fieldItems []any) (resp types.JSResp) {
rdb, ctx, err := c.getRedisClient(connName, db)
if err != nil {
resp.Msg = err.Error()
return
}
+ key := strutil.DecodeRedisKey(k)
_, err = rdb.XAdd(ctx, &redis.XAddArgs{
Stream: key,
ID: ID,
@@ -1148,26 +1161,28 @@ func (c *connectionService) AddStreamValue(connName string, db int, key, ID stri
}
// RemoveStreamValues remove stream values by id
-func (c *connectionService) RemoveStreamValues(connName string, db int, key string, IDs []string) (resp types.JSResp) {
+func (c *connectionService) RemoveStreamValues(connName string, db int, k any, IDs []string) (resp types.JSResp) {
rdb, ctx, err := c.getRedisClient(connName, db)
if err != nil {
resp.Msg = err.Error()
return
}
+ key := strutil.DecodeRedisKey(k)
_, err = rdb.XDel(ctx, key, IDs...).Result()
resp.Success = true
return
}
// SetKeyTTL set ttl of key
-func (c *connectionService) SetKeyTTL(connName string, db int, key string, ttl int64) (resp types.JSResp) {
+func (c *connectionService) SetKeyTTL(connName string, db int, k any, ttl int64) (resp types.JSResp) {
rdb, ctx, err := c.getRedisClient(connName, db)
if err != nil {
resp.Msg = err.Error()
return
}
+ key := strutil.DecodeRedisKey(k)
var expiration time.Duration
if ttl < 0 {
if err = rdb.Persist(ctx, key).Err(); err != nil {
@@ -1187,14 +1202,15 @@ func (c *connectionService) SetKeyTTL(connName string, db int, key string, ttl i
}
// DeleteKey remove redis key
-func (c *connectionService) DeleteKey(connName string, db int, key string) (resp types.JSResp) {
+func (c *connectionService) DeleteKey(connName string, db int, k any) (resp types.JSResp) {
rdb, ctx, err := c.getRedisClient(connName, db)
if err != nil {
resp.Msg = err.Error()
return
}
- var deletedKeys []string
+ key := strutil.DecodeRedisKey(k)
+ var deletedKeys []string
if strings.HasSuffix(key, "*") {
// delete by prefix
var cursor uint64
diff --git a/backend/utils/string/common.go b/backend/utils/string/common.go
new file mode 100644
index 0000000..c93d177
--- /dev/null
+++ b/backend/utils/string/common.go
@@ -0,0 +1,19 @@
+package strutil
+
+import "unicode/utf8"
+
+func containsBinary(str string) bool {
+ //buf := []byte(str)
+ //size := 0
+ //for start := 0; start < len(buf); start += size {
+ // var r rune
+ // if r, size = utf8.DecodeRune(buf[start:]); r == utf8.RuneError {
+ // return true
+ // }
+ //}
+
+ if !utf8.ValidString(str) {
+ return true
+ }
+ return false
+}
diff --git a/backend/utils/string/convert.go b/backend/utils/string/convert.go
index 72e5caf..cae1d18 100644
--- a/backend/utils/string/convert.go
+++ b/backend/utils/string/convert.go
@@ -14,7 +14,6 @@ import (
"strconv"
"strings"
"tinyrdm/backend/types"
- "unicode/utf8"
)
// ConvertTo convert string to specified type
@@ -55,7 +54,7 @@ func ConvertTo(str, targetType string) (value, resultType string) {
return
case types.HEX:
- if hexStr, ok := decodeHex(str); ok {
+ if hexStr, ok := decodeToHex(str); ok {
value = hexStr
} else {
value = str
@@ -162,8 +161,8 @@ func autoToType(str string) (value, resultType string) {
return
}
- if isBinary(str) {
- if value, ok = decodeHex(str); ok {
+ if containsBinary(str) {
+ if value, ok = decodeToHex(str); ok {
resultType = types.HEX
return
}
@@ -175,22 +174,6 @@ func autoToType(str string) (value, resultType string) {
return
}
-func isBinary(str string) bool {
- //buf := []byte(str)
- //size := 0
- //for start := 0; start < len(buf); start += size {
- // var r rune
- // if r, size = utf8.DecodeRune(buf[start:]); r == utf8.RuneError {
- // return true
- // }
- //}
-
- if !utf8.ValidString(str) {
- return true
- }
- return false
-}
-
func decodeJson(str string) (string, bool) {
var data any
if (strings.HasPrefix(str, "{") && strings.HasSuffix(str, "}")) ||
@@ -220,7 +203,7 @@ func decodeBinary(str string) (string, bool) {
return binary.String(), true
}
-func decodeHex(str string) (string, bool) {
+func decodeToHex(str string) (string, bool) {
decodeStr := hex.EncodeToString([]byte(str))
var resultStr strings.Builder
for i := 0; i < len(decodeStr); i += 2 {
diff --git a/backend/utils/string/key_convert.go b/backend/utils/string/key_convert.go
new file mode 100644
index 0000000..ef5b3a5
--- /dev/null
+++ b/backend/utils/string/key_convert.go
@@ -0,0 +1,76 @@
+package strutil
+
+import (
+ "strconv"
+ sliceutil "tinyrdm/backend/utils/slice"
+)
+
+// EncodeRedisKey encode the redis key to integer array
+// if key contains binary which could not display on ui, convert the key to char array
+func EncodeRedisKey(key string) any {
+ if containsBinary(key) {
+ b := []byte(key)
+ arr := make([]int, len(b))
+ for i, bb := range b {
+ arr[i] = int(bb)
+ }
+ return arr
+ }
+ return key
+}
+
+// DecodeRedisKey decode redis key to readable string
+func DecodeRedisKey(key any) string {
+ switch key.(type) {
+ case string:
+ return key.(string)
+
+ case []any:
+ arr := key.([]any)
+ bytes := sliceutil.Map(arr, func(i int) byte {
+ if c, ok := AnyToInt(arr[i]); ok {
+ return byte(c)
+ }
+ return '0'
+ })
+ return string(bytes)
+
+ case []int:
+ arr := key.([]int)
+ b := make([]byte, len(arr))
+ for i, bb := range arr {
+ b[i] = byte(bb)
+ }
+ return string(b)
+ }
+ return ""
+}
+
+// AnyToInt convert any value to int
+func AnyToInt(val any) (int, bool) {
+ switch val.(type) {
+ case string:
+ num, err := strconv.Atoi(val.(string))
+ if err != nil {
+ return 0, false
+ }
+ return num, true
+ case float64:
+ return int(val.(float64)), true
+ case float32:
+ return int(val.(float32)), true
+ case int64:
+ return int(val.(int64)), true
+ case int32:
+ return int(val.(int32)), true
+ case int:
+ return val.(int), true
+ case bool:
+ if val.(bool) {
+ return 1, true
+ } else {
+ return 0, true
+ }
+ }
+ return 0, false
+}
diff --git a/frontend/src/components/common/RedisTypeTag.vue b/frontend/src/components/common/RedisTypeTag.vue
index 5ab4390..3bba2de 100644
--- a/frontend/src/components/common/RedisTypeTag.vue
+++ b/frontend/src/components/common/RedisTypeTag.vue
@@ -1,6 +1,7 @@
+
+
+
+
+
+
diff --git a/frontend/src/components/sidebar/BrowserTree.vue b/frontend/src/components/sidebar/BrowserTree.vue
index 57bd23a..baf7366 100644
--- a/frontend/src/components/sidebar/BrowserTree.vue
+++ b/frontend/src/components/sidebar/BrowserTree.vue
@@ -3,6 +3,7 @@ import { computed, h, nextTick, onMounted, reactive, ref } from 'vue'
import { ConnectionType } from '@/consts/connection_type.js'
import { NIcon, NSpace, NTag } from 'naive-ui'
import Key from '@/components/icons/Key.vue'
+import Binary from '@/components/icons/Binary.vue'
import ToggleDb from '@/components/icons/ToggleDb.vue'
import { find, get, includes, indexOf, isEmpty, pull, remove, size } from 'lodash'
import { useI18n } from 'vue-i18n'
@@ -223,7 +224,9 @@ const handleSelectContextMenu = (key) => {
return
}
const node = connectionStore.getNode(selectedKey)
- const { db, key: nodeKey, redisKey } = node || {}
+ const { db, key: nodeKey } = node || {}
+ const redisKey = node.redisKeyCode || node.redisKey
+ const redisKeyName = !!node.redisKeyCode ? node.label : redisKey
switch (key) {
case 'server_info':
tabStore.setSelectedKeys(props.server)
@@ -267,10 +270,10 @@ const handleSelectContextMenu = (key) => {
dialogStore.openDeleteKeyDialog(props.server, db, isEmpty(redisKey) ? '*' : redisKey + ':*')
break
case 'value_remove':
- $dialog.warning(i18n.t('dialogue.remove_tip', { name: redisKey }), () => {
+ $dialog.warning(i18n.t('dialogue.remove_tip', { name: redisKeyName }), () => {
connectionStore.deleteKey(props.server, db, redisKey).then((success) => {
if (success) {
- $message.success(i18n.t('dialogue.delete_key_succ', { key: redisKey }))
+ $message.success(i18n.t('dialogue.delete_key_succ', { key: redisKeyName }))
}
})
})
@@ -327,7 +330,8 @@ const onUpdateSelectedKeys = (keys, options) => {
// prevent load duplicate key
for (const node of options) {
if (node.type === ConnectionType.RedisValue) {
- const { key, db, redisKey } = node
+ const { key, db } = node
+ const redisKey = node.redisKeyCode || node.redisKey
if (!includes(selectedKeys.value, key)) {
connectionStore.loadKeyValue(props.server, db, redisKey)
}
@@ -373,7 +377,7 @@ const renderPrefix = ({ option }) => {
NIcon,
{ size: 20 },
{
- default: () => h(Key),
+ default: () => h(!!option.redisKeyCode ? Binary : Key),
},
)
}
diff --git a/frontend/src/langs/en.json b/frontend/src/langs/en.json
index 342927b..89496eb 100644
--- a/frontend/src/langs/en.json
+++ b/frontend/src/langs/en.json
@@ -80,6 +80,7 @@
"batch_delete": "Batch Delete",
"copy_path": "Copy Path",
"copy_key": "Copy Key",
+ "binary_key": "Binary Key Name",
"remove_key": "Remove Key",
"new_key": "Add New Key",
"nonexist_tab_content": "Selected key does not exist. Please retry",
@@ -105,6 +106,7 @@
"delete_key_succ": "\"{key}\" has been deleted",
"save_value_succ": "Value Saved !",
"copy_succ": "Value Copied !",
+ "rename_binary_key_fail": "Rename binary key name is unsupported",
"handle_succ": "Success!",
"reload_succ": "Reloaded!",
"field_required": "This item should not be blank",
diff --git a/frontend/src/langs/zh-cn.json b/frontend/src/langs/zh-cn.json
index 243db65..4daa08e 100644
--- a/frontend/src/langs/zh-cn.json
+++ b/frontend/src/langs/zh-cn.json
@@ -80,6 +80,7 @@
"batch_delete": "批量删除键",
"copy_path": "复制路径",
"copy_key": "复制键名",
+ "binary_key": "二进制键名",
"remove_key": "删除键",
"new_key": "添加新键",
"nonexist_tab_content": "所选键不存在,请尝试刷新重试",
@@ -105,6 +106,7 @@
"delete_key_succ": "{key} 已被删除",
"save_value_succ": "已保存值",
"copy_succ": "已复制到剪切板",
+ "rename_binary_key_fail": "不支持重命名二进制键名",
"handle_succ": "操作成功",
"reload_succ": "已重新载入",
"field_required": "此项不能为空",
diff --git a/frontend/src/stores/connections.js b/frontend/src/stores/connections.js
index d591356..a731a13 100644
--- a/frontend/src/stores/connections.js
+++ b/frontend/src/stores/connections.js
@@ -5,6 +5,7 @@ import {
get,
isEmpty,
join,
+ map,
remove,
size,
slice,
@@ -49,6 +50,7 @@ import {
import { ConnectionType } from '@/consts/connection_type.js'
import useTabStore from './tab.js'
import { types } from '@/consts/support_redis_type.js'
+import { decodeRedisKey, nativeRedisKey } from '@/utils/key_convert.js'
const useConnectionStore = defineStore('connections', {
/**
@@ -68,6 +70,7 @@ const useConnectionStore = defineStore('connections', {
* @property {number} type
* @property {number} [db] - database index, type == ConnectionType.RedisDB only
* @property {string} [redisKey] - redis key, type == ConnectionType.RedisKey || type == ConnectionType.RedisValue only
+ * @property {string} [redisKeyCode] - redis key char code array, optional for redis key which contains binary data
* @property {number} [keys] - children key count
* @property {boolean} [isLeaf]
* @property {boolean} [opened] - redis db is opened, type == ConnectionType.RedisDB only
@@ -592,7 +595,7 @@ const useConnectionStore = defineStore('connections', {
* load redis key
* @param {string} server
* @param {number} db
- * @param {string} [key] when key is null or blank, update tab to display normal content (blank content or server status)
+ * @param {string|number[]} [key] when key is null or blank, update tab to display normal content (blank content or server status)
* @param {string} [viewType]
*/
async loadKeyValue(server, db, key, viewType) {
@@ -602,12 +605,15 @@ const useConnectionStore = defineStore('connections', {
const { data, success, msg } = await GetKeyValue(server, db, key, viewType)
if (success) {
const { type, ttl, value, size, viewAs } = data
+ const k = decodeRedisKey(key)
+ const binaryKey = k !== key
tab.upsertTab({
server,
db,
type,
ttl,
- key,
+ keyCode: binaryKey ? key : undefined,
+ key: k,
value,
size,
viewAs,
@@ -629,6 +635,7 @@ const useConnectionStore = defineStore('connections', {
type: 'none',
ttl: -1,
key: null,
+ keyCode: null,
value: null,
size: 0,
})
@@ -713,7 +720,7 @@ const useConnectionStore = defineStore('connections', {
* remove keys in db
* @param {string} connName
* @param {number} db
- * @param {string[]} keys
+ * @param {Array} keys
* @param {boolean} [sortInsert]
* @return {{success: boolean, newKey: number, newLayer: number, replaceKey: number}}
* @private
@@ -735,7 +742,9 @@ const useConnectionStore = defineStore('connections', {
const nodeMap = this._getNodeMap(connName, db)
const rootChildren = selDB.children
for (const key of keys) {
- const keyParts = split(key, separator)
+ const k = decodeRedisKey(key)
+ const binaryKey = k !== key
+ const keyParts = binaryKey ? [nativeRedisKey(key)] : split(k, separator)
const len = size(keyParts)
const lastIdx = len - 1
let handlePath = ''
@@ -776,10 +785,11 @@ const useConnectionStore = defineStore('connections', {
const replaceKey = nodeMap.has(nodeKey)
const selectedNode = {
key: `${connName}/db${db}#${nodeKey}`,
- label: keyParts[i],
+ label: binaryKey ? k : keyParts[i],
db,
keys: 0,
redisKey: handlePath,
+ redisKeyCode: binaryKey ? key : undefined,
type: ConnectionType.RedisValue,
isLeaf: true,
}
@@ -926,7 +936,7 @@ const useConnectionStore = defineStore('connections', {
* set redis key
* @param {string} connName
* @param {number} db
- * @param {string} key
+ * @param {string|number[]} key
* @param {string} keyType
* @param {any} value
* @param {number} ttl
@@ -959,7 +969,7 @@ const useConnectionStore = defineStore('connections', {
* when both field and newField are set, and field !== newField, delete field and add newField
* @param {string} connName
* @param {number} db
- * @param {string} key
+ * @param {string|number[]} key
* @param {string} field
* @param {string} newField
* @param {string} value
@@ -983,7 +993,7 @@ const useConnectionStore = defineStore('connections', {
* insert or update hash field item
* @param {string} connName
* @param {number} db
- * @param {string} key
+ * @param {string|number[]} key
* @param {number }action 0:ignore duplicated fields 1:overwrite duplicated fields
* @param {string[]} fieldItems field1, value1, filed2, value2...
* @returns {Promise<{[msg]: string, success: boolean, [updated]: {}}>}
@@ -1028,7 +1038,7 @@ const useConnectionStore = defineStore('connections', {
* insert list item
* @param {string} connName
* @param {number} db
- * @param {string} key
+ * @param {string|number[]} key
* @param {int} action 0: push to head, 1: push to tail
* @param {string[]}values
* @returns {Promise<*|{msg, success: boolean}>}
@@ -1089,7 +1099,7 @@ const useConnectionStore = defineStore('connections', {
* update value of list item by index
* @param {string} connName
* @param {number} db
- * @param {string} key
+ * @param {string|number[]} key
* @param {number} index
* @param {string} value
* @returns {Promise<{[msg]: string, success: boolean, [updated]: {}}>}
@@ -1112,7 +1122,7 @@ const useConnectionStore = defineStore('connections', {
* remove list item
* @param {string} connName
* @param {number} db
- * @param {string} key
+ * @param {string|number[]} key
* @param {number} index
* @returns {Promise<{[msg]: string, success: boolean, [removed]: string[]}>}
*/
@@ -1134,7 +1144,7 @@ const useConnectionStore = defineStore('connections', {
* add item to set
* @param {string} connName
* @param {number} db
- * @param {string} key
+ * @param {string|number} key
* @param {string} value
* @returns {Promise<{[msg]: string, success: boolean}>}
*/
@@ -1155,7 +1165,7 @@ const useConnectionStore = defineStore('connections', {
* update value of set item
* @param {string} connName
* @param {number} db
- * @param {string} key
+ * @param {string|number[]} key
* @param {string} value
* @param {string} newValue
* @returns {Promise<{[msg]: string, success: boolean}>}
@@ -1175,10 +1185,10 @@ const useConnectionStore = defineStore('connections', {
/**
* remove item from set
- * @param connName
- * @param db
- * @param key
- * @param value
+ * @param {string} connName
+ * @param {number} db
+ * @param {string|number[]} key
+ * @param {string} value
* @returns {Promise<{[msg]: string, success: boolean}>}
*/
async removeSetItem(connName, db, key, value) {
@@ -1198,7 +1208,7 @@ const useConnectionStore = defineStore('connections', {
* add item to sorted set
* @param {string} connName
* @param {number} db
- * @param {string} key
+ * @param {string|number[]} key
* @param {number} action
* @param {Object.} vs value: score
* @returns {Promise<{[msg]: string, success: boolean}>}
@@ -1220,7 +1230,7 @@ const useConnectionStore = defineStore('connections', {
* update item of sorted set
* @param {string} connName
* @param {number} db
- * @param {string} key
+ * @param {string|number[]} key
* @param {string} value
* @param {string} newValue
* @param {number} score
@@ -1244,7 +1254,7 @@ const useConnectionStore = defineStore('connections', {
* remove item from sorted set
* @param {string} connName
* @param {number} db
- * @param key
+ * @param {string|number[]} key
* @param {string} value
* @returns {Promise<{[msg]: string, success: boolean, [removed]: []}>}
*/
@@ -1266,7 +1276,7 @@ const useConnectionStore = defineStore('connections', {
* insert new stream field item
* @param {string} connName
* @param {number} db
- * @param {string} key
+ * @param {string|number[]} key
* @param {string} id
* @param {string[]} values field1, value1, filed2, value2...
* @returns {Promise<{[msg]: string, success: boolean, [updated]: {}}>}
@@ -1289,7 +1299,7 @@ const useConnectionStore = defineStore('connections', {
* remove stream field
* @param {string} connName
* @param {number} db
- * @param {string} key
+ * @param {string|number[]} key
* @param {string[]|string} ids
* @returns {Promise<{[msg]: {}, success: boolean, [removed]: string[]}>}
*/
@@ -1427,7 +1437,7 @@ const useConnectionStore = defineStore('connections', {
* delete redis key
* @param {string} connName
* @param {number} db
- * @param {string} key
+ * @param {string|number[]} key
* @param {boolean} [soft] do not try to remove from redis if true, just remove from tree data
* @returns {Promise}
*/
@@ -1437,9 +1447,10 @@ const useConnectionStore = defineStore('connections', {
await DeleteKey(connName, db, key)
}
+ const k = nativeRedisKey(key)
// update tree view data
- this._deleteKeyNode(connName, db, key)
- this._tidyNode(connName, db, key, true)
+ this._deleteKeyNode(connName, db, k)
+ this._tidyNode(connName, db, k, true)
// set tab content empty
const tab = useTabStore()
diff --git a/frontend/src/stores/dialog.js b/frontend/src/stores/dialog.js
index 7d5d4b4..4652e85 100644
--- a/frontend/src/stores/dialog.js
+++ b/frontend/src/stores/dialog.js
@@ -45,6 +45,7 @@ const useDialogStore = defineStore('dialog', {
server: '',
db: 0,
key: '',
+ keyCode: null,
type: null,
},
addFieldsDialogVisible: false,
@@ -185,12 +186,14 @@ const useDialogStore = defineStore('dialog', {
* @param {string} server
* @param {number} db
* @param {string} key
+ * @param {number[]|null} keyCode
* @param {string} type
*/
- openAddFieldsDialog(server, db, key, type) {
+ openAddFieldsDialog(server, db, key, keyCode, type) {
this.addFieldParam.server = server
this.addFieldParam.db = db
this.addFieldParam.key = key
+ this.addFieldParam.keyCode = keyCode
this.addFieldParam.type = type
this.addFieldsDialogVisible = true
},
diff --git a/frontend/src/stores/tab.js b/frontend/src/stores/tab.js
index 8ed3d9b..ebc8bf2 100644
--- a/frontend/src/stores/tab.js
+++ b/frontend/src/stores/tab.js
@@ -14,6 +14,7 @@ const useTabStore = defineStore('tab', {
* @property {string} [server] server name
* @property {int} [db] database index
* @property {string} [key] current key name
+ * @property {number[]|null|undefined} [keyCode] current key name as char array
* @property {int} [ttl] ttl of current key
*/
@@ -83,11 +84,12 @@ const useTabStore = defineStore('tab', {
* @param {number} [type]
* @param {number} [ttl]
* @param {string} [key]
+ * @param {string} [keyCode]
* @param {number} [size]
* @param {*} [value]
* @param {string} [viewAs]
*/
- upsertTab({ server, db, type, ttl, key, size, value, viewAs }) {
+ upsertTab({ server, db, type, ttl, key, keyCode, size, value, viewAs }) {
let tabIndex = findIndex(this.tabList, { name: server })
if (tabIndex === -1) {
this.tabList.push({
@@ -97,6 +99,7 @@ const useTabStore = defineStore('tab', {
type,
ttl,
key,
+ keyCode,
size,
value,
viewAs,
@@ -112,6 +115,7 @@ const useTabStore = defineStore('tab', {
tab.type = type
tab.ttl = ttl
tab.key = key
+ tab.keyCode = keyCode
tab.size = size
tab.value = value
tab.viewAs = viewAs
@@ -123,7 +127,7 @@ const useTabStore = defineStore('tab', {
* update ttl by tag
* @param {string} server
* @param {number} db
- * @param {string} key
+ * @param {string|number[]} key
* @param {number} ttl
*/
updateTTL({ server, db, key, ttl }) {
diff --git a/frontend/src/utils/key_convert.js b/frontend/src/utils/key_convert.js
new file mode 100644
index 0000000..7aef0f8
--- /dev/null
+++ b/frontend/src/utils/key_convert.js
@@ -0,0 +1,35 @@
+import { join, map } from 'lodash'
+
+/**
+ * converted binary data in strings to hex format
+ * @param {string|number[]} key
+ * @return {string}
+ */
+export function decodeRedisKey(key) {
+ if (key instanceof Array) {
+ // char array, convert to hex string
+ return join(
+ map(key, (k) => {
+ if (k >= 32 && k <= 126) {
+ return String.fromCharCode(k)
+ }
+ return '\\x' + k.toString(16).toUpperCase().padStart(2, '0')
+ }),
+ '',
+ )
+ }
+
+ return key
+}
+
+/**
+ * convert char code array to string
+ * @param {string|number[]} key
+ * @return {string}
+ */
+export function nativeRedisKey(key) {
+ if (key instanceof Array) {
+ return map(key, (c) => String.fromCharCode(c)).join('')
+ }
+ return key
+}
diff --git a/wails.json b/wails.json
index 59fe550..6ffc825 100644
--- a/wails.json
+++ b/wails.json
@@ -13,7 +13,7 @@
"info": {
"companyName": "Tiny Craft",
"productName": "Tiny RDM",
- "productVersion": "0.9.0",
+ "productVersion": "1.0.0",
"copyright": "Copyright © 2023",
"comments": "Tiny Redis Desktop Manager"
}