fix: aggregate nested notebook note counts
This commit is contained in:
1 parent
63a01b0181
commit
f302f9d584
2 files changed
+70
-3
No files matched your search
@@ -0,0 +1,56 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { buildNotebookTree } from "./utils.ts";
|
||||
|
||||
const notebook = (id, parentId, memoCount, lastMemoUpdatedAt = null) => ({
|
||||
id,
|
||||
parentId,
|
||||
name: id,
|
||||
slug: null,
|
||||
icon: null,
|
||||
color: null,
|
||||
sortOrder: 0,
|
||||
memoCount,
|
||||
lastMemoUpdatedAt,
|
||||
createdAt: "2026-01-01T00:00:00.000Z",
|
||||
updatedAt: "2026-01-01T00:00:00.000Z",
|
||||
});
|
||||
|
||||
describe("buildNotebookTree", () => {
|
||||
test("rolls descendant memo counts and update times into every ancestor", () => {
|
||||
const [root] = buildNotebookTree([
|
||||
notebook("root", null, 2, "2026-01-02T00:00:00.000Z"),
|
||||
notebook("child", "root", 3, "2026-01-03T00:00:00.000Z"),
|
||||
notebook("grandchild", "child", 5, "2026-01-04T00:00:00.000Z"),
|
||||
]);
|
||||
|
||||
expect(root.memoCount).toBe(10);
|
||||
expect(root.lastMemoUpdatedAt).toBe("2026-01-04T00:00:00.000Z");
|
||||
expect(root.children[0].memoCount).toBe(8);
|
||||
expect(root.children[0].lastMemoUpdatedAt).toBe("2026-01-04T00:00:00.000Z");
|
||||
expect(root.children[0].children[0].memoCount).toBe(5);
|
||||
});
|
||||
|
||||
test("sorts siblings after descendant counts have been rolled up", () => {
|
||||
const roots = buildNotebookTree(
|
||||
[
|
||||
notebook("larger-subtree", null, 0),
|
||||
notebook("child", "larger-subtree", 4),
|
||||
notebook("smaller-subtree", null, 3),
|
||||
],
|
||||
(first, second) => second.memoCount - first.memoCount,
|
||||
);
|
||||
|
||||
expect(roots.map((node) => node.id)).toEqual(["larger-subtree", "smaller-subtree"]);
|
||||
expect(roots.map((node) => node.memoCount)).toEqual([4, 3]);
|
||||
});
|
||||
|
||||
test("does not mutate the notebook records returned by the repository", () => {
|
||||
const root = notebook("root", null, 1);
|
||||
const child = notebook("child", "root", 2);
|
||||
|
||||
buildNotebookTree([root, child]);
|
||||
|
||||
expect(root.memoCount).toBe(1);
|
||||
expect(root).not.toHaveProperty("children");
|
||||
});
|
||||
});
|
||||
@@ -29,12 +29,23 @@ export const buildNotebookTree = (notebooks: Notebook[], compareNodes: NotebookN
|
||||
}
|
||||
}
|
||||
|
||||
const sortNodes = (items: NotebookNode[]) => {
|
||||
const rollUpAndSortNodes = (items: NotebookNode[]) => {
|
||||
for (const item of items) {
|
||||
rollUpAndSortNodes(item.children);
|
||||
|
||||
for (const child of item.children) {
|
||||
item.memoCount += child.memoCount;
|
||||
|
||||
if (child.lastMemoUpdatedAt && (!item.lastMemoUpdatedAt || child.lastMemoUpdatedAt > item.lastMemoUpdatedAt)) {
|
||||
item.lastMemoUpdatedAt = child.lastMemoUpdatedAt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
items.sort(compareNodes);
|
||||
items.forEach((item) => sortNodes(item.children));
|
||||
};
|
||||
|
||||
sortNodes(roots);
|
||||
rollUpAndSortNodes(roots);
|
||||
return roots;
|
||||
};
|
||||
|
||||
|
||||
Reference in new issue
Block a user