feat: add stream type support
This commit is contained in:
parent
9b63e51300
commit
2d0e8f5445
|
@ -497,6 +497,21 @@ func (c *connectionService) GetKeyValue(connName string, db int, key string) (re
|
|||
}
|
||||
}
|
||||
value = items
|
||||
case "stream":
|
||||
var msgs []redis.XMessage
|
||||
items := []types.StreamItem{}
|
||||
msgs, err = rdb.XRevRange(ctx, key, "+", "-").Result()
|
||||
if err != nil {
|
||||
resp.Msg = err.Error()
|
||||
return
|
||||
}
|
||||
for _, msg := range msgs {
|
||||
items = append(items, types.StreamItem{
|
||||
ID: msg.ID,
|
||||
Value: msg.Values,
|
||||
})
|
||||
}
|
||||
value = items
|
||||
}
|
||||
if err != nil {
|
||||
resp.Msg = err.Error()
|
||||
|
@ -538,13 +553,10 @@ func (c *connectionService) SetKeyValue(connName string, db int, key, keyType st
|
|||
resp.Msg = "invalid list value"
|
||||
return
|
||||
} else {
|
||||
_, err = rdb.Pipelined(ctx, func(pipe redis.Pipeliner) error {
|
||||
pipe.LPush(ctx, key, strs...)
|
||||
if expiration > 0 {
|
||||
pipe.Expire(ctx, key, expiration)
|
||||
err = rdb.LPush(ctx, key, strs...).Err()
|
||||
if err == nil && expiration > 0 {
|
||||
rdb.Expire(ctx, key, expiration)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
case "hash":
|
||||
if strs, ok := value.([]any); !ok {
|
||||
|
@ -552,11 +564,7 @@ func (c *connectionService) SetKeyValue(connName string, db int, key, keyType st
|
|||
return
|
||||
} else {
|
||||
if len(strs) > 1 {
|
||||
kvs := map[string]any{}
|
||||
for i := 0; i < len(strs); i += 2 {
|
||||
kvs[strs[i].(string)] = strs[i+1]
|
||||
}
|
||||
err = rdb.HSet(ctx, key, kvs).Err()
|
||||
err = rdb.HSet(ctx, key, strs).Err()
|
||||
if err == nil && expiration > 0 {
|
||||
rdb.Expire(ctx, key, expiration)
|
||||
}
|
||||
|
@ -594,6 +602,22 @@ func (c *connectionService) SetKeyValue(connName string, db int, key, keyType st
|
|||
}
|
||||
}
|
||||
}
|
||||
case "stream":
|
||||
if strs, ok := value.([]any); !ok {
|
||||
resp.Msg = "invalid stream value"
|
||||
return
|
||||
} else {
|
||||
if len(strs) > 2 {
|
||||
err = rdb.XAdd(ctx, &redis.XAddArgs{
|
||||
Stream: key,
|
||||
ID: strs[0].(string),
|
||||
Values: strs[1:],
|
||||
}).Err()
|
||||
if err == nil && expiration > 0 {
|
||||
rdb.Expire(ctx, key, expiration)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
@ -886,6 +910,41 @@ func (c *connectionService) AddZSetValue(connName string, db int, key string, ac
|
|||
return
|
||||
}
|
||||
|
||||
// AddStreamValue add stream field
|
||||
func (c *connectionService) AddStreamValue(connName string, db int, key, ID string, fieldItems []any) (resp types.JSResp) {
|
||||
rdb, ctx, err := c.getRedisClient(connName, db)
|
||||
if err != nil {
|
||||
resp.Msg = err.Error()
|
||||
return
|
||||
}
|
||||
|
||||
_, err = rdb.XAdd(ctx, &redis.XAddArgs{
|
||||
Stream: key,
|
||||
ID: ID,
|
||||
Values: fieldItems,
|
||||
}).Result()
|
||||
if err != nil {
|
||||
resp.Msg = err.Error()
|
||||
return
|
||||
}
|
||||
|
||||
resp.Success = true
|
||||
return
|
||||
}
|
||||
|
||||
// RemoveStreamValues remove stream values by id
|
||||
func (c *connectionService) RemoveStreamValues(connName string, db int, key string, IDs []string) (resp types.JSResp) {
|
||||
rdb, ctx, err := c.getRedisClient(connName, db)
|
||||
if err != nil {
|
||||
resp.Msg = err.Error()
|
||||
return
|
||||
}
|
||||
|
||||
_, 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) {
|
||||
rdb, ctx, err := c.getRedisClient(connName, db)
|
||||
|
|
|
@ -4,3 +4,8 @@ type ZSetItem struct {
|
|||
Value string `json:"value"`
|
||||
Score float64 `json:"score"`
|
||||
}
|
||||
|
||||
type StreamItem struct {
|
||||
ID string `json:"id"`
|
||||
Value map[string]any `json:"value"`
|
||||
}
|
|
@ -8,6 +8,7 @@ import Save from '../icons/Save.vue'
|
|||
const props = defineProps({
|
||||
bindKey: String,
|
||||
editing: Boolean,
|
||||
readonly: Boolean,
|
||||
})
|
||||
|
||||
const emit = defineEmits(['edit', 'delete', 'save', 'cancel'])
|
||||
|
@ -20,7 +21,7 @@ const emit = defineEmits(['edit', 'delete', 'save', 'cancel'])
|
|||
<icon-button :icon="Close" @click="emit('cancel')" />
|
||||
</div>
|
||||
<div v-else class="flex-box-h edit-column-func">
|
||||
<icon-button :icon="Edit" @click="emit('edit')" />
|
||||
<icon-button v-if="!props.readonly" :icon="Edit" @click="emit('edit')" />
|
||||
<n-popconfirm :negative-text="$t('cancel')" :positive-text="$t('confirm')" @positive-click="emit('delete')">
|
||||
<template #trigger>
|
||||
<icon-button :icon="Delete" />
|
||||
|
|
|
@ -13,6 +13,7 @@ import useConnectionStore from '../../stores/connections.js'
|
|||
import { useI18n } from 'vue-i18n'
|
||||
import { useConfirmDialog } from '../../utils/confirm_dialog.js'
|
||||
import ContentServerStatus from '../content_value/ContentServerStatus.vue'
|
||||
import ContentValueStream from '../content_value/ContentValueStream.vue'
|
||||
|
||||
const serverInfo = ref({})
|
||||
const autoRefresh = ref(false)
|
||||
|
@ -62,6 +63,7 @@ const valueComponents = {
|
|||
[types.LIST]: ContentValueList,
|
||||
[types.SET]: ContentValueSet,
|
||||
[types.ZSET]: ContentValueZset,
|
||||
[types.STREAM]: ContentValueStream,
|
||||
}
|
||||
|
||||
const dialog = useDialog()
|
||||
|
@ -71,7 +73,7 @@ const tab = computed(() =>
|
|||
map(tabStore.tabs, (item) => ({
|
||||
key: item.name,
|
||||
label: item.title,
|
||||
}))
|
||||
})),
|
||||
)
|
||||
|
||||
watch(
|
||||
|
@ -80,7 +82,7 @@ watch(
|
|||
if (nav === 'browser') {
|
||||
refreshInfo()
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
const tabContent = computed(() => {
|
||||
|
|
|
@ -11,6 +11,8 @@ import { useMessage } from 'naive-ui'
|
|||
import IconButton from '../common/IconButton.vue'
|
||||
import useConnectionStore from '../../stores/connections.js'
|
||||
import { useConfirmDialog } from '../../utils/confirm_dialog.js'
|
||||
import Copy from '../icons/Copy.vue'
|
||||
import { ClipboardSetText } from '../../../wailsjs/runtime/runtime.js'
|
||||
|
||||
const props = defineProps({
|
||||
server: String,
|
||||
|
@ -38,6 +40,18 @@ const onReloadKey = () => {
|
|||
connectionStore.loadKeyValue(props.server, props.db, props.keyPath)
|
||||
}
|
||||
|
||||
const onCopyKey = () => {
|
||||
ClipboardSetText(props.keyPath)
|
||||
.then((succ) => {
|
||||
if (succ) {
|
||||
message.success(i18n.t('copy_succ'))
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
message.error(e.message)
|
||||
})
|
||||
}
|
||||
|
||||
const confirmDialog = useConfirmDialog()
|
||||
const onDeleteKey = () => {
|
||||
confirmDialog.warning(i18n.t('remove_tip', { name: props.keyPath }), () => {
|
||||
|
@ -53,12 +67,13 @@ const onDeleteKey = () => {
|
|||
<template>
|
||||
<div class="content-toolbar flex-box-h">
|
||||
<n-input-group>
|
||||
<redis-type-tag :type="props.keyType" size="large"></redis-type-tag>
|
||||
<redis-type-tag :type="props.keyType" size="large" />
|
||||
<n-input v-model:value="props.keyPath">
|
||||
<template #suffix>
|
||||
<icon-button :icon="Refresh" t-tooltip="reload" size="18" @click="onReloadKey" />
|
||||
</template>
|
||||
</n-input>
|
||||
<icon-button :icon="Copy" t-tooltip="copy_key" size="18" border @click="onCopyKey" />
|
||||
</n-input-group>
|
||||
<n-button-group>
|
||||
<n-tooltip>
|
||||
|
|
|
@ -0,0 +1,202 @@
|
|||
<script setup>
|
||||
import { computed, h, reactive, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import ContentToolbar from './ContentToolbar.vue'
|
||||
import AddLink from '../icons/AddLink.vue'
|
||||
import { NButton, NCode, NIcon, NInput, useMessage } from 'naive-ui'
|
||||
import { types, types as redisTypes } from '../../consts/support_redis_type.js'
|
||||
import EditableTableColumn from '../common/EditableTableColumn.vue'
|
||||
import useDialogStore from '../../stores/dialog.js'
|
||||
import useConnectionStore from '../../stores/connections.js'
|
||||
import { includes, keys, some, values } from 'lodash'
|
||||
|
||||
const i18n = useI18n()
|
||||
|
||||
const props = defineProps({
|
||||
name: String,
|
||||
db: Number,
|
||||
keyPath: String,
|
||||
ttl: {
|
||||
type: Number,
|
||||
default: -1,
|
||||
},
|
||||
value: Object,
|
||||
})
|
||||
|
||||
const filterOption = computed(() => [
|
||||
{
|
||||
value: 1,
|
||||
label: i18n.t('field'),
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
label: i18n.t('value'),
|
||||
},
|
||||
])
|
||||
const filterType = ref(1)
|
||||
|
||||
const connectionStore = useConnectionStore()
|
||||
const dialogStore = useDialogStore()
|
||||
const keyType = redisTypes.STREAM
|
||||
const idColumn = reactive({
|
||||
key: 'id',
|
||||
title: 'ID',
|
||||
align: 'center',
|
||||
titleAlign: 'center',
|
||||
resizable: true,
|
||||
})
|
||||
const valueColumn = reactive({
|
||||
key: 'value',
|
||||
title: i18n.t('value'),
|
||||
align: 'center',
|
||||
titleAlign: 'center',
|
||||
resizable: true,
|
||||
filterOptionValue: null,
|
||||
filter(value, row) {
|
||||
const v = value.toString()
|
||||
if (filterType.value === 1) {
|
||||
// filter key
|
||||
return some(keys(row.value), (key) => includes(key, v))
|
||||
} else {
|
||||
// filter value
|
||||
return some(values(row.value), (val) => includes(val, v))
|
||||
}
|
||||
},
|
||||
// sorter: (row1, row2) => row1.value - row2.value,
|
||||
// ellipsis: {
|
||||
// tooltip: true
|
||||
// },
|
||||
render: (row) => {
|
||||
return h(NCode, { language: 'json', wordWrap: true }, { default: () => JSON.stringify(row.value) })
|
||||
},
|
||||
})
|
||||
const actionColumn = {
|
||||
key: 'action',
|
||||
title: i18n.t('action'),
|
||||
width: 60,
|
||||
align: 'center',
|
||||
titleAlign: 'center',
|
||||
fixed: 'right',
|
||||
render: (row) => {
|
||||
return h(EditableTableColumn, {
|
||||
bindKey: row.id,
|
||||
readonly: true,
|
||||
onDelete: async () => {
|
||||
try {
|
||||
const { success, msg } = await connectionStore.removeStreamValues(
|
||||
props.name,
|
||||
props.db,
|
||||
props.keyPath,
|
||||
row.id,
|
||||
)
|
||||
if (success) {
|
||||
connectionStore.loadKeyValue(props.name, props.db, props.keyPath).then((r) => {})
|
||||
message.success(i18n.t('delete_key_succ', { key: row.id }))
|
||||
// update display value
|
||||
// if (!isEmpty(removed)) {
|
||||
// for (const elem of removed) {
|
||||
// delete props.value[elem]
|
||||
// }
|
||||
// }
|
||||
} else {
|
||||
message.error(msg)
|
||||
}
|
||||
} catch (e) {
|
||||
message.error(e.message)
|
||||
}
|
||||
},
|
||||
})
|
||||
},
|
||||
}
|
||||
const columns = reactive([idColumn, valueColumn, actionColumn])
|
||||
|
||||
const tableData = computed(() => {
|
||||
const data = []
|
||||
for (const elem of props.value) {
|
||||
data.push({
|
||||
id: elem.id,
|
||||
value: elem.value,
|
||||
})
|
||||
}
|
||||
return data
|
||||
})
|
||||
const message = useMessage()
|
||||
const onAddRow = () => {
|
||||
dialogStore.openAddFieldsDialog(props.name, props.db, props.keyPath, types.STREAM)
|
||||
}
|
||||
|
||||
const filterValue = ref('')
|
||||
const onFilterInput = (val) => {
|
||||
valueColumn.filterOptionValue = val
|
||||
}
|
||||
|
||||
const onChangeFilterType = (type) => {
|
||||
onFilterInput(filterValue.value)
|
||||
}
|
||||
|
||||
const clearFilter = () => {
|
||||
idColumn.filterOptionValue = null
|
||||
valueColumn.filterOptionValue = null
|
||||
}
|
||||
|
||||
const onUpdateFilter = (filters, sourceColumn) => {
|
||||
switch (filterType.value) {
|
||||
case filterOption[0].value:
|
||||
idColumn.filterOptionValue = filters[sourceColumn.key]
|
||||
break
|
||||
case filterOption[1].value:
|
||||
valueColumn.filterOptionValue = filters[sourceColumn.key]
|
||||
break
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="content-wrapper flex-box-v">
|
||||
<content-toolbar :db="props.db" :key-path="props.keyPath" :key-type="keyType" :server="props.name" :ttl="ttl" />
|
||||
<div class="tb2 flex-box-h">
|
||||
<div class="flex-box-h">
|
||||
<n-input-group>
|
||||
<n-select
|
||||
v-model:value="filterType"
|
||||
:consistent-menu-width="false"
|
||||
:options="filterOption"
|
||||
style="width: 120px"
|
||||
@update:value="onChangeFilterType"
|
||||
/>
|
||||
<n-input
|
||||
v-model:value="filterValue"
|
||||
:placeholder="$t('search')"
|
||||
clearable
|
||||
@clear="clearFilter"
|
||||
@update:value="onFilterInput"
|
||||
/>
|
||||
</n-input-group>
|
||||
</div>
|
||||
<div class="flex-item-expand"></div>
|
||||
<n-button plain @click="onAddRow">
|
||||
<template #icon>
|
||||
<n-icon :component="AddLink" size="18" />
|
||||
</template>
|
||||
{{ $t('add_row') }}
|
||||
</n-button>
|
||||
</div>
|
||||
<div class="fill-height flex-box-h" style="user-select: text">
|
||||
<n-data-table
|
||||
:key="(row) => row.id"
|
||||
:columns="columns"
|
||||
:data="tableData"
|
||||
:single-column="true"
|
||||
:single-line="false"
|
||||
flex-height
|
||||
max-height="100%"
|
||||
size="small"
|
||||
striped
|
||||
virtual-scroll
|
||||
@update:filters="onUpdateFilter"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped></style>
|
|
@ -10,6 +10,8 @@ import AddListValue from '../new_value/AddListValue.vue'
|
|||
import AddHashValue from '../new_value/AddHashValue.vue'
|
||||
import AddZSetValue from '../new_value/AddZSetValue.vue'
|
||||
import useConnectionStore from '../../stores/connections.js'
|
||||
import NewStreamValue from '../new_value/NewStreamValue.vue'
|
||||
import { size, slice } from 'lodash'
|
||||
|
||||
const i18n = useI18n()
|
||||
const newForm = reactive({
|
||||
|
@ -29,6 +31,7 @@ const addValueComponent = {
|
|||
[types.LIST]: AddListValue,
|
||||
[types.SET]: NewSetValue,
|
||||
[types.ZSET]: AddZSetValue,
|
||||
[types.STREAM]: NewStreamValue,
|
||||
}
|
||||
const defaultValue = {
|
||||
[types.STRING]: '',
|
||||
|
@ -36,6 +39,7 @@ const defaultValue = {
|
|||
[types.LIST]: [],
|
||||
[types.SET]: [],
|
||||
[types.ZSET]: [],
|
||||
[types.STREAM]: ['*'],
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -52,6 +56,8 @@ const title = computed(() => {
|
|||
return i18n.t('new_field')
|
||||
case types.ZSET:
|
||||
return i18n.t('new_field')
|
||||
case types.STREAM:
|
||||
return i18n.t('new_field')
|
||||
}
|
||||
return ''
|
||||
})
|
||||
|
@ -69,7 +75,7 @@ watch(
|
|||
newForm.opType = 0
|
||||
newForm.value = null
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
const connectionStore = useConnectionStore()
|
||||
|
@ -143,6 +149,28 @@ const onAdd = async () => {
|
|||
}
|
||||
}
|
||||
break
|
||||
|
||||
case types.STREAM:
|
||||
{
|
||||
if (size(value) > 2) {
|
||||
const { success, msg } = await connectionStore.addStreamValue(
|
||||
server,
|
||||
db,
|
||||
key,
|
||||
value[0],
|
||||
slice(value, 1),
|
||||
)
|
||||
if (success) {
|
||||
if (newForm.reload) {
|
||||
connectionStore.loadKeyValue(server, db, key).then(() => {})
|
||||
}
|
||||
message.success(i18n.t('handle_succ'))
|
||||
} else {
|
||||
message.error(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
dialogStore.closeAddFieldsDialog()
|
||||
} catch (e) {
|
||||
|
|
|
@ -12,6 +12,7 @@ import { useI18n } from 'vue-i18n'
|
|||
import useConnectionStore from '../../stores/connections.js'
|
||||
import { NSpace, useMessage } from 'naive-ui'
|
||||
import useTabStore from '../../stores/tab.js'
|
||||
import NewStreamValue from '../new_value/NewStreamValue.vue'
|
||||
|
||||
const i18n = useI18n()
|
||||
const newForm = reactive({
|
||||
|
@ -52,6 +53,7 @@ const addValueComponent = {
|
|||
[types.LIST]: NewListValue,
|
||||
[types.SET]: NewSetValue,
|
||||
[types.ZSET]: NewZSetValue,
|
||||
[types.STREAM]: NewStreamValue,
|
||||
}
|
||||
const defaultValue = {
|
||||
[types.STRING]: '',
|
||||
|
@ -59,6 +61,7 @@ const defaultValue = {
|
|||
[types.LIST]: [],
|
||||
[types.SET]: [],
|
||||
[types.ZSET]: [],
|
||||
[types.STREAM]: [],
|
||||
}
|
||||
|
||||
const dialogStore = useDialog()
|
||||
|
@ -165,7 +168,7 @@ const onClose = () => {
|
|||
<n-input v-model:value="newForm.key" placeholder="" />
|
||||
</n-form-item>
|
||||
<n-form-item :label="$t('db_index')" path="db" required>
|
||||
<n-select v-model:value="newForm.db" :options="dbOptions" />
|
||||
<n-select v-model:value="newForm.db" :options="dbOptions" filterable />
|
||||
</n-form-item>
|
||||
<n-form-item :label="$t('type')" path="type" required>
|
||||
<n-select v-model:value="newForm.type" :options="options" :render-label="renderTypeLabel" />
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { defineOptions, ref } from 'vue'
|
||||
import { isEmpty, reject } from 'lodash'
|
||||
import Add from '../icons/Add.vue'
|
||||
import Delete from '../icons/Delete.vue'
|
||||
|
@ -10,6 +10,9 @@ const props = defineProps({
|
|||
type: Number,
|
||||
value: Object,
|
||||
})
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
})
|
||||
const emit = defineEmits(['update:value', 'update:type'])
|
||||
|
||||
const i18n = useI18n()
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
<script setup>
|
||||
import { defineOptions, ref } from 'vue'
|
||||
import { flatMap, isEmpty, reject } from 'lodash'
|
||||
import Add from '../icons/Add.vue'
|
||||
import Delete from '../icons/Delete.vue'
|
||||
import IconButton from '../common/IconButton.vue'
|
||||
|
||||
const props = defineProps({
|
||||
value: Array,
|
||||
})
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
})
|
||||
const id = ref('*')
|
||||
const emit = defineEmits(['update:value'])
|
||||
|
||||
/**
|
||||
* @typedef Hash
|
||||
* @property {string} key
|
||||
* @property {string} [value]
|
||||
*/
|
||||
const kvList = ref([{ key: '', value: '' }])
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Hash[]} val
|
||||
*/
|
||||
const onUpdate = (val) => {
|
||||
val = reject(val, { key: '' })
|
||||
const vals = flatMap(val, (item) => [item.key, item.value])
|
||||
vals.splice(0, 0, id.value || '*')
|
||||
emit('update:value', vals)
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
validate: () => {
|
||||
return !isEmpty(props.value)
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-form-item label="ID">
|
||||
<n-input v-model:value="id" />
|
||||
</n-form-item>
|
||||
<n-form-item :label="$t('element')" required>
|
||||
<n-dynamic-input
|
||||
v-model:value="kvList"
|
||||
:key-placeholder="$t('enter_field')"
|
||||
:value-placeholder="$t('enter_value')"
|
||||
preset="pair"
|
||||
@update:value="onUpdate"
|
||||
>
|
||||
<template #action="{ index, create, remove, move }">
|
||||
<icon-button v-if="kvList.length > 1" :icon="Delete" size="18" @click="() => remove(index)" />
|
||||
<icon-button :icon="Add" size="18" @click="() => create(index)" />
|
||||
</template>
|
||||
</n-dynamic-input>
|
||||
</n-form-item>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped></style>
|
|
@ -4,14 +4,16 @@ export const types = {
|
|||
LIST: 'LIST',
|
||||
SET: 'SET',
|
||||
ZSET: 'ZSET',
|
||||
STREAM: 'STREAM',
|
||||
}
|
||||
|
||||
export const typesColor = {
|
||||
[types.STRING]: '#8256DC',
|
||||
[types.HASH]: '#2983ED',
|
||||
[types.LIST]: '#26A15E',
|
||||
[types.SET]: '#EE9F33',
|
||||
[types.ZSET]: '#CE3352',
|
||||
[types.HASH]: '#0171F5',
|
||||
[types.LIST]: '#23C338',
|
||||
[types.SET]: '#F29E33',
|
||||
[types.ZSET]: '#F53227',
|
||||
[types.STREAM]: '#F5C201',
|
||||
}
|
||||
|
||||
export const typesBgColor = {
|
||||
|
@ -20,6 +22,7 @@ export const typesBgColor = {
|
|||
[types.LIST]: '#E3F3EB',
|
||||
[types.SET]: '#FDF1DF',
|
||||
[types.ZSET]: '#FAEAED',
|
||||
[types.STREAM]: '#FFF8DF',
|
||||
}
|
||||
|
||||
// export const typesName = Object.fromEntries(Object.entries(types).map(([key, value]) => [key, value.name]))
|
||||
|
|
|
@ -3,6 +3,7 @@ import { endsWith, get, isEmpty, join, remove, size, slice, sortedIndexBy, split
|
|||
import {
|
||||
AddHashField,
|
||||
AddListItem,
|
||||
AddStreamValue,
|
||||
AddZSetValue,
|
||||
CloseConnection,
|
||||
CreateGroup,
|
||||
|
@ -15,6 +16,7 @@ import {
|
|||
ListConnection,
|
||||
OpenConnection,
|
||||
OpenDatabase,
|
||||
RemoveStreamValues,
|
||||
RenameGroup,
|
||||
RenameKey,
|
||||
SaveConnection,
|
||||
|
@ -1134,6 +1136,54 @@ const useConnectionStore = defineStore('connections', {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* insert new stream field item
|
||||
* @param {string} connName
|
||||
* @param {number} db
|
||||
* @param {string} key
|
||||
* @param {string} id
|
||||
* @param {string[]} values field1, value1, filed2, value2...
|
||||
* @returns {Promise<{[msg]: string, success: boolean, [updated]: {}}>}
|
||||
*/
|
||||
async addStreamValue(connName, db, key, id, values) {
|
||||
try {
|
||||
const { data = {}, success, msg } = await AddStreamValue(connName, db, key, id, values)
|
||||
if (success) {
|
||||
const { updated = {} } = data
|
||||
return { success, updated }
|
||||
} else {
|
||||
return { success: false, msg }
|
||||
}
|
||||
} catch (e) {
|
||||
return { success: false, msg: e.message }
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* remove stream field
|
||||
* @param {string} connName
|
||||
* @param {number} db
|
||||
* @param {string} key
|
||||
* @param {string[]|string} ids
|
||||
* @returns {Promise<{[msg]: {}, success: boolean, [removed]: string[]}>}
|
||||
*/
|
||||
async removeStreamValues(connName, db, key, ids) {
|
||||
if (typeof ids === 'string') {
|
||||
ids = [ids]
|
||||
}
|
||||
try {
|
||||
const { data = {}, success, msg } = await RemoveStreamValues(connName, db, key, ids)
|
||||
if (success) {
|
||||
const { removed = [] } = data
|
||||
return { success, removed }
|
||||
} else {
|
||||
return { success, msg }
|
||||
}
|
||||
} catch (e) {
|
||||
return { success: false, msg: e.message }
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* reset key's ttl
|
||||
* @param {string} connName
|
||||
|
|
Loading…
Reference in New Issue