feat: add sync/async delete key option to delete key dialog

This commit is contained in:
tiny-craft 2023-10-16 01:09:04 +08:00
parent 4a0807e463
commit d61eb1323f
5 changed files with 37 additions and 16 deletions

View File

@ -1330,7 +1330,7 @@ func (c *connectionService) SetKeyTTL(connName string, db int, k any, ttl int64)
} }
// DeleteKey remove redis key // DeleteKey remove redis key
func (c *connectionService) DeleteKey(connName string, db int, k any) (resp types.JSResp) { func (c *connectionService) DeleteKey(connName string, db int, k any, async bool) (resp types.JSResp) {
client, ctx, err := c.getRedisClient(connName, db) client, ctx, err := c.getRedisClient(connName, db)
if err != nil { if err != nil {
resp.Msg = err.Error() resp.Msg = err.Error()
@ -1344,10 +1344,15 @@ func (c *connectionService) DeleteKey(connName string, db int, k any) (resp type
var mutex sync.Mutex var mutex sync.Mutex
del := func(ctx context.Context, cli redis.UniversalClient) error { del := func(ctx context.Context, cli redis.UniversalClient) error {
iter := cli.Scan(ctx, 0, key, 10000).Iterator() iter := cli.Scan(ctx, 0, key, 10000).Iterator()
var fn func(c context.Context, ks ...string) *redis.IntCmd
if async {
fn = cli.Unlink
} else {
fn = cli.Del
}
for iter.Next(ctx) { for iter.Next(ctx) {
subKey := iter.Val() subKey := iter.Val()
if err = cli.Unlink(ctx, subKey).Err(); err != nil { if err = fn(ctx, subKey).Err(); err != nil {
log.Println("unlink error", err.Error())
return err return err
} else { } else {
mutex.Lock() mutex.Lock()
@ -1373,11 +1378,17 @@ func (c *connectionService) DeleteKey(connName string, db int, k any) (resp type
} }
} else { } else {
// delete key only // delete key only
_, err = client.Del(ctx, key).Result() if async {
if err != nil { if _, err = client.Unlink(ctx, key).Result(); err != nil {
resp.Msg = err.Error() resp.Msg = err.Error()
return return
} }
} else {
if _, err = client.Del(ctx, key).Result(); err != nil {
resp.Msg = err.Error()
return
}
}
deletedKeys = append(deletedKeys, key) deletedKeys = append(deletedKeys, key)
} }

View File

@ -12,6 +12,7 @@ const deleteForm = reactive({
showAffected: false, showAffected: false,
loadingAffected: false, loadingAffected: false,
affectedKeys: [], affectedKeys: [],
async: true,
}) })
const dialogStore = useDialog() const dialogStore = useDialog()
@ -27,6 +28,7 @@ watch(
deleteForm.showAffected = false deleteForm.showAffected = false
deleteForm.loadingAffected = false deleteForm.loadingAffected = false
deleteForm.affectedKeys = [] deleteForm.affectedKeys = []
deleteForm.async = true
} }
}, },
) )
@ -50,8 +52,8 @@ const resetAffected = () => {
const i18n = useI18n() const i18n = useI18n()
const onConfirmDelete = async () => { const onConfirmDelete = async () => {
try { try {
const { server, db, key } = deleteForm const { server, db, key, async } = deleteForm
const success = await connectionStore.deleteKeyPrefix(server, db, key) const success = await connectionStore.deleteKeyPrefix(server, db, key, async)
if (success) { if (success) {
$message.success(i18n.t('dialogue.handle_succ')) $message.success(i18n.t('dialogue.handle_succ'))
} }
@ -86,6 +88,9 @@ const onClose = () => {
<n-form-item :label="$t('dialogue.key.key_expression')" required> <n-form-item :label="$t('dialogue.key.key_expression')" required>
<n-input v-model:value="deleteForm.key" placeholder="" @input="resetAffected" /> <n-input v-model:value="deleteForm.key" placeholder="" @input="resetAffected" />
</n-form-item> </n-form-item>
<n-form-item :label="$t('dialogue.key.async_delete')" required>
<n-checkbox v-model:checked="deleteForm.async">{{ $t('dialogue.key.async_delete_title') }}</n-checkbox>
</n-form-item>
<n-card v-if="deleteForm.showAffected" :title="$t('dialogue.key.affected_key')" size="small"> <n-card v-if="deleteForm.showAffected" :title="$t('dialogue.key.affected_key')" size="small">
<n-skeleton v-if="deleteForm.loadingAffected" :repeat="10" text /> <n-skeleton v-if="deleteForm.loadingAffected" :repeat="10" text />
<n-log <n-log

View File

@ -199,7 +199,9 @@
"key_expression": "Key Expression", "key_expression": "Key Expression",
"affected_key": "Affected Keys", "affected_key": "Affected Keys",
"show_affected_key": "Show Affected Keys", "show_affected_key": "Show Affected Keys",
"confirm_delete_key": "Confirm Delete {num} Keys" "confirm_delete_key": "Confirm Delete {num} Key(s)",
"async_delete": "Asynchronously Execute",
"async_delete_title": "Do not waiting for the operation's result"
}, },
"field": { "field": {
"new": "Add New Field", "new": "Add New Field",

View File

@ -198,7 +198,9 @@
"key_expression": "键名表达式", "key_expression": "键名表达式",
"affected_key": "受影响的键名", "affected_key": "受影响的键名",
"show_affected_key": "查看受影响的键名", "show_affected_key": "查看受影响的键名",
"confirm_delete_key": "确认删除{num}个键" "confirm_delete_key": "确认删除{num}个键",
"async_delete": "异步执行",
"async_delete_title": "不等待操作结果"
}, },
"field": { "field": {
"new": "添加新字段", "new": "添加新字段",

View File

@ -1479,12 +1479,13 @@ const useConnectionStore = defineStore('connections', {
/** /**
* delete keys with prefix * delete keys with prefix
* @param connName * @param {string} connName
* @param db * @param {number} db
* @param prefix * @param {string} prefix
* @param {boolean} async
* @returns {Promise<boolean>} * @returns {Promise<boolean>}
*/ */
async deleteKeyPrefix(connName, db, prefix) { async deleteKeyPrefix(connName, db, prefix, async) {
if (isEmpty(prefix)) { if (isEmpty(prefix)) {
return false return false
} }
@ -1492,7 +1493,7 @@ const useConnectionStore = defineStore('connections', {
if (!endsWith(prefix, '*')) { if (!endsWith(prefix, '*')) {
prefix += '*' prefix += '*'
} }
const { data, success, msg } = await DeleteKey(connName, db, prefix) const { data, success, msg } = await DeleteKey(connName, db, prefix, async)
if (success) { if (success) {
// const { deleted: keys = [] } = data // const { deleted: keys = [] } = data
// for (const key of keys) { // for (const key of keys) {