Skip to content

Commit 760e682

Browse files
Merge branch 'tree-widget/next' into mast/classifications-tree-rename-action
2 parents 30b274a + 84569a5 commit 760e682

File tree

11 files changed

+140
-115
lines changed

11 files changed

+140
-115
lines changed

packages/itwin/tree-widget/src/test/trees/categories-tree/internal/CategoriesTreeIdsCache.test.ts

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ describe("CategoriesTreeIdsCache", () => {
5656
});
5757
const { imodel, ...keys } = buildIModelResult;
5858
using idsCache = new CategoriesTreeIdsCache(createIModelAccess(imodel), "3d");
59-
expect(await idsCache.getDirectChildDefinitionContainersAndCategories([keys.definitionContainer.id])).to.deep.eq({
59+
expect(await idsCache.getDirectChildDefinitionContainersAndCategories(keys.definitionContainer.id)).to.deep.eq({
6060
categories: [],
6161
definitionContainers: [],
6262
});
@@ -73,7 +73,7 @@ describe("CategoriesTreeIdsCache", () => {
7373
});
7474
const { imodel, ...keys } = buildIModelResult;
7575
using idsCache = new CategoriesTreeIdsCache(createIModelAccess(imodel), "3d");
76-
expect(await idsCache.getDirectChildDefinitionContainersAndCategories([keys.definitionContainerRoot.id])).to.deep.eq({
76+
expect(await idsCache.getDirectChildDefinitionContainersAndCategories(keys.definitionContainerRoot.id)).to.deep.eq({
7777
categories: [],
7878
definitionContainers: [],
7979
});
@@ -93,7 +93,7 @@ describe("CategoriesTreeIdsCache", () => {
9393
});
9494
const { imodel, ...keys } = buildIModelResult;
9595
using idsCache = new CategoriesTreeIdsCache(createIModelAccess(imodel), "3d");
96-
expect(await idsCache.getDirectChildDefinitionContainersAndCategories([keys.definitionContainerRoot.id])).to.deep.eq({
96+
expect(await idsCache.getDirectChildDefinitionContainersAndCategories(keys.definitionContainerRoot.id)).to.deep.eq({
9797
categories: [],
9898
definitionContainers: [keys.definitionContainerChild.id],
9999
});
@@ -111,7 +111,7 @@ describe("CategoriesTreeIdsCache", () => {
111111
});
112112
const { imodel, ...keys } = buildIModelResult;
113113
using idsCache = new CategoriesTreeIdsCache(createIModelAccess(imodel), "3d");
114-
expect(await idsCache.getDirectChildDefinitionContainersAndCategories([keys.definitionContainerRoot.id])).to.deep.eq({
114+
expect(await idsCache.getDirectChildDefinitionContainersAndCategories(keys.definitionContainerRoot.id)).to.deep.eq({
115115
categories: [{ id: keys.category.id, subCategoryChildCount: 1 }],
116116
definitionContainers: [],
117117
});
@@ -131,7 +131,7 @@ describe("CategoriesTreeIdsCache", () => {
131131
});
132132
const { imodel, ...keys } = buildIModelResult;
133133
using idsCache = new CategoriesTreeIdsCache(createIModelAccess(imodel), "3d");
134-
expect(await idsCache.getDirectChildDefinitionContainersAndCategories([keys.definitionContainerRoot.id])).to.deep.eq({
134+
expect(await idsCache.getDirectChildDefinitionContainersAndCategories(keys.definitionContainerRoot.id)).to.deep.eq({
135135
categories: [{ id: keys.category.id, subCategoryChildCount: 1 }],
136136
definitionContainers: [],
137137
});
@@ -154,7 +154,7 @@ describe("CategoriesTreeIdsCache", () => {
154154
});
155155
const { imodel, ...keys } = buildIModelResult;
156156
using idsCache = new CategoriesTreeIdsCache(createIModelAccess(imodel), "3d");
157-
expect(await idsCache.getDirectChildDefinitionContainersAndCategories([keys.definitionContainerRoot.id])).to.deep.eq({
157+
expect(await idsCache.getDirectChildDefinitionContainersAndCategories(keys.definitionContainerRoot.id)).to.deep.eq({
158158
categories: [{ id: keys.directCategory.id, subCategoryChildCount: 1 }],
159159
definitionContainers: [keys.definitionModelChild.id],
160160
});
@@ -175,7 +175,7 @@ describe("CategoriesTreeIdsCache", () => {
175175
});
176176
const { imodel, ...keys } = buildIModelResult;
177177
using idsCache = new CategoriesTreeIdsCache(createIModelAccess(imodel), "3d");
178-
expect(await idsCache.getDirectChildDefinitionContainersAndCategories([keys.definitionModelChild.id])).to.deep.eq({
178+
expect(await idsCache.getDirectChildDefinitionContainersAndCategories(keys.definitionModelChild.id)).to.deep.eq({
179179
categories: [{ id: keys.indirectCategory.id, subCategoryChildCount: 1 }],
180180
definitionContainers: [],
181181
});
@@ -193,7 +193,7 @@ describe("CategoriesTreeIdsCache", () => {
193193
});
194194
const { imodel, ...keys } = buildIModelResult;
195195
using idsCache = new CategoriesTreeIdsCache(createIModelAccess(imodel), "3d");
196-
expect(await idsCache.getAllContainedCategories([keys.definitionContainer.id])).to.deep.eq([]);
196+
expect(await idsCache.getAllContainedCategories(keys.definitionContainer.id)).to.deep.eq([]);
197197
});
198198

199199
it("returns indirectly contained categories when definition container contains definition container that has categories", async function () {
@@ -210,7 +210,7 @@ describe("CategoriesTreeIdsCache", () => {
210210
});
211211
const { imodel, ...keys } = buildIModelResult;
212212
using idsCache = new CategoriesTreeIdsCache(createIModelAccess(imodel), "3d");
213-
expect(await idsCache.getAllContainedCategories([keys.definitionContainerRoot.id])).to.deep.eq([keys.category.id]);
213+
expect(await idsCache.getAllContainedCategories(keys.definitionContainerRoot.id)).to.deep.eq([keys.category.id]);
214214
});
215215

216216
it("returns child categories when definition container contains categories", async function () {
@@ -225,7 +225,7 @@ describe("CategoriesTreeIdsCache", () => {
225225
});
226226
const { imodel, ...keys } = buildIModelResult;
227227
using idsCache = new CategoriesTreeIdsCache(createIModelAccess(imodel), "3d");
228-
expect(await idsCache.getAllContainedCategories([keys.definitionContainer.id])).to.deep.eq([keys.category.id]);
228+
expect(await idsCache.getAllContainedCategories(keys.definitionContainer.id)).to.deep.eq([keys.category.id]);
229229
});
230230

231231
it("returns direct and indirect categories when definition container contains categories and definition containers that contain categories", async function () {
@@ -245,7 +245,7 @@ describe("CategoriesTreeIdsCache", () => {
245245
});
246246
const { imodel, ...keys } = buildIModelResult;
247247
using idsCache = new CategoriesTreeIdsCache(createIModelAccess(imodel), "3d");
248-
const result = await idsCache.getAllContainedCategories([keys.definitionContainerRoot.id]);
248+
const result = await idsCache.getAllContainedCategories(keys.definitionContainerRoot.id);
249249
const expectedResult = [keys.indirectCategory.id, keys.directCategory.id];
250250
expect(expectedResult.every((id) => result.includes(id))).to.be.true;
251251
});
@@ -708,7 +708,7 @@ describe("CategoriesTreeIdsCache", () => {
708708
});
709709
const { imodel } = buildIModelResult;
710710
using idsCache = new CategoriesTreeIdsCache(createIModelAccess(imodel), "3d");
711-
expect([...getDistinctMapValues(await idsCache.getSubCategories(["0x123"]))]).to.deep.eq([]);
711+
expect([...getDistinctMapValues(await idsCache.getSubCategories("0x123"))]).to.deep.eq([]);
712712
});
713713

714714
it("returns empty list when category has one subCategory", async function () {
@@ -720,7 +720,7 @@ describe("CategoriesTreeIdsCache", () => {
720720
});
721721
const { imodel, ...keys } = buildIModelResult;
722722
using idsCache = new CategoriesTreeIdsCache(createIModelAccess(imodel), "3d");
723-
expect([...getDistinctMapValues(await idsCache.getSubCategories([keys.category.id]))]).to.deep.eq([]);
723+
expect([...getDistinctMapValues(await idsCache.getSubCategories(keys.category.id))]).to.deep.eq([]);
724724
});
725725

726726
it("returns subCategories when category has multiple subCategories", async function () {
@@ -734,7 +734,7 @@ describe("CategoriesTreeIdsCache", () => {
734734
});
735735
const { imodel, ...keys } = buildIModelResult;
736736
using idsCache = new CategoriesTreeIdsCache(createIModelAccess(imodel), "3d");
737-
const result = [...getDistinctMapValues(await idsCache.getSubCategories([keys.category.id]))];
737+
const result = [...getDistinctMapValues(await idsCache.getSubCategories(keys.category.id))];
738738
expect(result.includes(keys.subCategory.id)).to.be.true;
739739
expect(result.length).to.be.eq(2);
740740
});
@@ -754,7 +754,7 @@ describe("CategoriesTreeIdsCache", () => {
754754
});
755755
const { imodel, ...keys } = buildIModelResult;
756756
using idsCache = new CategoriesTreeIdsCache(createIModelAccess(imodel), "3d");
757-
const result = [...getDistinctMapValues(await idsCache.getSubCategories([keys.category2.id]))];
757+
const result = [...getDistinctMapValues(await idsCache.getSubCategories(keys.category2.id))];
758758
expect(result.includes(keys.subCategory2.id)).to.be.true;
759759
expect(result.length).to.be.eq(2);
760760
});

packages/itwin/tree-widget/src/test/trees/models-tree/Utils.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import { concatMap, EMPTY, expand, firstValueFrom, from, toArray } from "rxjs";
77
import sinon from "sinon";
8+
import { Id64 } from "@itwin/core-bentley";
89
import { createIModelHierarchyProvider } from "@itwin/presentation-hierarchies";
910
import {
1011
CLASS_NAME_Element,
@@ -87,17 +88,17 @@ interface IdsCacheMockProps {
8788

8889
export function createFakeIdsCache(props?: IdsCacheMockProps): ModelsTreeIdsCache {
8990
return sinon.createStubInstance(ModelsTreeIdsCache, {
90-
getChildSubjectIds: sinon.stub<[Id64Array], Promise<Id64Array>>().callsFake(async (subjectIds) => {
91-
const obs = from(subjectIds).pipe(
91+
getChildSubjectIds: sinon.stub<[Id64Arg], Promise<Id64Array>>().callsFake(async (subjectIds) => {
92+
const obs = from(Id64.iterable(subjectIds)).pipe(
9293
concatMap((id) => props?.subjectsHierarchy?.get(id) ?? EMPTY),
9394
expand((id) => props?.subjectsHierarchy?.get(id) ?? EMPTY),
9495
toArray(),
9596
);
9697
return firstValueFrom(obs);
9798
}),
9899
getChildSubjectModelIds: sinon.stub(),
99-
getSubjectModelIds: sinon.stub<[Id64Array], Promise<Id64Array>>().callsFake(async (subjectIds) => {
100-
const obs = from(subjectIds).pipe(
100+
getSubjectModelIds: sinon.stub<[Id64Arg], Promise<Id64Array>>().callsFake(async (subjectIds) => {
101+
const obs = from(Id64.iterable(subjectIds)).pipe(
101102
expand((id) => props?.subjectsHierarchy?.get(id) ?? EMPTY),
102103
concatMap((id) => props?.subjectModels?.get(id) ?? EMPTY),
103104
toArray(),

packages/itwin/tree-widget/src/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.ts

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
* See LICENSE.md in the project root for license terms and full copyright notice.
44
*--------------------------------------------------------------------------------------------*/
55

6+
import { Id64 } from "@itwin/core-bentley";
67
import { CLASS_NAME_DefinitionContainer, CLASS_NAME_Model, CLASS_NAME_SubCategory } from "../../common/internal/ClassNameDefinitions.js";
78
import { ModelCategoryElementsCountCache } from "../../common/internal/ModelCategoryElementsCountCache.js";
8-
import { getClassesByView, getDistinctMapValues } from "../../common/internal/Utils.js";
9+
import { getClassesByView, getDistinctMapValues, joinId64Arg } from "../../common/internal/Utils.js";
910

11+
import type { Id64Arg, Id64Array, Id64Set, Id64String } from "@itwin/core-bentley";
1012
import type { CategoryId, DefinitionContainerId, ElementId, ModelId, SubCategoryId } from "../../common/internal/Types.js";
11-
import type { Id64Array, Id64Set, Id64String } from "@itwin/core-bentley";
1213
import type { LimitingECSqlQueryExecutor } from "@itwin/presentation-hierarchies";
1314
import type { InstanceKey } from "@itwin/presentation-shared";
1415

@@ -65,22 +66,22 @@ export class CategoriesTreeIdsCache implements Disposable {
6566
this._categoryElementCounts[Symbol.dispose]();
6667
}
6768

68-
private async *queryFilteredElementsModels(filteredElementIds: Id64Array): AsyncIterableIterator<{
69+
private async *queryFilteredElementsModels(filteredElementIds: Id64Arg): AsyncIterableIterator<{
6970
modelId: Id64String;
7071
id: ElementId;
7172
}> {
7273
const query = `
7374
SELECT Model.Id modelId, ECInstanceId id
7475
FROM ${this._categoryElementClass}
75-
WHERE ECInstanceId IN (${filteredElementIds.join(", ")})
76+
WHERE ECInstanceId IN (${joinId64Arg(filteredElementIds, ",")})
7677
`;
7778
for await (const row of this._queryExecutor.createQueryReader({ ecsql: query }, { rowFormat: "ECSqlPropertyNames", limit: "unbounded" })) {
7879
yield { modelId: row.modelId, id: row.id };
7980
}
8081
}
8182

82-
public async getFilteredElementsModels(filteredElementIds: Id64Array) {
83-
if (filteredElementIds.length === 0) {
83+
public async getFilteredElementsModels(filteredElementIds: Id64Arg) {
84+
if (Id64.sizeOf(filteredElementIds) === 0) {
8485
return new Map<ElementId, ModelId>();
8586
}
8687

@@ -329,10 +330,10 @@ export class CategoriesTreeIdsCache implements Disposable {
329330
return this._modelWithCategoryModeledElements;
330331
}
331332

332-
public async getCategoriesModeledElements(modelId: Id64String, categoryIds: Id64Array): Promise<Id64Array> {
333+
public async getCategoriesModeledElements(modelId: Id64String, categoryIds: Id64Arg): Promise<Id64Array> {
333334
const modelWithCategoryModeledElements = await this.getModelWithCategoryModeledElements();
334335
const result = new Array<ElementId>();
335-
for (const categoryId of categoryIds) {
336+
for (const categoryId of Id64.iterable(categoryIds)) {
336337
const entry = modelWithCategoryModeledElements.get(`${modelId}-${categoryId}`);
337338
if (entry !== undefined) {
338339
result.push(...entry);
@@ -400,26 +401,26 @@ export class CategoriesTreeIdsCache implements Disposable {
400401
}
401402

402403
public async getDirectChildDefinitionContainersAndCategories(
403-
parentDefinitionContainerIds: Id64Array,
404+
parentDefinitionContainerIds: Id64Arg,
404405
): Promise<{ categories: CategoryInfo[]; definitionContainers: Array<DefinitionContainerId> }> {
405406
const definitionContainersInfo = await this.getDefinitionContainersInfo();
406407

407408
const result = { definitionContainers: new Array<DefinitionContainerId>(), categories: new Array<CategoryInfo>() };
408-
409-
parentDefinitionContainerIds.forEach((parentDefinitionContainerId) => {
409+
for (const parentDefinitionContainerId of Id64.iterable(parentDefinitionContainerIds)) {
410410
const parentDefinitionContainerInfo = definitionContainersInfo.get(parentDefinitionContainerId);
411-
if (parentDefinitionContainerInfo !== undefined) {
412-
result.definitionContainers.push(...parentDefinitionContainerInfo.childDefinitionContainerIds);
413-
result.categories.push(...parentDefinitionContainerInfo.childCategories);
411+
if (!parentDefinitionContainerInfo) {
412+
continue;
414413
}
415-
});
414+
result.definitionContainers.push(...parentDefinitionContainerInfo.childDefinitionContainerIds);
415+
result.categories.push(...parentDefinitionContainerInfo.childCategories);
416+
}
416417
return result;
417418
}
418419

419-
public async getCategoriesElementModels(categoryIds: Id64Array, includeSubModels?: boolean): Promise<Map<CategoryId, Set<ModelId>>> {
420+
public async getCategoriesElementModels(categoryIds: Id64Arg, includeSubModels?: boolean): Promise<Map<CategoryId, Set<ModelId>>> {
420421
const elementModelsCategories = await this.getElementModelsCategories();
421422
const result = new Map<CategoryId, Set<ModelId>>();
422-
for (const categoryId of categoryIds) {
423+
for (const categoryId of Id64.iterable(categoryIds)) {
423424
for (const [modelId, { categoryIds: categories, isSubModel }] of elementModelsCategories) {
424425
if ((includeSubModels || !isSubModel) && categories.has(categoryId)) {
425426
let categoryModels = result.get(categoryId);
@@ -444,20 +445,21 @@ export class CategoriesTreeIdsCache implements Disposable {
444445
return elementModelsCategories.has(elementId);
445446
}
446447

447-
public async getAllContainedCategories(definitionContainerIds: Id64Array): Promise<Id64Array> {
448+
public async getAllContainedCategories(definitionContainerIds: Id64Arg): Promise<Id64Array> {
448449
const result = new Array<CategoryId>();
449450

450451
const definitionContainersInfo = await this.getDefinitionContainersInfo();
451-
const indirectCategories = await Promise.all(
452-
definitionContainerIds.map(async (definitionContainerId) => {
453-
const definitionContainerInfo = definitionContainersInfo.get(definitionContainerId);
454-
if (definitionContainerInfo === undefined) {
455-
return [];
456-
}
457-
result.push(...definitionContainerInfo.childCategories.map((category) => category.id));
458-
return this.getAllContainedCategories(definitionContainerInfo.childDefinitionContainerIds);
459-
}),
460-
);
452+
const indirectCategoryPromises = new Array<Promise<Id64Array>>();
453+
for (const definitionContainerId of Id64.iterable(definitionContainerIds)) {
454+
const definitionContainerInfo = definitionContainersInfo.get(definitionContainerId);
455+
if (definitionContainerInfo === undefined) {
456+
continue;
457+
}
458+
result.push(...definitionContainerInfo.childCategories.map((category) => category.id));
459+
indirectCategoryPromises.push(this.getAllContainedCategories(definitionContainerInfo.childDefinitionContainerIds));
460+
}
461+
462+
const indirectCategories = await Promise.all(indirectCategoryPromises);
461463
for (const categories of indirectCategories) {
462464
result.push(...categories);
463465
}
@@ -538,10 +540,10 @@ export class CategoriesTreeIdsCache implements Disposable {
538540
return result;
539541
}
540542

541-
public async getSubCategories(categoryIds: Id64Array): Promise<Map<CategoryId, Array<SubCategoryId>>> {
543+
public async getSubCategories(categoryIds: Id64Arg): Promise<Map<CategoryId, Array<SubCategoryId>>> {
542544
const subCategoriesInfo = await this.getSubCategoriesInfo();
543545
const result = new Map<CategoryId, Array<SubCategoryId>>();
544-
for (const categoryId of categoryIds) {
546+
for (const categoryId of Id64.iterable(categoryIds)) {
545547
for (const [subCategoryId, subCategoryInfo] of subCategoriesInfo) {
546548
if (subCategoryInfo.categoryId === categoryId) {
547549
let categoryEntry = result.get(categoryId);

0 commit comments

Comments
 (0)