fix(redis): recognize OBJECT subcommands
This commit is contained in:
1 parent
08d73ce371
commit
7ca5e76c14
4 files changed
+55
-12
No files matched your search
@@ -115,11 +115,13 @@ const RAW_COMMANDS: Record<string, Spec> = {
|
|||||||
KEYS: [2, "generic", "blocked"],
|
KEYS: [2, "generic", "blocked"],
|
||||||
MIGRATE: [-6, "generic", "blocked"],
|
MIGRATE: [-6, "generic", "blocked"],
|
||||||
MOVE: [3, "generic", "confirm"],
|
MOVE: [3, "generic", "confirm"],
|
||||||
OBJECT_ENCODING: [3, "generic"],
|
// Redis exposes OBJECT operations as space-delimited subcommands; keep these
|
||||||
OBJECT_FREQ: [3, "generic"],
|
// keys aligned with COMMAND metadata so shared parsing and completion work.
|
||||||
OBJECT_IDLETIME: [3, "generic"],
|
"OBJECT ENCODING": [3, "generic"],
|
||||||
OBJECT_REFCOUNT: [3, "generic"],
|
"OBJECT FREQ": [3, "generic"],
|
||||||
OBJECT_HELP: [2, "generic"],
|
"OBJECT IDLETIME": [3, "generic"],
|
||||||
|
"OBJECT REFCOUNT": [3, "generic"],
|
||||||
|
"OBJECT HELP": [2, "generic"],
|
||||||
PERSIST: [2, "generic", "confirm"],
|
PERSIST: [2, "generic", "confirm"],
|
||||||
PEXPIRE: [-3, "generic", "confirm"],
|
PEXPIRE: [-3, "generic", "confirm"],
|
||||||
PEXPIREAT: [-3, "generic", "confirm"],
|
PEXPIREAT: [-3, "generic", "confirm"],
|
||||||
|
|||||||
+19
@@ -59,6 +59,25 @@ test("resolveRedisCommandSpec resolves subcommand then main", () => {
|
|||||||
assert.equal(main?.group, "string");
|
assert.equal(main?.group, "string");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("resolveRedisCommandSpec resolves every OBJECT subcommand with Redis arity", () => {
|
||||||
|
const expectedArities = new Map([
|
||||||
|
["ENCODING", 3],
|
||||||
|
["FREQ", 3],
|
||||||
|
["IDLETIME", 3],
|
||||||
|
["REFCOUNT", 3],
|
||||||
|
["HELP", 2],
|
||||||
|
]);
|
||||||
|
|
||||||
|
for (const [subcommand, arity] of expectedArities) {
|
||||||
|
const spec = resolveRedisCommandSpec(["OBJECT", subcommand]);
|
||||||
|
assert.ok(spec, `OBJECT ${subcommand} should resolve`);
|
||||||
|
assert.equal(spec.arity, arity);
|
||||||
|
assert.equal(spec.group, "generic");
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.equal(resolveRedisCommandSpec(["OBJECT", "UNKNOWN"]), undefined);
|
||||||
|
});
|
||||||
|
|
||||||
test("normal writes do not require confirmation but destructive commands do", () => {
|
test("normal writes do not require confirmation but destructive commands do", () => {
|
||||||
assert.equal(resolveRedisCommandSpec(["SET"])?.safety, "write");
|
assert.equal(resolveRedisCommandSpec(["SET"])?.safety, "write");
|
||||||
assert.equal(resolveRedisCommandSpec(["HSET"])?.safety, "write");
|
assert.equal(resolveRedisCommandSpec(["HSET"])?.safety, "write");
|
||||||
|
|||||||
+11
-7
@@ -1,12 +1,6 @@
|
|||||||
import assert from "node:assert/strict";
|
import assert from "node:assert/strict";
|
||||||
import { test } from "vitest";
|
import { test } from "vitest";
|
||||||
import {
|
import { buildRedisCompletionItems, getRedisCompletionContext, getRedisCompletionResultValidFor, shouldAutoOpenRedisCompletion, takesKeyArgument } from "../../apps/desktop/src/lib/redis/redisCompletion.ts";
|
||||||
buildRedisCompletionItems,
|
|
||||||
getRedisCompletionContext,
|
|
||||||
getRedisCompletionResultValidFor,
|
|
||||||
shouldAutoOpenRedisCompletion,
|
|
||||||
takesKeyArgument,
|
|
||||||
} from "../../apps/desktop/src/lib/redis/redisCompletion.ts";
|
|
||||||
|
|
||||||
function labels(items: { label: string }[]): string[] {
|
function labels(items: { label: string }[]): string[] {
|
||||||
return items.map((item) => item.label);
|
return items.map((item) => item.label);
|
||||||
@@ -60,6 +54,16 @@ test("subcommand mode: filters subcommands by prefix", () => {
|
|||||||
assert.ok(!names.includes("DESTROY"));
|
assert.ok(!names.includes("DESTROY"));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("OBJECT completion uses Redis space-delimited subcommands", () => {
|
||||||
|
const commandNames = labels(buildRedisCompletionItems("OBJECT", 6));
|
||||||
|
assert.ok(commandNames.includes("OBJECT"));
|
||||||
|
assert.ok(!commandNames.some((name) => name.startsWith("OBJECT_")));
|
||||||
|
|
||||||
|
const subcommands = labels(buildRedisCompletionItems("OBJECT ", 7));
|
||||||
|
assert.deepEqual(new Set(subcommands), new Set(["ENCODING", "FREQ", "IDLETIME", "REFCOUNT", "HELP"]));
|
||||||
|
assert.ok(!subcommands.some((name) => name.includes("_")));
|
||||||
|
});
|
||||||
|
|
||||||
test("argument mode: offers key names for key-taking commands", () => {
|
test("argument mode: offers key names for key-taking commands", () => {
|
||||||
const items = buildRedisCompletionItems("GET ", 4, { keys: ["user:1", "user:2", "config:db"] });
|
const items = buildRedisCompletionItems("GET ", 4, { keys: ["user:1", "user:2", "config:db"] });
|
||||||
const names = labels(items);
|
const names = labels(items);
|
||||||
|
|||||||
@@ -90,6 +90,24 @@ test("subcommands resolve via MAIN SUB key", () => {
|
|||||||
assert.equal(diags.length, 0);
|
assert.equal(diags.length, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("accepts all Redis OBJECT subcommands", () => {
|
||||||
|
for (const command of ["OBJECT ENCODING key", "OBJECT FREQ key", "OBJECT IDLETIME key", "OBJECT REFCOUNT key", "OBJECT HELP"]) {
|
||||||
|
assert.deepEqual(messages(command), [], `${command} should be valid`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("validates OBJECT subcommand arity and rejects unknown subcommands", () => {
|
||||||
|
for (const command of ["OBJECT ENCODING", "OBJECT FREQ", "OBJECT IDLETIME", "OBJECT REFCOUNT", "OBJECT HELP extra"]) {
|
||||||
|
const diags = buildRedisSyntaxDiagnostics(command);
|
||||||
|
assert.equal(diags.length, 1, `${command} should have one diagnostic`);
|
||||||
|
assert.match(diags[0].message, /Wrong number of arguments for 'OBJECT'/);
|
||||||
|
}
|
||||||
|
|
||||||
|
const unknown = buildRedisSyntaxDiagnostics("OBJECT UNKNOWN key");
|
||||||
|
assert.equal(unknown.length, 1);
|
||||||
|
assert.match(unknown[0].message, /Unknown command 'OBJECT'/);
|
||||||
|
});
|
||||||
|
|
||||||
test("treats command names case-insensitively", () => {
|
test("treats command names case-insensitively", () => {
|
||||||
assert.deepEqual(messages("get foo"), []);
|
assert.deepEqual(messages("get foo"), []);
|
||||||
const setDiag = buildRedisSyntaxDiagnostics("Set a b");
|
const setDiag = buildRedisSyntaxDiagnostics("Set a b");
|
||||||
|
|||||||
Reference in new issue
Block a user