@itwin/tree-widget-react 3.16.0 → 3.17.0

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 (120) hide show
  1. package/CHANGELOG.md +23 -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 +90 -73
  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 +290 -242
  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 +16 -7
  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/UseActiveViewport.js.map +1 -1
  27. package/lib/cjs/tree-widget-react/components/trees/common/UseHierarchyVisibility.js.map +1 -1
  28. package/lib/cjs/tree-widget-react/components/trees/common/components/ProgressOverlay.js.map +1 -1
  29. package/lib/cjs/tree-widget-react/components/trees/common/components/Tree.d.ts +2 -2
  30. package/lib/cjs/tree-widget-react/components/trees/common/components/Tree.js.map +1 -1
  31. package/lib/cjs/tree-widget-react/components/trees/common/components/TreeNodeCheckbox.d.ts +1 -1
  32. package/lib/cjs/tree-widget-react/components/trees/common/components/TreeNodeCheckbox.js.map +1 -1
  33. package/lib/cjs/tree-widget-react/components/trees/common/components/TreeRenderer.d.ts +1 -1
  34. package/lib/cjs/tree-widget-react/components/trees/common/components/TreeRenderer.js +2 -2
  35. package/lib/cjs/tree-widget-react/components/trees/common/components/TreeRenderer.js.map +1 -1
  36. package/lib/cjs/tree-widget-react/components/trees/common/components/VisibilityTree.d.ts +3 -3
  37. package/lib/cjs/tree-widget-react/components/trees/common/components/VisibilityTree.js.map +1 -1
  38. package/lib/cjs/tree-widget-react/components/trees/common/components/VisibilityTreeRenderer.d.ts +1 -1
  39. package/lib/cjs/tree-widget-react/components/trees/common/components/VisibilityTreeRenderer.js.map +1 -1
  40. package/lib/cjs/tree-widget-react/components/trees/models-tree/ModelsTree.d.ts +1 -1
  41. package/lib/cjs/tree-widget-react/components/trees/models-tree/ModelsTree.js.map +1 -1
  42. package/lib/cjs/tree-widget-react/components/trees/models-tree/ModelsTreeButtons.js.map +1 -1
  43. package/lib/cjs/tree-widget-react/components/trees/models-tree/ModelsTreeComponent.js.map +1 -1
  44. package/lib/cjs/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.js +8 -5
  45. package/lib/cjs/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.js.map +1 -1
  46. package/lib/cjs/tree-widget-react/components/trees/models-tree/UseModelsTree.js +2 -1
  47. package/lib/cjs/tree-widget-react/components/trees/models-tree/UseModelsTree.js.map +1 -1
  48. package/lib/cjs/tree-widget-react/components/trees/models-tree/Utils.d.ts +1 -4
  49. package/lib/cjs/tree-widget-react/components/trees/models-tree/Utils.js +1 -4
  50. package/lib/cjs/tree-widget-react/components/trees/models-tree/Utils.js.map +1 -1
  51. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.d.ts +13 -12
  52. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js +252 -275
  53. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js.map +1 -1
  54. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeNode.d.ts +1 -1
  55. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeNode.js.map +1 -1
  56. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js +47 -35
  57. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js.map +1 -1
  58. package/lib/cjs/tree-widget-react-internal.d.ts +2 -1
  59. package/lib/cjs/tree-widget-react-internal.js +4 -1
  60. package/lib/cjs/tree-widget-react-internal.js.map +1 -1
  61. package/lib/esm/tree-widget-react/components/SelectableTree.js.map +1 -1
  62. package/lib/esm/tree-widget-react/components/TreeSelector.js.map +1 -1
  63. package/lib/esm/tree-widget-react/components/TreeWidgetUiItemsProvider.js +1 -1
  64. package/lib/esm/tree-widget-react/components/TreeWidgetUiItemsProvider.js.map +1 -1
  65. package/lib/esm/tree-widget-react/components/tree-header/TreeHeader.js.map +1 -1
  66. package/lib/esm/tree-widget-react/components/tree-header/TreeWithHeader.js.map +1 -1
  67. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTree.d.ts +2 -2
  68. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTree.js +2 -1
  69. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTree.js.map +1 -1
  70. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeButtons.js.map +1 -1
  71. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeComponent.d.ts +1 -1
  72. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeComponent.js.map +1 -1
  73. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.d.ts +13 -0
  74. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.js +90 -73
  75. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.js.map +1 -1
  76. package/lib/esm/tree-widget-react/components/trees/categories-tree/UseCategoriesTree.d.ts +3 -1
  77. package/lib/esm/tree-widget-react/components/trees/categories-tree/UseCategoriesTree.js +22 -9
  78. package/lib/esm/tree-widget-react/components/trees/categories-tree/UseCategoriesTree.js.map +1 -1
  79. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.d.ts +21 -9
  80. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.js +290 -242
  81. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.js.map +1 -1
  82. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.d.ts +2 -0
  83. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.js +16 -7
  84. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.js.map +1 -1
  85. package/lib/esm/tree-widget-react/components/trees/common/UseActiveViewport.js.map +1 -1
  86. package/lib/esm/tree-widget-react/components/trees/common/UseHierarchyVisibility.js.map +1 -1
  87. package/lib/esm/tree-widget-react/components/trees/common/components/ProgressOverlay.js.map +1 -1
  88. package/lib/esm/tree-widget-react/components/trees/common/components/Tree.d.ts +2 -2
  89. package/lib/esm/tree-widget-react/components/trees/common/components/Tree.js.map +1 -1
  90. package/lib/esm/tree-widget-react/components/trees/common/components/TreeNodeCheckbox.d.ts +1 -1
  91. package/lib/esm/tree-widget-react/components/trees/common/components/TreeNodeCheckbox.js.map +1 -1
  92. package/lib/esm/tree-widget-react/components/trees/common/components/TreeRenderer.d.ts +1 -1
  93. package/lib/esm/tree-widget-react/components/trees/common/components/TreeRenderer.js +2 -2
  94. package/lib/esm/tree-widget-react/components/trees/common/components/TreeRenderer.js.map +1 -1
  95. package/lib/esm/tree-widget-react/components/trees/common/components/VisibilityTree.d.ts +3 -3
  96. package/lib/esm/tree-widget-react/components/trees/common/components/VisibilityTree.js.map +1 -1
  97. package/lib/esm/tree-widget-react/components/trees/common/components/VisibilityTreeRenderer.d.ts +1 -1
  98. package/lib/esm/tree-widget-react/components/trees/common/components/VisibilityTreeRenderer.js.map +1 -1
  99. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTree.d.ts +1 -1
  100. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTree.js.map +1 -1
  101. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeButtons.js.map +1 -1
  102. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeComponent.js.map +1 -1
  103. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.js +9 -6
  104. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.js.map +1 -1
  105. package/lib/esm/tree-widget-react/components/trees/models-tree/UseModelsTree.js +2 -1
  106. package/lib/esm/tree-widget-react/components/trees/models-tree/UseModelsTree.js.map +1 -1
  107. package/lib/esm/tree-widget-react/components/trees/models-tree/Utils.d.ts +1 -4
  108. package/lib/esm/tree-widget-react/components/trees/models-tree/Utils.js +1 -4
  109. package/lib/esm/tree-widget-react/components/trees/models-tree/Utils.js.map +1 -1
  110. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.d.ts +13 -12
  111. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js +253 -276
  112. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js.map +1 -1
  113. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeNode.d.ts +1 -1
  114. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeNode.js.map +1 -1
  115. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js +47 -35
  116. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js.map +1 -1
  117. package/lib/esm/tree-widget-react-internal.d.ts +2 -1
  118. package/lib/esm/tree-widget-react-internal.js +2 -1
  119. package/lib/esm/tree-widget-react-internal.js.map +1 -1
  120. package/package.json +1 -1
@@ -2,10 +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 { bufferCount, bufferTime, filter, firstValueFrom, from, map, mergeAll, mergeMap, reduce, ReplaySubject, Subject } from "rxjs";
5
+ import { bufferCount, bufferTime, defer, filter, forkJoin, from, map, mergeAll, mergeMap, reduce, ReplaySubject, shareReplay, Subject, take, toArray, } from "rxjs";
6
6
  import { assert, Guid, Id64 } from "@itwin/core-bentley";
7
7
  import { IModel } from "@itwin/core-common";
8
- import { collect } from "../../common/Rxjs.js";
9
8
  import { pushToMap } from "../../common/Utils.js";
10
9
  /** @internal */
11
10
  export class ModelsTreeIdsCache {
@@ -24,7 +23,7 @@ export class ModelsTreeIdsCache {
24
23
  constructor(queryExecutor, hierarchyConfig, componentId) {
25
24
  this.#hierarchyConfig = hierarchyConfig;
26
25
  this.#queryExecutor = queryExecutor;
27
- this.#categoryElementCounts = new ModelCategoryElementsCountCache(async (input) => this.queryCategoryElementCounts(input));
26
+ this.#categoryElementCounts = new ModelCategoryElementsCountCache((input) => this.queryCategoryElementCounts(input));
28
27
  this.#modelKeyPaths = new Map();
29
28
  this.#subjectKeyPaths = new Map();
30
29
  this.#categoryKeyPaths = new Map();
@@ -34,78 +33,77 @@ export class ModelsTreeIdsCache {
34
33
  [Symbol.dispose]() {
35
34
  this.#categoryElementCounts[Symbol.dispose]();
36
35
  }
37
- async *querySubjects() {
38
- const subjectsQuery = `
39
- SELECT
40
- s.ECInstanceId id,
41
- s.Parent.Id parentId,
42
- (
43
- SELECT m.ECInstanceId
44
- FROM bis.GeometricModel3d m
45
- WHERE m.ECInstanceId = HexToId(json_extract(s.JsonProperties, '$.Subject.Model.TargetPartition'))
46
- AND NOT m.IsPrivate
47
- AND EXISTS (SELECT 1 FROM ${this.#hierarchyConfig.elementClassSpecification} WHERE Model.Id = m.ECInstanceId)
48
- ) targetPartitionId,
49
- CASE
50
- WHEN (
51
- json_extract(s.JsonProperties, '$.Subject.Job.Bridge') IS NOT NULL
52
- OR json_extract(s.JsonProperties, '$.Subject.Model.Type') = 'Hierarchy'
53
- ) THEN 1
54
- ELSE 0
55
- END hideInHierarchy
56
- FROM bis.Subject s
57
- `;
58
- for await (const row of this.#queryExecutor.createQueryReader({ ecsql: subjectsQuery }, { rowFormat: "ECSqlPropertyNames", limit: "unbounded", restartToken: `${this.#componentName}/${this.#componentId}/subjects` })) {
59
- yield { id: row.id, parentId: row.parentId, targetPartitionId: row.targetPartitionId, hideInHierarchy: !!row.hideInHierarchy };
60
- }
36
+ querySubjects() {
37
+ return defer(() => {
38
+ const subjectsQuery = `
39
+ SELECT
40
+ s.ECInstanceId id,
41
+ s.Parent.Id parentId,
42
+ (
43
+ SELECT m.ECInstanceId
44
+ FROM bis.GeometricModel3d m
45
+ WHERE m.ECInstanceId = HexToId(json_extract(s.JsonProperties, '$.Subject.Model.TargetPartition'))
46
+ AND NOT m.IsPrivate
47
+ AND EXISTS (SELECT 1 FROM ${this.#hierarchyConfig.elementClassSpecification} WHERE Model.Id = m.ECInstanceId)
48
+ ) targetPartitionId,
49
+ CASE
50
+ WHEN (
51
+ json_extract(s.JsonProperties, '$.Subject.Job.Bridge') IS NOT NULL
52
+ OR json_extract(s.JsonProperties, '$.Subject.Model.Type') = 'Hierarchy'
53
+ ) THEN 1
54
+ ELSE 0
55
+ END hideInHierarchy
56
+ FROM bis.Subject s
57
+ `;
58
+ return this.#queryExecutor.createQueryReader({ ecsql: subjectsQuery }, { rowFormat: "ECSqlPropertyNames", limit: "unbounded", restartToken: `${this.#componentName}/${this.#componentId}/subjects` });
59
+ }).pipe(map((row) => {
60
+ return { id: row.id, parentId: row.parentId, targetPartitionId: row.targetPartitionId, hideInHierarchy: !!row.hideInHierarchy };
61
+ }));
61
62
  }
62
- async *queryModels() {
63
- const modelsQuery = `
63
+ queryModels() {
64
+ return defer(() => {
65
+ const modelsQuery = `
64
66
  SELECT p.ECInstanceId id, p.Parent.Id parentId
65
- FROM bis.InformationPartitionElement p
66
- INNER JOIN bis.GeometricModel3d m ON m.ModeledElement.Id = p.ECInstanceId
67
- WHERE
68
- NOT m.IsPrivate
69
- ${this.#hierarchyConfig.showEmptyModels ? "" : `AND EXISTS (SELECT 1 FROM ${this.#hierarchyConfig.elementClassSpecification} WHERE Model.Id = m.ECInstanceId)`}
70
- `;
71
- for await (const row of this.#queryExecutor.createQueryReader({ ecsql: modelsQuery }, { rowFormat: "ECSqlPropertyNames", limit: "unbounded", restartToken: `${this.#componentName}/${this.#componentId}/models` })) {
72
- yield { id: row.id, parentId: row.parentId };
73
- }
67
+ FROM bis.InformationPartitionElement p
68
+ INNER JOIN bis.GeometricModel3d m ON m.ModeledElement.Id = p.ECInstanceId
69
+ WHERE
70
+ NOT m.IsPrivate
71
+ ${this.#hierarchyConfig.showEmptyModels ? "" : `AND EXISTS (SELECT 1 FROM ${this.#hierarchyConfig.elementClassSpecification} WHERE Model.Id = m.ECInstanceId)`}
72
+ `;
73
+ return this.#queryExecutor.createQueryReader({ ecsql: modelsQuery }, { rowFormat: "ECSqlPropertyNames", limit: "unbounded", restartToken: `${this.#componentName}/${this.#componentId}/models` });
74
+ }).pipe(map((row) => {
75
+ return { id: row.id, parentId: row.parentId };
76
+ }));
74
77
  }
75
- async getSubjectInfos() {
76
- this.#subjectInfos ??= (async () => {
77
- const [subjectInfos, targetPartitionSubjects] = await Promise.all([
78
- (async () => {
79
- const result = new Map();
80
- for await (const subject of this.querySubjects()) {
81
- const subjectInfo = {
82
- parentSubject: subject.parentId,
83
- hideInHierarchy: subject.hideInHierarchy,
84
- childSubjects: new Set(),
85
- childModels: new Set(),
86
- };
87
- if (subject.targetPartitionId) {
88
- subjectInfo.childModels.add(subject.targetPartitionId);
89
- }
90
- result.set(subject.id, subjectInfo);
91
- }
92
- return result;
93
- })(),
94
- (async () => {
95
- const result = new Map();
96
- for await (const model of this.queryModels()) {
97
- pushToMap(result, model.id, model.parentId);
78
+ getSubjectInfos() {
79
+ this.#subjectInfos ??= forkJoin({
80
+ subjectInfos: this.querySubjects().pipe(reduce((acc, subject) => {
81
+ const subjectInfo = {
82
+ parentSubject: subject.parentId,
83
+ hideInHierarchy: subject.hideInHierarchy,
84
+ childSubjects: new Set(),
85
+ childModels: new Set(),
86
+ };
87
+ if (subject.targetPartitionId) {
88
+ subjectInfo.childModels.add(subject.targetPartitionId);
89
+ }
90
+ acc.set(subject.id, subjectInfo);
91
+ return acc;
92
+ }, new Map()), map((subjectInfos) => {
93
+ for (const [subjectId, { parentSubject: parentSubjectId }] of subjectInfos.entries()) {
94
+ if (parentSubjectId) {
95
+ const parentSubjectInfo = subjectInfos.get(parentSubjectId);
96
+ assert(!!parentSubjectInfo);
97
+ parentSubjectInfo.childSubjects.add(subjectId);
98
98
  }
99
- return result;
100
- })(),
101
- ]);
102
- for (const [subjectId, { parentSubject: parentSubjectId }] of subjectInfos.entries()) {
103
- if (parentSubjectId) {
104
- const parentSubjectInfo = subjectInfos.get(parentSubjectId);
105
- assert(!!parentSubjectInfo);
106
- parentSubjectInfo.childSubjects.add(subjectId);
107
99
  }
108
- }
100
+ return subjectInfos;
101
+ })),
102
+ targetPartitionSubjects: this.queryModels().pipe(reduce((acc, model) => {
103
+ pushToMap(acc, model.id, model.parentId);
104
+ return acc;
105
+ }, new Map())),
106
+ }).pipe(map(({ subjectInfos, targetPartitionSubjects }) => {
109
107
  for (const [partitionId, subjectIds] of targetPartitionSubjects) {
110
108
  subjectIds.forEach((subjectId) => {
111
109
  const subjectInfo = subjectInfos.get(subjectId);
@@ -114,13 +112,12 @@ export class ModelsTreeIdsCache {
114
112
  });
115
113
  }
116
114
  return subjectInfos;
117
- })();
115
+ }), shareReplay());
118
116
  return this.#subjectInfos;
119
117
  }
120
118
  /** Returns ECInstanceIDs of Subjects that either have direct Model or at least one child Subject with a Model. */
121
- async getParentSubjectIds() {
122
- this.#parentSubjectIds ??= (async () => {
123
- const subjectInfos = await this.getSubjectInfos();
119
+ getParentSubjectIds() {
120
+ this.#parentSubjectIds ??= this.getSubjectInfos().pipe(map((subjectInfos) => {
124
121
  const parentSubjectIds = new Set();
125
122
  subjectInfos.forEach((subjectInfo, subjectId) => {
126
123
  if (subjectInfo.childModels.size > 0) {
@@ -133,71 +130,73 @@ export class ModelsTreeIdsCache {
133
130
  }
134
131
  });
135
132
  return [...parentSubjectIds];
136
- })();
133
+ }), shareReplay());
137
134
  return this.#parentSubjectIds;
138
135
  }
139
136
  /**
140
137
  * Returns child subjects of the specified parent subjects as they're displayed in the hierarchy - taking into
141
138
  * account `hideInHierarchy` flag.
142
139
  */
143
- async getChildSubjectIds(parentSubjectIds) {
144
- const childSubjectIds = new Array();
145
- const subjectInfos = await this.getSubjectInfos();
146
- parentSubjectIds.forEach((subjectId) => {
147
- forEachChildSubject(subjectInfos, subjectId, (childSubjectId, childSubjectInfo) => {
148
- if (!childSubjectInfo.hideInHierarchy) {
149
- childSubjectIds.push(childSubjectId);
150
- return "break";
151
- }
152
- return "continue";
140
+ getChildSubjectIds(parentSubjectIds) {
141
+ return this.getSubjectInfos().pipe(map((subjectInfos) => {
142
+ const childSubjectIds = new Array();
143
+ parentSubjectIds.forEach((subjectId) => {
144
+ forEachChildSubject(subjectInfos, subjectId, (childSubjectId, childSubjectInfo) => {
145
+ if (!childSubjectInfo.hideInHierarchy) {
146
+ childSubjectIds.push(childSubjectId);
147
+ return "break";
148
+ }
149
+ return "continue";
150
+ });
153
151
  });
154
- });
155
- return childSubjectIds;
152
+ return childSubjectIds;
153
+ }));
156
154
  }
157
155
  /** Returns ECInstanceIDs of all Models under specific parent Subjects, including their child Subjects, etc. */
158
- async getSubjectModelIds(subjectIds) {
159
- const subjectInfos = await this.getSubjectInfos();
160
- const subjectStack = [...subjectIds];
161
- const result = new Array();
162
- while (true) {
163
- const subjectId = subjectStack.pop();
164
- if (subjectId === undefined) {
165
- break;
166
- }
167
- const subjectInfo = subjectInfos.get(subjectId);
168
- if (!subjectInfo) {
169
- continue;
156
+ getSubjectModelIds(subjectIds) {
157
+ return this.getSubjectInfos().pipe(map((subjectInfos) => {
158
+ const subjectStack = [...subjectIds];
159
+ const result = new Array();
160
+ while (true) {
161
+ const subjectId = subjectStack.pop();
162
+ if (subjectId === undefined) {
163
+ break;
164
+ }
165
+ const subjectInfo = subjectInfos.get(subjectId);
166
+ if (!subjectInfo) {
167
+ continue;
168
+ }
169
+ result.push(...subjectInfo.childModels);
170
+ subjectStack.push(...subjectInfo.childSubjects);
170
171
  }
171
- result.push(...subjectInfo.childModels);
172
- subjectStack.push(...subjectInfo.childSubjects);
173
- }
174
- return result;
172
+ return result;
173
+ }));
175
174
  }
176
175
  /** Returns ECInstanceIDs of Models under specific parent Subjects as they are displayed in the hierarchy. */
177
- async getChildSubjectModelIds(parentSubjectIds) {
178
- const subjectInfos = await this.getSubjectInfos();
179
- const hiddenSubjectIds = new Array();
180
- parentSubjectIds.forEach((subjectId) => {
181
- forEachChildSubject(subjectInfos, subjectId, (childSubjectId, childSubjectInfo) => {
182
- if (childSubjectInfo.hideInHierarchy) {
183
- hiddenSubjectIds.push(childSubjectId);
184
- return "continue";
185
- }
186
- return "break";
176
+ getChildSubjectModelIds(parentSubjectIds) {
177
+ return this.getSubjectInfos().pipe(map((subjectInfos) => {
178
+ const hiddenSubjectIds = new Array();
179
+ parentSubjectIds.forEach((subjectId) => {
180
+ forEachChildSubject(subjectInfos, subjectId, (childSubjectId, childSubjectInfo) => {
181
+ if (childSubjectInfo.hideInHierarchy) {
182
+ hiddenSubjectIds.push(childSubjectId);
183
+ return "continue";
184
+ }
185
+ return "break";
186
+ });
187
187
  });
188
- });
189
- const modelIds = new Array();
190
- [...parentSubjectIds, ...hiddenSubjectIds].forEach((subjectId) => {
191
- const subjectInfo = subjectInfos.get(subjectId);
192
- subjectInfo && modelIds.push(...subjectInfo.childModels);
193
- });
194
- return modelIds;
188
+ const modelIds = new Array();
189
+ [...parentSubjectIds, ...hiddenSubjectIds].forEach((subjectId) => {
190
+ const subjectInfo = subjectInfos.get(subjectId);
191
+ subjectInfo && modelIds.push(...subjectInfo.childModels);
192
+ });
193
+ return modelIds;
194
+ }));
195
195
  }
196
- async createSubjectInstanceKeysPath(targetSubjectId) {
196
+ createSubjectInstanceKeysPath(targetSubjectId) {
197
197
  let entry = this.#subjectKeyPaths.get(targetSubjectId);
198
198
  if (!entry) {
199
- entry = (async () => {
200
- const subjectInfos = await this.getSubjectInfos();
199
+ entry = this.getSubjectInfos().pipe(map((subjectInfos) => {
201
200
  const result = new Array();
202
201
  let currParentId = targetSubjectId;
203
202
  while (currParentId) {
@@ -211,128 +210,111 @@ export class ModelsTreeIdsCache {
211
210
  currParentId = parentInfo?.parentSubject;
212
211
  }
213
212
  return result.reverse();
214
- })();
213
+ }), shareReplay());
215
214
  this.#subjectKeyPaths.set(targetSubjectId, entry);
216
215
  }
217
216
  return entry;
218
217
  }
219
- async *queryModelCategories() {
220
- const query = `
221
- SELECT
222
- this.Model.Id modelId,
223
- this.Category.Id categoryId,
224
- m.IsPrivate isModelPrivate,
225
- MAX(IIF(this.Parent.Id IS NULL, 1, 0)) isRootElementCategory
226
- FROM BisCore.Model m
227
- JOIN ${this.#hierarchyConfig.elementClassSpecification} this ON m.ECInstanceId = this.Model.Id
228
- GROUP BY modelId, categoryId, isModelPrivate
229
- `;
230
- for await (const row of this.#queryExecutor.createQueryReader({ ecsql: query }, { rowFormat: "ECSqlPropertyNames", limit: "unbounded", restartToken: `${this.#componentName}/${this.#componentId}/model-categories` })) {
231
- yield { modelId: row.modelId, categoryId: row.categoryId, isModelPrivate: !!row.isModelPrivate, isRootElementCategory: !!row.isRootElementCategory };
232
- }
218
+ queryModelCategories() {
219
+ return defer(() => {
220
+ const query = `
221
+ SELECT
222
+ this.Model.Id modelId,
223
+ this.Category.Id categoryId,
224
+ m.IsPrivate isModelPrivate,
225
+ MAX(IIF(this.Parent.Id IS NULL, 1, 0)) isRootElementCategory
226
+ FROM BisCore.Model m
227
+ JOIN ${this.#hierarchyConfig.elementClassSpecification} this ON m.ECInstanceId = this.Model.Id
228
+ GROUP BY modelId, categoryId, isModelPrivate
229
+ `;
230
+ return this.#queryExecutor.createQueryReader({ ecsql: query }, { rowFormat: "ECSqlPropertyNames", limit: "unbounded", restartToken: `${this.#componentName}/${this.#componentId}/model-categories` });
231
+ }).pipe(map((row) => {
232
+ return { modelId: row.modelId, categoryId: row.categoryId, isModelPrivate: !!row.isModelPrivate, isRootElementCategory: !!row.isRootElementCategory };
233
+ }));
233
234
  }
234
- async *queryModeledElements() {
235
- const query = `
236
- SELECT
237
- pe.ECInstanceId modeledElementId,
238
- pe.Category.Id categoryId,
239
- pe.Model.Id modelId
240
- FROM BisCore.Model m
241
- JOIN ${this.#hierarchyConfig.elementClassSpecification} pe ON pe.ECInstanceId = m.ModeledElement.Id
242
- WHERE
243
- m.IsPrivate = false
244
- AND m.ECInstanceId IN (SELECT Model.Id FROM ${this.#hierarchyConfig.elementClassSpecification})
245
- `;
246
- for await (const row of this.#queryExecutor.createQueryReader({ ecsql: query }, { rowFormat: "ECSqlPropertyNames", limit: "unbounded", restartToken: `${this.#componentName}/${this.#componentId}/modeled-elements` })) {
247
- yield { modelId: row.modelId, categoryId: row.categoryId, modeledElementId: row.modeledElementId };
248
- }
235
+ queryModeledElements() {
236
+ return defer(() => {
237
+ const query = `
238
+ SELECT
239
+ pe.ECInstanceId modeledElementId,
240
+ pe.Category.Id categoryId,
241
+ pe.Model.Id modelId
242
+ FROM BisCore.Model m
243
+ JOIN ${this.#hierarchyConfig.elementClassSpecification} pe ON pe.ECInstanceId = m.ModeledElement.Id
244
+ WHERE
245
+ m.IsPrivate = false
246
+ AND m.ECInstanceId IN (SELECT Model.Id FROM ${this.#hierarchyConfig.elementClassSpecification})
247
+ `;
248
+ return this.#queryExecutor.createQueryReader({ ecsql: query }, { rowFormat: "ECSqlPropertyNames", limit: "unbounded", restartToken: `${this.#componentName}/${this.#componentId}/modeled-elements` });
249
+ }).pipe(map((row) => {
250
+ return { modelId: row.modelId, categoryId: row.categoryId, modeledElementId: row.modeledElementId };
251
+ }));
249
252
  }
250
- async getModelWithCategoryModeledElements() {
251
- this.#modelWithCategoryModeledElements ??= (async () => {
252
- const modelWithCategoryModeledElements = new Map();
253
- for await (const { modelId, categoryId, modeledElementId } of this.queryModeledElements()) {
254
- const key = `${modelId}-${categoryId}`;
255
- const entry = modelWithCategoryModeledElements.get(key);
256
- if (entry === undefined) {
257
- modelWithCategoryModeledElements.set(key, new Set([modeledElementId]));
258
- }
259
- else {
260
- entry.add(modeledElementId);
261
- }
253
+ getModelWithCategoryModeledElements() {
254
+ this.#modelWithCategoryModeledElements ??= this.queryModeledElements().pipe(reduce((acc, { modelId, categoryId, modeledElementId }) => {
255
+ const key = `${modelId}-${categoryId}`;
256
+ const entry = acc.get(key);
257
+ if (entry === undefined) {
258
+ acc.set(key, new Set([modeledElementId]));
259
+ }
260
+ else {
261
+ entry.add(modeledElementId);
262
262
  }
263
- return modelWithCategoryModeledElements;
264
- })();
263
+ return acc;
264
+ }, new Map()), shareReplay());
265
265
  return this.#modelWithCategoryModeledElements;
266
266
  }
267
- async getModelInfos() {
268
- this.#modelInfos ??= (async () => {
269
- const modelInfos = new Map();
270
- for await (const { modelId, categoryId, isModelPrivate, isRootElementCategory } of this.queryModelCategories()) {
271
- const entry = modelInfos.get(modelId);
272
- if (entry) {
273
- entry.categories.set(categoryId, { isRootElementCategory });
274
- entry.isModelPrivate = isModelPrivate;
275
- }
276
- else {
277
- modelInfos.set(modelId, { categories: new Map([[categoryId, { isRootElementCategory }]]), isModelPrivate });
278
- }
267
+ getModelInfos() {
268
+ this.#modelInfos ??= this.queryModelCategories().pipe(reduce((acc, { modelId, categoryId, isModelPrivate, isRootElementCategory }) => {
269
+ const entry = acc.get(modelId);
270
+ if (entry) {
271
+ entry.categories.set(categoryId, { isRootElementCategory });
272
+ entry.isModelPrivate = isModelPrivate;
279
273
  }
280
- return modelInfos;
281
- })();
274
+ else {
275
+ acc.set(modelId, { categories: new Map([[categoryId, { isRootElementCategory }]]), isModelPrivate });
276
+ }
277
+ return acc;
278
+ }, new Map()), shareReplay());
282
279
  return this.#modelInfos;
283
280
  }
284
- async getAllCategories() {
285
- const modelInfos = await this.getModelInfos();
286
- const result = new Set();
287
- modelInfos.forEach(({ categories }) => {
288
- categories.forEach((_, categoryId) => result.add(categoryId));
289
- });
290
- return result;
281
+ getAllCategories() {
282
+ return this.getModelInfos().pipe(mergeMap((modelInfos) => modelInfos.values()), mergeMap(({ categories }) => categories.keys()), reduce((acc, categoryId) => {
283
+ acc.add(categoryId);
284
+ return acc;
285
+ }, new Set()));
291
286
  }
292
- async getModelCategories(modelId) {
293
- const modelInfos = await this.getModelInfos();
294
- const categories = modelInfos.get(modelId)?.categories.keys();
295
- return categories ? [...categories] : [];
287
+ getModelCategories(modelId) {
288
+ return this.getModelInfos().pipe(mergeMap((modelInfos) => modelInfos.get(modelId)?.categories.keys() ?? []), toArray());
296
289
  }
297
- async hasSubModel(elementId) {
298
- const modelInfos = await this.getModelInfos();
299
- const modeledElementInfo = modelInfos.get(elementId);
300
- if (!modeledElementInfo) {
301
- return false;
302
- }
303
- return !modeledElementInfo.isModelPrivate;
290
+ hasSubModel(elementId) {
291
+ return this.getModelInfos().pipe(map((modelInfos) => {
292
+ const modeledElementInfo = modelInfos.get(elementId);
293
+ if (!modeledElementInfo) {
294
+ return false;
295
+ }
296
+ return !modeledElementInfo.isModelPrivate;
297
+ }));
304
298
  }
305
- async getCategoriesModeledElements(modelId, categoryIds) {
306
- const modelWithCategoryModeledElements = await this.getModelWithCategoryModeledElements();
307
- const result = new Array();
308
- for (const categoryId of Id64.iterable(categoryIds)) {
299
+ getCategoriesModeledElements(modelId, categoryIds) {
300
+ return this.getModelWithCategoryModeledElements().pipe(mergeMap((modelWithCategoryModeledElements) => from(Id64.iterable(categoryIds)).pipe(reduce((acc, categoryId) => {
309
301
  const entry = modelWithCategoryModeledElements.get(`${modelId}-${categoryId}`);
310
302
  if (entry !== undefined) {
311
- result.push(...entry);
303
+ acc.push(...entry);
312
304
  }
313
- }
314
- return result;
305
+ return acc;
306
+ }, new Array()))));
315
307
  }
316
- async createModelInstanceKeyPaths(modelId) {
308
+ createModelInstanceKeyPaths(modelId) {
317
309
  let entry = this.#modelKeyPaths.get(modelId);
318
310
  if (!entry) {
319
- entry = (async () => {
320
- const result = new Array();
321
- const subjectInfos = (await this.getSubjectInfos()).entries();
322
- for (const [modelSubjectId, subjectInfo] of subjectInfos) {
323
- if (subjectInfo.childModels.has(modelId)) {
324
- const subjectPath = await this.createSubjectInstanceKeysPath(modelSubjectId);
325
- result.push([...subjectPath, { className: "BisCore.GeometricModel3d", id: modelId }]);
326
- }
327
- }
328
- return result;
329
- })();
311
+ entry = this.getSubjectInfos().pipe(mergeMap((subjectInfos) => subjectInfos.entries()), filter(([_, subjectInfo]) => subjectInfo.childModels.has(modelId)), mergeMap(([modelSubjectId]) => this.createSubjectInstanceKeysPath(modelSubjectId).pipe(map((path) => [...path, { className: "BisCore.GeometricModel3d", id: modelId }]))), toArray(), shareReplay());
330
312
  this.#modelKeyPaths.set(modelId, entry);
331
313
  }
332
314
  return entry;
333
315
  }
334
- async queryCategoryElementCounts(input) {
335
- return collect(from(input).pipe(reduce((acc, { modelId, categoryId }) => {
316
+ queryCategoryElementCounts(input) {
317
+ return from(input).pipe(reduce((acc, { modelId, categoryId }) => {
336
318
  const entry = acc.get(modelId);
337
319
  if (!entry) {
338
320
  acc.set(modelId, new Set([categoryId]));
@@ -344,69 +326,64 @@ export class ModelsTreeIdsCache {
344
326
  }, new Map()), mergeMap((modelCategoryMap) => modelCategoryMap.entries()), map(([modelId, categoryIds]) => `Model.Id = ${modelId} AND Category.Id IN (${[...categoryIds].join(", ")})`),
345
327
  // we may have thousands of where clauses here, and sending a single query with all of them could take a
346
328
  // long time - instead, split it into smaller chunks
347
- bufferCount(100), mergeMap(async (whereClauses) => {
348
- const reader = this.#queryExecutor.createQueryReader({
349
- ctes: [
350
- `
351
- CategoryElements(id, modelId, categoryId) AS (
352
- SELECT ECInstanceId, Model.Id, Category.Id
353
- FROM ${this.#hierarchyConfig.elementClassSpecification}
354
- WHERE
355
- Parent.Id IS NULL
356
- AND (
357
- ${whereClauses.join(" OR ")}
358
- )
329
+ bufferCount(100), mergeMap((whereClauses) => defer(() => this.#queryExecutor.createQueryReader({
330
+ ctes: [
331
+ `
332
+ CategoryElements(id, modelId, categoryId) AS (
333
+ SELECT ECInstanceId, Model.Id, Category.Id
334
+ FROM ${this.#hierarchyConfig.elementClassSpecification}
335
+ WHERE
336
+ Parent.Id IS NULL
337
+ AND (
338
+ ${whereClauses.join(" OR ")}
339
+ )
359
340
 
360
- UNION ALL
341
+ UNION ALL
361
342
 
362
- SELECT c.ECInstanceId, p.modelId, p.categoryId
363
- FROM ${this.#hierarchyConfig.elementClassSpecification} c
364
- JOIN CategoryElements p ON c.Parent.Id = p.id
365
- )
343
+ SELECT c.ECInstanceId, p.modelId, p.categoryId
344
+ FROM ${this.#hierarchyConfig.elementClassSpecification} c
345
+ JOIN CategoryElements p ON c.Parent.Id = p.id
346
+ )
347
+ `,
348
+ ],
349
+ ecsql: `
350
+ SELECT modelId, categoryId, COUNT(id) elementsCount
351
+ FROM CategoryElements
352
+ GROUP BY modelId, categoryId
366
353
  `,
367
- ],
368
- ecsql: `
369
- SELECT modelId, categoryId, COUNT(id) elementsCount
370
- FROM CategoryElements
371
- GROUP BY modelId, categoryId
372
- `,
373
- }, { rowFormat: "ECSqlPropertyNames", limit: "unbounded", restartToken: `${this.#componentName}/${this.#componentId}/category-element-counts` });
374
- const result = new Array();
375
- for await (const row of reader) {
376
- result.push({ modelId: row.modelId, categoryId: row.categoryId, elementsCount: row.elementsCount });
377
- }
354
+ }, {
355
+ rowFormat: "ECSqlPropertyNames",
356
+ limit: "unbounded",
357
+ restartToken: `${this.#componentName}/${this.#componentId}/category-element-counts/${Guid.createValue()}`,
358
+ }))), reduce(({ acc, createKey }, row) => {
359
+ acc.set(createKey({ modelId: row.modelId, categoryId: row.categoryId }), {
360
+ modelId: row.modelId,
361
+ categoryId: row.categoryId,
362
+ elementsCount: row.elementsCount,
363
+ });
364
+ return { acc, createKey };
365
+ }, {
366
+ acc: new Map(),
367
+ createKey: (keyProps) => `${keyProps.modelId}-${keyProps.categoryId}`,
368
+ }), mergeMap(({ acc: result, createKey }) => {
378
369
  input.forEach(({ modelId, categoryId }) => {
379
- if (!result.some((queriedResult) => queriedResult.categoryId === categoryId && queriedResult.modelId === modelId)) {
380
- result.push({ categoryId, modelId, elementsCount: 0 });
370
+ if (!result.has(createKey({ modelId, categoryId }))) {
371
+ result.set(createKey({ modelId, categoryId }), { categoryId, modelId, elementsCount: 0 });
381
372
  }
382
373
  });
383
- return result;
384
- }), mergeAll()));
374
+ return from(result.values());
375
+ }), toArray());
385
376
  }
386
- async getCategoryElementsCount(modelId, categoryId) {
377
+ getCategoryElementsCount(modelId, categoryId) {
387
378
  return this.#categoryElementCounts.getCategoryElementsCount(modelId, categoryId);
388
379
  }
389
- async createCategoryInstanceKeyPaths(categoryId) {
380
+ createCategoryInstanceKeyPaths(categoryId) {
390
381
  let entry = this.#categoryKeyPaths.get(categoryId);
391
382
  if (!entry) {
392
- entry = (async () => {
393
- const result = new Set();
394
- const modelInfos = await this.getModelInfos();
395
- modelInfos?.forEach((modelInfo, modelId) => {
396
- const categoryEntry = modelInfo.categories.get(categoryId);
397
- if (categoryEntry?.isRootElementCategory) {
398
- result.add(modelId);
399
- }
400
- });
401
- const categoryPaths = new Array();
402
- for (const categoryModelId of [...result]) {
403
- const modelPaths = await this.createModelInstanceKeyPaths(categoryModelId);
404
- for (const modelPath of modelPaths) {
405
- categoryPaths.push([...modelPath, { className: "BisCore.SpatialCategory", id: categoryId }]);
406
- }
407
- }
408
- return categoryPaths;
409
- })();
383
+ entry = this.getModelInfos().pipe(mergeMap((modelInfos) => modelInfos.entries()), filter(([_, modelInfo]) => !!modelInfo.categories.get(categoryId)?.isRootElementCategory), mergeMap(([categoryModelId]) => this.createModelInstanceKeyPaths(categoryModelId)), mergeMap((modelPaths) => modelPaths), reduce((acc, modelPath) => {
384
+ acc.push([...modelPath, { className: "BisCore.SpatialCategory", id: categoryId }]);
385
+ return acc;
386
+ }, new Array()), shareReplay());
410
387
  this.#categoryKeyPaths.set(categoryId, entry);
411
388
  }
412
389
  return entry;
@@ -429,7 +406,7 @@ class ModelCategoryElementsCountCache {
429
406
  #subscription;
430
407
  constructor(loader) {
431
408
  this.#subscription = this.#requestsStream
432
- .pipe(bufferTime(20), filter((requests) => requests.length > 0), mergeMap(async (requests) => loader(requests)), mergeAll())
409
+ .pipe(bufferTime(20), filter((requests) => requests.length > 0), mergeMap((requests) => loader(requests)), mergeAll())
433
410
  .subscribe({
434
411
  next: ({ modelId, categoryId, elementsCount }) => {
435
412
  const subject = this.#cache.get(`${modelId}${categoryId}`);
@@ -441,16 +418,16 @@ class ModelCategoryElementsCountCache {
441
418
  [Symbol.dispose]() {
442
419
  this.#subscription.unsubscribe();
443
420
  }
444
- async getCategoryElementsCount(modelId, categoryId) {
421
+ getCategoryElementsCount(modelId, categoryId) {
445
422
  const cacheKey = `${modelId}${categoryId}`;
446
423
  let result = this.#cache.get(cacheKey);
447
424
  if (result !== undefined) {
448
- return firstValueFrom(result);
425
+ return from(result).pipe(take(1));
449
426
  }
450
427
  result = new ReplaySubject(1);
451
428
  this.#cache.set(cacheKey, result);
452
429
  this.#requestsStream.next({ modelId, categoryId });
453
- return firstValueFrom(result);
430
+ return from(result).pipe(take(1));
454
431
  }
455
432
  }
456
433
  //# sourceMappingURL=ModelsTreeIdsCache.js.map