diff --git a/packages/web/src/appobj/DatabaseAppObject.svelte b/packages/web/src/appobj/DatabaseAppObject.svelte index 28431c2a4..a92010eda 100644 --- a/packages/web/src/appobj/DatabaseAppObject.svelte +++ b/packages/web/src/appobj/DatabaseAppObject.svelte @@ -167,6 +167,11 @@ }, }); + if (data.errorMessage) { + showSnackbarError(data.errorMessage); + return; + } + newQuery({ title: 'Export #', initialData: data, @@ -252,7 +257,7 @@ import getElectron from '../utility/getElectron'; import openNewTab from '../utility/openNewTab'; import AppObjectCore from './AppObjectCore.svelte'; - import { showSnackbarSuccess } from '../utility/snackbar'; + import { showSnackbarError, showSnackbarSuccess } from '../utility/snackbar'; import { findEngineDriver } from 'dbgate-tools'; import InputTextModal from '../modals/InputTextModal.svelte'; import { getDatabaseInfo, useUsedApps } from '../utility/metadataLoaders'; diff --git a/packages/web/src/modals/DbKeyAddItemModal.svelte b/packages/web/src/modals/DbKeyAddItemModal.svelte index a6ed6de77..ffbf1931a 100644 --- a/packages/web/src/modals/DbKeyAddItemModal.svelte +++ b/packages/web/src/modals/DbKeyAddItemModal.svelte @@ -13,8 +13,9 @@ let item = {}; const handleSubmit = async () => { - closeCurrentModal(); - onConfirm(item); + if (await onConfirm(item)) { + closeCurrentModal(); + } }; @@ -24,7 +25,7 @@
{ item = value; diff --git a/packages/web/src/tabs/DbKeyDetailTab.svelte b/packages/web/src/tabs/DbKeyDetailTab.svelte index 830ee92f4..35cbb1f24 100644 --- a/packages/web/src/tabs/DbKeyDetailTab.svelte +++ b/packages/web/src/tabs/DbKeyDetailTab.svelte @@ -24,6 +24,7 @@ import _ from 'lodash'; import DbKeyItemDetail from '../dbkeyvalue/DbKeyItemDetail.svelte'; import DbKeyAddItemModal from '../modals/DbKeyAddItemModal.svelte'; + import ErrorMessageModal from '../modals/ErrorMessageModal.svelte'; export let conid; export let database; @@ -86,13 +87,18 @@ showModal(DbKeyAddItemModal, { keyInfo, onConfirm: async row => { - await apiCall('database-connections/call-method', { + const res = await apiCall('database-connections/call-method', { conid, database, method: keyInfo.keyType.addMethod, args: [keyInfo.key, ...keyInfo.keyType.dbKeyFields.map(col => row[col.name])], }); + if (res.errorMessage) { + showModal(ErrorMessageModal, { message: res.errorMessage }); + return false; + } refresh(); + return true; }, }); } diff --git a/packages/web/src/widgets/DbKeysTreeNode.svelte b/packages/web/src/widgets/DbKeysTreeNode.svelte index d8cfcb9e6..600f24b90 100644 --- a/packages/web/src/widgets/DbKeysTreeNode.svelte +++ b/packages/web/src/widgets/DbKeysTreeNode.svelte @@ -5,12 +5,13 @@ import { plusExpandIcon } from '../icons/expandIcons'; import FontIcon from '../icons/FontIcon.svelte'; import ConfirmModal from '../modals/ConfirmModal.svelte'; -import InputTextModal from '../modals/InputTextModal.svelte'; + import InputTextModal from '../modals/InputTextModal.svelte'; import { showModal } from '../modals/modalTools'; import newQuery from '../query/newQuery'; import { activeDbKeysStore } from '../stores'; import { apiCall } from '../utility/api'; import openNewTab from '../utility/openNewTab'; +import { showSnackbarError } from '../utility/snackbar'; import DbKeysSubTree from './DbKeysSubTree.svelte'; @@ -111,6 +112,11 @@ import InputTextModal from '../modals/InputTextModal.svelte'; }, }); + if (data.errorMessage) { + showSnackbarError(data.errorMessage); + return; + } + newQuery({ title: 'Export #', initialData: data, diff --git a/plugins/dbgate-plugin-redis/src/backend/driver.js b/plugins/dbgate-plugin-redis/src/backend/driver.js index 63eb1d421..a788cbf53 100644 --- a/plugins/dbgate-plugin-redis/src/backend/driver.js +++ b/plugins/dbgate-plugin-redis/src/backend/driver.js @@ -297,6 +297,14 @@ const driver = { switch (method) { case 'mdel': return await this.deleteBranch(pool, args[0]); + case 'xaddjson': + let json; + try { + json = JSON.parse(args[2]); + } catch (e) { + throw new Error('Value must be valid JSON. ' + e.message); + } + return await pool.xadd(args[0], args[1] || '*', ..._.flatten(_.toPairs(json))); } return await pool[method](...args); }, @@ -332,6 +340,22 @@ const driver = { items: _.chunk(res[1], 2).map((item) => ({ key: item[0], value: item[1] })), }; } + case 'stream': { + const res = await pool.xrange(key, cursor == 0 ? '-' : cursor, '+', 'COUNT', count); + let newCursor = 0; + if (res.length > 0) { + const id = res[res.length - 1][0]; + const idParts = id.split('-'); + newCursor = `${idParts[0]}-${parseInt(idParts[1] + 1)}`; + } + return { + cursor: newCursor, + items: res.map(([id, vals]) => ({ + id, + value: JSON.stringify(_.fromPairs(_.chunk(vals, 2)), undefined, 2), + })), + }; + } } return null; }, diff --git a/plugins/dbgate-plugin-redis/src/frontend/driver.js b/plugins/dbgate-plugin-redis/src/frontend/driver.js index cf6a25990..843b41d10 100644 --- a/plugins/dbgate-plugin-redis/src/frontend/driver.js +++ b/plugins/dbgate-plugin-redis/src/frontend/driver.js @@ -64,6 +64,14 @@ const driver = { addMethod: 'hset', showItemList: true, }, + { + name: 'stream', + label: 'Stream', + dbKeyFields: [{ name: 'id' }, { name: 'value' }], + keyColumn: 'id', + addMethod: 'xaddjson', + showItemList: true, + }, ], showConnectionField: (field, values) => {