Skip to content

Commit 2780849

Browse files
authored
Accept { name: string }[] in kv bulk delete (#7479)
1 parent 8ad5be9 commit 2780849

File tree

4 files changed

+111
-11
lines changed

4 files changed

+111
-11
lines changed

.changeset/wise-pens-walk.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"wrangler": minor
3+
---
4+
5+
Accept a JSON file of the format `{ name: string }[]` in `wrangler kv bulk delete`, as well as the current `string[]` format.

packages/wrangler/src/__tests__/kv.local.test.ts

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ describe("wrangler", () => {
207207
`);
208208
});
209209

210-
it("should delete local bulk kv storage", async () => {
210+
it("should delete local bulk kv storage (string)", async () => {
211211
const keyValues = [
212212
{
213213
key: "hello",
@@ -268,6 +268,74 @@ describe("wrangler", () => {
268268
`);
269269
});
270270

271+
it("should delete local bulk kv storage ({ name })", async () => {
272+
const keyValues = [
273+
{
274+
key: "hello",
275+
value: "world",
276+
},
277+
{
278+
key: "test",
279+
value: "value",
280+
},
281+
];
282+
writeFileSync("./keys.json", JSON.stringify(keyValues));
283+
await runWrangler(
284+
`kv bulk put keys.json --namespace-id bulk-namespace-id --local`
285+
);
286+
await runWrangler(`kv key list --namespace-id bulk-namespace-id --local`);
287+
expect(std.out).toMatchInlineSnapshot(`
288+
"Success!
289+
[
290+
{
291+
\\"name\\": \\"hello\\"
292+
},
293+
{
294+
\\"name\\": \\"test\\"
295+
}
296+
]"
297+
`);
298+
const keys = [
299+
{
300+
name: "hello",
301+
},
302+
{
303+
name: "test",
304+
},
305+
];
306+
writeFileSync("./keys.json", JSON.stringify(keys));
307+
await runWrangler(
308+
`kv bulk delete keys.json --namespace-id bulk-namespace-id --local --force`
309+
);
310+
expect(std.out).toMatchInlineSnapshot(`
311+
"Success!
312+
[
313+
{
314+
\\"name\\": \\"hello\\"
315+
},
316+
{
317+
\\"name\\": \\"test\\"
318+
}
319+
]
320+
Success!"
321+
`);
322+
323+
await runWrangler(`kv key list --namespace-id bulk-namespace-id --local`);
324+
expect(std.out).toMatchInlineSnapshot(`
325+
"Success!
326+
[
327+
{
328+
\\"name\\": \\"hello\\"
329+
},
330+
{
331+
\\"name\\": \\"test\\"
332+
}
333+
]
334+
Success!
335+
[]"
336+
`);
337+
});
338+
271339
it("should follow persist-to for local kv storage", async () => {
272340
await runWrangler(
273341
`kv:key put val value --namespace-id some-namespace-id --local`

packages/wrangler/src/__tests__/kv.test.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1629,7 +1629,7 @@ describe("wrangler", () => {
16291629
return requests;
16301630
}
16311631

1632-
it("should delete the keys parsed from a file", async () => {
1632+
it("should delete the keys parsed from a file (string)", async () => {
16331633
const keys = ["someKey1", "ns:someKey2"];
16341634
writeFileSync("./keys.json", JSON.stringify(keys));
16351635
mockConfirm({
@@ -1646,6 +1646,26 @@ describe("wrangler", () => {
16461646
expect(std.err).toMatchInlineSnapshot(`""`);
16471647
});
16481648

1649+
it("should delete the keys parsed from a file ({ name })", async () => {
1650+
const keys = [{ name: "someKey1" }, { name: "ns:someKey2" }];
1651+
writeFileSync("./keys.json", JSON.stringify(keys));
1652+
mockConfirm({
1653+
text: `Are you sure you want to delete all the keys read from "keys.json" from kv-namespace with id "some-namespace-id"?`,
1654+
result: true,
1655+
});
1656+
const requests = mockDeleteRequest(
1657+
"some-namespace-id",
1658+
keys.map((k) => k.name)
1659+
);
1660+
await runWrangler(
1661+
`kv bulk delete --namespace-id some-namespace-id keys.json`
1662+
);
1663+
expect(requests.count).toEqual(1);
1664+
expect(std.out).toMatchInlineSnapshot(`"Success!"`);
1665+
expect(std.warn).toMatchInlineSnapshot(`""`);
1666+
expect(std.err).toMatchInlineSnapshot(`""`);
1667+
});
1668+
16491669
it("should delete the keys in batches of 5000 parsed from a file", async () => {
16501670
const keys = new Array(12000).fill("some-key");
16511671
writeFileSync("./keys.json", JSON.stringify(keys));
@@ -1754,7 +1774,7 @@ describe("wrangler", () => {
17541774
)
17551775
).rejects.toThrowErrorMatchingInlineSnapshot(`
17561776
[Error: Unexpected JSON input from "keys.json".
1757-
Expected an array of strings.
1777+
Expected an array of strings or objects with a "name" key.
17581778
The item at index 1 is type: "number" - 12354
17591779
The item at index 2 is type: "object" - {"key":"someKey"}
17601780
The item at index 3 is type: "object" - null]

packages/wrangler/src/kv/index.ts

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -815,7 +815,10 @@ export const kvBulkDeleteCommand = createCommand({
815815
}
816816
}
817817

818-
const content = parseJSON(readFileSync(filename), filename) as string[];
818+
const content = parseJSON(readFileSync(filename), filename) as (
819+
| string
820+
| { name: string }
821+
)[];
819822

820823
if (!Array.isArray(content)) {
821824
throw new UserError(
@@ -825,21 +828,25 @@ export const kvBulkDeleteCommand = createCommand({
825828
}
826829

827830
const errors: string[] = [];
828-
for (let i = 0; i < content.length; i++) {
829-
const key = content[i];
831+
832+
const keysToDelete: string[] = [];
833+
for (const [index, item] of content.entries()) {
834+
const key = typeof item !== "string" ? item?.name : item;
835+
830836
if (typeof key !== "string") {
831837
errors.push(
832-
`The item at index ${i} is type: "${typeof key}" - ${JSON.stringify(
833-
key
838+
`The item at index ${index} is type: "${typeof item}" - ${JSON.stringify(
839+
item
834840
)}`
835841
);
836842
}
843+
keysToDelete.push(key);
837844
}
838845

839846
if (errors.length > 0) {
840847
throw new UserError(
841848
`Unexpected JSON input from "${filename}".\n` +
842-
`Expected an array of strings.\n` +
849+
`Expected an array of strings or objects with a "name" key.\n` +
843850
errors.join("\n")
844851
);
845852
}
@@ -851,7 +858,7 @@ export const kvBulkDeleteCommand = createCommand({
851858
config.configPath,
852859
namespaceId,
853860
async (namespace) => {
854-
for (const key of content) {
861+
for (const key of keysToDelete) {
855862
await namespace.delete(key);
856863
}
857864
}
@@ -861,7 +868,7 @@ export const kvBulkDeleteCommand = createCommand({
861868
} else {
862869
const accountId = await requireAuth(config);
863870

864-
await deleteKVBulkKeyValue(accountId, namespaceId, content);
871+
await deleteKVBulkKeyValue(accountId, namespaceId, keysToDelete);
865872
metricEvent = "delete kv key-values (bulk)";
866873
}
867874

0 commit comments

Comments
 (0)