feat(FN-4785): complete Step 1 — add batched task column lookup
Fusion-Task-Id: FN-4785 Fusion-Task-Lineage: be241ee7-9df0-433c-a00b-997bcd558862
This commit is contained in:
committed by
gsxdsm
parent
d89a4569f1
commit
5ca7f45fe1
77
packages/core/src/__tests__/store-get-task-columns.test.ts
Normal file
77
packages/core/src/__tests__/store-get-task-columns.test.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { createTaskStoreTestHarness } from "./store-test-helpers.js";
|
||||
|
||||
describe("TaskStore.getTaskColumns", () => {
|
||||
const harness = createTaskStoreTestHarness();
|
||||
|
||||
beforeEach(async () => {
|
||||
await harness.beforeEach();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await harness.afterEach();
|
||||
});
|
||||
|
||||
it("returns empty map for empty input", async () => {
|
||||
const store = harness.store();
|
||||
const prepareSpy = vi.spyOn((store as any).db, "prepare");
|
||||
|
||||
const result = await store.getTaskColumns([]);
|
||||
|
||||
expect(result.size).toBe(0);
|
||||
expect(prepareSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("returns columns for active tasks", async () => {
|
||||
const store = harness.store();
|
||||
const one = await harness.createTestTask();
|
||||
const two = await harness.createTestTask();
|
||||
await store.moveTask(two.id, "in-progress");
|
||||
|
||||
const result = await store.getTaskColumns([one.id, two.id]);
|
||||
|
||||
expect(result.get(one.id)).toBe("todo");
|
||||
expect(result.get(two.id)).toBe("in-progress");
|
||||
});
|
||||
|
||||
it("maps archived tasks to archived column", async () => {
|
||||
const store = harness.store();
|
||||
const task = await harness.createTestTask();
|
||||
await store.moveTask(task.id, "done");
|
||||
await store.archiveTask(task.id);
|
||||
|
||||
const result = await store.getTaskColumns([task.id]);
|
||||
|
||||
expect(result.get(task.id)).toBe("archived");
|
||||
});
|
||||
|
||||
it("handles mixed active, archived, and unknown ids", async () => {
|
||||
const store = harness.store();
|
||||
const active = await harness.createTestTask();
|
||||
const archived = await harness.createTestTask();
|
||||
await store.moveTask(archived.id, "done");
|
||||
await store.archiveTask(archived.id);
|
||||
|
||||
const result = await store.getTaskColumns([active.id, archived.id, "FN-DOES-NOT-EXIST"]);
|
||||
|
||||
expect(result.get(active.id)).toBe("todo");
|
||||
expect(result.get(archived.id)).toBe("archived");
|
||||
expect(result.has("FN-DOES-NOT-EXIST")).toBe(false);
|
||||
});
|
||||
|
||||
it("queries live tasks once for large batches", async () => {
|
||||
const store = harness.store();
|
||||
const tasks = await Promise.all(Array.from({ length: 120 }, () => harness.createTestTask()));
|
||||
const ids = tasks.map((task) => task.id);
|
||||
|
||||
const prepareSpy = vi.spyOn((store as any).db, "prepare");
|
||||
const result = await store.getTaskColumns(ids);
|
||||
|
||||
const liveColumnQueryCalls = prepareSpy.mock.calls.filter(([sql]) =>
|
||||
typeof sql === "string" && sql.includes('SELECT id, "column" FROM tasks WHERE id IN ('),
|
||||
);
|
||||
|
||||
expect(result.size).toBe(ids.length);
|
||||
expect(liveColumnQueryCalls).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
@@ -3300,6 +3300,44 @@ export class TaskStore extends EventEmitter<TaskStoreEvents> {
|
||||
});
|
||||
}
|
||||
|
||||
async getTaskColumns(ids: string[]): Promise<Map<string, Column>> {
|
||||
if (ids.length === 0) {
|
||||
return new Map();
|
||||
}
|
||||
|
||||
const uniqueIds = [...new Set(ids)];
|
||||
const placeholders = uniqueIds.map(() => "?").join(",");
|
||||
const rows = this.db
|
||||
.prepare(`SELECT id, "column" FROM tasks WHERE id IN (${placeholders})`)
|
||||
.all(...uniqueIds) as Array<{ id: string; column: Column }>;
|
||||
|
||||
const activeById = new Map<string, Column>();
|
||||
for (const row of rows) {
|
||||
activeById.set(row.id, row.column);
|
||||
}
|
||||
|
||||
const missingIds: string[] = [];
|
||||
for (const id of uniqueIds) {
|
||||
if (!activeById.has(id)) {
|
||||
missingIds.push(id);
|
||||
}
|
||||
}
|
||||
|
||||
const archivedSet = missingIds.length > 0 ? this.archiveDb.filterArchived(missingIds) : new Set<string>();
|
||||
|
||||
const result = new Map<string, Column>();
|
||||
for (const id of uniqueIds) {
|
||||
const activeColumn = activeById.get(id);
|
||||
if (activeColumn !== undefined) {
|
||||
result.set(id, activeColumn);
|
||||
} else if (archivedSet.has(id)) {
|
||||
result.set(id, "archived");
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async listTasks(options?: {
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
|
||||
Reference in New Issue
Block a user