[Tree widget]: implement descendants count cache on next#1680
Conversation
There was a problem hiding this comment.
Pull request overview
This PR expands the tree widget descendant-count cache so counts can be grouped by category and requested for either category roots or element parents, while keeping the legacy element-count API through aggregation.
Changes:
- Reworked
DescendantsCountCacherequest/cached value shape and query to return grouped descendant counts. - Restored
BaseIdsCache/BaseIdsCacheImplAPIs for descendant counts and element counts. - Updated and expanded unit coverage, plus corrected cache references in visibility documentation.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
packages/itwin/tree-widget/src/tree-widget-react/components/trees/common/internal/caches/DescendantsCountCache.ts |
Implements grouped descendant count batching, querying, and caching. |
packages/itwin/tree-widget/src/tree-widget-react/components/trees/common/internal/caches/BaseIdsCache.ts |
Exposes grouped descendant counts and aggregates them for element counts. |
packages/itwin/tree-widget/src/test/trees/models-tree/internal/ModelsTreeIdsCache.test.ts |
Updates model tree count cache tests for the new query result shape. |
packages/itwin/tree-widget/src/test/trees/common/internal/DescendantsCountCache.test.ts |
Expands cache tests to cover grouped category and element descendant count scenarios. |
packages/itwin/tree-widget/docs/Visibility.md |
Fixes documentation references from ElementChildrenCache to ChildElementsCache. |
Comments suppressed due to low confidence (2)
packages/itwin/tree-widget/src/tree-widget-react/components/trees/common/internal/caches/DescendantsCountCache.ts:198
- Rows produced for root-category and element requests use SQL NULL for
reqParent/reqCategory, but requests are keyed in the cache with JavaScriptundefined. Storing rows undernullmakes the subsequent lookup forundefinedmiss, so thetapdefault path overwrites these requests with 0/empty results. Normalize nullable request keys (for example,row.reqParent ?? undefinedandrow.reqCategory ?? undefined) before accessing the cache maps.
let parentEntry = modelEntry.get(row.reqParent);
if (!parentEntry) {
parentEntry = new Map();
modelEntry.set(row.reqParent, parentEntry);
}
let categoryEntry = parentEntry.get(row.reqCategory);
packages/itwin/tree-widget/src/test/trees/models-tree/internal/ModelsTreeIdsCache.test.ts:52
- This expected substring has the predicates in a different order than the query now generated (
Category.Id IN (...)comes beforeParent.Id IS NULL), so the stub rejects the intended query. Update this matcher or make it check the individual predicates independently.
if (query.includes("Descendants") && query.includes(`Model.Id = ${modelId} AND Parent.Id IS NULL AND Category.Id IN (${categoryId}, ${categoryId2})`)) {
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Tree-Widget Next benchmark
| Benchmark suite | Current: 85e13c7 | Previous: 72114e0 | Deviation | Status |
|---|---|---|---|---|
models tree 50k 3D elements search > get search paths |
1224 ms |
1262 ms |
-3.01% |
〰️ |
models tree 50k 3D elements search > get search paths (P95 of main thread blocks) |
65 ms |
62 ms |
4.84% |
〰️ |
models tree 50k 3D elements search > load hierarchy from search paths |
112513 ms |
110444 ms |
1.87% |
〰️ |
models tree 50k 3D elements search > load hierarchy from search paths (P95 of main thread blocks) |
38 ms |
40 ms |
-5% |
〰️ |
models tree 50k categories > collect nodes |
2992 ms |
2970 ms |
0.74% |
〰️ |
models tree 50k categories > collect nodes (P95 of main thread blocks) |
138 ms |
102 ms |
35.29% |
〰️ |
models tree 50k categories > validate initial visibility |
2572 ms |
2522 ms |
1.98% |
〰️ |
models tree 50k categories > validate initial visibility (P95 of main thread blocks) |
0 ms |
0 ms |
0% |
🟰 |
models tree 50k categories > change visibility |
90 ms |
76 ms |
18.42% |
〰️ |
models tree 50k categories > change visibility (P95 of main thread blocks) |
80 ms |
65 ms |
23.08% |
〰️ |
models tree 50k categories > validate changed visibility |
4648 ms |
4626 ms |
0.48% |
〰️ |
models tree 50k categories > validate changed visibility (P95 of main thread blocks) |
25 ms |
25 ms |
0% |
🟰 |
models tree 50k 3D elements > collect nodes |
44385 ms |
44420 ms |
-0.08% |
〰️ |
models tree 50k 3D elements > collect nodes (P95 of main thread blocks) |
72 ms |
67 ms |
7.46% |
〰️ |
models tree 50k 3D elements > validate initial visibility |
2509 ms |
2489 ms |
0.80% |
〰️ |
models tree 50k 3D elements > validate initial visibility (P95 of main thread blocks) |
0 ms |
0 ms |
0% |
🟰 |
models tree 50k 3D elements > change model visibility |
21 ms |
19 ms |
10.53% |
〰️ |
models tree 50k 3D elements > change model visibility (P95 of main thread blocks) |
0 ms |
0 ms |
0% |
🟰 |
models tree 50k 3D elements > validate changed model visibility |
2593 ms |
2493 ms |
4.01% |
〰️ |
models tree 50k 3D elements > validate changed model visibility (P95 of main thread blocks) |
23 ms |
0 ms |
2300% |
〰️ |
models tree 50k 3D elements > change category node visibility |
507 ms |
515 ms |
-1.55% |
〰️ |
models tree 50k 3D elements > change category node visibility (P95 of main thread blocks) |
52 ms |
62 ms |
-16.13% |
〰️ |
models tree 50k 3D elements > validate changed category visibility |
2515 ms |
2526 ms |
-0.44% |
〰️ |
models tree 50k 3D elements > validate changed category visibility (P95 of main thread blocks) |
0 ms |
0 ms |
0% |
🟰 |
models tree 50k 3D elements > validate per-model category override |
2519 ms |
2475 ms |
1.78% |
〰️ |
models tree 50k 3D elements > validate per-model category override (P95 of main thread blocks) |
0 ms |
0 ms |
0% |
🟰 |
models tree 50k 3D elements > change element visibility |
10 ms |
10 ms |
0% |
🟰 |
models tree 50k 3D elements > change element visibility (P95 of main thread blocks) |
0 ms |
0 ms |
0% |
🟰 |
models tree 50k 3D elements > validate changed element visibility |
3251 ms |
3187 ms |
2.01% |
〰️ |
models tree 50k 3D elements > validate changed element visibility (P95 of main thread blocks) |
72 ms |
73 ms |
-1.37% |
〰️ |
models tree 50k 3D child elements with different categories > collect nodes |
45847 ms |
44439 ms |
3.17% |
〰️ |
models tree 50k 3D child elements with different categories > collect nodes (P95 of main thread blocks) |
60 ms |
61 ms |
-1.64% |
〰️ |
models tree 50k 3D child elements with different categories > validate initial visibility |
2518 ms |
2459 ms |
2.40% |
〰️ |
models tree 50k 3D child elements with different categories > validate initial visibility (P95 of main thread blocks) |
0 ms |
0 ms |
0% |
🟰 |
models tree 50k 3D child elements with different categories > change visibility |
10 ms |
10 ms |
0% |
🟰 |
models tree 50k 3D child elements with different categories > change visibility (P95 of main thread blocks) |
0 ms |
0 ms |
0% |
🟰 |
models tree 50k 3D child elements with different categories > validate changed visibility |
3350 ms |
3219 ms |
4.07% |
〰️ |
models tree 50k 3D child elements with different categories > validate changed visibility (P95 of main thread blocks) |
64 ms |
57 ms |
12.28% |
〰️ |
categories tree 50k subCategories search > get search paths |
1884 ms |
1872 ms |
0.64% |
〰️ |
categories tree 50k subCategories search > get search paths (P95 of main thread blocks) |
41 ms |
43 ms |
-4.65% |
〰️ |
categories tree 50k subCategories search > load hierarchy from search paths |
5541 ms |
5522 ms |
0.34% |
〰️ |
categories tree 50k subCategories search > load hierarchy from search paths (P95 of main thread blocks) |
54 ms |
49 ms |
10.20% |
〰️ |
categories tree 50k subCategories > collect nodes |
6096 ms |
5994 ms |
1.70% |
〰️ |
categories tree 50k subCategories > collect nodes (P95 of main thread blocks) |
50 ms |
51 ms |
-1.96% |
〰️ |
categories tree 50k subCategories > validate initial visibility |
1689 ms |
1708 ms |
-1.11% |
〰️ |
categories tree 50k subCategories > validate initial visibility (P95 of main thread blocks) |
21 ms |
21 ms |
0% |
🟰 |
categories tree 50k subCategories > change visibility |
346 ms |
352 ms |
-1.70% |
〰️ |
categories tree 50k subCategories > change visibility (P95 of main thread blocks) |
27 ms |
23 ms |
17.39% |
〰️ |
categories tree 50k subCategories > validate changed visibility |
1614 ms |
1619 ms |
-0.31% |
〰️ |
categories tree 50k subCategories > validate changed visibility (P95 of main thread blocks) |
30 ms |
29 ms |
3.45% |
〰️ |
categories tree 50k categories > collect nodes |
2485 ms |
2537 ms |
-2.05% |
〰️ |
categories tree 50k categories > collect nodes (P95 of main thread blocks) |
139 ms |
130 ms |
6.92% |
〰️ |
categories tree 50k categories > validate initial visibility |
7397 ms |
7478 ms |
-1.08% |
〰️ |
categories tree 50k categories > validate initial visibility (P95 of main thread blocks) |
75 ms |
81 ms |
-7.41% |
〰️ |
categories tree 50k categories > change visibility |
698 ms |
708 ms |
-1.41% |
〰️ |
categories tree 50k categories > change visibility (P95 of main thread blocks) |
46 ms |
56 ms |
-17.86% |
〰️ |
categories tree 50k categories > validate changed visibility |
7356 ms |
7327 ms |
0.40% |
〰️ |
categories tree 50k categories > validate changed visibility (P95 of main thread blocks) |
37 ms |
34 ms |
8.82% |
〰️ |
classifications tree 50k classifications search > get search paths |
2224 ms |
2210 ms |
0.63% |
〰️ |
classifications tree 50k classifications search > get search paths (P95 of main thread blocks) |
140 ms |
137 ms |
2.19% |
〰️ |
classifications tree 50k classifications search > load hierarchy from search paths |
69615 ms |
69057 ms |
0.81% |
〰️ |
classifications tree 50k classifications search > load hierarchy from search paths (P95 of main thread blocks) |
23 ms |
31 ms |
-25.81% |
〰️ |
classifications tree 50k classifications > collect nodes |
37580 ms |
37360 ms |
0.59% |
〰️ |
classifications tree 50k classifications > collect nodes (P95 of main thread blocks) |
93 ms |
75 ms |
24% |
〰️ |
classifications tree 50k classifications > validate initial visibility |
4873 ms |
4833 ms |
0.83% |
〰️ |
classifications tree 50k classifications > validate initial visibility (P95 of main thread blocks) |
67 ms |
59 ms |
13.56% |
〰️ |
classifications tree 50k classifications > change visibility |
29 ms |
31 ms |
-6.45% |
〰️ |
classifications tree 50k classifications > change visibility (P95 of main thread blocks) |
0 ms |
0 ms |
0% |
🟰 |
classifications tree 50k classifications > validate changed visibility |
5228 ms |
5091 ms |
2.69% |
〰️ |
classifications tree 50k classifications > validate changed visibility (P95 of main thread blocks) |
161 ms |
90 ms |
78.89% |
🚨 |
This comment was automatically generated by workflow using github-action-benchmark.
Implement 1st stage of #1678.