@itwin/tree-widget-react 3.16.1 → 3.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/CHANGELOG.md +24 -2
  2. package/lib/cjs/tree-widget-react/components/SelectableTree.js.map +1 -1
  3. package/lib/cjs/tree-widget-react/components/TreeSelector.js.map +1 -1
  4. package/lib/cjs/tree-widget-react/components/TreeWidgetUiItemsProvider.js +1 -1
  5. package/lib/cjs/tree-widget-react/components/TreeWidgetUiItemsProvider.js.map +1 -1
  6. package/lib/cjs/tree-widget-react/components/tree-header/TreeHeader.js.map +1 -1
  7. package/lib/cjs/tree-widget-react/components/tree-header/TreeWithHeader.js.map +1 -1
  8. package/lib/cjs/tree-widget-react/components/trees/categories-tree/CategoriesTree.d.ts +2 -2
  9. package/lib/cjs/tree-widget-react/components/trees/categories-tree/CategoriesTree.js +2 -1
  10. package/lib/cjs/tree-widget-react/components/trees/categories-tree/CategoriesTree.js.map +1 -1
  11. package/lib/cjs/tree-widget-react/components/trees/categories-tree/CategoriesTreeButtons.js.map +1 -1
  12. package/lib/cjs/tree-widget-react/components/trees/categories-tree/CategoriesTreeComponent.d.ts +1 -1
  13. package/lib/cjs/tree-widget-react/components/trees/categories-tree/CategoriesTreeComponent.js.map +1 -1
  14. package/lib/cjs/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.d.ts +13 -0
  15. package/lib/cjs/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.js +92 -74
  16. package/lib/cjs/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.js.map +1 -1
  17. package/lib/cjs/tree-widget-react/components/trees/categories-tree/UseCategoriesTree.d.ts +3 -1
  18. package/lib/cjs/tree-widget-react/components/trees/categories-tree/UseCategoriesTree.js +21 -8
  19. package/lib/cjs/tree-widget-react/components/trees/categories-tree/UseCategoriesTree.js.map +1 -1
  20. package/lib/cjs/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.d.ts +21 -9
  21. package/lib/cjs/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.js +300 -251
  22. package/lib/cjs/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.js.map +1 -1
  23. package/lib/cjs/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.d.ts +2 -0
  24. package/lib/cjs/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.js +66 -107
  25. package/lib/cjs/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.js.map +1 -1
  26. package/lib/cjs/tree-widget-react/components/trees/common/CategoriesVisibilityUtils.js +22 -12
  27. package/lib/cjs/tree-widget-react/components/trees/common/CategoriesVisibilityUtils.js.map +1 -1
  28. package/lib/cjs/tree-widget-react/components/trees/common/UseActiveViewport.js.map +1 -1
  29. package/lib/cjs/tree-widget-react/components/trees/common/UseHierarchyVisibility.js.map +1 -1
  30. package/lib/cjs/tree-widget-react/components/trees/common/components/ProgressOverlay.js.map +1 -1
  31. package/lib/cjs/tree-widget-react/components/trees/common/components/Tree.d.ts +2 -2
  32. package/lib/cjs/tree-widget-react/components/trees/common/components/Tree.js.map +1 -1
  33. package/lib/cjs/tree-widget-react/components/trees/common/components/TreeNodeCheckbox.d.ts +1 -1
  34. package/lib/cjs/tree-widget-react/components/trees/common/components/TreeNodeCheckbox.js.map +1 -1
  35. package/lib/cjs/tree-widget-react/components/trees/common/components/TreeRenderer.d.ts +1 -1
  36. package/lib/cjs/tree-widget-react/components/trees/common/components/TreeRenderer.js +2 -2
  37. package/lib/cjs/tree-widget-react/components/trees/common/components/TreeRenderer.js.map +1 -1
  38. package/lib/cjs/tree-widget-react/components/trees/common/components/VisibilityTree.d.ts +3 -3
  39. package/lib/cjs/tree-widget-react/components/trees/common/components/VisibilityTree.js.map +1 -1
  40. package/lib/cjs/tree-widget-react/components/trees/common/components/VisibilityTreeRenderer.d.ts +1 -1
  41. package/lib/cjs/tree-widget-react/components/trees/common/components/VisibilityTreeRenderer.js.map +1 -1
  42. package/lib/cjs/tree-widget-react/components/trees/common/internal/Utils.d.ts +25 -0
  43. package/lib/cjs/tree-widget-react/components/trees/common/internal/Utils.js +83 -0
  44. package/lib/cjs/tree-widget-react/components/trees/common/internal/Utils.js.map +1 -0
  45. package/lib/cjs/tree-widget-react/components/trees/models-tree/ModelsTree.d.ts +1 -1
  46. package/lib/cjs/tree-widget-react/components/trees/models-tree/ModelsTree.js.map +1 -1
  47. package/lib/cjs/tree-widget-react/components/trees/models-tree/ModelsTreeButtons.js.map +1 -1
  48. package/lib/cjs/tree-widget-react/components/trees/models-tree/ModelsTreeComponent.js.map +1 -1
  49. package/lib/cjs/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.d.ts +1 -0
  50. package/lib/cjs/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.js +86 -28
  51. package/lib/cjs/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.js.map +1 -1
  52. package/lib/cjs/tree-widget-react/components/trees/models-tree/UseModelsTree.js +2 -1
  53. package/lib/cjs/tree-widget-react/components/trees/models-tree/UseModelsTree.js.map +1 -1
  54. package/lib/cjs/tree-widget-react/components/trees/models-tree/Utils.d.ts +5 -6
  55. package/lib/cjs/tree-widget-react/components/trees/models-tree/Utils.js +5 -17
  56. package/lib/cjs/tree-widget-react/components/trees/models-tree/Utils.js.map +1 -1
  57. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.js +5 -4
  58. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.js.map +1 -1
  59. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/FilteredTree.d.ts +7 -1
  60. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/FilteredTree.js +52 -0
  61. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/FilteredTree.js.map +1 -1
  62. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.d.ts +28 -12
  63. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js +382 -278
  64. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js.map +1 -1
  65. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeNode.d.ts +1 -1
  66. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeNode.js.map +1 -1
  67. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js +272 -139
  68. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js.map +1 -1
  69. package/lib/cjs/tree-widget-react-internal.d.ts +2 -1
  70. package/lib/cjs/tree-widget-react-internal.js +4 -1
  71. package/lib/cjs/tree-widget-react-internal.js.map +1 -1
  72. package/lib/esm/tree-widget-react/components/SelectableTree.js.map +1 -1
  73. package/lib/esm/tree-widget-react/components/TreeSelector.js.map +1 -1
  74. package/lib/esm/tree-widget-react/components/TreeWidgetUiItemsProvider.js +1 -1
  75. package/lib/esm/tree-widget-react/components/TreeWidgetUiItemsProvider.js.map +1 -1
  76. package/lib/esm/tree-widget-react/components/tree-header/TreeHeader.js.map +1 -1
  77. package/lib/esm/tree-widget-react/components/tree-header/TreeWithHeader.js.map +1 -1
  78. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTree.d.ts +2 -2
  79. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTree.js +2 -1
  80. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTree.js.map +1 -1
  81. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeButtons.js.map +1 -1
  82. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeComponent.d.ts +1 -1
  83. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeComponent.js.map +1 -1
  84. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.d.ts +13 -0
  85. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.js +92 -74
  86. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.js.map +1 -1
  87. package/lib/esm/tree-widget-react/components/trees/categories-tree/UseCategoriesTree.d.ts +3 -1
  88. package/lib/esm/tree-widget-react/components/trees/categories-tree/UseCategoriesTree.js +22 -9
  89. package/lib/esm/tree-widget-react/components/trees/categories-tree/UseCategoriesTree.js.map +1 -1
  90. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.d.ts +21 -9
  91. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.js +301 -252
  92. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.js.map +1 -1
  93. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.d.ts +2 -0
  94. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.js +67 -108
  95. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.js.map +1 -1
  96. package/lib/esm/tree-widget-react/components/trees/common/CategoriesVisibilityUtils.js +23 -13
  97. package/lib/esm/tree-widget-react/components/trees/common/CategoriesVisibilityUtils.js.map +1 -1
  98. package/lib/esm/tree-widget-react/components/trees/common/UseActiveViewport.js.map +1 -1
  99. package/lib/esm/tree-widget-react/components/trees/common/UseHierarchyVisibility.js.map +1 -1
  100. package/lib/esm/tree-widget-react/components/trees/common/components/ProgressOverlay.js.map +1 -1
  101. package/lib/esm/tree-widget-react/components/trees/common/components/Tree.d.ts +2 -2
  102. package/lib/esm/tree-widget-react/components/trees/common/components/Tree.js.map +1 -1
  103. package/lib/esm/tree-widget-react/components/trees/common/components/TreeNodeCheckbox.d.ts +1 -1
  104. package/lib/esm/tree-widget-react/components/trees/common/components/TreeNodeCheckbox.js.map +1 -1
  105. package/lib/esm/tree-widget-react/components/trees/common/components/TreeRenderer.d.ts +1 -1
  106. package/lib/esm/tree-widget-react/components/trees/common/components/TreeRenderer.js +2 -2
  107. package/lib/esm/tree-widget-react/components/trees/common/components/TreeRenderer.js.map +1 -1
  108. package/lib/esm/tree-widget-react/components/trees/common/components/VisibilityTree.d.ts +3 -3
  109. package/lib/esm/tree-widget-react/components/trees/common/components/VisibilityTree.js.map +1 -1
  110. package/lib/esm/tree-widget-react/components/trees/common/components/VisibilityTreeRenderer.d.ts +1 -1
  111. package/lib/esm/tree-widget-react/components/trees/common/components/VisibilityTreeRenderer.js.map +1 -1
  112. package/lib/esm/tree-widget-react/components/trees/common/internal/Utils.d.ts +25 -0
  113. package/lib/esm/tree-widget-react/components/trees/common/internal/Utils.js +74 -0
  114. package/lib/esm/tree-widget-react/components/trees/common/internal/Utils.js.map +1 -0
  115. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTree.d.ts +1 -1
  116. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTree.js.map +1 -1
  117. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeButtons.js.map +1 -1
  118. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeComponent.js.map +1 -1
  119. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.d.ts +1 -0
  120. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.js +83 -25
  121. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.js.map +1 -1
  122. package/lib/esm/tree-widget-react/components/trees/models-tree/UseModelsTree.js +2 -1
  123. package/lib/esm/tree-widget-react/components/trees/models-tree/UseModelsTree.js.map +1 -1
  124. package/lib/esm/tree-widget-react/components/trees/models-tree/Utils.d.ts +5 -6
  125. package/lib/esm/tree-widget-react/components/trees/models-tree/Utils.js +4 -16
  126. package/lib/esm/tree-widget-react/components/trees/models-tree/Utils.js.map +1 -1
  127. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.js +4 -3
  128. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.js.map +1 -1
  129. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/FilteredTree.d.ts +7 -1
  130. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/FilteredTree.js +52 -0
  131. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/FilteredTree.js.map +1 -1
  132. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.d.ts +28 -12
  133. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js +382 -278
  134. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js.map +1 -1
  135. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeNode.d.ts +1 -1
  136. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeNode.js.map +1 -1
  137. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js +257 -124
  138. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js.map +1 -1
  139. package/lib/esm/tree-widget-react-internal.d.ts +2 -1
  140. package/lib/esm/tree-widget-react-internal.js +2 -1
  141. package/lib/esm/tree-widget-react-internal.js.map +1 -1
  142. package/package.json +1 -1
@@ -2,7 +2,9 @@
2
2
  * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
3
3
  * See LICENSE.md in the project root for license terms and full copyright notice.
4
4
  *--------------------------------------------------------------------------------------------*/
5
- import { Guid } from "@itwin/core-bentley";
5
+ import { defer, forkJoin, from, map, mergeMap, of, reduce, shareReplay, toArray } from "rxjs";
6
+ import { Guid, Id64 } from "@itwin/core-bentley";
7
+ import { setIntersection } from "../../common/internal/Utils.js";
6
8
  import { DEFINITION_CONTAINER_CLASS, SUB_CATEGORY_CLASS } from "./ClassNameDefinitions.js";
7
9
  /** @internal */
8
10
  export class CategoriesTreeIdsCache {
@@ -27,311 +29,355 @@ export class CategoriesTreeIdsCache {
27
29
  this.#componentName = "CategoriesTreeIdsCache";
28
30
  }
29
31
  [Symbol.dispose]() { }
30
- async *queryElementModelCategories() {
31
- const query = `
32
- SELECT this.Model.Id modelId, this.Category.Id categoryId
33
- FROM ${this.#categoryModelClass} m
34
- JOIN ${this.#categoryElementClass} this ON m.ECInstanceId = this.Model.Id
35
- WHERE m.IsPrivate = false
36
- GROUP BY modelId, categoryId
37
- `;
38
- for await (const row of this.#queryExecutor.createQueryReader({ ecsql: query }, {
39
- rowFormat: "ECSqlPropertyNames",
40
- limit: "unbounded",
41
- restartToken: `${this.#componentName}/${this.#componentId}/element-models-and-categories`,
42
- })) {
43
- yield { modelId: row.modelId, categoryId: row.categoryId };
44
- }
32
+ queryElementModelCategories() {
33
+ return defer(() => {
34
+ const query = `
35
+ SELECT this.Model.Id modelId, this.Category.Id categoryId
36
+ FROM ${this.#categoryModelClass} m
37
+ JOIN ${this.#categoryElementClass} this ON m.ECInstanceId = this.Model.Id
38
+ WHERE m.IsPrivate = false
39
+ GROUP BY modelId, categoryId
40
+ `;
41
+ return this.#queryExecutor.createQueryReader({ ecsql: query }, {
42
+ rowFormat: "ECSqlPropertyNames",
43
+ limit: "unbounded",
44
+ restartToken: `${this.#componentName}/${this.#componentId}/element-models-and-categories`,
45
+ });
46
+ }).pipe(map((row) => {
47
+ return { modelId: row.modelId, categoryId: row.categoryId };
48
+ }));
45
49
  }
46
- async *queryCategories() {
47
- const isDefinitionContainerSupported = await this.getIsDefinitionContainerSupported();
48
- const categoriesQuery = `
49
- SELECT
50
- this.ECInstanceId id,
51
- COUNT(sc.ECInstanceId) childCount,
52
- this.Model.Id modelId,
53
- ${isDefinitionContainerSupported
54
- ? `
55
- IIF(this.Model.Id IN (SELECT dc.ECInstanceId FROM ${DEFINITION_CONTAINER_CLASS} dc),
56
- true,
57
- false
58
- )`
59
- : "false"} parentDefinitionContainerExists
60
- FROM
61
- ${this.#categoryClass} this
62
- JOIN ${SUB_CATEGORY_CLASS} sc ON sc.Parent.Id = this.ECInstanceId
63
- JOIN BisCore.Model m ON m.ECInstanceId = this.Model.Id
64
- WHERE
65
- NOT this.IsPrivate
66
- AND (NOT m.IsPrivate OR m.ECClassId IS (BisCore.DictionaryModel))
67
- AND EXISTS (SELECT 1 FROM ${this.#categoryElementClass} e WHERE e.Category.Id = this.ECInstanceId)
68
- GROUP BY this.ECInstanceId
69
- `;
70
- for await (const row of this.#queryExecutor.createQueryReader({ ecsql: categoriesQuery }, { rowFormat: "ECSqlPropertyNames", limit: "unbounded", restartToken: `${this.#componentName}/${this.#componentId}/categories` })) {
71
- yield { id: row.id, modelId: row.modelId, parentDefinitionContainerExists: row.parentDefinitionContainerExists, childCount: row.childCount };
72
- }
50
+ queryCategories() {
51
+ return this.getIsDefinitionContainerSupported().pipe(mergeMap((isDefinitionContainerSupported) => defer(() => {
52
+ const categoriesQuery = `
53
+ SELECT
54
+ this.ECInstanceId id,
55
+ COUNT(sc.ECInstanceId) childCount,
56
+ this.Model.Id modelId,
57
+ ${isDefinitionContainerSupported
58
+ ? `
59
+ IIF(this.Model.Id IN (SELECT dc.ECInstanceId FROM ${DEFINITION_CONTAINER_CLASS} dc),
60
+ true,
61
+ false
62
+ )`
63
+ : "false"} parentDefinitionContainerExists,
64
+ IFNULL(
65
+ (SELECT 1 FROM ${this.#categoryElementClass} e WHERE e.Category.Id = this.ECInstanceId LIMIT 1),
66
+ 0
67
+ ) hasElements
68
+ FROM
69
+ ${this.#categoryClass} this
70
+ JOIN ${SUB_CATEGORY_CLASS} sc ON sc.Parent.Id = this.ECInstanceId
71
+ JOIN BisCore.Model m ON m.ECInstanceId = this.Model.Id
72
+ WHERE
73
+ NOT this.IsPrivate
74
+ AND (NOT m.IsPrivate OR m.ECClassId IS (BisCore.DictionaryModel))
75
+ GROUP BY this.ECInstanceId
76
+ `;
77
+ return this.#queryExecutor.createQueryReader({ ecsql: categoriesQuery }, { rowFormat: "ECSqlPropertyNames", limit: "unbounded", restartToken: `${this.#componentName}/${this.#componentId}/categories` });
78
+ }).pipe(map((row) => {
79
+ return {
80
+ id: row.id,
81
+ modelId: row.modelId,
82
+ parentDefinitionContainerExists: row.parentDefinitionContainerExists,
83
+ childCount: row.childCount,
84
+ hasElements: !!row.hasElements,
85
+ };
86
+ }))));
73
87
  }
74
- async queryIsDefinitionContainersSupported() {
75
- const query = `
76
- SELECT
77
- 1
78
- FROM
79
- ECDbMeta.ECSchemaDef s
80
- JOIN ECDbMeta.ECClassDef c ON c.Schema.Id = s.ECInstanceId
81
- WHERE
82
- s.Name = 'BisCore'
83
- AND c.Name = 'DefinitionContainer'
84
- `;
85
- for await (const _row of this.#queryExecutor.createQueryReader({ ecsql: query }, { restartToken: `${this.#componentName}/${this.#componentId}/is-definition-container-supported` })) {
86
- return true;
87
- }
88
- return false;
88
+ queryIsDefinitionContainersSupported() {
89
+ return defer(() => {
90
+ const query = `
91
+ SELECT
92
+ 1
93
+ FROM
94
+ ECDbMeta.ECSchemaDef s
95
+ JOIN ECDbMeta.ECClassDef c ON c.Schema.Id = s.ECInstanceId
96
+ WHERE
97
+ s.Name = 'BisCore'
98
+ AND c.Name = 'DefinitionContainer'
99
+ LIMIT 1
100
+ `;
101
+ return this.#queryExecutor.createQueryReader({ ecsql: query }, { restartToken: `${this.#componentName}/${this.#componentId}/is-definition-container-supported` });
102
+ }).pipe(toArray(), map((rows) => rows.length > 0));
89
103
  }
90
- async *queryDefinitionContainers() {
91
- // DefinitionModel ECInstanceId will always be the same as modeled DefinitionContainer ECInstanceId, if this wasn't the case, we would need to do something like:
92
- // JOIN BisCore.DefinitionModel dm ON dm.ECInstanceId = ${modelIdAccessor}
93
- // JOIN BisCore.DefinitionModelBreaksDownDefinitionContainer dr ON dr.SourceECInstanceId = dm.ECInstanceId
94
- // JOIN BisCore.DefinitionContainer dc ON dc.ECInstanceId = dr.TargetECInstanceId
95
- const DEFINITION_CONTAINERS_CTE = "DefinitionContainers";
96
- const ctes = [
97
- `
98
- ${DEFINITION_CONTAINERS_CTE}(ECInstanceId, ModelId) AS (
104
+ queryDefinitionContainers() {
105
+ return defer(() => {
106
+ // DefinitionModel ECInstanceId will always be the same as modeled DefinitionContainer ECInstanceId, if this wasn't the case, we would need to do something like:
107
+ // JOIN BisCore.DefinitionModel dm ON dm.ECInstanceId = ${modelIdAccessor}
108
+ // JOIN BisCore.DefinitionModelBreaksDownDefinitionContainer dr ON dr.SourceECInstanceId = dm.ECInstanceId
109
+ // JOIN BisCore.DefinitionContainer dc ON dc.ECInstanceId = dr.TargetECInstanceId
110
+ const DEFINITION_CONTAINERS_CTE = "DefinitionContainers";
111
+ const CATEGORIES_MODELS_CTE = "CategoriesModels";
112
+ const ctes = [
113
+ `${CATEGORIES_MODELS_CTE}(ModelId, HasElements) AS (
99
114
  SELECT
100
- dc.ECInstanceId,
101
- dc.Model.Id
115
+ c.Model.Id,
116
+ IFNULL((
117
+ SELECT 1
118
+ FROM ${this.#categoryElementClass} e
119
+ WHERE e.Category.Id = c.ECInstanceId
120
+ LIMIT 1
121
+ ), 0)
102
122
  FROM
103
- ${DEFINITION_CONTAINER_CLASS} dc
123
+ ${this.#categoryClass} c
104
124
  WHERE
105
- dc.ECInstanceId IN (SELECT c.Model.Id FROM ${this.#categoryClass} c WHERE NOT c.IsPrivate AND EXISTS (SELECT 1 FROM ${this.#categoryElementClass} e WHERE e.Category.Id = c.ECInstanceId))
106
- AND NOT dc.IsPrivate
125
+ NOT c.IsPrivate
126
+ )`,
127
+ `
128
+ ${DEFINITION_CONTAINERS_CTE}(ECInstanceId, ModelId, HasElements) AS (
129
+ SELECT
130
+ dc.ECInstanceId,
131
+ dc.Model.Id,
132
+ c.HasElements
133
+ FROM ${DEFINITION_CONTAINER_CLASS} dc
134
+ JOIN ${CATEGORIES_MODELS_CTE} c ON dc.ECInstanceId = c.ModelId
135
+ WHERE NOT dc.IsPrivate
107
136
 
108
- UNION ALL
137
+ UNION ALL
109
138
 
110
- SELECT
111
- pdc.ECInstanceId,
112
- pdc.Model.Id
113
- FROM
114
- ${DEFINITION_CONTAINERS_CTE} cdc
115
- JOIN ${DEFINITION_CONTAINER_CLASS} pdc ON pdc.ECInstanceId = cdc.ModelId
116
- WHERE
117
- NOT pdc.IsPrivate
118
- )
119
- `,
120
- ];
121
- const definitionsQuery = `
122
- SELECT dc.ECInstanceId id, dc.ModelId modelId FROM ${DEFINITION_CONTAINERS_CTE} dc GROUP BY dc.ECInstanceId
123
- `;
124
- for await (const row of this.#queryExecutor.createQueryReader({ ctes, ecsql: definitionsQuery }, { rowFormat: "ECSqlPropertyNames", limit: "unbounded", restartToken: `${this.#componentName}/${this.#componentId}/definition-containers` })) {
125
- yield { id: row.id, modelId: row.modelId };
126
- }
139
+ SELECT
140
+ pdc.ECInstanceId,
141
+ pdc.Model.Id,
142
+ cdc.HasElements
143
+ FROM
144
+ ${DEFINITION_CONTAINERS_CTE} cdc
145
+ JOIN ${DEFINITION_CONTAINER_CLASS} pdc ON pdc.ECInstanceId = cdc.ModelId
146
+ WHERE NOT pdc.IsPrivate
147
+ )
148
+ `,
149
+ ];
150
+ const definitionsQuery = `
151
+ SELECT dc.ECInstanceId id, dc.ModelId modelId, MAX(dc.HasElements) hasElements FROM ${DEFINITION_CONTAINERS_CTE} dc GROUP BY dc.ECInstanceId
152
+ `;
153
+ return this.#queryExecutor.createQueryReader({ ctes, ecsql: definitionsQuery }, { rowFormat: "ECSqlPropertyNames", limit: "unbounded", restartToken: `${this.#componentName}/${this.#componentId}/definition-containers` });
154
+ }).pipe(map((row) => {
155
+ return { id: row.id, modelId: row.modelId, hasElements: !!row.hasElements };
156
+ }));
127
157
  }
128
- async *queryVisibleSubCategories(categoriesInfo) {
129
- const definitionsQuery = `
130
- SELECT
131
- sc.ECInstanceId id,
132
- sc.Parent.Id categoryId
133
- FROM
134
- ${SUB_CATEGORY_CLASS} sc
135
- WHERE
136
- NOT sc.IsPrivate
137
- AND sc.Parent.Id IN (${categoriesInfo.join(",")})
138
- `;
139
- for await (const row of this.#queryExecutor.createQueryReader({ ecsql: definitionsQuery }, { rowFormat: "ECSqlPropertyNames", limit: "unbounded", restartToken: `${this.#componentName}/${this.#componentId}/visible-sub-categories` })) {
140
- yield { id: row.id, parentId: row.categoryId };
141
- }
158
+ queryVisibleSubCategories(categoriesInfo) {
159
+ return defer(() => {
160
+ const definitionsQuery = `
161
+ SELECT
162
+ sc.ECInstanceId id,
163
+ sc.Parent.Id categoryId
164
+ FROM
165
+ ${SUB_CATEGORY_CLASS} sc
166
+ WHERE
167
+ NOT sc.IsPrivate
168
+ AND sc.Parent.Id IN (${categoriesInfo.join(",")})
169
+ `;
170
+ return this.#queryExecutor.createQueryReader({ ecsql: definitionsQuery }, { rowFormat: "ECSqlPropertyNames", limit: "unbounded", restartToken: `${this.#componentName}/${this.#componentId}/visible-sub-categories` });
171
+ }).pipe(map((row) => {
172
+ return { id: row.id, parentId: row.categoryId };
173
+ }));
142
174
  }
143
- async getModelsCategoriesInfo() {
144
- this.#modelsCategoriesInfo ??= (async () => {
145
- const allModelsCategories = new Map();
146
- for await (const queriedCategory of this.queryCategories()) {
147
- let modelCategories = allModelsCategories.get(queriedCategory.modelId);
148
- if (modelCategories === undefined) {
149
- modelCategories = { parentDefinitionContainerExists: queriedCategory.parentDefinitionContainerExists, childCategories: [] };
150
- allModelsCategories.set(queriedCategory.modelId, modelCategories);
151
- }
152
- modelCategories.childCategories.push({ id: queriedCategory.id, childCount: queriedCategory.childCount });
175
+ getModelsCategoriesInfo() {
176
+ this.#modelsCategoriesInfo ??= this.queryCategories()
177
+ .pipe(reduce((acc, queriedCategory) => {
178
+ let modelCategories = acc.get(queriedCategory.modelId);
179
+ if (modelCategories === undefined) {
180
+ modelCategories = { parentDefinitionContainerExists: queriedCategory.parentDefinitionContainerExists, childCategories: [] };
181
+ acc.set(queriedCategory.modelId, modelCategories);
153
182
  }
154
- return allModelsCategories;
155
- })();
183
+ modelCategories.childCategories.push({ id: queriedCategory.id, childCount: queriedCategory.childCount, hasElements: queriedCategory.hasElements });
184
+ return acc;
185
+ }, new Map()))
186
+ .pipe(shareReplay());
156
187
  return this.#modelsCategoriesInfo;
157
188
  }
158
- async getElementModelsCategories() {
159
- this.#elementModelsCategories ??= (async () => {
160
- const elementModelsCategories = new Map();
161
- for await (const queriedCategory of this.queryElementModelCategories()) {
162
- let modelEntry = elementModelsCategories.get(queriedCategory.modelId);
163
- if (modelEntry === undefined) {
164
- modelEntry = new Set();
165
- elementModelsCategories.set(queriedCategory.modelId, modelEntry);
166
- }
167
- modelEntry.add(queriedCategory.categoryId);
189
+ getElementModelsCategories() {
190
+ this.#elementModelsCategories ??= this.queryElementModelCategories()
191
+ .pipe(reduce((acc, queriedCategory) => {
192
+ let modelEntry = acc.get(queriedCategory.modelId);
193
+ if (modelEntry === undefined) {
194
+ modelEntry = new Set();
195
+ acc.set(queriedCategory.modelId, modelEntry);
168
196
  }
169
- return elementModelsCategories;
170
- })();
197
+ modelEntry.add(queriedCategory.categoryId);
198
+ return acc;
199
+ }, new Map()))
200
+ .pipe(shareReplay());
171
201
  return this.#elementModelsCategories;
172
202
  }
173
- async getSubCategoriesInfo() {
174
- this.#subCategoriesInfo ??= (async () => {
203
+ getSubCategoriesInfo() {
204
+ this.#subCategoriesInfo ??= this.getModelsCategoriesInfo()
205
+ .pipe(mergeMap((modelsCategoriesInfo) => from(modelsCategoriesInfo.values())), reduce((acc, modelCategoriesInfo) => {
206
+ acc.push(...modelCategoriesInfo.childCategories.filter((categoryInfo) => categoryInfo.childCount > 1).map((categoryInfo) => categoryInfo.id));
207
+ return acc;
208
+ }, new Array()), mergeMap((categoriesWithMoreThanOneSubCategory) => {
175
209
  const allSubCategories = new Map();
176
- const modelsCategoriesInfo = await this.getModelsCategoriesInfo();
177
- const categoriesWithMoreThanOneSubCategory = new Array();
178
- for (const modelCategoriesInfo of modelsCategoriesInfo.values()) {
179
- categoriesWithMoreThanOneSubCategory.push(...modelCategoriesInfo.childCategories.filter((categoryInfo) => categoryInfo.childCount > 1).map((categoryInfo) => categoryInfo.id));
180
- }
181
210
  if (categoriesWithMoreThanOneSubCategory.length === 0) {
182
- return allSubCategories;
183
- }
184
- for await (const queriedSubCategory of this.queryVisibleSubCategories(categoriesWithMoreThanOneSubCategory)) {
185
- allSubCategories.set(queriedSubCategory.id, { categoryId: queriedSubCategory.parentId });
211
+ return of(allSubCategories);
186
212
  }
187
- return allSubCategories;
188
- })();
213
+ return this.queryVisibleSubCategories(categoriesWithMoreThanOneSubCategory).pipe(reduce((acc, queriedSubCategory) => {
214
+ const entry = acc.get(queriedSubCategory.parentId);
215
+ if (!entry) {
216
+ acc.set(queriedSubCategory.parentId, new Set([queriedSubCategory.id]));
217
+ return acc;
218
+ }
219
+ entry.add(queriedSubCategory.id);
220
+ return acc;
221
+ }, allSubCategories));
222
+ }))
223
+ .pipe(shareReplay());
189
224
  return this.#subCategoriesInfo;
190
225
  }
191
- async getDefinitionContainersInfo() {
192
- this.#definitionContainersInfo ??= (async () => {
226
+ getDefinitionContainersInfo() {
227
+ this.#definitionContainersInfo ??= forkJoin({
228
+ isDefinitionContainerSupported: this.getIsDefinitionContainerSupported(),
229
+ modelsCategoriesInfo: this.getModelsCategoriesInfo(),
230
+ })
231
+ .pipe(mergeMap(({ isDefinitionContainerSupported, modelsCategoriesInfo }) => {
193
232
  const definitionContainersInfo = new Map();
194
- const [isDefinitionContainerSupported, modelsCategoriesInfo] = await Promise.all([
195
- this.getIsDefinitionContainerSupported(),
196
- this.getModelsCategoriesInfo(),
197
- ]);
198
233
  if (!isDefinitionContainerSupported || modelsCategoriesInfo.size === 0) {
199
- return definitionContainersInfo;
234
+ return of(definitionContainersInfo);
200
235
  }
201
- for await (const queriedDefinitionContainer of this.queryDefinitionContainers()) {
236
+ return this.queryDefinitionContainers().pipe(reduce((acc, queriedDefinitionContainer) => {
202
237
  const modelCategoriesInfo = modelsCategoriesInfo.get(queriedDefinitionContainer.id);
203
- definitionContainersInfo.set(queriedDefinitionContainer.id, {
238
+ acc.set(queriedDefinitionContainer.id, {
204
239
  childCategories: modelCategoriesInfo?.childCategories ?? [],
205
240
  modelId: queriedDefinitionContainer.modelId,
206
241
  childDefinitionContainers: [],
207
242
  parentDefinitionContainerExists: false,
243
+ hasElements: queriedDefinitionContainer.hasElements,
208
244
  });
209
- }
210
- for (const [definitionContainerId, definitionContainerInfo] of definitionContainersInfo) {
211
- const parentDefinitionContainer = definitionContainersInfo.get(definitionContainerInfo.modelId);
212
- if (parentDefinitionContainer !== undefined) {
213
- parentDefinitionContainer.childDefinitionContainers.push(definitionContainerId);
214
- definitionContainerInfo.parentDefinitionContainerExists = true;
245
+ return acc;
246
+ }, definitionContainersInfo), map((result) => {
247
+ for (const [definitionContainerId, definitionContainerInfo] of result) {
248
+ const parentDefinitionContainer = result.get(definitionContainerInfo.modelId);
249
+ if (parentDefinitionContainer !== undefined) {
250
+ parentDefinitionContainer.childDefinitionContainers.push({ id: definitionContainerId, hasElements: definitionContainerInfo.hasElements });
251
+ definitionContainerInfo.parentDefinitionContainerExists = true;
252
+ parentDefinitionContainer.hasElements = parentDefinitionContainer.hasElements || definitionContainerInfo.hasElements;
253
+ }
215
254
  }
216
- }
217
- return definitionContainersInfo;
218
- })();
255
+ return result;
256
+ }));
257
+ }))
258
+ .pipe(shareReplay());
219
259
  return this.#definitionContainersInfo;
220
260
  }
221
- async getDirectChildDefinitionContainersAndCategories(parentDefinitionContainerIds) {
222
- const definitionContainersInfo = await this.getDefinitionContainersInfo();
223
- const result = { definitionContainers: new Array(), categories: new Array() };
224
- parentDefinitionContainerIds.forEach((parentDefinitionContainerId) => {
261
+ getDirectChildDefinitionContainersAndCategories({ parentDefinitionContainerIds, includeEmpty, }) {
262
+ return this.getDefinitionContainersInfo().pipe(mergeMap((definitionContainersInfo) => from(parentDefinitionContainerIds).pipe(reduce((acc, parentDefinitionContainerId) => {
225
263
  const parentDefinitionContainerInfo = definitionContainersInfo.get(parentDefinitionContainerId);
226
264
  if (parentDefinitionContainerInfo !== undefined) {
227
- result.definitionContainers.push(...parentDefinitionContainerInfo.childDefinitionContainers);
228
- result.categories.push(...parentDefinitionContainerInfo.childCategories);
265
+ acc.definitionContainers.push(...applyElementsFilter(parentDefinitionContainerInfo.childDefinitionContainers, includeEmpty).map((dc) => dc.id));
266
+ acc.categories.push(...applyElementsFilter(parentDefinitionContainerInfo.childCategories, includeEmpty));
229
267
  }
230
- });
231
- return result;
268
+ return acc;
269
+ }, { definitionContainers: new Array(), categories: new Array() }))));
232
270
  }
233
- async getCategoriesElementModels(categoryIds) {
234
- const elementModelsCategories = await this.getElementModelsCategories();
235
- const result = new Map();
236
- for (const categoryId of categoryIds) {
237
- for (const [modelId, categories] of elementModelsCategories) {
238
- if (categories.has(categoryId)) {
239
- let categoryModels = result.get(categoryId);
240
- if (!categoryModels) {
241
- categoryModels = new Array();
242
- result.set(categoryId, categoryModels);
243
- }
244
- categoryModels.push(modelId);
245
- }
271
+ getCategoriesElementModels(categoryIds) {
272
+ return this.getElementModelsCategories().pipe(mergeMap((elementModelsCategories) => elementModelsCategories.entries()), reduce((acc, [modelId, modelCategoryIds]) => {
273
+ const sharedCategories = setIntersection(Id64.iterable(categoryIds), modelCategoryIds);
274
+ if (sharedCategories.size > 0) {
275
+ acc.set(modelId, sharedCategories);
246
276
  }
247
- }
248
- return result;
277
+ return acc;
278
+ }, new Map()));
249
279
  }
250
- async getAllContainedCategories(definitionContainerIds) {
251
- const result = new Array();
252
- const definitionContainersInfo = await this.getDefinitionContainersInfo();
253
- const indirectCategories = await Promise.all(definitionContainerIds.map(async (definitionContainerId) => {
280
+ getAllContainedCategories({ definitionContainerIds, includeEmptyCategories, }) {
281
+ return this.getDefinitionContainersInfo().pipe(mergeMap((definitionContainersInfo) => from(definitionContainerIds).pipe(mergeMap((definitionContainerId) => {
254
282
  const definitionContainerInfo = definitionContainersInfo.get(definitionContainerId);
255
283
  if (definitionContainerInfo === undefined) {
256
- return [];
284
+ return of({ directCategories: undefined, indirectCategories: undefined });
257
285
  }
258
- result.push(...definitionContainerInfo.childCategories.map((category) => category.id));
259
- return this.getAllContainedCategories(definitionContainerInfo.childDefinitionContainers);
260
- }));
261
- for (const categories of indirectCategories) {
262
- result.push(...categories);
263
- }
264
- return result;
286
+ const childDefinitionContainerIds = definitionContainerInfo.childDefinitionContainers.map(({ id }) => id);
287
+ return (childDefinitionContainerIds.length > 0
288
+ ? this.getAllContainedCategories({
289
+ definitionContainerIds: childDefinitionContainerIds,
290
+ includeEmptyCategories,
291
+ })
292
+ : of(new Set())).pipe(map((indirectCategories) => {
293
+ return {
294
+ directCategories: applyElementsFilter(definitionContainerInfo.childCategories, includeEmptyCategories).map((category) => category.id),
295
+ indirectCategories,
296
+ };
297
+ }));
298
+ }), reduce((acc, { directCategories, indirectCategories }) => {
299
+ directCategories?.forEach((categoryId) => acc.add(categoryId));
300
+ indirectCategories?.forEach((categoryId) => acc.add(categoryId));
301
+ return acc;
302
+ }, new Set()))));
265
303
  }
266
- async getInstanceKeyPaths(props) {
304
+ getInstanceKeyPaths(props) {
267
305
  if ("subCategoryId" in props) {
268
- const subCategoriesInfo = await this.getSubCategoriesInfo();
269
- const subCategoryInfo = subCategoriesInfo.get(props.subCategoryId);
270
- if (subCategoryInfo === undefined) {
271
- return [];
272
- }
273
- return [...(await this.getInstanceKeyPaths({ categoryId: subCategoryInfo.categoryId })), { id: props.subCategoryId, className: SUB_CATEGORY_CLASS }];
306
+ return this.getSubCategoriesInfo().pipe(mergeMap((subCategoriesInfo) => {
307
+ let categoryOfSubCategory;
308
+ for (const [categoryId, subCategories] of subCategoriesInfo.entries()) {
309
+ if (subCategories.has(props.subCategoryId)) {
310
+ categoryOfSubCategory = categoryId;
311
+ break;
312
+ }
313
+ }
314
+ if (categoryOfSubCategory === undefined) {
315
+ return of([]);
316
+ }
317
+ return this.getInstanceKeyPaths({ categoryId: categoryOfSubCategory }).pipe(map((pathToCategory) => [...pathToCategory, { id: props.subCategoryId, className: SUB_CATEGORY_CLASS }]));
318
+ }));
274
319
  }
275
320
  if ("categoryId" in props) {
276
- const modelsCategoriesInfo = await this.getModelsCategoriesInfo();
277
- for (const [modelId, modelCategoriesInfo] of modelsCategoriesInfo) {
278
- if (modelCategoriesInfo.childCategories.find((childCategory) => childCategory.id === props.categoryId)) {
279
- if (!modelCategoriesInfo.parentDefinitionContainerExists) {
280
- return [{ id: props.categoryId, className: this.#categoryClass }];
321
+ return this.getModelsCategoriesInfo().pipe(mergeMap((modelsCategoriesInfo) => {
322
+ for (const [modelId, modelCategoriesInfo] of modelsCategoriesInfo) {
323
+ if (modelCategoriesInfo.childCategories.find((childCategory) => childCategory.id === props.categoryId)) {
324
+ const instanceKey = { id: props.categoryId, className: this.#categoryClass };
325
+ if (!modelCategoriesInfo.parentDefinitionContainerExists) {
326
+ return of([instanceKey]);
327
+ }
328
+ return this.getInstanceKeyPaths({ definitionContainerId: modelId }).pipe(map((pathToDefinitionContainer) => [...pathToDefinitionContainer, instanceKey]));
281
329
  }
282
- return [...(await this.getInstanceKeyPaths({ definitionContainerId: modelId })), { id: props.categoryId, className: this.#categoryClass }];
283
330
  }
284
- }
285
- return [];
286
- }
287
- const definitionContainersInfo = await this.getDefinitionContainersInfo();
288
- const definitionContainerInfo = definitionContainersInfo.get(props.definitionContainerId);
289
- if (definitionContainerInfo === undefined) {
290
- return [];
331
+ return of([]);
332
+ }));
291
333
  }
292
- if (!definitionContainerInfo.parentDefinitionContainerExists) {
293
- return [{ id: props.definitionContainerId, className: DEFINITION_CONTAINER_CLASS }];
294
- }
295
- return [
296
- ...(await this.getInstanceKeyPaths({ definitionContainerId: definitionContainerInfo.modelId })),
297
- { id: props.definitionContainerId, className: DEFINITION_CONTAINER_CLASS },
298
- ];
299
- }
300
- async getAllDefinitionContainersAndCategories() {
301
- const [modelsCategoriesInfo, definitionContainersInfo] = await Promise.all([this.getModelsCategoriesInfo(), this.getDefinitionContainersInfo()]);
302
- const result = { definitionContainers: [...definitionContainersInfo.keys()], categories: new Array() };
303
- for (const modelCategoriesInfo of modelsCategoriesInfo.values()) {
304
- result.categories.push(...modelCategoriesInfo.childCategories.map((childCategory) => childCategory.id));
305
- }
306
- return result;
307
- }
308
- async getRootDefinitionContainersAndCategories() {
309
- const [modelsCategoriesInfo, definitionContainersInfo] = await Promise.all([this.getModelsCategoriesInfo(), this.getDefinitionContainersInfo()]);
310
- const result = { definitionContainers: new Array(), categories: new Array() };
311
- for (const modelCategoriesInfo of modelsCategoriesInfo.values()) {
312
- if (!modelCategoriesInfo.parentDefinitionContainerExists) {
313
- result.categories.push(...modelCategoriesInfo.childCategories);
334
+ return this.getDefinitionContainersInfo().pipe(mergeMap((definitionContainersInfo) => {
335
+ const definitionContainerInfo = definitionContainersInfo.get(props.definitionContainerId);
336
+ if (definitionContainerInfo === undefined) {
337
+ return of([]);
314
338
  }
315
- }
316
- for (const [definitionContainerId, definitionContainerInfo] of definitionContainersInfo) {
339
+ const instanceKey = { id: props.definitionContainerId, className: DEFINITION_CONTAINER_CLASS };
317
340
  if (!definitionContainerInfo.parentDefinitionContainerExists) {
318
- result.definitionContainers.push(definitionContainerId);
341
+ return of([instanceKey]);
319
342
  }
320
- }
321
- return result;
343
+ return this.getInstanceKeyPaths({ definitionContainerId: definitionContainerInfo.modelId }).pipe(map((pathToParentDefinitionContainer) => [...pathToParentDefinitionContainer, instanceKey]));
344
+ }));
322
345
  }
323
- async getSubCategories(categoryId) {
324
- const subCategoriesInfo = await this.getSubCategoriesInfo();
325
- const result = new Array();
326
- for (const [subCategoryId, subCategoryInfo] of subCategoriesInfo) {
327
- if (subCategoryInfo.categoryId === categoryId) {
328
- result.push(subCategoryId);
329
- }
330
- }
331
- return result;
346
+ getAllDefinitionContainersAndCategories(props) {
347
+ return forkJoin({
348
+ categories: this.getModelsCategoriesInfo().pipe(mergeMap((modelsCategoriesInfo) => modelsCategoriesInfo.values()), reduce((acc, modelCategoriesInfo) => {
349
+ applyElementsFilter(modelCategoriesInfo.childCategories, props?.includeEmpty).forEach((categoryInfo) => acc.push(categoryInfo.id));
350
+ return acc;
351
+ }, new Array())),
352
+ definitionContainers: this.getDefinitionContainersInfo().pipe(mergeMap((definitionContainersInfo) => definitionContainersInfo.entries()), reduce((acc, [definitionContainerId, definitionContainerInfo]) => {
353
+ if (definitionContainerInfo.hasElements || !!props?.includeEmpty) {
354
+ acc.push(definitionContainerId);
355
+ }
356
+ return acc;
357
+ }, new Array())),
358
+ });
332
359
  }
333
- async getIsDefinitionContainerSupported() {
334
- this.#isDefinitionContainerSupported ??= this.queryIsDefinitionContainersSupported();
360
+ getRootDefinitionContainersAndCategories(props) {
361
+ return forkJoin({
362
+ categories: this.getModelsCategoriesInfo().pipe(mergeMap((modelsCategoriesInfo) => modelsCategoriesInfo.values()), reduce((acc, modelCategoriesInfo) => {
363
+ if (!modelCategoriesInfo.parentDefinitionContainerExists) {
364
+ applyElementsFilter(modelCategoriesInfo.childCategories, props?.includeEmpty).forEach((categoryInfo) => acc.push(categoryInfo));
365
+ }
366
+ return acc;
367
+ }, new Array())),
368
+ definitionContainers: this.getDefinitionContainersInfo().pipe(mergeMap((definitionContainersInfo) => definitionContainersInfo.entries()), reduce((acc, [definitionContainerId, definitionContainerInfo]) => {
369
+ if (!definitionContainerInfo.parentDefinitionContainerExists && (definitionContainerInfo.hasElements || !!props?.includeEmpty)) {
370
+ acc.push(definitionContainerId);
371
+ }
372
+ return acc;
373
+ }, new Array())),
374
+ });
375
+ }
376
+ getSubCategories(categoryId) {
377
+ return this.getSubCategoriesInfo().pipe(map((subCategoriesInfo) => subCategoriesInfo.get(categoryId) ?? new Set()));
378
+ }
379
+ getIsDefinitionContainerSupported() {
380
+ this.#isDefinitionContainerSupported ??= this.queryIsDefinitionContainersSupported().pipe(shareReplay());
335
381
  return this.#isDefinitionContainerSupported;
336
382
  }
337
383
  }
@@ -341,4 +387,7 @@ export function getClassesByView(viewType) {
341
387
  ? { categoryClass: "BisCore.DrawingCategory", categoryElementClass: "BisCore.GeometricElement2d", categoryModelClass: "BisCore.GeometricModel2d" }
342
388
  : { categoryClass: "BisCore.SpatialCategory", categoryElementClass: "BisCore.GeometricElement3d", categoryModelClass: "BisCore.GeometricModel3d" };
343
389
  }
390
+ function applyElementsFilter(list, includeEmpty) {
391
+ return includeEmpty ? list : list.filter(({ hasElements }) => !!hasElements);
392
+ }
344
393
  //# sourceMappingURL=CategoriesTreeIdsCache.js.map