@upstash/react-redis-browser 0.1.8 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +57 -177
- package/dist/index.mjs +63 -183
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/components/databrowser/index.tsx
|
|
2
2
|
var _react = require('react'); var React = _interopRequireWildcard(_react); var React2 = _interopRequireWildcard(_react); var React3 = _interopRequireWildcard(_react); var React4 = _interopRequireWildcard(_react); var React5 = _interopRequireWildcard(_react); var React6 = _interopRequireWildcard(_react); var React7 = _interopRequireWildcard(_react); var React8 = _interopRequireWildcard(_react); var React9 = _interopRequireWildcard(_react); var React10 = _interopRequireWildcard(_react); var React11 = _interopRequireWildcard(_react); var React12 = _interopRequireWildcard(_react);
|
|
3
3
|
|
|
4
4
|
// src/store.tsx
|
|
@@ -2917,181 +2917,51 @@ function Toaster() {
|
|
|
2917
2917
|
|
|
2918
2918
|
|
|
2919
2919
|
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
// src/components/databrowser/hooks/use-fetch-key-type.tsx
|
|
2927
|
-
|
|
2928
|
-
var FETCH_KEY_TYPE_QUERY_KEY = "fetch-key-type";
|
|
2929
|
-
var useFetchKeyType = (key) => {
|
|
2930
|
-
const { redisNoPipeline: redis } = useDatabrowser();
|
|
2931
|
-
return _reactquery.useQuery.call(void 0, {
|
|
2932
|
-
queryKey: [FETCH_KEY_TYPE_QUERY_KEY, key],
|
|
2933
|
-
queryFn: async () => {
|
|
2934
|
-
if (!key) return "none";
|
|
2935
|
-
return await redis.type(key);
|
|
2936
|
-
}
|
|
2937
|
-
});
|
|
2938
|
-
};
|
|
2939
|
-
|
|
2940
|
-
// src/components/databrowser/hooks/use-fetch-keys.ts
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
// src/types/index.ts
|
|
2944
|
-
var DATA_TYPES = ["string", "list", "hash", "set", "zset", "json", "stream"];
|
|
2945
|
-
var DATA_TYPE_NAMES = {
|
|
2946
|
-
string: "String",
|
|
2947
|
-
list: "List",
|
|
2948
|
-
hash: "Hash",
|
|
2949
|
-
set: "Set",
|
|
2950
|
-
zset: "Sorted Set",
|
|
2951
|
-
json: "JSON",
|
|
2952
|
-
stream: "Stream"
|
|
2953
|
-
};
|
|
2954
|
-
|
|
2955
|
-
// src/components/databrowser/hooks/use-fetch-keys.ts
|
|
2956
|
-
var PAGE_SIZE = 30;
|
|
2957
|
-
var FETCH_COUNTS = [100, 200, 400, 800];
|
|
2958
|
-
var useFetchKeys = (search) => {
|
|
2959
|
-
const { redisNoPipeline: redis } = useDatabrowser();
|
|
2960
|
-
const cache = _react.useRef.call(void 0, );
|
|
2961
|
-
const lastKey = _react.useRef.call(void 0, );
|
|
2962
|
-
const fetchKeys = _react.useCallback.call(void 0, () => {
|
|
2963
|
-
const newKey = JSON.stringify(search);
|
|
2964
|
-
if (!cache.current || lastKey.current !== newKey) {
|
|
2965
|
-
cache.current = new PaginationCache(redis, search.key, search.type);
|
|
2966
|
-
lastKey.current = newKey;
|
|
2967
|
-
}
|
|
2968
|
-
return cache.current.fetchNewKeys();
|
|
2969
|
-
}, [search]);
|
|
2970
|
-
const resetCache = _react.useCallback.call(void 0, () => {
|
|
2971
|
-
cache.current = void 0;
|
|
2972
|
-
lastKey.current = void 0;
|
|
2973
|
-
}, []);
|
|
2974
|
-
return {
|
|
2975
|
-
fetchKeys,
|
|
2976
|
-
resetCache
|
|
2977
|
-
};
|
|
2978
|
-
};
|
|
2979
|
-
var PaginationCache = (_class = class {
|
|
2980
|
-
constructor(redis, searchTerm, typeFilter) {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this);_class.prototype.__init3.call(this);_class.prototype.__init4.call(this);
|
|
2981
|
-
this.redis = redis;
|
|
2982
|
-
this.searchTerm = searchTerm;
|
|
2983
|
-
this.typeFilter = typeFilter;
|
|
2984
|
-
if (typeFilter && !DATA_TYPES.includes(typeFilter)) {
|
|
2985
|
-
throw new Error(`Invalid type filter: ${typeFilter}`);
|
|
2986
|
-
}
|
|
2987
|
-
}
|
|
2988
|
-
// Cursor is 0 initially, then it is set to -1 when we reach the end
|
|
2989
|
-
__init() {this.cache = Object.fromEntries(
|
|
2990
|
-
DATA_TYPES.map((type) => [type, { cursor: "0", keys: [] }])
|
|
2991
|
-
)}
|
|
2992
|
-
__init2() {this.targetCount = 0}
|
|
2993
|
-
__init3() {this.isFetching = false}
|
|
2994
|
-
async fetchNewKeys() {
|
|
2995
|
-
const initialKeys = new Set(this.getKeys().map(([key]) => key));
|
|
2996
|
-
this.targetCount = this.getKeys().length + PAGE_SIZE;
|
|
2997
|
-
void this.startFetch();
|
|
2998
|
-
await new Promise((resolve) => {
|
|
2999
|
-
const interval = setInterval(() => {
|
|
3000
|
-
if (this.getLength() >= this.targetCount || this.isAllEnded()) {
|
|
3001
|
-
clearInterval(interval);
|
|
3002
|
-
resolve();
|
|
3003
|
-
}
|
|
3004
|
-
}, 100);
|
|
3005
|
-
});
|
|
3006
|
-
const hasNextPage = !this.isAllEnded();
|
|
3007
|
-
return {
|
|
3008
|
-
keys: this.getKeys().filter(([key]) => !initialKeys.has(key)),
|
|
3009
|
-
hasNextPage
|
|
3010
|
-
};
|
|
3011
|
-
}
|
|
3012
|
-
getLength() {
|
|
3013
|
-
return Object.values(this.cache).reduce((acc, curr) => acc + curr.keys.length, 0);
|
|
3014
|
-
}
|
|
3015
|
-
getKeys() {
|
|
3016
|
-
const keys = Object.entries(this.cache).flatMap(([type, { keys: keys2 }]) => {
|
|
3017
|
-
return keys2.map((key) => [key, type]);
|
|
3018
|
-
});
|
|
3019
|
-
const sorted = keys.sort((a, b) => a[0].localeCompare(b[0]));
|
|
3020
|
-
return sorted;
|
|
3021
|
-
}
|
|
3022
|
-
async startFetch() {
|
|
3023
|
-
if (this.isFetching) {
|
|
3024
|
-
return;
|
|
3025
|
-
}
|
|
3026
|
-
this.isFetching = true;
|
|
3027
|
-
try {
|
|
3028
|
-
await this.fetch();
|
|
3029
|
-
} finally {
|
|
3030
|
-
this.isFetching = false;
|
|
3031
|
-
}
|
|
3032
|
-
}
|
|
3033
|
-
__init4() {this.fetchForType = async (type) => {
|
|
3034
|
-
let i = 0;
|
|
3035
|
-
while (true) {
|
|
3036
|
-
const cursor = this.cache[type].cursor;
|
|
3037
|
-
if (cursor === "-1" || this.getLength() >= this.targetCount) {
|
|
3038
|
-
break;
|
|
3039
|
-
}
|
|
3040
|
-
const fetchCount = FETCH_COUNTS[Math.min(i, FETCH_COUNTS.length - 1)];
|
|
3041
|
-
const [nextCursor, newKeys] = await this.redis.scan(cursor, {
|
|
3042
|
-
count: fetchCount,
|
|
3043
|
-
match: this.searchTerm,
|
|
3044
|
-
type
|
|
3045
|
-
});
|
|
3046
|
-
this.cache[type].keys = [...this.cache[type].keys, ...newKeys];
|
|
3047
|
-
this.cache[type].cursor = nextCursor === "0" ? "-1" : nextCursor;
|
|
3048
|
-
i++;
|
|
3049
|
-
}
|
|
3050
|
-
}}
|
|
3051
|
-
async fetch() {
|
|
3052
|
-
const types = this.typeFilter ? [this.typeFilter] : DATA_TYPES;
|
|
3053
|
-
await Promise.all(types.map(this.fetchForType));
|
|
3054
|
-
}
|
|
3055
|
-
isAllEnded() {
|
|
3056
|
-
const types = this.typeFilter ? [this.typeFilter] : DATA_TYPES;
|
|
3057
|
-
return types.every((type) => this.cache[type] && this.cache[type].cursor === "-1");
|
|
3058
|
-
}
|
|
3059
|
-
}, _class);
|
|
3060
|
-
|
|
3061
|
-
// src/components/databrowser/hooks/use-keys.tsx
|
|
3062
|
-
|
|
3063
2920
|
var KeysContext = _react.createContext.call(void 0, void 0);
|
|
3064
2921
|
var FETCH_KEYS_QUERY_KEY = "use-fetch-keys";
|
|
2922
|
+
var SCAN_COUNT = 100;
|
|
3065
2923
|
var KeysProvider = ({ children }) => {
|
|
3066
2924
|
const { search } = useDatabrowserStore();
|
|
3067
|
-
const
|
|
3068
|
-
const { data: exactMatchType, isFetching, isLoading } = useFetchKeyType(cleanSearchKey);
|
|
3069
|
-
const { fetchKeys, resetCache } = useFetchKeys(search);
|
|
3070
|
-
const pageRef = _react.useRef.call(void 0, 0);
|
|
2925
|
+
const { redisNoPipeline: redis } = useDatabrowser();
|
|
3071
2926
|
const query = _reactquery.useInfiniteQuery.call(void 0, {
|
|
3072
2927
|
queryKey: [FETCH_KEYS_QUERY_KEY, search],
|
|
3073
|
-
initialPageParam: 0,
|
|
3074
|
-
queryFn: async ({ pageParam:
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
2928
|
+
initialPageParam: "0",
|
|
2929
|
+
queryFn: async ({ pageParam: lastCursor }) => {
|
|
2930
|
+
const args = [lastCursor];
|
|
2931
|
+
if (search.key) {
|
|
2932
|
+
args.push("MATCH", search.key);
|
|
2933
|
+
}
|
|
2934
|
+
if (search.type) {
|
|
2935
|
+
args.push("TYPE", search.type);
|
|
2936
|
+
}
|
|
2937
|
+
args.push("COUNT", SCAN_COUNT.toString());
|
|
2938
|
+
if (!search.type) args.push("WITHTYPE");
|
|
2939
|
+
const [cursor, values] = await redis.exec(["SCAN", ...args]);
|
|
2940
|
+
const keys2 = [];
|
|
2941
|
+
let index = 0;
|
|
2942
|
+
while (true) {
|
|
2943
|
+
if (search.type) {
|
|
2944
|
+
if (index >= values.length) break;
|
|
2945
|
+
keys2.push([values[index], search.type]);
|
|
2946
|
+
index += 1;
|
|
2947
|
+
} else {
|
|
2948
|
+
if (index + 1 >= values.length) break;
|
|
2949
|
+
keys2.push([values[index], values[index + 1]]);
|
|
2950
|
+
index += 2;
|
|
2951
|
+
}
|
|
2952
|
+
}
|
|
2953
|
+
return {
|
|
2954
|
+
cursor: cursor === "0" ? void 0 : cursor,
|
|
2955
|
+
keys: keys2,
|
|
2956
|
+
hasNextPage: cursor !== "0"
|
|
2957
|
+
};
|
|
3078
2958
|
},
|
|
3079
2959
|
select: (data) => data,
|
|
3080
|
-
getNextPageParam: (
|
|
3081
|
-
return lastPage.hasNextPage ? lastPageIndex + 1 : void 0;
|
|
3082
|
-
},
|
|
3083
|
-
enabled: !isFetching,
|
|
2960
|
+
getNextPageParam: ({ cursor }) => cursor,
|
|
3084
2961
|
refetchOnMount: false
|
|
3085
2962
|
});
|
|
3086
|
-
const refetch = _react.useCallback.call(void 0, () => {
|
|
3087
|
-
resetCache();
|
|
3088
|
-
query.refetch();
|
|
3089
|
-
}, [query, resetCache]);
|
|
3090
2963
|
const keys = _react.useMemo.call(void 0, () => {
|
|
3091
2964
|
const keys2 = _nullishCoalesce(_optionalChain([query, 'access', _10 => _10.data, 'optionalAccess', _11 => _11.pages, 'access', _12 => _12.flatMap, 'call', _13 => _13((page) => page.keys)]), () => ( []));
|
|
3092
|
-
if (exactMatchType && exactMatchType !== "none" && (search.type === void 0 || search.type === exactMatchType)) {
|
|
3093
|
-
keys2.push([cleanSearchKey, exactMatchType]);
|
|
3094
|
-
}
|
|
3095
2965
|
const keysSet = /* @__PURE__ */ new Set();
|
|
3096
2966
|
const dedupedKeys = [];
|
|
3097
2967
|
for (const key of keys2) {
|
|
@@ -3100,19 +2970,13 @@ var KeysProvider = ({ children }) => {
|
|
|
3100
2970
|
dedupedKeys.push(key);
|
|
3101
2971
|
}
|
|
3102
2972
|
return dedupedKeys;
|
|
3103
|
-
}, [query.data
|
|
2973
|
+
}, [query.data]);
|
|
3104
2974
|
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3105
2975
|
KeysContext.Provider,
|
|
3106
2976
|
{
|
|
3107
2977
|
value: {
|
|
3108
2978
|
keys,
|
|
3109
|
-
|
|
3110
|
-
query: {
|
|
3111
|
-
...query,
|
|
3112
|
-
isLoading: isLoading || query.isLoading,
|
|
3113
|
-
isFetching: isFetching || query.isFetching
|
|
3114
|
-
},
|
|
3115
|
-
refetch
|
|
2979
|
+
query
|
|
3116
2980
|
},
|
|
3117
2981
|
children
|
|
3118
2982
|
}
|
|
@@ -3295,6 +3159,10 @@ var useAddKey = () => {
|
|
|
3295
3159
|
// src/components/databrowser/hooks/use-delete-key-cache.ts
|
|
3296
3160
|
|
|
3297
3161
|
|
|
3162
|
+
// src/components/databrowser/hooks/use-fetch-key-type.tsx
|
|
3163
|
+
|
|
3164
|
+
var FETCH_KEY_TYPE_QUERY_KEY = "fetch-key-type";
|
|
3165
|
+
|
|
3298
3166
|
// src/components/databrowser/hooks/use-fetch-list-items.tsx
|
|
3299
3167
|
|
|
3300
3168
|
var LIST_DISPLAY_PAGE_SIZE = 50;
|
|
@@ -3443,7 +3311,6 @@ var sortObject = (obj) => {
|
|
|
3443
3311
|
// src/components/databrowser/hooks/use-delete-key-cache.ts
|
|
3444
3312
|
var useDeleteKeyCache = () => {
|
|
3445
3313
|
const { setSelectedKey } = useDatabrowserStore();
|
|
3446
|
-
const { refetch } = useKeys();
|
|
3447
3314
|
const deleteKeyCache = _react.useCallback.call(void 0,
|
|
3448
3315
|
(key) => {
|
|
3449
3316
|
setSelectedKey(void 0);
|
|
@@ -3459,9 +3326,8 @@ var useDeleteKeyCache = () => {
|
|
|
3459
3326
|
queryClient.invalidateQueries({
|
|
3460
3327
|
queryKey: [FETCH_KEY_TYPE_QUERY_KEY, key]
|
|
3461
3328
|
});
|
|
3462
|
-
refetch();
|
|
3463
3329
|
},
|
|
3464
|
-
[setSelectedKey
|
|
3330
|
+
[setSelectedKey]
|
|
3465
3331
|
);
|
|
3466
3332
|
return { deleteKeyCache };
|
|
3467
3333
|
};
|
|
@@ -4457,6 +4323,18 @@ var InfiniteScroll = ({
|
|
|
4457
4323
|
// src/components/databrowser/components/display/display-header.tsx
|
|
4458
4324
|
|
|
4459
4325
|
|
|
4326
|
+
// src/types/index.ts
|
|
4327
|
+
var DATA_TYPES = ["string", "list", "hash", "set", "zset", "json", "stream"];
|
|
4328
|
+
var DATA_TYPE_NAMES = {
|
|
4329
|
+
string: "String",
|
|
4330
|
+
list: "List",
|
|
4331
|
+
hash: "Hash",
|
|
4332
|
+
set: "Set",
|
|
4333
|
+
zset: "Sorted Set",
|
|
4334
|
+
json: "JSON",
|
|
4335
|
+
stream: "Stream"
|
|
4336
|
+
};
|
|
4337
|
+
|
|
4460
4338
|
// src/components/databrowser/components/type-tag.tsx
|
|
4461
4339
|
|
|
4462
4340
|
|
|
@@ -5720,7 +5598,7 @@ function DataTypeSelector() {
|
|
|
5720
5598
|
// src/components/databrowser/components/sidebar/index.tsx
|
|
5721
5599
|
|
|
5722
5600
|
function Sidebar() {
|
|
5723
|
-
const { keys, query
|
|
5601
|
+
const { keys, query } = useKeys();
|
|
5724
5602
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex h-full flex-col gap-2 rounded-xl border bg-white p-1", children: [
|
|
5725
5603
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "rounded-lg bg-zinc-100 px-3 py-2", children: [
|
|
5726
5604
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex h-10 items-center justify-between pl-1", children: [
|
|
@@ -5731,7 +5609,9 @@ function Sidebar() {
|
|
|
5731
5609
|
{
|
|
5732
5610
|
className: "h-7 w-7 px-0",
|
|
5733
5611
|
onClick: () => {
|
|
5734
|
-
|
|
5612
|
+
queryClient.invalidateQueries({
|
|
5613
|
+
queryKey: [FETCH_KEYS_QUERY_KEY]
|
|
5614
|
+
});
|
|
5735
5615
|
queryClient.invalidateQueries({
|
|
5736
5616
|
queryKey: [FETCH_LIST_ITEMS_QUERY_KEY]
|
|
5737
5617
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -2914,184 +2914,54 @@ function Toaster() {
|
|
|
2914
2914
|
}
|
|
2915
2915
|
|
|
2916
2916
|
// src/components/databrowser/hooks/use-keys.tsx
|
|
2917
|
-
import {
|
|
2918
|
-
createContext as createContext2,
|
|
2919
|
-
useCallback as useCallback2,
|
|
2920
|
-
useContext as useContext2,
|
|
2921
|
-
useMemo as useMemo2,
|
|
2922
|
-
useRef as useRef2
|
|
2923
|
-
} from "react";
|
|
2917
|
+
import { createContext as createContext2, useContext as useContext2, useMemo as useMemo2 } from "react";
|
|
2924
2918
|
import { useInfiniteQuery } from "@tanstack/react-query";
|
|
2925
|
-
|
|
2926
|
-
// src/components/databrowser/hooks/use-fetch-key-type.tsx
|
|
2927
|
-
import { useQuery } from "@tanstack/react-query";
|
|
2928
|
-
var FETCH_KEY_TYPE_QUERY_KEY = "fetch-key-type";
|
|
2929
|
-
var useFetchKeyType = (key) => {
|
|
2930
|
-
const { redisNoPipeline: redis } = useDatabrowser();
|
|
2931
|
-
return useQuery({
|
|
2932
|
-
queryKey: [FETCH_KEY_TYPE_QUERY_KEY, key],
|
|
2933
|
-
queryFn: async () => {
|
|
2934
|
-
if (!key) return "none";
|
|
2935
|
-
return await redis.type(key);
|
|
2936
|
-
}
|
|
2937
|
-
});
|
|
2938
|
-
};
|
|
2939
|
-
|
|
2940
|
-
// src/components/databrowser/hooks/use-fetch-keys.ts
|
|
2941
|
-
import { useCallback, useRef } from "react";
|
|
2942
|
-
|
|
2943
|
-
// src/types/index.ts
|
|
2944
|
-
var DATA_TYPES = ["string", "list", "hash", "set", "zset", "json", "stream"];
|
|
2945
|
-
var DATA_TYPE_NAMES = {
|
|
2946
|
-
string: "String",
|
|
2947
|
-
list: "List",
|
|
2948
|
-
hash: "Hash",
|
|
2949
|
-
set: "Set",
|
|
2950
|
-
zset: "Sorted Set",
|
|
2951
|
-
json: "JSON",
|
|
2952
|
-
stream: "Stream"
|
|
2953
|
-
};
|
|
2954
|
-
|
|
2955
|
-
// src/components/databrowser/hooks/use-fetch-keys.ts
|
|
2956
|
-
var PAGE_SIZE = 30;
|
|
2957
|
-
var FETCH_COUNTS = [100, 200, 400, 800];
|
|
2958
|
-
var useFetchKeys = (search) => {
|
|
2959
|
-
const { redisNoPipeline: redis } = useDatabrowser();
|
|
2960
|
-
const cache = useRef();
|
|
2961
|
-
const lastKey = useRef();
|
|
2962
|
-
const fetchKeys = useCallback(() => {
|
|
2963
|
-
const newKey = JSON.stringify(search);
|
|
2964
|
-
if (!cache.current || lastKey.current !== newKey) {
|
|
2965
|
-
cache.current = new PaginationCache(redis, search.key, search.type);
|
|
2966
|
-
lastKey.current = newKey;
|
|
2967
|
-
}
|
|
2968
|
-
return cache.current.fetchNewKeys();
|
|
2969
|
-
}, [search]);
|
|
2970
|
-
const resetCache = useCallback(() => {
|
|
2971
|
-
cache.current = void 0;
|
|
2972
|
-
lastKey.current = void 0;
|
|
2973
|
-
}, []);
|
|
2974
|
-
return {
|
|
2975
|
-
fetchKeys,
|
|
2976
|
-
resetCache
|
|
2977
|
-
};
|
|
2978
|
-
};
|
|
2979
|
-
var PaginationCache = class {
|
|
2980
|
-
constructor(redis, searchTerm, typeFilter) {
|
|
2981
|
-
this.redis = redis;
|
|
2982
|
-
this.searchTerm = searchTerm;
|
|
2983
|
-
this.typeFilter = typeFilter;
|
|
2984
|
-
if (typeFilter && !DATA_TYPES.includes(typeFilter)) {
|
|
2985
|
-
throw new Error(`Invalid type filter: ${typeFilter}`);
|
|
2986
|
-
}
|
|
2987
|
-
}
|
|
2988
|
-
// Cursor is 0 initially, then it is set to -1 when we reach the end
|
|
2989
|
-
cache = Object.fromEntries(
|
|
2990
|
-
DATA_TYPES.map((type) => [type, { cursor: "0", keys: [] }])
|
|
2991
|
-
);
|
|
2992
|
-
targetCount = 0;
|
|
2993
|
-
isFetching = false;
|
|
2994
|
-
async fetchNewKeys() {
|
|
2995
|
-
const initialKeys = new Set(this.getKeys().map(([key]) => key));
|
|
2996
|
-
this.targetCount = this.getKeys().length + PAGE_SIZE;
|
|
2997
|
-
void this.startFetch();
|
|
2998
|
-
await new Promise((resolve) => {
|
|
2999
|
-
const interval = setInterval(() => {
|
|
3000
|
-
if (this.getLength() >= this.targetCount || this.isAllEnded()) {
|
|
3001
|
-
clearInterval(interval);
|
|
3002
|
-
resolve();
|
|
3003
|
-
}
|
|
3004
|
-
}, 100);
|
|
3005
|
-
});
|
|
3006
|
-
const hasNextPage = !this.isAllEnded();
|
|
3007
|
-
return {
|
|
3008
|
-
keys: this.getKeys().filter(([key]) => !initialKeys.has(key)),
|
|
3009
|
-
hasNextPage
|
|
3010
|
-
};
|
|
3011
|
-
}
|
|
3012
|
-
getLength() {
|
|
3013
|
-
return Object.values(this.cache).reduce((acc, curr) => acc + curr.keys.length, 0);
|
|
3014
|
-
}
|
|
3015
|
-
getKeys() {
|
|
3016
|
-
const keys = Object.entries(this.cache).flatMap(([type, { keys: keys2 }]) => {
|
|
3017
|
-
return keys2.map((key) => [key, type]);
|
|
3018
|
-
});
|
|
3019
|
-
const sorted = keys.sort((a, b) => a[0].localeCompare(b[0]));
|
|
3020
|
-
return sorted;
|
|
3021
|
-
}
|
|
3022
|
-
async startFetch() {
|
|
3023
|
-
if (this.isFetching) {
|
|
3024
|
-
return;
|
|
3025
|
-
}
|
|
3026
|
-
this.isFetching = true;
|
|
3027
|
-
try {
|
|
3028
|
-
await this.fetch();
|
|
3029
|
-
} finally {
|
|
3030
|
-
this.isFetching = false;
|
|
3031
|
-
}
|
|
3032
|
-
}
|
|
3033
|
-
fetchForType = async (type) => {
|
|
3034
|
-
let i = 0;
|
|
3035
|
-
while (true) {
|
|
3036
|
-
const cursor = this.cache[type].cursor;
|
|
3037
|
-
if (cursor === "-1" || this.getLength() >= this.targetCount) {
|
|
3038
|
-
break;
|
|
3039
|
-
}
|
|
3040
|
-
const fetchCount = FETCH_COUNTS[Math.min(i, FETCH_COUNTS.length - 1)];
|
|
3041
|
-
const [nextCursor, newKeys] = await this.redis.scan(cursor, {
|
|
3042
|
-
count: fetchCount,
|
|
3043
|
-
match: this.searchTerm,
|
|
3044
|
-
type
|
|
3045
|
-
});
|
|
3046
|
-
this.cache[type].keys = [...this.cache[type].keys, ...newKeys];
|
|
3047
|
-
this.cache[type].cursor = nextCursor === "0" ? "-1" : nextCursor;
|
|
3048
|
-
i++;
|
|
3049
|
-
}
|
|
3050
|
-
};
|
|
3051
|
-
async fetch() {
|
|
3052
|
-
const types = this.typeFilter ? [this.typeFilter] : DATA_TYPES;
|
|
3053
|
-
await Promise.all(types.map(this.fetchForType));
|
|
3054
|
-
}
|
|
3055
|
-
isAllEnded() {
|
|
3056
|
-
const types = this.typeFilter ? [this.typeFilter] : DATA_TYPES;
|
|
3057
|
-
return types.every((type) => this.cache[type] && this.cache[type].cursor === "-1");
|
|
3058
|
-
}
|
|
3059
|
-
};
|
|
3060
|
-
|
|
3061
|
-
// src/components/databrowser/hooks/use-keys.tsx
|
|
3062
2919
|
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
3063
2920
|
var KeysContext = createContext2(void 0);
|
|
3064
2921
|
var FETCH_KEYS_QUERY_KEY = "use-fetch-keys";
|
|
2922
|
+
var SCAN_COUNT = 100;
|
|
3065
2923
|
var KeysProvider = ({ children }) => {
|
|
3066
2924
|
const { search } = useDatabrowserStore();
|
|
3067
|
-
const
|
|
3068
|
-
const { data: exactMatchType, isFetching, isLoading } = useFetchKeyType(cleanSearchKey);
|
|
3069
|
-
const { fetchKeys, resetCache } = useFetchKeys(search);
|
|
3070
|
-
const pageRef = useRef2(0);
|
|
2925
|
+
const { redisNoPipeline: redis } = useDatabrowser();
|
|
3071
2926
|
const query = useInfiniteQuery({
|
|
3072
2927
|
queryKey: [FETCH_KEYS_QUERY_KEY, search],
|
|
3073
|
-
initialPageParam: 0,
|
|
3074
|
-
queryFn: async ({ pageParam:
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
2928
|
+
initialPageParam: "0",
|
|
2929
|
+
queryFn: async ({ pageParam: lastCursor }) => {
|
|
2930
|
+
const args = [lastCursor];
|
|
2931
|
+
if (search.key) {
|
|
2932
|
+
args.push("MATCH", search.key);
|
|
2933
|
+
}
|
|
2934
|
+
if (search.type) {
|
|
2935
|
+
args.push("TYPE", search.type);
|
|
2936
|
+
}
|
|
2937
|
+
args.push("COUNT", SCAN_COUNT.toString());
|
|
2938
|
+
if (!search.type) args.push("WITHTYPE");
|
|
2939
|
+
const [cursor, values] = await redis.exec(["SCAN", ...args]);
|
|
2940
|
+
const keys2 = [];
|
|
2941
|
+
let index = 0;
|
|
2942
|
+
while (true) {
|
|
2943
|
+
if (search.type) {
|
|
2944
|
+
if (index >= values.length) break;
|
|
2945
|
+
keys2.push([values[index], search.type]);
|
|
2946
|
+
index += 1;
|
|
2947
|
+
} else {
|
|
2948
|
+
if (index + 1 >= values.length) break;
|
|
2949
|
+
keys2.push([values[index], values[index + 1]]);
|
|
2950
|
+
index += 2;
|
|
2951
|
+
}
|
|
2952
|
+
}
|
|
2953
|
+
return {
|
|
2954
|
+
cursor: cursor === "0" ? void 0 : cursor,
|
|
2955
|
+
keys: keys2,
|
|
2956
|
+
hasNextPage: cursor !== "0"
|
|
2957
|
+
};
|
|
3078
2958
|
},
|
|
3079
2959
|
select: (data) => data,
|
|
3080
|
-
getNextPageParam: (
|
|
3081
|
-
return lastPage.hasNextPage ? lastPageIndex + 1 : void 0;
|
|
3082
|
-
},
|
|
3083
|
-
enabled: !isFetching,
|
|
2960
|
+
getNextPageParam: ({ cursor }) => cursor,
|
|
3084
2961
|
refetchOnMount: false
|
|
3085
2962
|
});
|
|
3086
|
-
const refetch = useCallback2(() => {
|
|
3087
|
-
resetCache();
|
|
3088
|
-
query.refetch();
|
|
3089
|
-
}, [query, resetCache]);
|
|
3090
2963
|
const keys = useMemo2(() => {
|
|
3091
2964
|
const keys2 = query.data?.pages.flatMap((page) => page.keys) ?? [];
|
|
3092
|
-
if (exactMatchType && exactMatchType !== "none" && (search.type === void 0 || search.type === exactMatchType)) {
|
|
3093
|
-
keys2.push([cleanSearchKey, exactMatchType]);
|
|
3094
|
-
}
|
|
3095
2965
|
const keysSet = /* @__PURE__ */ new Set();
|
|
3096
2966
|
const dedupedKeys = [];
|
|
3097
2967
|
for (const key of keys2) {
|
|
@@ -3100,19 +2970,13 @@ var KeysProvider = ({ children }) => {
|
|
|
3100
2970
|
dedupedKeys.push(key);
|
|
3101
2971
|
}
|
|
3102
2972
|
return dedupedKeys;
|
|
3103
|
-
}, [query.data
|
|
2973
|
+
}, [query.data]);
|
|
3104
2974
|
return /* @__PURE__ */ jsx4(
|
|
3105
2975
|
KeysContext.Provider,
|
|
3106
2976
|
{
|
|
3107
2977
|
value: {
|
|
3108
2978
|
keys,
|
|
3109
|
-
|
|
3110
|
-
query: {
|
|
3111
|
-
...query,
|
|
3112
|
-
isLoading: isLoading || query.isLoading,
|
|
3113
|
-
isFetching: isFetching || query.isFetching
|
|
3114
|
-
},
|
|
3115
|
-
refetch
|
|
2979
|
+
query
|
|
3116
2980
|
},
|
|
3117
2981
|
children
|
|
3118
2982
|
}
|
|
@@ -3179,7 +3043,7 @@ Button.displayName = "Button";
|
|
|
3179
3043
|
import { useMutation } from "@tanstack/react-query";
|
|
3180
3044
|
|
|
3181
3045
|
// src/components/databrowser/components/sidebar/db-size.tsx
|
|
3182
|
-
import { useQuery
|
|
3046
|
+
import { useQuery } from "@tanstack/react-query";
|
|
3183
3047
|
|
|
3184
3048
|
// src/components/ui/skeleton.tsx
|
|
3185
3049
|
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
@@ -3198,7 +3062,7 @@ import { jsx as jsx7, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
|
3198
3062
|
var FETCH_DB_SIZE_QUERY_KEY = "fetch-db-size";
|
|
3199
3063
|
var DisplayDbSize = () => {
|
|
3200
3064
|
const { redis } = useDatabrowser();
|
|
3201
|
-
const { data: keyCount } =
|
|
3065
|
+
const { data: keyCount } = useQuery({
|
|
3202
3066
|
queryKey: [FETCH_DB_SIZE_QUERY_KEY],
|
|
3203
3067
|
queryFn: async () => {
|
|
3204
3068
|
return await redis.dbsize();
|
|
@@ -3293,7 +3157,11 @@ import { useEffect as useEffect2, useState as useState3 } from "react";
|
|
|
3293
3157
|
import { useMutation as useMutation2 } from "@tanstack/react-query";
|
|
3294
3158
|
|
|
3295
3159
|
// src/components/databrowser/hooks/use-delete-key-cache.ts
|
|
3296
|
-
import { useCallback
|
|
3160
|
+
import { useCallback } from "react";
|
|
3161
|
+
|
|
3162
|
+
// src/components/databrowser/hooks/use-fetch-key-type.tsx
|
|
3163
|
+
import { useQuery as useQuery2 } from "@tanstack/react-query";
|
|
3164
|
+
var FETCH_KEY_TYPE_QUERY_KEY = "fetch-key-type";
|
|
3297
3165
|
|
|
3298
3166
|
// src/components/databrowser/hooks/use-fetch-list-items.tsx
|
|
3299
3167
|
import { useInfiniteQuery as useInfiniteQuery2 } from "@tanstack/react-query";
|
|
@@ -3443,8 +3311,7 @@ var sortObject = (obj) => {
|
|
|
3443
3311
|
// src/components/databrowser/hooks/use-delete-key-cache.ts
|
|
3444
3312
|
var useDeleteKeyCache = () => {
|
|
3445
3313
|
const { setSelectedKey } = useDatabrowserStore();
|
|
3446
|
-
const
|
|
3447
|
-
const deleteKeyCache = useCallback3(
|
|
3314
|
+
const deleteKeyCache = useCallback(
|
|
3448
3315
|
(key) => {
|
|
3449
3316
|
setSelectedKey(void 0);
|
|
3450
3317
|
queryClient.invalidateQueries({
|
|
@@ -3459,9 +3326,8 @@ var useDeleteKeyCache = () => {
|
|
|
3459
3326
|
queryClient.invalidateQueries({
|
|
3460
3327
|
queryKey: [FETCH_KEY_TYPE_QUERY_KEY, key]
|
|
3461
3328
|
});
|
|
3462
|
-
refetch();
|
|
3463
3329
|
},
|
|
3464
|
-
[setSelectedKey
|
|
3330
|
+
[setSelectedKey]
|
|
3465
3331
|
);
|
|
3466
3332
|
return { deleteKeyCache };
|
|
3467
3333
|
};
|
|
@@ -4457,6 +4323,18 @@ var InfiniteScroll = ({
|
|
|
4457
4323
|
// src/components/databrowser/components/display/display-header.tsx
|
|
4458
4324
|
import { IconPlus } from "@tabler/icons-react";
|
|
4459
4325
|
|
|
4326
|
+
// src/types/index.ts
|
|
4327
|
+
var DATA_TYPES = ["string", "list", "hash", "set", "zset", "json", "stream"];
|
|
4328
|
+
var DATA_TYPE_NAMES = {
|
|
4329
|
+
string: "String",
|
|
4330
|
+
list: "List",
|
|
4331
|
+
hash: "Hash",
|
|
4332
|
+
set: "Set",
|
|
4333
|
+
zset: "Sorted Set",
|
|
4334
|
+
json: "JSON",
|
|
4335
|
+
stream: "Stream"
|
|
4336
|
+
};
|
|
4337
|
+
|
|
4460
4338
|
// src/components/databrowser/components/type-tag.tsx
|
|
4461
4339
|
import {
|
|
4462
4340
|
IconArrowsSort,
|
|
@@ -4810,7 +4688,7 @@ var ContentTypeSelect = ({
|
|
|
4810
4688
|
};
|
|
4811
4689
|
|
|
4812
4690
|
// src/components/databrowser/components/display/input/custom-editor.tsx
|
|
4813
|
-
import { useEffect as useEffect6, useRef
|
|
4691
|
+
import { useEffect as useEffect6, useRef } from "react";
|
|
4814
4692
|
import { Editor, useMonaco } from "@monaco-editor/react";
|
|
4815
4693
|
|
|
4816
4694
|
// src/components/databrowser/copy-button.tsx
|
|
@@ -4859,7 +4737,7 @@ var CustomEditor = ({
|
|
|
4859
4737
|
readOnly
|
|
4860
4738
|
}) => {
|
|
4861
4739
|
const monaco = useMonaco();
|
|
4862
|
-
const editorRef =
|
|
4740
|
+
const editorRef = useRef();
|
|
4863
4741
|
useEffect6(() => {
|
|
4864
4742
|
if (!monaco || !editorRef.current) {
|
|
4865
4743
|
return;
|
|
@@ -5720,7 +5598,7 @@ function DataTypeSelector() {
|
|
|
5720
5598
|
// src/components/databrowser/components/sidebar/index.tsx
|
|
5721
5599
|
import { jsx as jsx44, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
5722
5600
|
function Sidebar() {
|
|
5723
|
-
const { keys, query
|
|
5601
|
+
const { keys, query } = useKeys();
|
|
5724
5602
|
return /* @__PURE__ */ jsxs31("div", { className: "flex h-full flex-col gap-2 rounded-xl border bg-white p-1", children: [
|
|
5725
5603
|
/* @__PURE__ */ jsxs31("div", { className: "rounded-lg bg-zinc-100 px-3 py-2", children: [
|
|
5726
5604
|
/* @__PURE__ */ jsxs31("div", { className: "flex h-10 items-center justify-between pl-1", children: [
|
|
@@ -5731,7 +5609,9 @@ function Sidebar() {
|
|
|
5731
5609
|
{
|
|
5732
5610
|
className: "h-7 w-7 px-0",
|
|
5733
5611
|
onClick: () => {
|
|
5734
|
-
|
|
5612
|
+
queryClient.invalidateQueries({
|
|
5613
|
+
queryKey: [FETCH_KEYS_QUERY_KEY]
|
|
5614
|
+
});
|
|
5735
5615
|
queryClient.invalidateQueries({
|
|
5736
5616
|
queryKey: [FETCH_LIST_ITEMS_QUERY_KEY]
|
|
5737
5617
|
});
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{ "name": "@upstash/react-redis-browser", "version": "v0.1.
|
|
1
|
+
{ "name": "@upstash/react-redis-browser", "version": "v0.1.10", "main": "./dist/index.js", "types": "./dist/index.d.ts", "license": "MIT", "private": false, "publishConfig": { "access": "public" }, "bugs": { "url": "https://github.com/upstash/react-redis-browser/issues" }, "homepage": "https://github.com/upstash/react-redis-browser", "files": [ "./dist/**" ], "scripts": { "build": "tsup", "dev": "vite", "lint": "tsc && eslint", "fmt": "prettier --write ./src" }, "lint-staged": { "**/*.{js,ts,tsx}": [ "prettier --write", "eslint --fix" ] }, "dependencies": { "@ianvs/prettier-plugin-sort-imports": "^4.4.0", "@monaco-editor/react": "^4.6.0", "@radix-ui/react-alert-dialog": "^1.0.5", "@radix-ui/react-context-menu": "^2.2.2", "@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-dropdown-menu": "^2.1.2", "@radix-ui/react-icons": "1.3.0", "@radix-ui/react-popover": "^1.0.7", "@radix-ui/react-portal": "^1.1.2", "@radix-ui/react-scroll-area": "^1.0.3", "@radix-ui/react-select": "^2.0.0", "@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-toast": "^1.1.5", "@radix-ui/react-tooltip": "^1.0.7", "@tabler/icons-react": "^3.19.0", "@tanstack/react-query": "^5.32.0", "@types/bytes": "^3.1.4", "@upstash/redis": "^1.34.8", "bytes": "^3.1.2", "react-hook-form": "^7.53.0", "react-resizable-panels": "^2.1.4", "zustand": "5.0.0" }, "devDependencies": { "postcss-prefix-selector": "^2.1.0", "@types/node": "^22.8.4", "@types/react": "^18.3.12", "@types/react-dom": "^18.3.1", "@typescript-eslint/eslint-plugin": "8.4.0", "@typescript-eslint/parser": "8.4.0", "@vitejs/plugin-react": "^4.1.0", "autoprefixer": "^10.4.14", "class-variance-authority": "^0.7.0", "clsx": "^2.0.0", "eslint": "9.10.0", "eslint-plugin-unicorn": "55.0.0", "postcss": "^8.4.31", "prettier": "^3.0.3", "prettier-plugin-tailwindcss": "^0.5.5", "react": "^18.3.1", "react-dom": "^18.3.1", "tailwind-merge": "^2.5.4", "tailwindcss": "^3.4.14", "tailwindcss-animate": "^1.0.7", "tsup": "^8.3.5", "typescript": "^5.0.4", "vite": "^5.4.10", "vite-tsconfig-paths": "^5.0.1" }, "peerDependencies": { "react": "^18.2.0 || ^19", "react-dom": "^18.2.0 || ^19" } }
|