fix(redis): scope standalone load more cursor to its connection

This commit is contained in:
lxk955
2026-10-19 13:29:40 +08:00
committed by GitHub
parent 6a2caa5083
commit eea80fc31a
4 changed files with 82 additions and 21 deletions
@@ -654,4 +654,54 @@ describe("Redis collection member search", () => {
expect(document.body.textContent).toContain("1 members");
expect(document.body.textContent).not.toContain("/ 100 members loaded");
});
it("loads more hash fields when clicking load more in hash viewer", async () => {
mocks.redisGetValue.mockResolvedValue({
key_display: "key",
key_raw: "key",
ttl: -1,
redis_type: "hash",
data: {
kind: "hash",
items: [{ field: blob("f1"), value: blob("v1") }],
total: 4000,
scan_cursor: 1234,
},
});
mocks.redisLoadMore.mockResolvedValueOnce({
kind: "hash",
items: [{ field: blob("f2"), value: blob("v2") }],
scan_cursor: 5678,
});
mountViewer();
await settle();
expect(document.body.textContent).toContain("f1");
expect(document.body.textContent).not.toContain("f2");
loadMoreButton().click();
await settle();
expect(mocks.redisLoadMore).toHaveBeenCalledWith("connection", 0, "key", "hash", 1234, 200, undefined, undefined);
expect(document.body.textContent).toContain("f1");
expect(document.body.textContent).toContain("f2");
});
it("shows error toast when ordinary hash load more fails", async () => {
mocks.redisGetValue.mockResolvedValue({
key_display: "key",
key_raw: "key",
ttl: -1,
redis_type: "hash",
data: {
kind: "hash",
items: [{ field: blob("f1"), value: blob("v1") }],
total: 4000,
scan_cursor: 1234,
},
});
mocks.redisLoadMore.mockRejectedValueOnce(new Error("Collection cursor is invalid, expired, or belongs to a different connection/database"));
mountViewer();
await settle();
loadMoreButton().click();
await settle();
expect(mocks.toast).toHaveBeenCalledWith("Collection cursor is invalid, expired, or belongs to a different connection/database", 3000);
});
});
@@ -1898,8 +1898,14 @@ async function loadMore() {
if (!collectionSearchSupported.value) return;
const scope = collectionScope();
if (!scope) return;
if (activeCollectionSearchQuery.value) await collectionSearchController.start();
else await collectionSearchController.browse(scope, collectionItems.value, scanCursor.value!);
if (activeCollectionSearchQuery.value) {
await collectionSearchController.start();
} else {
await collectionSearchController.browse(scope, collectionItems.value, scanCursor.value!);
if (collectionSearchState.value.status === "failed" && collectionSearchState.value.error) {
toast(errorMessage(collectionSearchState.value.error), 3000);
}
}
}
async function saveString() {
@@ -113,8 +113,13 @@ export class RedisCollectionSearchController {
browse(scope: RedisCollectionScope, items: RedisCollectionItem[], cursor: number) {
const current = this.session;
const sameScope = current && this.sameScope(current.scope, scope);
if (!sameScope || current.state.query || current.state.cursor !== cursor) this.prepare(scope, "");
this.session!.state = { status: "searching", query: "", items, cursor };
if (!sameScope || current.state.query || current.state.cursor !== cursor) {
this.invalidate();
this.browsingSession = undefined;
this.session = { scope: { ...scope }, state: { status: "searching", query: "", items, cursor } };
} else {
this.session!.state = { ...this.session!.state, status: "searching", query: "", items, cursor };
}
return this.start();
}
+17 -17
View File
@@ -153,28 +153,18 @@ pub async fn redis_get_value_in_db_with_preview_limit_core(
match &pool {
PoolKind::Redis(redis) => {
let key = redis_driver::redis_key_raw_to_bytes(key_raw)?;
let scope = redis_driver::RedisOperationScope { connection_id: connection_id.to_string(), db };
match redis.as_ref() {
RedisConnection::Direct(con) => {
let mut con = con.lock().await;
redis_driver::select_db(&mut *con, db).await?;
redis_driver::get_value_scoped_with_preview_limit(
&mut *con,
&key,
&redis_driver::RedisOperationScope { connection_id: connection_id.to_string(), db },
preview_limit_bytes,
)
.await
redis_driver::get_value_scoped_with_preview_limit(&mut *con, &key, &scope, preview_limit_bytes)
.await
}
RedisConnection::Cluster(cluster) => {
redis_driver::ensure_cluster_database(cluster, db).await?;
let mut con = redis_driver::cluster_key_connection_in_db(cluster, &key, db).await?;
redis_driver::get_value_scoped_with_preview_limit(
&mut con,
&key,
&redis_driver::RedisOperationScope { connection_id: connection_id.to_string(), db },
preview_limit_bytes,
)
.await
redis_driver::get_value_scoped_with_preview_limit(&mut con, &key, &scope, preview_limit_bytes).await
}
}
}
@@ -1300,12 +1290,22 @@ pub async fn redis_load_more_in_db_core(
match &pool {
PoolKind::Redis(redis) => {
let key = redis_driver::redis_key_raw_to_bytes(key_raw)?;
let scope = redis_driver::RedisOperationScope { connection_id: connection_id.to_string(), db };
match redis.as_ref() {
RedisConnection::Direct(con) => {
let mut con = con.lock().await;
redis_driver::select_db(&mut *con, db).await?;
redis_driver::load_more_collection(&mut *con, &key, key_type, cursor, count, filter, sort_direction)
.await
redis_driver::load_more_collection_scoped(
&mut *con,
&key,
key_type,
cursor,
count,
filter,
sort_direction,
&scope,
)
.await
}
RedisConnection::Cluster(cluster) => {
redis_driver::ensure_cluster_database(cluster, db).await?;
@@ -1318,7 +1318,7 @@ pub async fn redis_load_more_in_db_core(
count,
filter,
sort_direction,
&redis_driver::RedisOperationScope { connection_id: connection_id.to_string(), db },
&scope,
)
.await
}