Skip to content

Commit fcebfe6

Browse files
committed
feat: Add table-level compaction commands for R2 Data Catalog
1 parent e483b78 commit fcebfe6

File tree

4 files changed

+352
-42
lines changed

4 files changed

+352
-42
lines changed

.changeset/fine-pans-sit.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
"wrangler": minor
3+
---
4+
5+
Add table-level compaction commands for R2 Data Catalog:
6+
7+
- `wrangler r2 bucket catalog compaction enable <bucket> [namespace] [table]`
8+
- `wrangler r2 bucket catalog compaction disable <bucket> [namespace] [table]`
9+
10+
This allows you to enable and disable automatic file compaction for a specific R2 data catalog table.

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

Lines changed: 155 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1312,8 +1312,8 @@ describe("r2", () => {
13121312
Control settings for automatic file compaction maintenance jobs for your R2 data catalog [open-beta]
13131313
13141314
COMMANDS
1315-
wrangler r2 bucket catalog compaction enable <bucket> Enable automatic file compaction for your R2 data catalog [open-beta]
1316-
wrangler r2 bucket catalog compaction disable <bucket> Disable automatic file compaction for your R2 data catalog [open-beta]
1315+
wrangler r2 bucket catalog compaction enable <bucket> [namespace] [table] Enable automatic file compaction for your R2 data catalog or a specific table [open-beta]
1316+
wrangler r2 bucket catalog compaction disable <bucket> [namespace] [table] Disable automatic file compaction for your R2 data catalog or a specific table [open-beta]
13171317
13181318
GLOBAL FLAGS
13191319
-c, --config Path to Wrangler configuration file [string]
@@ -1381,12 +1381,14 @@ describe("r2", () => {
13811381
);
13821382
expect(std.out).toMatchInlineSnapshot(`
13831383
"
1384-
wrangler r2 bucket catalog compaction enable <bucket>
1384+
wrangler r2 bucket catalog compaction enable <bucket> [namespace] [table]
13851385
1386-
Enable automatic file compaction for your R2 data catalog [open-beta]
1386+
Enable automatic file compaction for your R2 data catalog or a specific table [open-beta]
13871387
13881388
POSITIONALS
1389-
bucket The name of the bucket which contains the catalog [string] [required]
1389+
bucket The name of the bucket which contains the catalog [string] [required]
1390+
namespace The namespace containing the table (optional, for table-level compaction) [string]
1391+
table The name of the table (optional, for table-level compaction) [string]
13901392
13911393
GLOBAL FLAGS
13921394
-c, --config Path to Wrangler configuration file [string]
@@ -1398,7 +1400,7 @@ describe("r2", () => {
13981400
13991401
OPTIONS
14001402
--target-size The target size for compacted files in MB (allowed values: 64, 128, 256, 512) [number] [default: 128]
1401-
--token A cloudflare api token with access to R2 and R2 Data Catalog which will be used to read/write files for compaction. [string] [required]"
1403+
--token A cloudflare api token with access to R2 and R2 Data Catalog (required for catalog-level compaction settings only) [string]"
14021404
`);
14031405
expect(std.err).toMatchInlineSnapshot(`
14041406
"X [ERROR] Not enough non-option arguments: got 0, need at least 1
@@ -1407,13 +1409,99 @@ describe("r2", () => {
14071409
`);
14081410
});
14091411

1410-
it("should error if --token is not provided", async () => {
1412+
it("should error if --token is not provided for catalog-level", async () => {
14111413
await expect(
14121414
runWrangler(
14131415
"r2 bucket catalog compaction enable testBucket --target-size 512"
14141416
)
14151417
).rejects.toThrowErrorMatchingInlineSnapshot(
1416-
`[Error: Missing required argument: token]`
1418+
`[Error: Token is required for catalog-level compaction. Use --token flag to provide a Cloudflare API token.]`
1419+
);
1420+
});
1421+
1422+
it("should enable table compaction without token", async () => {
1423+
msw.use(
1424+
http.post(
1425+
"*/accounts/some-account-id/r2-catalog/testBucket/namespaces/testNamespace/tables/testTable/maintenance-configs",
1426+
async ({ request }) => {
1427+
const body = await request.json();
1428+
expect(request.method).toEqual("POST");
1429+
expect(body).toEqual({
1430+
compaction: {
1431+
state: "enabled",
1432+
},
1433+
});
1434+
return HttpResponse.json(
1435+
createFetchResult({ success: true }, true)
1436+
);
1437+
},
1438+
{ once: true }
1439+
)
1440+
);
1441+
await runWrangler(
1442+
"r2 bucket catalog compaction enable testBucket testNamespace testTable"
1443+
);
1444+
expect(std.out).toMatchInlineSnapshot(
1445+
`
1446+
"
1447+
⛅️ wrangler x.x.x
1448+
──────────────────
1449+
✨ Successfully enabled file compaction for table 'testNamespace.testTable' in bucket 'testBucket'."
1450+
`
1451+
);
1452+
});
1453+
1454+
it("should enable table compaction with custom target size", async () => {
1455+
msw.use(
1456+
http.post(
1457+
"*/accounts/some-account-id/r2-catalog/testBucket/namespaces/testNamespace/tables/testTable/maintenance-configs",
1458+
async ({ request }) => {
1459+
const body = await request.json();
1460+
expect(request.method).toEqual("POST");
1461+
expect(body).toEqual({
1462+
compaction: {
1463+
state: "enabled",
1464+
target_size_mb: 256,
1465+
},
1466+
});
1467+
return HttpResponse.json(
1468+
createFetchResult({ success: true }, true)
1469+
);
1470+
},
1471+
{ once: true }
1472+
)
1473+
);
1474+
await runWrangler(
1475+
"r2 bucket catalog compaction enable testBucket testNamespace testTable --target-size 256"
1476+
);
1477+
expect(std.out).toMatchInlineSnapshot(
1478+
`
1479+
"
1480+
⛅️ wrangler x.x.x
1481+
──────────────────
1482+
✨ Successfully enabled file compaction for table 'testNamespace.testTable' in bucket 'testBucket'."
1483+
`
1484+
);
1485+
});
1486+
1487+
it("should error if only namespace is provided", async () => {
1488+
await expect(
1489+
runWrangler(
1490+
"r2 bucket catalog compaction enable testBucket testNamespace"
1491+
)
1492+
).rejects.toThrowErrorMatchingInlineSnapshot(
1493+
`[Error: Table name is required when namespace is specified]`
1494+
);
1495+
});
1496+
1497+
it("should error if only table is provided", async () => {
1498+
// This test ensures that if table is passed as namespace position, it errors properly
1499+
await expect(
1500+
runWrangler(
1501+
'r2 bucket catalog compaction enable testBucket "" testTable'
1502+
)
1503+
).rejects.toThrowErrorMatchingInlineSnapshot(
1504+
`[Error: Namespace is required when table is specified]`
14171505
);
14181506
});
14191507
});
@@ -1429,12 +1517,14 @@ describe("r2", () => {
14291517
);
14301518
expect(std.out).toMatchInlineSnapshot(`
14311519
"
1432-
wrangler r2 bucket catalog compaction disable <bucket>
1520+
wrangler r2 bucket catalog compaction disable <bucket> [namespace] [table]
14331521
1434-
Disable automatic file compaction for your R2 data catalog [open-beta]
1522+
Disable automatic file compaction for your R2 data catalog or a specific table [open-beta]
14351523
14361524
POSITIONALS
1437-
bucket The name of the bucket which contains the catalog [string] [required]
1525+
bucket The name of the bucket which contains the catalog [string] [required]
1526+
namespace The namespace containing the table (optional, for table-level compaction) [string]
1527+
table The name of the table (optional, for table-level compaction) [string]
14381528
14391529
GLOBAL FLAGS
14401530
-c, --config Path to Wrangler configuration file [string]
@@ -1503,6 +1593,60 @@ describe("r2", () => {
15031593
Disable cancelled."
15041594
`);
15051595
});
1596+
1597+
it("should disable table compaction when confirmed", async () => {
1598+
setIsTTY(true);
1599+
mockConfirm({
1600+
text: "Are you sure you want to disable file compaction for table 'testNamespace.testTable' in bucket 'testBucket'?",
1601+
result: true,
1602+
});
1603+
msw.use(
1604+
http.post(
1605+
"*/accounts/some-account-id/r2-catalog/testBucket/namespaces/testNamespace/tables/testTable/maintenance-configs",
1606+
async ({ request }) => {
1607+
const body = await request.json();
1608+
expect(request.method).toEqual("POST");
1609+
expect(body).toEqual({
1610+
compaction: {
1611+
state: "disabled",
1612+
},
1613+
});
1614+
return HttpResponse.json(
1615+
createFetchResult({ success: true }, true)
1616+
);
1617+
},
1618+
{ once: true }
1619+
)
1620+
);
1621+
await runWrangler(
1622+
"r2 bucket catalog compaction disable testBucket testNamespace testTable"
1623+
);
1624+
expect(std.out).toMatchInlineSnapshot(
1625+
`
1626+
"
1627+
⛅️ wrangler x.x.x
1628+
──────────────────
1629+
Successfully disabled file compaction for table 'testNamespace.testTable' in bucket 'testBucket'."
1630+
`
1631+
);
1632+
});
1633+
1634+
it("should cancel table compaction disable when rejected", async () => {
1635+
setIsTTY(true);
1636+
mockConfirm({
1637+
text: "Are you sure you want to disable file compaction for table 'testNamespace.testTable' in bucket 'testBucket'?",
1638+
result: false,
1639+
});
1640+
await runWrangler(
1641+
"r2 bucket catalog compaction disable testBucket testNamespace testTable"
1642+
);
1643+
expect(std.out).toMatchInlineSnapshot(`
1644+
"
1645+
⛅️ wrangler x.x.x
1646+
──────────────────
1647+
Disable cancelled."
1648+
`);
1649+
});
15061650
});
15071651
});
15081652
});

0 commit comments

Comments
 (0)