@itwin/presentation-backend 5.14.0-dev.8 → 5.14.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.
package/CHANGELOG.md CHANGED
@@ -1,6 +1,49 @@
1
1
  # Change Log - @itwin/presentation-backend
2
2
 
3
- This log was last generated on Thu, 03 Sep 2026 18:51:17 GMT and should not be manually modified.
3
+ This log was last generated on Fri, 02 Oct 2026 14:55:04 GMT and should not be manually modified.
4
+
5
+ ## 5.14.0
6
+ Fri, 02 Oct 2026 14:55:04 GMT
7
+
8
+ ### Updates
9
+
10
+ - Improve performance of `PresentationManager.getElementProperties` overload that takes `elementIds` prop.
11
+ - Further `PresentationManager.getElementProperties` performance improvements for the case when elements have more than 1k properties and most of them come from aspects.
12
+
13
+ ## 5.13.7
14
+ Thu, 01 Oct 2026 15:15:30 GMT
15
+
16
+ _Version update only_
17
+
18
+ ## 5.13.6
19
+ Fri, 25 Sep 2026 22:27:22 GMT
20
+
21
+ _Version update only_
22
+
23
+ ## 5.13.5
24
+ Tue, 22 Sep 2026 22:38:08 GMT
25
+
26
+ _Version update only_
27
+
28
+ ## 5.13.4
29
+ Fri, 18 Sep 2026 15:11:19 GMT
30
+
31
+ _Version update only_
32
+
33
+ ## 5.13.3
34
+ Tue, 15 Sep 2026 20:25:28 GMT
35
+
36
+ _Version update only_
37
+
38
+ ## 5.13.2
39
+ Mon, 14 Sep 2026 20:22:20 GMT
40
+
41
+ _Version update only_
42
+
43
+ ## 5.13.1
44
+ Tue, 08 Sep 2026 18:43:29 GMT
45
+
46
+ _Version update only_
4
47
 
5
48
  ## 5.13.0
6
49
  Thu, 03 Sep 2026 18:49:56 GMT
@@ -21,23 +21,6 @@ export declare function getContentItemsObservableFromClassNames(imodel: IModelDb
21
21
  }>;
22
22
  count: Observable<number>;
23
23
  };
24
- /**
25
- * Given a sorted list of ECInstanceIds and a batch size, create a stream of batches. Because the IDs won't necessarily
26
- * be sequential, a batch is defined a list of from-to pairs.
27
- * @internal
28
- */
29
- export declare function createIdBatches(sortedIds: Id64String[], batchSize: number): Observable<Array<{
30
- from: Id64String;
31
- to: Id64String;
32
- }>>;
33
- /**
34
- * Query all ECInstanceIds from given class and stream from-to pairs that batch the items into batches of `batchSize` size.
35
- * @internal
36
- */
37
- export declare function getBatchedClassElementIds(imodel: IModelDb, fullClassName: string, batchSize: number): Observable<Array<{
38
- from: Id64String;
39
- to: Id64String;
40
- }>>;
41
24
  /** @internal */
42
25
  export declare function getElementsCount(db: IModelDb, classNames: string[]): Promise<any>;
43
26
  //# sourceMappingURL=ElementPropertiesHelper.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ElementPropertiesHelper.d.ts","sourceRoot":"","sources":["../../../src/presentation-backend/ElementPropertiesHelper.ts"],"names":[],"mappings":"AAIA;;GAEG;AAEH,OAAO,EAAoD,UAAU,EAAsC,MAAM,MAAM,CAAC;AACxH,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAmB,UAAU,EAAuB,MAAM,qBAAqB,CAAC;AAEvF,OAAO,EACL,+BAA+B,EAC/B,qBAAqB,EACrB,UAAU,EACV,IAAI,EACJ,MAAM,EAIN,eAAe,EAChB,MAAM,4BAA4B,CAAC;AAQpC,gBAAgB;AAChB,wBAAgB,uCAAuC,CACrD,MAAM,EAAE,QAAQ,EAChB,uBAAuB,EAAE,CACvB,YAAY,EAAE,IAAI,CAAC,+BAA+B,CAAC,QAAQ,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,aAAa,GAAG,MAAM,CAAC,KAC3G,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,EACpC,gBAAgB,EAAE,CAChB,YAAY,EAAE,IAAI,CAAC,qBAAqB,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,aAAa,GAAG,MAAM,GAAG,YAAY,CAAC,KAC5H,OAAO,CAAC,IAAI,EAAE,CAAC,EACpB,UAAU,EAAE,UAAU,EAAE,EACxB,gBAAgB,EAAE,MAAM,EACxB,kBAAkB,EAAE,MAAM,EAC1B,SAAS,EAAE,MAAM,GAChB;IAAE,WAAW,EAAE,UAAU,CAAC;QAAE,UAAU,EAAE,UAAU,CAAC;QAAC,KAAK,EAAE,IAAI,EAAE,CAAA;KAAE,CAAC,CAAC;IAAC,KAAK,EAAE,UAAU,CAAC,MAAM,CAAC,CAAA;CAAE,CAiBnG;AAED,gBAAgB;AAChB,wBAAgB,uCAAuC,CACrD,MAAM,EAAE,QAAQ,EAChB,uBAAuB,EAAE,CACvB,YAAY,EAAE,IAAI,CAAC,+BAA+B,CAAC,QAAQ,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,aAAa,GAAG,MAAM,CAAC,KAC3G,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,EACpC,gBAAgB,EAAE,CAChB,YAAY,EAAE,IAAI,CAAC,qBAAqB,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,aAAa,GAAG,MAAM,GAAG,YAAY,CAAC,KAC5H,OAAO,CAAC,IAAI,EAAE,CAAC,EACpB,cAAc,EAAE,MAAM,EAAE,EACxB,gBAAgB,EAAE,MAAM,EACxB,kBAAkB,EAAE,MAAM,EAC1B,SAAS,EAAE,MAAM,GAChB;IAAE,WAAW,EAAE,UAAU,CAAC;QAAE,UAAU,EAAE,UAAU,CAAC;QAAC,KAAK,EAAE,IAAI,EAAE,CAAA;KAAE,CAAC,CAAC;IAAC,KAAK,EAAE,UAAU,CAAC,MAAM,CAAC,CAAA;CAAE,CAiBnG;AA4ID;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,UAAU,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,EAAE,EAAE,UAAU,CAAA;CAAE,CAAC,CAAC,CAuBnI;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,EAAE,EAAE,UAAU,CAAA;CAAE,CAAC,CAAC,CAM7J;AAED,gBAAgB;AAChB,wBAAsB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,gBA0BxE"}
1
+ {"version":3,"file":"ElementPropertiesHelper.d.ts","sourceRoot":"","sources":["../../../src/presentation-backend/ElementPropertiesHelper.ts"],"names":[],"mappings":"AAIA;;GAEG;AAEH,OAAO,EAAoD,UAAU,EAAsC,MAAM,MAAM,CAAC;AACxH,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAa,UAAU,EAAuB,MAAM,qBAAqB,CAAC;AAEjF,OAAO,EACL,+BAA+B,EAC/B,qBAAqB,EACrB,UAAU,EAEV,IAAI,EACJ,MAAM,EAKN,eAAe,EAChB,MAAM,4BAA4B,CAAC;AAQpC,gBAAgB;AAChB,wBAAgB,uCAAuC,CACrD,MAAM,EAAE,QAAQ,EAChB,uBAAuB,EAAE,CACvB,YAAY,EAAE,IAAI,CAAC,+BAA+B,CAAC,QAAQ,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,aAAa,GAAG,MAAM,CAAC,KAC3G,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,EACpC,gBAAgB,EAAE,CAChB,YAAY,EAAE,IAAI,CAAC,qBAAqB,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,aAAa,GAAG,MAAM,GAAG,YAAY,CAAC,KAC5H,OAAO,CAAC,IAAI,EAAE,CAAC,EACpB,UAAU,EAAE,UAAU,EAAE,EACxB,gBAAgB,EAAE,MAAM,EACxB,kBAAkB,EAAE,MAAM,EAC1B,SAAS,EAAE,MAAM,GAChB;IAAE,WAAW,EAAE,UAAU,CAAC;QAAE,UAAU,EAAE,UAAU,CAAC;QAAC,KAAK,EAAE,IAAI,EAAE,CAAA;KAAE,CAAC,CAAC;IAAC,KAAK,EAAE,UAAU,CAAC,MAAM,CAAC,CAAA;CAAE,CAkBnG;AAED,gBAAgB;AAChB,wBAAgB,uCAAuC,CACrD,MAAM,EAAE,QAAQ,EAChB,uBAAuB,EAAE,CACvB,YAAY,EAAE,IAAI,CAAC,+BAA+B,CAAC,QAAQ,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,aAAa,GAAG,MAAM,CAAC,KAC3G,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,EACpC,gBAAgB,EAAE,CAChB,YAAY,EAAE,IAAI,CAAC,qBAAqB,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,aAAa,GAAG,MAAM,GAAG,YAAY,CAAC,KAC5H,OAAO,CAAC,IAAI,EAAE,CAAC,EACpB,cAAc,EAAE,MAAM,EAAE,EACxB,gBAAgB,EAAE,MAAM,EACxB,kBAAkB,EAAE,MAAM,EAC1B,SAAS,EAAE,MAAM,GAChB;IAAE,WAAW,EAAE,UAAU,CAAC;QAAE,UAAU,EAAE,UAAU,CAAC;QAAC,KAAK,EAAE,IAAI,EAAE,CAAA;KAAE,CAAC,CAAC;IAAC,KAAK,EAAE,UAAU,CAAC,MAAM,CAAC,CAAA;CAAE,CAkBnG;AAsQD,gBAAgB;AAChB,wBAAsB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,gBA0BxE"}
@@ -9,11 +9,10 @@
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.getContentItemsObservableFromElementIds = getContentItemsObservableFromElementIds;
11
11
  exports.getContentItemsObservableFromClassNames = getContentItemsObservableFromClassNames;
12
- exports.createIdBatches = createIdBatches;
13
- exports.getBatchedClassElementIds = getBatchedClassElementIds;
14
12
  exports.getElementsCount = getElementsCount;
15
13
  const rxjs_1 = require("rxjs");
16
14
  const core_bentley_1 = require("@itwin/core-bentley");
15
+ const core_common_1 = require("@itwin/core-common");
17
16
  const presentation_common_1 = require("@itwin/presentation-common");
18
17
  const presentation_shared_1 = require("@itwin/presentation-shared");
19
18
  function getECSqlName(fullClassName) {
@@ -23,18 +22,18 @@ function getECSqlName(fullClassName) {
23
22
  /** @internal */
24
23
  function getContentItemsObservableFromElementIds(imodel, contentDescriptorGetter, contentSetGetter, elementIds, classParallelism, batchesParallelism, batchSize) {
25
24
  return {
26
- itemBatches: getElementClassesFromIds(imodel, elementIds).pipe((0, rxjs_1.mergeMap)(({ classFullName, ids }) => getBatchedClassContentItems(classFullName, contentDescriptorGetter, contentSetGetter, () => createIdBatches(core_bentley_1.OrderedId64Iterable.sortArray(ids), batchSize), batchesParallelism), classParallelism)),
25
+ itemBatches: getElementClassesFromIds(imodel, elementIds).pipe((0, rxjs_1.mergeMap)(({ classFullName, ids }) => getBatchedClassContentItems(imodel, classFullName, contentDescriptorGetter, contentSetGetter, () => createIdBatches(ids, batchSize), batchesParallelism), classParallelism)),
27
26
  count: (0, rxjs_1.of)(elementIds.length),
28
27
  };
29
28
  }
30
29
  /** @internal */
31
30
  function getContentItemsObservableFromClassNames(imodel, contentDescriptorGetter, contentSetGetter, elementClasses, classParallelism, batchesParallelism, batchSize) {
32
31
  return {
33
- itemBatches: getClassesWithInstances(imodel, elementClasses).pipe((0, rxjs_1.mergeMap)((classFullName) => getBatchedClassContentItems(classFullName, contentDescriptorGetter, contentSetGetter, () => getBatchedClassElementIds(imodel, classFullName, batchSize), batchesParallelism), classParallelism)),
32
+ itemBatches: getClassesWithInstances(imodel, elementClasses).pipe((0, rxjs_1.mergeMap)((classFullName) => getBatchedClassContentItems(imodel, classFullName, contentDescriptorGetter, contentSetGetter, () => getBatchedClassElementIds(imodel, classFullName, batchSize), batchesParallelism), classParallelism)),
34
33
  count: (0, rxjs_1.from)(getElementsCount(imodel, elementClasses)),
35
34
  };
36
35
  }
37
- function getBatchedClassContentItems(classFullName, contentDescriptorGetter, contentSetGetter, batcher, batchesParallelism) {
36
+ function getBatchedClassContentItems(imodel, classFullName, contentDescriptorGetter, contentSetGetter, batcher, batchesParallelism) {
38
37
  return (0, rxjs_1.defer)(async () => {
39
38
  const ruleset = createClassContentRuleset(classFullName);
40
39
  const keys = new presentation_common_1.KeySet();
@@ -42,41 +41,70 @@ function getBatchedClassContentItems(classFullName, contentDescriptorGetter, con
42
41
  if (!descriptor) {
43
42
  throw new presentation_common_1.PresentationError(presentation_common_1.PresentationStatus.Error, `Failed to get descriptor for class ${classFullName}`);
44
43
  }
45
- return { descriptor, keys, ruleset };
46
- }).pipe(
47
- // create elements' id batches
48
- (0, rxjs_1.mergeMap)((x) => batcher().pipe((0, rxjs_1.map)((batch) => ({ ...x, batch })))),
49
- // request content for each batch, filter by IDs for performance
50
- (0, rxjs_1.mergeMap)(({ descriptor, keys, ruleset, batch }) => (0, rxjs_1.defer)(async () => {
51
- const filteringDescriptor = new presentation_common_1.Descriptor(descriptor);
52
- filteringDescriptor.instanceFilter = {
44
+ const aspectFields = getPrunableAspectFields(descriptor, classFullName);
45
+ return { descriptor, keys, ruleset, aspectFields };
46
+ }).pipe((0, rxjs_1.mergeMap)((x) => batcher().pipe((0, rxjs_1.map)((batch) => ({ ...x, batch })))), (0, rxjs_1.mergeMap)(({ descriptor, keys, ruleset, batch, aspectFields }) => (0, rxjs_1.defer)(async () => {
47
+ const batchDescriptor = new presentation_common_1.Descriptor(descriptor);
48
+ batchDescriptor.instanceFilter = {
53
49
  selectClassName: classFullName,
54
- expression: createElementIdsECExpressionFilter(batch),
50
+ expression: batch.ranges
51
+ .map(({ from: fromId, to }) => fromId === to ? `this.ECInstanceId = ${fromId}` : `this.ECInstanceId >= ${fromId} AND this.ECInstanceId <= ${to}`)
52
+ .join(" OR "),
55
53
  };
56
- return contentSetGetter({
54
+ if (aspectFields.length) {
55
+ await selectBatchAspectFields(imodel, batchDescriptor, aspectFields, batch.ids);
56
+ }
57
+ const items = await contentSetGetter({
57
58
  rulesetOrId: ruleset,
58
59
  keys,
59
- descriptor: filteringDescriptor,
60
+ descriptor: batchDescriptor,
60
61
  });
61
- }).pipe((0, rxjs_1.map)((items) => ({ descriptor, items }))), batchesParallelism));
62
+ return { descriptor: batchDescriptor, items };
63
+ }), batchesParallelism));
62
64
  }
63
- function createElementIdsECExpressionFilter(batch) {
64
- let filter = "";
65
- function appendCondition(cond) {
66
- if (filter.length > 0) {
67
- filter += " OR ";
68
- }
69
- filter += cond;
65
+ function getPrunableAspectFields(descriptor, classFullName) {
66
+ // Caller selections take precedence; don't replace an include/exclude selector with our own.
67
+ if (descriptor.fieldsSelector || countFields(descriptor.fields) <= 1000) {
68
+ return [];
70
69
  }
71
- for (const item of batch) {
72
- if (item.from === item.to) {
73
- appendCondition(`this.ECInstanceId = ${item.from}`);
74
- }
75
- else {
76
- appendCondition(`this.ECInstanceId >= ${item.from} AND this.ECInstanceId <= ${item.to}`);
70
+ const { schemaName, className } = (0, presentation_shared_1.parseFullClassName)(classFullName);
71
+ return descriptor.fields.filter((field) => {
72
+ if (!field.isNestedContentField() || field.pathToPrimaryClass.length !== 1) {
73
+ return false;
77
74
  }
75
+ const step = field.pathToPrimaryClass[0];
76
+ return (!step.isForwardRelationship &&
77
+ (step.relationshipInfo.name === "BisCore:ElementOwnsMultiAspects" || step.relationshipInfo.name === "BisCore:ElementOwnsUniqueAspect") &&
78
+ step.sourceClassInfo.id === field.contentClassInfo.id &&
79
+ step.targetClassInfo.name === `${schemaName}:${className}`);
80
+ });
81
+ }
82
+ function countFields(fields) {
83
+ return fields.reduce((count, field) => count + 1 + (field.isNestedContentField() ? countFields(field.nestedFields) : 0), 0);
84
+ }
85
+ async function selectBatchAspectFields(imodel, descriptor, aspectFields, batch) {
86
+ const query = `
87
+ WITH aspectClasses(ClassId) AS (
88
+ SELECT DISTINCT a.ECClassId
89
+ FROM bis.ElementMultiAspect a
90
+ JOIN IdSet(:elementIds) e ON e.id = a.Element.Id
91
+ UNION ALL
92
+ SELECT DISTINCT a.ECClassId
93
+ FROM bis.ElementUniqueAspect a
94
+ JOIN IdSet(:elementIds) e ON e.id = a.Element.Id
95
+ )
96
+ SELECT IdToHex(b.TargetECInstanceId) classId
97
+ FROM meta.ClassHasAllBaseClasses b
98
+ JOIN aspectClasses a ON a.ClassId = b.SourceECInstanceId
99
+ `;
100
+ const aspectClasses = new Set();
101
+ for await (const row of imodel.createQueryReader(query, core_common_1.QueryBinder.from({ elementIds: batch }))) {
102
+ aspectClasses.add(row.classId);
103
+ }
104
+ const excludedFields = aspectFields.filter((field) => !aspectClasses.has(field.contentClassInfo.id));
105
+ if (excludedFields.length > 0) {
106
+ descriptor.fieldsSelector = { type: "exclude", fields: excludedFields.map((field) => field.getFieldDescriptor()) };
78
107
  }
79
- return filter;
80
108
  }
81
109
  function createClassContentRuleset(fullClassName) {
82
110
  const { schemaName, className } = (0, presentation_shared_1.parseFullClassName)(fullClassName);
@@ -100,27 +128,59 @@ function createClassContentRuleset(fullClassName) {
100
128
  ],
101
129
  };
102
130
  }
103
- /** Given a list of element ids, group them by class name. */
131
+ /**
132
+ * Given a list of element ids, group them by class name. In addition, for every element, get ID of the previous
133
+ * element of the same class, which lets us put requested IDs into ranges without other instances of the same class.
134
+ *
135
+ * The query reader re-executes the query for every page, so querying all IDs at once is much slower than querying
136
+ * them in chunks. Chunks are made of the sorted IDs list and run in parallel. `GROUP_CONCAT` order isn't guaranteed
137
+ * by SQLite, so each chunk's IDs are sorted individually (usually a no-op check), then stored at the chunk's index.
138
+ * Concatenating them gives each class its IDs sorted.
139
+ */
104
140
  function getElementClassesFromIds(imodel, elementIds) {
105
141
  const elementIdsBatchSize = 5000;
106
- return (0, rxjs_1.range)(0, elementIds.length / elementIdsBatchSize).pipe((0, rxjs_1.mergeMap)((batchIndex) => {
107
- const idsFrom = batchIndex * elementIdsBatchSize;
108
- const idsTo = Math.min(idsFrom + elementIdsBatchSize, elementIds.length);
142
+ const sortedElementIds = core_bentley_1.OrderedId64Iterable.sortArray([...elementIds]);
143
+ return (0, rxjs_1.range)(0, sortedElementIds.length / elementIdsBatchSize).pipe((0, rxjs_1.mergeMap)((_, chunkIndex) => {
144
+ const idsFrom = chunkIndex * elementIdsBatchSize;
145
+ const idsTo = Math.min(idsFrom + elementIdsBatchSize, sortedElementIds.length);
109
146
  return (0, rxjs_1.from)(imodel.createQueryReader(`
110
- SELECT ec_classname(e.ECClassId) className, GROUP_CONCAT(IdToHex(e.ECInstanceId)) ids
147
+ SELECT
148
+ ec_classname(e.ECClassId) className,
149
+ GROUP_CONCAT(
150
+ IdToHex(e.ECInstanceId) || ':' || IFNULL((
151
+ SELECT IdToHex(MAX(p.ECInstanceId))
152
+ FROM bis.Element p
153
+ WHERE p.ECClassId = e.ECClassId AND p.ECInstanceId < e.ECInstanceId
154
+ ), '')
155
+ ) ids
111
156
  FROM bis.Element e
112
- WHERE e.ECInstanceId IN (${elementIds.slice(idsFrom, idsTo).join(",")})
157
+ JOIN IdSet(:elementIds) elementIds ON elementIds.id = e.ECInstanceId
113
158
  GROUP BY e.ECClassId
114
- `));
115
- }), (0, rxjs_1.map)((row) => ({ className: row.className, ids: row.ids.split(",") })), (0, rxjs_1.groupBy)(({ className }) => className), (0, rxjs_1.mergeMap)((groups) => groups.pipe((0, rxjs_1.reduce)((acc, g) => {
116
- g.ids.forEach((id) => acc.ids.push(id));
117
- return {
118
- classFullName: g.className,
119
- ids: acc.ids,
120
- };
121
- }, { classFullName: "", ids: [] }))));
159
+ `, new core_common_1.QueryBinder().bindIdSet("elementIds", sortedElementIds.slice(idsFrom, idsTo)))).pipe((0, rxjs_1.map)((row) => ({
160
+ chunkIndex,
161
+ className: row.className,
162
+ ids: ensureSortedById(row.ids.split(",").map((pair) => {
163
+ const [id, prevClassInstanceId] = pair.split(":");
164
+ return { id, ...(prevClassInstanceId ? { prevClassInstanceId } : undefined) };
165
+ })),
166
+ })));
167
+ }), (0, rxjs_1.groupBy)(({ className }) => className), (0, rxjs_1.mergeMap)((groups) => groups.pipe((0, rxjs_1.reduce)((acc, g) => {
168
+ acc.chunks[g.chunkIndex] = g.ids;
169
+ return { classFullName: g.className, chunks: acc.chunks };
170
+ }, { classFullName: "", chunks: [] }))),
171
+ // chunks cover consecutive ID ranges and are sorted individually, so their concatenation is sorted as well;
172
+ // `flat` skips holes left by chunks that had no elements of the class
173
+ (0, rxjs_1.map)(({ classFullName, chunks }) => ({ classFullName, ids: chunks.flat() })));
174
+ }
175
+ function ensureSortedById(ids) {
176
+ for (let i = 1; i < ids.length; ++i) {
177
+ if (core_bentley_1.OrderedId64Iterable.compare(ids[i - 1].id, ids[i].id) > 0) {
178
+ return ids.sort((a, b) => core_bentley_1.OrderedId64Iterable.compare(a.id, b.id));
179
+ }
180
+ }
181
+ return ids;
122
182
  }
123
- /** Given a list of full class names, get a stream of actual class names that have instances. */
183
+ /** Given a list of full class names, get concrete class names with instances. */
124
184
  function getClassesWithInstances(imodel, fullClassNames) {
125
185
  return (0, rxjs_1.from)(fullClassNames).pipe((0, rxjs_1.mergeMap)((fullClassName) => (0, rxjs_1.from)(imodel.createQueryReader(`
126
186
  SELECT ec_classname(e.ECClassId, 's.c') className
@@ -129,38 +189,28 @@ function getClassesWithInstances(imodel, fullClassNames) {
129
189
  `))), (0, rxjs_1.map)((row) => row.className));
130
190
  }
131
191
  /**
132
- * Given a sorted list of ECInstanceIds and a batch size, create a stream of batches. Because the IDs won't necessarily
133
- * be sequential, a batch is defined a list of from-to pairs.
134
- * @internal
192
+ * Given a list of same-class ECInstanceIds, sorted by ID, and a batch size, create a stream of batches. Because the IDs won't
193
+ * necessarily be sequential, a batch is defined as a list of from-to pairs. An ID extends the current range if there are no other
194
+ * instances of the same class between it and the previous requested ID.
135
195
  */
136
196
  function createIdBatches(sortedIds, batchSize) {
137
197
  return (0, rxjs_1.range)(0, sortedIds.length / batchSize).pipe((0, rxjs_1.map)((batchIndex) => {
138
- const sequences = new Array();
198
+ const ranges = new Array();
139
199
  const startIndex = batchIndex * batchSize;
140
200
  const endIndex = Math.min((batchIndex + 1) * batchSize, sortedIds.length) - 1;
141
- let fromId = sortedIds[startIndex];
142
- let to = {
143
- id: sortedIds[startIndex],
144
- localId: core_bentley_1.Id64.getLocalId(sortedIds[startIndex]),
145
- };
201
+ let fromId = sortedIds[startIndex].id;
146
202
  for (let i = startIndex + 1; i <= endIndex; ++i) {
147
- const currLocalId = core_bentley_1.Id64.getLocalId(sortedIds[i]);
148
- if (currLocalId !== to.localId + 1) {
149
- sequences.push({ from: fromId, to: sortedIds[i - 1] });
150
- fromId = sortedIds[i];
203
+ if (sortedIds[i].prevClassInstanceId !== sortedIds[i - 1].id) {
204
+ ranges.push({ from: fromId, to: sortedIds[i - 1].id });
205
+ fromId = sortedIds[i].id;
151
206
  }
152
- to = { id: sortedIds[i], localId: currLocalId };
153
207
  }
154
- sequences.push({ from: fromId, to: sortedIds[endIndex] });
155
- return sequences;
208
+ ranges.push({ from: fromId, to: sortedIds[endIndex].id });
209
+ return { ids: sortedIds.slice(startIndex, endIndex + 1).map(({ id }) => id), ranges };
156
210
  }));
157
211
  }
158
- /**
159
- * Query all ECInstanceIds from given class and stream from-to pairs that batch the items into batches of `batchSize` size.
160
- * @internal
161
- */
162
212
  function getBatchedClassElementIds(imodel, fullClassName, batchSize) {
163
- return (0, rxjs_1.from)(imodel.createQueryReader(`SELECT IdToHex(ECInstanceId) id FROM ${getECSqlName(fullClassName)} ORDER BY ECInstanceId`)).pipe((0, rxjs_1.map)((row) => row.id), (0, rxjs_1.bufferCount)(batchSize), (0, rxjs_1.map)((batch) => [{ from: batch[0], to: batch[batch.length - 1] }]));
213
+ return (0, rxjs_1.from)(imodel.createQueryReader(`SELECT IdToHex(ECInstanceId) id FROM ONLY ${getECSqlName(fullClassName)} ORDER BY ECInstanceId`)).pipe((0, rxjs_1.map)((row) => row.id), (0, rxjs_1.bufferCount)(batchSize), (0, rxjs_1.map)((ids) => ({ ids, ranges: [{ from: ids[0], to: ids[ids.length - 1] }] })));
164
214
  }
165
215
  /** @internal */
166
216
  async function getElementsCount(db, classNames) {
@@ -1 +1 @@
1
- {"version":3,"file":"ElementPropertiesHelper.js","sourceRoot":"","sources":["../../../src/presentation-backend/ElementPropertiesHelper.ts"],"names":[],"mappings":";AAAA;;;gGAGgG;AAChG;;GAEG;;AAyBH,0FA6BC;AAGD,0FA6BC;AAiJD,0CAuBC;AAMD,8DAMC;AAGD,4CA0BC;AArSD,+BAAwH;AAExH,sDAAuF;AAEvF,oEAUoC;AACpC,oEAAgE;AAEhE,SAAS,YAAY,CAAC,aAAqB;IACzC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,IAAA,wCAAkB,EAAC,aAAa,CAAC,CAAC;IACpE,OAAO,IAAI,UAAU,MAAM,SAAS,GAAG,CAAC;AAC1C,CAAC;AAED,gBAAgB;AAChB,SAAgB,uCAAuC,CACrD,MAAgB,EAChB,uBAEoC,EACpC,gBAEoB,EACpB,UAAwB,EACxB,gBAAwB,EACxB,kBAA0B,EAC1B,SAAiB;IAEjB,OAAO;QACL,WAAW,EAAE,wBAAwB,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,IAAI,CAC5D,IAAA,eAAQ,EACN,CAAC,EAAE,aAAa,EAAE,GAAG,EAAE,EAAE,EAAE,CACzB,2BAA2B,CACzB,aAAa,EACb,uBAAuB,EACvB,gBAAgB,EAChB,GAAG,EAAE,CAAC,eAAe,CAAC,kCAAmB,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,SAAS,CAAC,EACpE,kBAAkB,CACnB,EACH,gBAAgB,CACjB,CACF;QACD,KAAK,EAAE,IAAA,SAAE,EAAC,UAAU,CAAC,MAAM,CAAC;KAC7B,CAAC;AACJ,CAAC;AAED,gBAAgB;AAChB,SAAgB,uCAAuC,CACrD,MAAgB,EAChB,uBAEoC,EACpC,gBAEoB,EACpB,cAAwB,EACxB,gBAAwB,EACxB,kBAA0B,EAC1B,SAAiB;IAEjB,OAAO;QACL,WAAW,EAAE,uBAAuB,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,IAAI,CAC/D,IAAA,eAAQ,EACN,CAAC,aAAa,EAAE,EAAE,CAChB,2BAA2B,CACzB,aAAa,EACb,uBAAuB,EACvB,gBAAgB,EAChB,GAAG,EAAE,CAAC,yBAAyB,CAAC,MAAM,EAAE,aAAa,EAAE,SAAS,CAAC,EACjE,kBAAkB,CACnB,EACH,gBAAgB,CACjB,CACF;QACD,KAAK,EAAE,IAAA,WAAI,EAAC,gBAAgB,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;KACtD,CAAC;AACJ,CAAC;AAED,SAAS,2BAA2B,CAClC,aAAqB,EACrB,uBAEoC,EACpC,gBAEoB,EACpB,OAAsE,EACtE,kBAA0B;IAE1B,OAAO,IAAA,YAAK,EAAC,KAAK,IAAI,EAAE;QACtB,MAAM,OAAO,GAAG,yBAAyB,CAAC,aAAa,CAAC,CAAC;QACzD,MAAM,IAAI,GAAG,IAAI,4BAAM,EAAE,CAAC;QAC1B,MAAM,UAAU,GAAG,MAAM,uBAAuB,CAAC,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QACjF,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,IAAI,uCAAiB,CAAC,wCAAkB,CAAC,KAAK,EAAE,sCAAsC,aAAa,EAAE,CAAC,CAAC;QAC/G,CAAC;QACD,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IACvC,CAAC,CAAC,CAAC,IAAI;IACL,8BAA8B;IAC9B,IAAA,eAAQ,EAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,IAAA,UAAG,EAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;IAClE,gEAAgE;IAChE,IAAA,eAAQ,EACN,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,CACvC,IAAA,YAAK,EAAC,KAAK,IAAI,EAAE;QACf,MAAM,mBAAmB,GAAG,IAAI,gCAAU,CAAC,UAAU,CAAC,CAAC;QACvD,mBAAmB,CAAC,cAAc,GAAG;YACnC,eAAe,EAAE,aAAa;YAC9B,UAAU,EAAE,kCAAkC,CAAC,KAAK,CAAC;SACtD,CAAC;QACF,OAAO,gBAAgB,CAAC;YACtB,WAAW,EAAE,OAAO;YACpB,IAAI;YACJ,UAAU,EAAE,mBAAmB;SAChC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC,IAAI,CAAC,IAAA,UAAG,EAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAClD,kBAAkB,CACnB,CACF,CAAC;AACJ,CAAC;AAED,SAAS,kCAAkC,CAAC,KAAkD;IAC5F,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,SAAS,eAAe,CAAC,IAAY;QACnC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,MAAM,IAAI,MAAM,CAAC;QACnB,CAAC;QACD,MAAM,IAAI,IAAI,CAAC;IACjB,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,EAAE,CAAC;YAC1B,eAAe,CAAC,uBAAuB,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACtD,CAAC;aAAM,CAAC;YACN,eAAe,CAAC,wBAAwB,IAAI,CAAC,IAAI,6BAA6B,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;QAC3F,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,yBAAyB,CAAC,aAAqB;IACtD,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,IAAA,wCAAkB,EAAC,aAAa,CAAC,CAAC;IACpE,OAAO;QACL,EAAE,EAAE,4BAA4B,aAAa,EAAE;QAC/C,KAAK,EAAE;YACL;gBACE,QAAQ,EAAE,SAAS;gBACnB,cAAc,EAAE;oBACd;wBACE,QAAQ,EAAE,mCAAmC;wBAC7C,OAAO,EAAE;4BACP,UAAU;4BACV,UAAU,EAAE,CAAC,SAAS,CAAC;4BACvB,cAAc,EAAE,KAAK;yBACtB;wBACD,+BAA+B,EAAE,IAAI;qBACtC;iBACF;aACF;SACF;KACF,CAAC;AACJ,CAAC;AAED,6DAA6D;AAC7D,SAAS,wBAAwB,CAAC,MAAgB,EAAE,UAAoB;IACtE,MAAM,mBAAmB,GAAG,IAAI,CAAC;IACjC,OAAO,IAAA,YAAK,EAAC,CAAC,EAAE,UAAU,CAAC,MAAM,GAAG,mBAAmB,CAAC,CAAC,IAAI,CAC3D,IAAA,eAAQ,EAAC,CAAC,UAAU,EAAE,EAAE;QACtB,MAAM,OAAO,GAAG,UAAU,GAAG,mBAAmB,CAAC;QACjD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,GAAG,mBAAmB,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;QACzE,OAAO,IAAA,WAAI,EACT,MAAM,CAAC,iBAAiB,CACtB;;;uCAG6B,UAAU,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;;WAEtE,CACF,CACF,CAAC;IACJ,CAAC,CAAC,EACF,IAAA,UAAG,EAAC,CAAC,GAAkB,EAAyC,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EAC3H,IAAA,cAAO,EAAC,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,SAAS,CAAC,EACrC,IAAA,eAAQ,EAAC,CAAC,MAAM,EAAE,EAAE,CAClB,MAAM,CAAC,IAAI,CACT,IAAA,aAAM,EACJ,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE;QACT,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;QACxC,OAAO;YACL,aAAa,EAAE,CAAC,CAAC,SAAS;YAC1B,GAAG,EAAE,GAAG,CAAC,GAAG;SACb,CAAC;IACJ,CAAC,EACD,EAAE,aAAa,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,CAC/B,CACF,CACF,CACF,CAAC;AACJ,CAAC;AAED,gGAAgG;AAChG,SAAS,uBAAuB,CAAC,MAAgB,EAAE,cAAwB;IACzE,OAAO,IAAA,WAAI,EAAC,cAAc,CAAC,CAAC,IAAI,CAC9B,IAAA,eAAQ,EAAC,CAAC,aAAa,EAAE,EAAE,CACzB,IAAA,WAAI,EACF,MAAM,CAAC,iBAAiB,CACtB;;mBAES,YAAY,CAAC,aAAa,CAAC;;WAEnC,CACF,CACF,CACF,EACD,IAAA,UAAG,EAAC,CAAC,GAAkB,EAAU,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,CACnD,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,SAAgB,eAAe,CAAC,SAAuB,EAAE,SAAiB;IACxE,OAAO,IAAA,YAAK,EAAC,CAAC,EAAE,SAAS,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC,IAAI,CAChD,IAAA,UAAG,EAAC,CAAC,UAAU,EAAE,EAAE;QACjB,MAAM,SAAS,GAAG,IAAI,KAAK,EAAwC,CAAC;QACpE,MAAM,UAAU,GAAG,UAAU,GAAG,SAAS,CAAC;QAC1C,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,GAAG,SAAS,EAAE,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC9E,IAAI,MAAM,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC;QACnC,IAAI,EAAE,GAAG;YACP,EAAE,EAAE,SAAS,CAAC,UAAU,CAAC;YACzB,OAAO,EAAE,mBAAI,CAAC,UAAU,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;SAChD,CAAC;QACF,KAAK,IAAI,CAAC,GAAG,UAAU,GAAG,CAAC,EAAE,CAAC,IAAI,QAAQ,EAAE,EAAE,CAAC,EAAE,CAAC;YAChD,MAAM,WAAW,GAAG,mBAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;YAClD,IAAI,WAAW,KAAK,EAAE,CAAC,OAAO,GAAG,CAAC,EAAE,CAAC;gBACnC,SAAS,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;gBACvD,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;YACxB,CAAC;YACD,EAAE,GAAG,EAAE,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;QAClD,CAAC;QACD,SAAS,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAC1D,OAAO,SAAS,CAAC;IACnB,CAAC,CAAC,CACH,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,SAAgB,yBAAyB,CAAC,MAAgB,EAAE,aAAqB,EAAE,SAAiB;IAClG,OAAO,IAAA,WAAI,EAAC,MAAM,CAAC,iBAAiB,CAAC,wCAAwC,YAAY,CAAC,aAAa,CAAC,wBAAwB,CAAC,CAAC,CAAC,IAAI,CACrI,IAAA,UAAG,EAAC,CAAC,GAAG,EAAc,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAChC,IAAA,kBAAW,EAAC,SAAS,CAAC,EACtB,IAAA,UAAG,EAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAClE,CAAC;AACJ,CAAC;AAED,gBAAgB;AACT,KAAK,UAAU,gBAAgB,CAAC,EAAY,EAAE,UAAoB;IACvE,MAAM,WAAW,GAAG,CAAC,GAAG,EAAE;QACxB,IAAI,UAAU,KAAK,SAAS,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxD,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,gDAAgD;QAChD,MAAM,eAAe,GAAG,IAAI,MAAM,CAAC,kBAAkB,CAAC,CAAC;QACvD,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC;QAC5E,IAAI,WAAW,EAAE,CAAC;YAChB,MAAM,IAAI,uCAAiB,CACzB,wCAAkB,CAAC,eAAe,EAClC,oCAAoC,WAAW;+GACwD,CACxG,CAAC;QACJ,CAAC;QACD,OAAO,mBAAmB,UAAU,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;IACtE,CAAC,CAAC,EAAE,CAAC;IACL,MAAM,KAAK,GAAG;;;MAGV,WAAW,CAAC,CAAC,CAAC,SAAS,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE;GAC5C,CAAC;IACF,IAAI,KAAK,EAAE,MAAM,GAAG,IAAI,EAAE,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC;QACpD,OAAO,GAAG,CAAC,YAAY,CAAC;IAC1B,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n * See LICENSE.md in the project root for license terms and full copyright notice.\r\n *--------------------------------------------------------------------------------------------*/\r\n/** @packageDocumentation\r\n * @module Core\r\n */\r\n\r\nimport { bufferCount, defer, from, groupBy, map, mergeMap, Observable, ObservedValueOf, of, range, reduce } from \"rxjs\";\r\nimport { IModelDb } from \"@itwin/core-backend\";\r\nimport { Id64, Id64Array, Id64String, OrderedId64Iterable } from \"@itwin/core-bentley\";\r\nimport { QueryRowProxy } from \"@itwin/core-common\";\r\nimport {\r\n ContentDescriptorRequestOptions,\r\n ContentRequestOptions,\r\n Descriptor,\r\n Item,\r\n KeySet,\r\n PresentationError,\r\n PresentationStatus,\r\n Ruleset,\r\n RulesetVariable,\r\n} from \"@itwin/presentation-common\";\r\nimport { parseFullClassName } from \"@itwin/presentation-shared\";\r\n\r\nfunction getECSqlName(fullClassName: string) {\r\n const { schemaName, className } = parseFullClassName(fullClassName);\r\n return `[${schemaName}].[${className}]`;\r\n}\r\n\r\n/** @internal */\r\nexport function getContentItemsObservableFromElementIds(\r\n imodel: IModelDb,\r\n contentDescriptorGetter: (\r\n partialProps: Pick<ContentDescriptorRequestOptions<IModelDb, KeySet, RulesetVariable>, \"rulesetOrId\" | \"keys\">,\r\n ) => Promise<Descriptor | undefined>,\r\n contentSetGetter: (\r\n partialProps: Pick<ContentRequestOptions<IModelDb, Descriptor, KeySet, RulesetVariable>, \"rulesetOrId\" | \"keys\" | \"descriptor\">,\r\n ) => Promise<Item[]>,\r\n elementIds: Id64String[],\r\n classParallelism: number,\r\n batchesParallelism: number,\r\n batchSize: number,\r\n): { itemBatches: Observable<{ descriptor: Descriptor; items: Item[] }>; count: Observable<number> } {\r\n return {\r\n itemBatches: getElementClassesFromIds(imodel, elementIds).pipe(\r\n mergeMap(\r\n ({ classFullName, ids }) =>\r\n getBatchedClassContentItems(\r\n classFullName,\r\n contentDescriptorGetter,\r\n contentSetGetter,\r\n () => createIdBatches(OrderedId64Iterable.sortArray(ids), batchSize),\r\n batchesParallelism,\r\n ),\r\n classParallelism,\r\n ),\r\n ),\r\n count: of(elementIds.length),\r\n };\r\n}\r\n\r\n/** @internal */\r\nexport function getContentItemsObservableFromClassNames(\r\n imodel: IModelDb,\r\n contentDescriptorGetter: (\r\n partialProps: Pick<ContentDescriptorRequestOptions<IModelDb, KeySet, RulesetVariable>, \"rulesetOrId\" | \"keys\">,\r\n ) => Promise<Descriptor | undefined>,\r\n contentSetGetter: (\r\n partialProps: Pick<ContentRequestOptions<IModelDb, Descriptor, KeySet, RulesetVariable>, \"rulesetOrId\" | \"keys\" | \"descriptor\">,\r\n ) => Promise<Item[]>,\r\n elementClasses: string[],\r\n classParallelism: number,\r\n batchesParallelism: number,\r\n batchSize: number,\r\n): { itemBatches: Observable<{ descriptor: Descriptor; items: Item[] }>; count: Observable<number> } {\r\n return {\r\n itemBatches: getClassesWithInstances(imodel, elementClasses).pipe(\r\n mergeMap(\r\n (classFullName) =>\r\n getBatchedClassContentItems(\r\n classFullName,\r\n contentDescriptorGetter,\r\n contentSetGetter,\r\n () => getBatchedClassElementIds(imodel, classFullName, batchSize),\r\n batchesParallelism,\r\n ),\r\n classParallelism,\r\n ),\r\n ),\r\n count: from(getElementsCount(imodel, elementClasses)),\r\n };\r\n}\r\n\r\nfunction getBatchedClassContentItems(\r\n classFullName: string,\r\n contentDescriptorGetter: (\r\n partialProps: Pick<ContentDescriptorRequestOptions<IModelDb, KeySet, RulesetVariable>, \"rulesetOrId\" | \"keys\">,\r\n ) => Promise<Descriptor | undefined>,\r\n contentSetGetter: (\r\n partialProps: Pick<ContentRequestOptions<IModelDb, Descriptor, KeySet, RulesetVariable>, \"rulesetOrId\" | \"keys\" | \"descriptor\">,\r\n ) => Promise<Item[]>,\r\n batcher: () => Observable<Array<{ from: Id64String; to: Id64String }>>,\r\n batchesParallelism: number,\r\n): Observable<{ descriptor: Descriptor; items: Item[] }> {\r\n return defer(async () => {\r\n const ruleset = createClassContentRuleset(classFullName);\r\n const keys = new KeySet();\r\n const descriptor = await contentDescriptorGetter({ rulesetOrId: ruleset, keys });\r\n if (!descriptor) {\r\n throw new PresentationError(PresentationStatus.Error, `Failed to get descriptor for class ${classFullName}`);\r\n }\r\n return { descriptor, keys, ruleset };\r\n }).pipe(\r\n // create elements' id batches\r\n mergeMap((x) => batcher().pipe(map((batch) => ({ ...x, batch })))),\r\n // request content for each batch, filter by IDs for performance\r\n mergeMap(\r\n ({ descriptor, keys, ruleset, batch }) =>\r\n defer(async () => {\r\n const filteringDescriptor = new Descriptor(descriptor);\r\n filteringDescriptor.instanceFilter = {\r\n selectClassName: classFullName,\r\n expression: createElementIdsECExpressionFilter(batch),\r\n };\r\n return contentSetGetter({\r\n rulesetOrId: ruleset,\r\n keys,\r\n descriptor: filteringDescriptor,\r\n });\r\n }).pipe(map((items) => ({ descriptor, items }))),\r\n batchesParallelism,\r\n ),\r\n );\r\n}\r\n\r\nfunction createElementIdsECExpressionFilter(batch: Array<{ from: Id64String; to: Id64String }>): string {\r\n let filter = \"\";\r\n function appendCondition(cond: string) {\r\n if (filter.length > 0) {\r\n filter += \" OR \";\r\n }\r\n filter += cond;\r\n }\r\n for (const item of batch) {\r\n if (item.from === item.to) {\r\n appendCondition(`this.ECInstanceId = ${item.from}`);\r\n } else {\r\n appendCondition(`this.ECInstanceId >= ${item.from} AND this.ECInstanceId <= ${item.to}`);\r\n }\r\n }\r\n return filter;\r\n}\r\n\r\nfunction createClassContentRuleset(fullClassName: string): Ruleset {\r\n const { schemaName, className } = parseFullClassName(fullClassName);\r\n return {\r\n id: `content/class-descriptor/${fullClassName}`,\r\n rules: [\r\n {\r\n ruleType: \"Content\",\r\n specifications: [\r\n {\r\n specType: \"ContentInstancesOfSpecificClasses\",\r\n classes: {\r\n schemaName,\r\n classNames: [className],\r\n arePolymorphic: false,\r\n },\r\n handlePropertiesPolymorphically: true,\r\n },\r\n ],\r\n },\r\n ],\r\n };\r\n}\r\n\r\n/** Given a list of element ids, group them by class name. */\r\nfunction getElementClassesFromIds(imodel: IModelDb, elementIds: string[]): Observable<{ classFullName: string; ids: Id64Array }> {\r\n const elementIdsBatchSize = 5000;\r\n return range(0, elementIds.length / elementIdsBatchSize).pipe(\r\n mergeMap((batchIndex) => {\r\n const idsFrom = batchIndex * elementIdsBatchSize;\r\n const idsTo = Math.min(idsFrom + elementIdsBatchSize, elementIds.length);\r\n return from(\r\n imodel.createQueryReader(\r\n `\r\n SELECT ec_classname(e.ECClassId) className, GROUP_CONCAT(IdToHex(e.ECInstanceId)) ids\r\n FROM bis.Element e\r\n WHERE e.ECInstanceId IN (${elementIds.slice(idsFrom, idsTo).join(\",\")})\r\n GROUP BY e.ECClassId\r\n `,\r\n ),\r\n );\r\n }),\r\n map((row: QueryRowProxy): { className: string; ids: Id64Array } => ({ className: row.className, ids: row.ids.split(\",\") })),\r\n groupBy(({ className }) => className),\r\n mergeMap((groups) =>\r\n groups.pipe(\r\n reduce<ObservedValueOf<typeof groups>, { classFullName: string; ids: Id64Array }>(\r\n (acc, g) => {\r\n g.ids.forEach((id) => acc.ids.push(id));\r\n return {\r\n classFullName: g.className,\r\n ids: acc.ids,\r\n };\r\n },\r\n { classFullName: \"\", ids: [] },\r\n ),\r\n ),\r\n ),\r\n );\r\n}\r\n\r\n/** Given a list of full class names, get a stream of actual class names that have instances. */\r\nfunction getClassesWithInstances(imodel: IModelDb, fullClassNames: string[]): Observable<string> {\r\n return from(fullClassNames).pipe(\r\n mergeMap((fullClassName) =>\r\n from(\r\n imodel.createQueryReader(\r\n `\r\n SELECT ec_classname(e.ECClassId, 's.c') className\r\n FROM ${getECSqlName(fullClassName)} e\r\n GROUP BY e.ECClassId\r\n `,\r\n ),\r\n ),\r\n ),\r\n map((row: QueryRowProxy): string => row.className),\r\n );\r\n}\r\n\r\n/**\r\n * Given a sorted list of ECInstanceIds and a batch size, create a stream of batches. Because the IDs won't necessarily\r\n * be sequential, a batch is defined a list of from-to pairs.\r\n * @internal\r\n */\r\nexport function createIdBatches(sortedIds: Id64String[], batchSize: number): Observable<Array<{ from: Id64String; to: Id64String }>> {\r\n return range(0, sortedIds.length / batchSize).pipe(\r\n map((batchIndex) => {\r\n const sequences = new Array<{ from: Id64String; to: Id64String }>();\r\n const startIndex = batchIndex * batchSize;\r\n const endIndex = Math.min((batchIndex + 1) * batchSize, sortedIds.length) - 1;\r\n let fromId = sortedIds[startIndex];\r\n let to = {\r\n id: sortedIds[startIndex],\r\n localId: Id64.getLocalId(sortedIds[startIndex]),\r\n };\r\n for (let i = startIndex + 1; i <= endIndex; ++i) {\r\n const currLocalId = Id64.getLocalId(sortedIds[i]);\r\n if (currLocalId !== to.localId + 1) {\r\n sequences.push({ from: fromId, to: sortedIds[i - 1] });\r\n fromId = sortedIds[i];\r\n }\r\n to = { id: sortedIds[i], localId: currLocalId };\r\n }\r\n sequences.push({ from: fromId, to: sortedIds[endIndex] });\r\n return sequences;\r\n }),\r\n );\r\n}\r\n\r\n/**\r\n * Query all ECInstanceIds from given class and stream from-to pairs that batch the items into batches of `batchSize` size.\r\n * @internal\r\n */\r\nexport function getBatchedClassElementIds(imodel: IModelDb, fullClassName: string, batchSize: number): Observable<Array<{ from: Id64String; to: Id64String }>> {\r\n return from(imodel.createQueryReader(`SELECT IdToHex(ECInstanceId) id FROM ${getECSqlName(fullClassName)} ORDER BY ECInstanceId`)).pipe(\r\n map((row): Id64String => row.id),\r\n bufferCount(batchSize),\r\n map((batch) => [{ from: batch[0], to: batch[batch.length - 1] }]),\r\n );\r\n}\r\n\r\n/** @internal */\r\nexport async function getElementsCount(db: IModelDb, classNames: string[]) {\r\n const whereClause = (() => {\r\n if (classNames === undefined || classNames.length === 0) {\r\n return undefined;\r\n }\r\n // check if list contains only valid class names\r\n const classNameRegExp = new RegExp(/^[\\w]+[.:][\\w]+$/);\r\n const invalidName = classNames.find((name) => !name.match(classNameRegExp));\r\n if (invalidName) {\r\n throw new PresentationError(\r\n PresentationStatus.InvalidArgument,\r\n `Encountered invalid class name - ${invalidName}.\r\n Valid class name formats: \"<schema name or alias>.<class name>\", \"<schema name or alias>:<class name>\"`,\r\n );\r\n }\r\n return `e.ECClassId IS (${classNames.map(getECSqlName).join(\",\")})`;\r\n })();\r\n const query = `\r\n SELECT COUNT(e.ECInstanceId) AS elementCount\r\n FROM bis.Element e\r\n ${whereClause ? `WHERE ${whereClause}` : \"\"}\r\n `;\r\n for await (const row of db.createQueryReader(query)) {\r\n return row.elementCount;\r\n }\r\n return 0;\r\n}\r\n"]}
1
+ {"version":3,"file":"ElementPropertiesHelper.js","sourceRoot":"","sources":["../../../src/presentation-backend/ElementPropertiesHelper.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n * Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n * See LICENSE.md in the project root for license terms and full copyright notice.\r\n *--------------------------------------------------------------------------------------------*/\r\n/** @packageDocumentation\r\n * @module Core\r\n */\r\n\r\nimport { bufferCount, defer, from, groupBy, map, mergeMap, Observable, ObservedValueOf, of, range, reduce } from \"rxjs\";\r\nimport { IModelDb } from \"@itwin/core-backend\";\r\nimport { Id64Array, Id64String, OrderedId64Iterable } from \"@itwin/core-bentley\";\r\nimport { QueryBinder, QueryRowProxy } from \"@itwin/core-common\";\r\nimport {\r\n ContentDescriptorRequestOptions,\r\n ContentRequestOptions,\r\n Descriptor,\r\n Field,\r\n Item,\r\n KeySet,\r\n NestedContentField,\r\n PresentationError,\r\n PresentationStatus,\r\n Ruleset,\r\n RulesetVariable,\r\n} from \"@itwin/presentation-common\";\r\nimport { parseFullClassName } from \"@itwin/presentation-shared\";\r\n\r\nfunction getECSqlName(fullClassName: string) {\r\n const { schemaName, className } = parseFullClassName(fullClassName);\r\n return `[${schemaName}].[${className}]`;\r\n}\r\n\r\n/** @internal */\r\nexport function getContentItemsObservableFromElementIds(\r\n imodel: IModelDb,\r\n contentDescriptorGetter: (\r\n partialProps: Pick<ContentDescriptorRequestOptions<IModelDb, KeySet, RulesetVariable>, \"rulesetOrId\" | \"keys\">,\r\n ) => Promise<Descriptor | undefined>,\r\n contentSetGetter: (\r\n partialProps: Pick<ContentRequestOptions<IModelDb, Descriptor, KeySet, RulesetVariable>, \"rulesetOrId\" | \"keys\" | \"descriptor\">,\r\n ) => Promise<Item[]>,\r\n elementIds: Id64String[],\r\n classParallelism: number,\r\n batchesParallelism: number,\r\n batchSize: number,\r\n): { itemBatches: Observable<{ descriptor: Descriptor; items: Item[] }>; count: Observable<number> } {\r\n return {\r\n itemBatches: getElementClassesFromIds(imodel, elementIds).pipe(\r\n mergeMap(\r\n ({ classFullName, ids }) =>\r\n getBatchedClassContentItems(\r\n imodel,\r\n classFullName,\r\n contentDescriptorGetter,\r\n contentSetGetter,\r\n () => createIdBatches(ids, batchSize),\r\n batchesParallelism,\r\n ),\r\n classParallelism,\r\n ),\r\n ),\r\n count: of(elementIds.length),\r\n };\r\n}\r\n\r\n/** @internal */\r\nexport function getContentItemsObservableFromClassNames(\r\n imodel: IModelDb,\r\n contentDescriptorGetter: (\r\n partialProps: Pick<ContentDescriptorRequestOptions<IModelDb, KeySet, RulesetVariable>, \"rulesetOrId\" | \"keys\">,\r\n ) => Promise<Descriptor | undefined>,\r\n contentSetGetter: (\r\n partialProps: Pick<ContentRequestOptions<IModelDb, Descriptor, KeySet, RulesetVariable>, \"rulesetOrId\" | \"keys\" | \"descriptor\">,\r\n ) => Promise<Item[]>,\r\n elementClasses: string[],\r\n classParallelism: number,\r\n batchesParallelism: number,\r\n batchSize: number,\r\n): { itemBatches: Observable<{ descriptor: Descriptor; items: Item[] }>; count: Observable<number> } {\r\n return {\r\n itemBatches: getClassesWithInstances(imodel, elementClasses).pipe(\r\n mergeMap(\r\n (classFullName) =>\r\n getBatchedClassContentItems(\r\n imodel,\r\n classFullName,\r\n contentDescriptorGetter,\r\n contentSetGetter,\r\n () => getBatchedClassElementIds(imodel, classFullName, batchSize),\r\n batchesParallelism,\r\n ),\r\n classParallelism,\r\n ),\r\n ),\r\n count: from(getElementsCount(imodel, elementClasses)),\r\n };\r\n}\r\n\r\nfunction getBatchedClassContentItems(\r\n imodel: IModelDb,\r\n classFullName: string,\r\n contentDescriptorGetter: (\r\n partialProps: Pick<ContentDescriptorRequestOptions<IModelDb, KeySet, RulesetVariable>, \"rulesetOrId\" | \"keys\">,\r\n ) => Promise<Descriptor | undefined>,\r\n contentSetGetter: (\r\n partialProps: Pick<ContentRequestOptions<IModelDb, Descriptor, KeySet, RulesetVariable>, \"rulesetOrId\" | \"keys\" | \"descriptor\">,\r\n ) => Promise<Item[]>,\r\n batcher: () => Observable<ElementIdBatch>,\r\n batchesParallelism: number,\r\n): Observable<{ descriptor: Descriptor; items: Item[] }> {\r\n return defer(async () => {\r\n const ruleset = createClassContentRuleset(classFullName);\r\n const keys = new KeySet();\r\n const descriptor = await contentDescriptorGetter({ rulesetOrId: ruleset, keys });\r\n if (!descriptor) {\r\n throw new PresentationError(PresentationStatus.Error, `Failed to get descriptor for class ${classFullName}`);\r\n }\r\n const aspectFields = getPrunableAspectFields(descriptor, classFullName);\r\n return { descriptor, keys, ruleset, aspectFields };\r\n }).pipe(\r\n mergeMap((x) => batcher().pipe(map((batch) => ({ ...x, batch })))),\r\n mergeMap(\r\n ({ descriptor, keys, ruleset, batch, aspectFields }) =>\r\n defer(async () => {\r\n const batchDescriptor = new Descriptor(descriptor);\r\n batchDescriptor.instanceFilter = {\r\n selectClassName: classFullName,\r\n expression: batch.ranges\r\n .map(({ from: fromId, to }) =>\r\n fromId === to ? `this.ECInstanceId = ${fromId}` : `this.ECInstanceId >= ${fromId} AND this.ECInstanceId <= ${to}`,\r\n )\r\n .join(\" OR \"),\r\n };\r\n if (aspectFields.length) {\r\n await selectBatchAspectFields(imodel, batchDescriptor, aspectFields, batch.ids);\r\n }\r\n const items = await contentSetGetter({\r\n rulesetOrId: ruleset,\r\n keys,\r\n descriptor: batchDescriptor,\r\n });\r\n return { descriptor: batchDescriptor, items };\r\n }),\r\n batchesParallelism,\r\n ),\r\n );\r\n}\r\n\r\nfunction getPrunableAspectFields(descriptor: Descriptor, classFullName: string): NestedContentField[] {\r\n // Caller selections take precedence; don't replace an include/exclude selector with our own.\r\n if (descriptor.fieldsSelector || countFields(descriptor.fields) <= 1000) {\r\n return [];\r\n }\r\n const { schemaName, className } = parseFullClassName(classFullName);\r\n return descriptor.fields.filter((field): field is NestedContentField => {\r\n if (!field.isNestedContentField() || field.pathToPrimaryClass.length !== 1) {\r\n return false;\r\n }\r\n const step = field.pathToPrimaryClass[0];\r\n return (\r\n !step.isForwardRelationship &&\r\n (step.relationshipInfo.name === \"BisCore:ElementOwnsMultiAspects\" || step.relationshipInfo.name === \"BisCore:ElementOwnsUniqueAspect\") &&\r\n step.sourceClassInfo.id === field.contentClassInfo.id &&\r\n step.targetClassInfo.name === `${schemaName}:${className}`\r\n );\r\n });\r\n}\r\n\r\nfunction countFields(fields: Field[]): number {\r\n return fields.reduce((count, field) => count + 1 + (field.isNestedContentField() ? countFields(field.nestedFields) : 0), 0);\r\n}\r\n\r\nasync function selectBatchAspectFields(imodel: IModelDb, descriptor: Descriptor, aspectFields: NestedContentField[], batch: Id64Array): Promise<void> {\r\n const query = `\r\n WITH aspectClasses(ClassId) AS (\r\n SELECT DISTINCT a.ECClassId\r\n FROM bis.ElementMultiAspect a\r\n JOIN IdSet(:elementIds) e ON e.id = a.Element.Id\r\n UNION ALL\r\n SELECT DISTINCT a.ECClassId\r\n FROM bis.ElementUniqueAspect a\r\n JOIN IdSet(:elementIds) e ON e.id = a.Element.Id\r\n )\r\n SELECT IdToHex(b.TargetECInstanceId) classId\r\n FROM meta.ClassHasAllBaseClasses b\r\n JOIN aspectClasses a ON a.ClassId = b.SourceECInstanceId\r\n `;\r\n const aspectClasses = new Set<Id64String>();\r\n for await (const row of imodel.createQueryReader(query, QueryBinder.from({ elementIds: batch }))) {\r\n aspectClasses.add(row.classId);\r\n }\r\n const excludedFields = aspectFields.filter((field) => !aspectClasses.has(field.contentClassInfo.id));\r\n if (excludedFields.length > 0) {\r\n descriptor.fieldsSelector = { type: \"exclude\", fields: excludedFields.map((field) => field.getFieldDescriptor()) };\r\n }\r\n}\r\n\r\nfunction createClassContentRuleset(fullClassName: string): Ruleset {\r\n const { schemaName, className } = parseFullClassName(fullClassName);\r\n return {\r\n id: `content/class-descriptor/${fullClassName}`,\r\n rules: [\r\n {\r\n ruleType: \"Content\",\r\n specifications: [\r\n {\r\n specType: \"ContentInstancesOfSpecificClasses\",\r\n classes: {\r\n schemaName,\r\n classNames: [className],\r\n arePolymorphic: false,\r\n },\r\n handlePropertiesPolymorphically: true,\r\n },\r\n ],\r\n },\r\n ],\r\n };\r\n}\r\n\r\ninterface ElementIdWithPrevClassInstance {\r\n id: Id64String;\r\n /** ID of the previous (by ECInstanceId) element of the same class, if any. */\r\n prevClassInstanceId?: Id64String;\r\n}\r\n\r\n/**\r\n * Given a list of element ids, group them by class name. In addition, for every element, get ID of the previous\r\n * element of the same class, which lets us put requested IDs into ranges without other instances of the same class.\r\n *\r\n * The query reader re-executes the query for every page, so querying all IDs at once is much slower than querying\r\n * them in chunks. Chunks are made of the sorted IDs list and run in parallel. `GROUP_CONCAT` order isn't guaranteed\r\n * by SQLite, so each chunk's IDs are sorted individually (usually a no-op check), then stored at the chunk's index.\r\n * Concatenating them gives each class its IDs sorted.\r\n */\r\nfunction getElementClassesFromIds(\r\n imodel: IModelDb,\r\n elementIds: Id64Array,\r\n): Observable<{ classFullName: string; ids: ElementIdWithPrevClassInstance[] }> {\r\n const elementIdsBatchSize = 5000;\r\n const sortedElementIds = OrderedId64Iterable.sortArray([...elementIds]);\r\n return range(0, sortedElementIds.length / elementIdsBatchSize).pipe(\r\n mergeMap((_, chunkIndex) => {\r\n const idsFrom = chunkIndex * elementIdsBatchSize;\r\n const idsTo = Math.min(idsFrom + elementIdsBatchSize, sortedElementIds.length);\r\n return from(\r\n imodel.createQueryReader(\r\n `\r\n SELECT\r\n ec_classname(e.ECClassId) className,\r\n GROUP_CONCAT(\r\n IdToHex(e.ECInstanceId) || ':' || IFNULL((\r\n SELECT IdToHex(MAX(p.ECInstanceId))\r\n FROM bis.Element p\r\n WHERE p.ECClassId = e.ECClassId AND p.ECInstanceId < e.ECInstanceId\r\n ), '')\r\n ) ids\r\n FROM bis.Element e\r\n JOIN IdSet(:elementIds) elementIds ON elementIds.id = e.ECInstanceId\r\n GROUP BY e.ECClassId\r\n `,\r\n new QueryBinder().bindIdSet(\"elementIds\", sortedElementIds.slice(idsFrom, idsTo)),\r\n ),\r\n ).pipe(\r\n map((row: QueryRowProxy) => ({\r\n chunkIndex,\r\n className: row.className as string,\r\n ids: ensureSortedById(\r\n (row.ids as string).split(\",\").map((pair): ElementIdWithPrevClassInstance => {\r\n const [id, prevClassInstanceId] = pair.split(\":\");\r\n return { id, ...(prevClassInstanceId ? { prevClassInstanceId } : undefined) };\r\n }),\r\n ),\r\n })),\r\n );\r\n }),\r\n groupBy(({ className }) => className),\r\n mergeMap((groups) =>\r\n groups.pipe(\r\n reduce<ObservedValueOf<typeof groups>, { classFullName: string; chunks: ElementIdWithPrevClassInstance[][] }>(\r\n (acc, g) => {\r\n acc.chunks[g.chunkIndex] = g.ids;\r\n return { classFullName: g.className, chunks: acc.chunks };\r\n },\r\n { classFullName: \"\", chunks: [] },\r\n ),\r\n ),\r\n ),\r\n // chunks cover consecutive ID ranges and are sorted individually, so their concatenation is sorted as well;\r\n // `flat` skips holes left by chunks that had no elements of the class\r\n map(({ classFullName, chunks }) => ({ classFullName, ids: chunks.flat() })),\r\n );\r\n}\r\n\r\nfunction ensureSortedById(ids: ElementIdWithPrevClassInstance[]): ElementIdWithPrevClassInstance[] {\r\n for (let i = 1; i < ids.length; ++i) {\r\n if (OrderedId64Iterable.compare(ids[i - 1].id, ids[i].id) > 0) {\r\n return ids.sort((a, b) => OrderedId64Iterable.compare(a.id, b.id));\r\n }\r\n }\r\n return ids;\r\n}\r\n\r\n/** Given a list of full class names, get concrete class names with instances. */\r\nfunction getClassesWithInstances(imodel: IModelDb, fullClassNames: string[]): Observable<string> {\r\n return from(fullClassNames).pipe(\r\n mergeMap((fullClassName) =>\r\n from(\r\n imodel.createQueryReader(\r\n `\r\n SELECT ec_classname(e.ECClassId, 's.c') className\r\n FROM ${getECSqlName(fullClassName)} e\r\n GROUP BY e.ECClassId\r\n `,\r\n ),\r\n ),\r\n ),\r\n map((row: QueryRowProxy): string => row.className),\r\n );\r\n}\r\n\r\ninterface ElementIdBatch {\r\n ids: Id64Array;\r\n ranges: Array<{ from: Id64String; to: Id64String }>;\r\n}\r\n\r\n/**\r\n * Given a list of same-class ECInstanceIds, sorted by ID, and a batch size, create a stream of batches. Because the IDs won't\r\n * necessarily be sequential, a batch is defined as a list of from-to pairs. An ID extends the current range if there are no other\r\n * instances of the same class between it and the previous requested ID.\r\n */\r\nfunction createIdBatches(sortedIds: ElementIdWithPrevClassInstance[], batchSize: number): Observable<ElementIdBatch> {\r\n return range(0, sortedIds.length / batchSize).pipe(\r\n map((batchIndex) => {\r\n const ranges = new Array<{ from: Id64String; to: Id64String }>();\r\n const startIndex = batchIndex * batchSize;\r\n const endIndex = Math.min((batchIndex + 1) * batchSize, sortedIds.length) - 1;\r\n let fromId = sortedIds[startIndex].id;\r\n for (let i = startIndex + 1; i <= endIndex; ++i) {\r\n if (sortedIds[i].prevClassInstanceId !== sortedIds[i - 1].id) {\r\n ranges.push({ from: fromId, to: sortedIds[i - 1].id });\r\n fromId = sortedIds[i].id;\r\n }\r\n }\r\n ranges.push({ from: fromId, to: sortedIds[endIndex].id });\r\n return { ids: sortedIds.slice(startIndex, endIndex + 1).map(({ id }) => id), ranges };\r\n }),\r\n );\r\n}\r\n\r\nfunction getBatchedClassElementIds(imodel: IModelDb, fullClassName: string, batchSize: number): Observable<ElementIdBatch> {\r\n return from(imodel.createQueryReader(`SELECT IdToHex(ECInstanceId) id FROM ONLY ${getECSqlName(fullClassName)} ORDER BY ECInstanceId`)).pipe(\r\n map((row): Id64String => row.id),\r\n bufferCount(batchSize),\r\n map((ids) => ({ ids, ranges: [{ from: ids[0], to: ids[ids.length - 1] }] })),\r\n );\r\n}\r\n\r\n/** @internal */\r\nexport async function getElementsCount(db: IModelDb, classNames: string[]) {\r\n const whereClause = (() => {\r\n if (classNames === undefined || classNames.length === 0) {\r\n return undefined;\r\n }\r\n // check if list contains only valid class names\r\n const classNameRegExp = new RegExp(/^[\\w]+[.:][\\w]+$/);\r\n const invalidName = classNames.find((name) => !name.match(classNameRegExp));\r\n if (invalidName) {\r\n throw new PresentationError(\r\n PresentationStatus.InvalidArgument,\r\n `Encountered invalid class name - ${invalidName}.\r\n Valid class name formats: \"<schema name or alias>.<class name>\", \"<schema name or alias>:<class name>\"`,\r\n );\r\n }\r\n return `e.ECClassId IS (${classNames.map(getECSqlName).join(\",\")})`;\r\n })();\r\n const query = `\r\n SELECT COUNT(e.ECInstanceId) AS elementCount\r\n FROM bis.Element e\r\n ${whereClause ? `WHERE ${whereClause}` : \"\"}\r\n `;\r\n for await (const row of db.createQueryReader(query)) {\r\n return row.elementCount;\r\n }\r\n return 0;\r\n}\r\n"]}
@@ -14,7 +14,7 @@ import { BackendDiagnosticsAttribute, BackendDiagnosticsOptions } from "./Utils.
14
14
  /**
15
15
  * Presentation hierarchy cache mode.
16
16
  * @public
17
- * @deprecated in 5.2 - will not be removed until after 2026-10-01. Use the new [@itwin/presentation-hierarchies](https://github.com/iTwin/presentation/blob/master/packages/hierarchies/README.md)
17
+ * @deprecated in 5.2 - might be removed in next major version. Use the new [@itwin/presentation-hierarchies](https://github.com/iTwin/presentation/blob/master/packages/hierarchies/README.md)
18
18
  * package for creating hierarchies.
19
19
  */
20
20
  export declare enum HierarchyCacheMode {
@@ -38,14 +38,14 @@ export declare enum HierarchyCacheMode {
38
38
  /**
39
39
  * Configuration for hierarchy cache.
40
40
  * @public
41
- * @deprecated in 5.2 - will not be removed until after 2026-10-01. Use the new [@itwin/presentation-hierarchies](https://github.com/iTwin/presentation/blob/master/packages/hierarchies/README.md)
41
+ * @deprecated in 5.2 - might be removed in next major version. Use the new [@itwin/presentation-hierarchies](https://github.com/iTwin/presentation/blob/master/packages/hierarchies/README.md)
42
42
  * package for creating hierarchies.
43
43
  */
44
44
  export type HierarchyCacheConfig = MemoryHierarchyCacheConfig | DiskHierarchyCacheConfig | HybridCacheConfig;
45
45
  /**
46
46
  * Base interface for all [[HierarchyCacheConfig]] implementations.
47
47
  * @public
48
- * @deprecated in 5.2 - will not be removed until after 2026-10-01. Use the new [@itwin/presentation-hierarchies](https://github.com/iTwin/presentation/blob/master/packages/hierarchies/README.md)
48
+ * @deprecated in 5.2 - might be removed in next major version. Use the new [@itwin/presentation-hierarchies](https://github.com/iTwin/presentation/blob/master/packages/hierarchies/README.md)
49
49
  * package for creating hierarchies.
50
50
  */
51
51
  export interface HierarchyCacheConfigBase {
@@ -56,7 +56,7 @@ export interface HierarchyCacheConfigBase {
56
56
  *
57
57
  * @see [Memory cache documentation page]($docs/presentation/advanced/Caching.md#memory-cache)
58
58
  * @public
59
- * @deprecated in 5.2 - will not be removed until after 2026-10-01. Use the new [@itwin/presentation-hierarchies](https://github.com/iTwin/presentation/blob/master/packages/hierarchies/README.md)
59
+ * @deprecated in 5.2 - might be removed in next major version. Use the new [@itwin/presentation-hierarchies](https://github.com/iTwin/presentation/blob/master/packages/hierarchies/README.md)
60
60
  * package for creating hierarchies.
61
61
  */
62
62
  export interface MemoryHierarchyCacheConfig extends HierarchyCacheConfigBase {
@@ -67,7 +67,7 @@ export interface MemoryHierarchyCacheConfig extends HierarchyCacheConfigBase {
67
67
  *
68
68
  * @see [Disk cache documentation page]($docs/presentation/advanced/Caching.md#disk-cache)
69
69
  * @public
70
- * @deprecated in 5.2 - will not be removed until after 2026-10-01. Use the new [@itwin/presentation-hierarchies](https://github.com/iTwin/presentation/blob/master/packages/hierarchies/README.md)
70
+ * @deprecated in 5.2 - might be removed in next major version. Use the new [@itwin/presentation-hierarchies](https://github.com/iTwin/presentation/blob/master/packages/hierarchies/README.md)
71
71
  * package for creating hierarchies.
72
72
  */
73
73
  export interface DiskHierarchyCacheConfig extends HierarchyCacheConfigBase {
@@ -92,7 +92,7 @@ export interface DiskHierarchyCacheConfig extends HierarchyCacheConfigBase {
92
92
  *
93
93
  * @see [Hybrid cache documentation page]($docs/presentation/advanced/Caching.md#hybrid-cache)
94
94
  * @public
95
- * @deprecated in 5.2 - will not be removed until after 2026-10-01. Use the new [@itwin/presentation-hierarchies](https://github.com/iTwin/presentation/blob/master/packages/hierarchies/README.md)
95
+ * @deprecated in 5.2 - might be removed in next major version. Use the new [@itwin/presentation-hierarchies](https://github.com/iTwin/presentation/blob/master/packages/hierarchies/README.md)
96
96
  * package for creating hierarchies.
97
97
  */
98
98
  export interface HybridCacheConfig extends HierarchyCacheConfigBase {
@@ -123,7 +123,7 @@ export interface PresentationManagerCachingConfig {
123
123
  * Hierarchies-related caching options.
124
124
  *
125
125
  * @see [Hierarchies cache documentation page]($docs/presentation/advanced/Caching.md#hierarchies-cache)
126
- * @deprecated in 5.2 - will not be removed until after 2026-10-01. Use the new [@itwin/presentation-hierarchies](https://github.com/iTwin/presentation/blob/master/packages/hierarchies/README.md)
126
+ * @deprecated in 5.2 - might be removed in next major version. Use the new [@itwin/presentation-hierarchies](https://github.com/iTwin/presentation/blob/master/packages/hierarchies/README.md)
127
127
  * package for creating hierarchies.
128
128
  */
129
129
  hierarchies?: HierarchyCacheConfig;
@@ -310,21 +310,21 @@ export declare class PresentationManager {
310
310
  /**
311
311
  * Retrieves nodes
312
312
  * @public
313
- * @deprecated in 5.2 - will not be removed until after 2026-10-01. Use the new [@itwin/presentation-hierarchies](https://github.com/iTwin/presentation/blob/master/packages/hierarchies/README.md)
313
+ * @deprecated in 5.2 - might be removed in next major version. Use the new [@itwin/presentation-hierarchies](https://github.com/iTwin/presentation/blob/master/packages/hierarchies/README.md)
314
314
  * package for creating hierarchies.
315
315
  */
316
316
  getNodes(requestOptions: WithCancelEvent<Prioritized<Paged<HierarchyRequestOptions<IModelDb, NodeKey, RulesetVariable>>>> & BackendDiagnosticsAttribute): Promise<Node[]>;
317
317
  /**
318
318
  * Retrieves nodes count
319
319
  * @public
320
- * @deprecated in 5.2 - will not be removed until after 2026-10-01. Use the new [@itwin/presentation-hierarchies](https://github.com/iTwin/presentation/blob/master/packages/hierarchies/README.md)
320
+ * @deprecated in 5.2 - might be removed in next major version. Use the new [@itwin/presentation-hierarchies](https://github.com/iTwin/presentation/blob/master/packages/hierarchies/README.md)
321
321
  * package for creating hierarchies.
322
322
  */
323
323
  getNodesCount(requestOptions: WithCancelEvent<Prioritized<HierarchyRequestOptions<IModelDb, NodeKey, RulesetVariable>>> & BackendDiagnosticsAttribute): Promise<number>;
324
324
  /**
325
325
  * Retrieves hierarchy level descriptor
326
326
  * @public
327
- * @deprecated in 5.2 - will not be removed until after 2026-10-01. Use the new [@itwin/presentation-hierarchies](https://github.com/iTwin/presentation/blob/master/packages/hierarchies/README.md)
327
+ * @deprecated in 5.2 - might be removed in next major version. Use the new [@itwin/presentation-hierarchies](https://github.com/iTwin/presentation/blob/master/packages/hierarchies/README.md)
328
328
  * package for creating hierarchies.
329
329
  */
330
330
  getNodesDescriptor(requestOptions: WithCancelEvent<Prioritized<HierarchyLevelDescriptorRequestOptions<IModelDb, NodeKey, RulesetVariable>>> & BackendDiagnosticsAttribute): Promise<Descriptor | undefined>;
@@ -332,7 +332,7 @@ export declare class PresentationManager {
332
332
  * Retrieves paths from root nodes to children nodes according to specified instance key paths. Intersecting paths will be merged.
333
333
  * TODO: Return results in pages
334
334
  * @public
335
- * @deprecated in 5.2 - will not be removed until after 2026-10-01. Use the new [@itwin/presentation-hierarchies](https://github.com/iTwin/presentation/blob/master/packages/hierarchies/README.md)
335
+ * @deprecated in 5.2 - might be removed in next major version. Use the new [@itwin/presentation-hierarchies](https://github.com/iTwin/presentation/blob/master/packages/hierarchies/README.md)
336
336
  * package for creating hierarchies.
337
337
  */
338
338
  getNodePaths(requestOptions: WithCancelEvent<Prioritized<FilterByInstancePathsHierarchyRequestOptions<IModelDb, RulesetVariable>>> & BackendDiagnosticsAttribute): Promise<NodePathElement[]>;
@@ -340,7 +340,7 @@ export declare class PresentationManager {
340
340
  * Retrieves paths from root nodes to nodes containing filter text in their label.
341
341
  * TODO: Return results in pages
342
342
  * @public
343
- * @deprecated in 5.2 - will not be removed until after 2026-10-01. Use the new [@itwin/presentation-hierarchies](https://github.com/iTwin/presentation/blob/master/packages/hierarchies/README.md)
343
+ * @deprecated in 5.2 - might be removed in next major version. Use the new [@itwin/presentation-hierarchies](https://github.com/iTwin/presentation/blob/master/packages/hierarchies/README.md)
344
344
  * package for creating hierarchies.
345
345
  */
346
346
  getFilteredNodePaths(requestOptions: WithCancelEvent<Prioritized<FilterByTextHierarchyRequestOptions<IModelDb, RulesetVariable>>> & BackendDiagnosticsAttribute): Promise<NodePathElement[]>;
@@ -416,7 +416,7 @@ export declare class PresentationManager {
416
416
  /**
417
417
  * Compares two hierarchies specified in the request options
418
418
  * @public
419
- * @deprecated in 5.2 - will not be removed until after 2026-10-01. Use the new [@itwin/presentation-hierarchies](https://github.com/iTwin/presentation/blob/master/packages/hierarchies/README.md)
419
+ * @deprecated in 5.2 - might be removed in next major version. Use the new [@itwin/presentation-hierarchies](https://github.com/iTwin/presentation/blob/master/packages/hierarchies/README.md)
420
420
  * package for creating hierarchies.
421
421
  */
422
422
  compareHierarchies(requestOptions: HierarchyCompareOptions<IModelDb, NodeKey>): Promise<HierarchyCompareInfo>;