mirror of
https://github.com/lancedb/lancedb.git
synced 2026-11-15 07:06:52 +00:00
feat: expose the remaining refresh options on the SDKs (#4890)
The server's backfill request takes a row filter, failure limits, per-call timeouts and worker sizing, and SQL exposes all of them through `REFRESH COLUMN ... WHERE ... WITH (...)`, but the typed SDKs could send only batch_size, GPU placement and the retry and error policies. Anyone needing a filtered refresh or a bounded skip policy had to drop to SQL. This adds `where`, `max_failed_fraction`, `max_failed_rows`, `row_timeout_seconds`, `init_timeout_seconds`, `num_workers` and `max_executor_processes_per_worker` to Python, Rust and Node, passed through unchanged. `RefreshColumnOptions` now serializes straight into the request body, so the three SDKs share one producer. Node gets a `RefreshColumnOptions` object, which also carries the options it lacked before. A LanceDB Embedded refresh rejects every option other than batch_size and GPU placement, naming the option.
This commit is contained in:
@@ -647,6 +647,80 @@ describe("remote connection", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it("forwards refresh options to the backfill request", async () => {
|
||||
const bodies: unknown[] = [];
|
||||
await withMockDatabase(
|
||||
(req, res) => {
|
||||
const path = req.url ?? "";
|
||||
if (path.endsWith("/describe/")) {
|
||||
res.writeHead(200, { "Content-Type": "application/json" }).end(
|
||||
JSON.stringify({
|
||||
name: "docs",
|
||||
version: 1,
|
||||
schema: { fields: [] },
|
||||
}),
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (path === "/v1/table/docs/backfill_column") {
|
||||
let body = "";
|
||||
req.on("data", (chunk) => {
|
||||
body += chunk;
|
||||
});
|
||||
req.on("end", () => {
|
||||
bodies.push(JSON.parse(body));
|
||||
res
|
||||
.writeHead(202, { "Content-Type": "application/json" })
|
||||
.end('{"job_id": "j-9"}');
|
||||
});
|
||||
return;
|
||||
}
|
||||
res.writeHead(404).end();
|
||||
},
|
||||
async (db) => {
|
||||
const table = await db.openTable("docs");
|
||||
const job = await table.refreshColumnAsync("embedding", {
|
||||
where: "id % 2 = 0",
|
||||
batchSize: 16,
|
||||
gpuClass: "a10g",
|
||||
gpuCount: 2,
|
||||
errorPolicy: "skip",
|
||||
maxFailedFraction: 0.01,
|
||||
maxFailedRows: 50,
|
||||
rowTimeoutSeconds: 30,
|
||||
initTimeoutSeconds: 120,
|
||||
maxExecutorProcessesPerWorker: 2,
|
||||
});
|
||||
expect(job.id).toBe("j-9");
|
||||
await table.refreshColumnAsync("embedding");
|
||||
// Invalid options reject before any request is sent.
|
||||
for (const [options, message] of [
|
||||
[{ maxFailedRows: -1 }, "maxFailedRows"],
|
||||
[{ errorPolicy: "retry" }, "errorPolicy"],
|
||||
[{ where: " " }, "where"],
|
||||
[{ maxFailedFraction: 2 }, "max_failed_fraction"],
|
||||
[{ rowTimeoutSeconds: 0 }, "row_timeout_seconds"],
|
||||
[{ numWorkers: 0 }, "num_workers"],
|
||||
[{ gpuCount: 0 }, "gpu_count"],
|
||||
] as const) {
|
||||
await expect(
|
||||
table.refreshColumnAsync("embedding", options),
|
||||
).rejects.toThrow(message);
|
||||
}
|
||||
},
|
||||
);
|
||||
expect(bodies).toEqual([
|
||||
JSON.parse(
|
||||
`{"column": "embedding", "where": "id % 2 = 0", "batch_size": 16,
|
||||
"gpu_class": "a10g", "gpu_count": 2, "error_policy": "skip",
|
||||
"max_failed_fraction": 0.01, "max_failed_rows": 50,
|
||||
"row_timeout_seconds": 30, "init_timeout_seconds": 120,
|
||||
"max_executor_processes_per_worker": 2}`,
|
||||
),
|
||||
{ column: "embedding" },
|
||||
]);
|
||||
});
|
||||
|
||||
it("surfaces JSON server errors from remote table operations", async () => {
|
||||
await withMockDatabase(
|
||||
(req, res) => {
|
||||
|
||||
@@ -5590,6 +5590,17 @@ describe("computed columns", () => {
|
||||
expect(rows.map((r) => r.doubled).sort()).toEqual([2, 4]);
|
||||
});
|
||||
|
||||
it("rejects Enterprise refresh options on local tables", async () => {
|
||||
const db = await connect(tmpDir.name);
|
||||
const table = await db.createTable("refresh_options_local", [{ x: 1 }]);
|
||||
await expect(table.refreshColumn("x", { where: "x > 0" })).rejects.toThrow(
|
||||
"where requires a LanceDB Enterprise refresh",
|
||||
);
|
||||
await expect(
|
||||
table.refreshColumnAsync("x", { errorPolicy: "skip" }),
|
||||
).rejects.toThrow("error_policy requires a LanceDB Enterprise refresh");
|
||||
});
|
||||
|
||||
it("records Function errors only on remote tables", async () => {
|
||||
const db = await connect(tmpDir.name);
|
||||
const table = await db.createTable("errors_local", [{ x: 1 }]);
|
||||
|
||||
Reference in New Issue
Block a user