@itwin/presentation-backend 5.14.0-dev.9 → 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 +44 -1
- package/lib/cjs/presentation-backend/ElementPropertiesHelper.d.ts +0 -17
- package/lib/cjs/presentation-backend/ElementPropertiesHelper.d.ts.map +1 -1
- package/lib/cjs/presentation-backend/ElementPropertiesHelper.js +117 -67
- package/lib/cjs/presentation-backend/ElementPropertiesHelper.js.map +1 -1
- package/lib/cjs/presentation-backend/PresentationManager.d.ts +13 -13
- package/lib/cjs/presentation-backend/PresentationManager.js +7 -7
- package/lib/cjs/presentation-backend/PresentationManager.js.map +1 -1
- package/lib/esm/presentation-backend/ElementPropertiesHelper.d.ts +0 -17
- package/lib/esm/presentation-backend/ElementPropertiesHelper.d.ts.map +1 -1
- package/lib/esm/presentation-backend/ElementPropertiesHelper.js +120 -68
- package/lib/esm/presentation-backend/ElementPropertiesHelper.js.map +1 -1
- package/lib/esm/presentation-backend/PresentationManager.d.ts +13 -13
- package/lib/esm/presentation-backend/PresentationManager.js +7 -7
- package/lib/esm/presentation-backend/PresentationManager.js.map +1 -1
- package/package.json +15 -15
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,49 @@
|
|
|
1
1
|
# Change Log - @itwin/presentation-backend
|
|
2
2
|
|
|
3
|
-
This log was last generated on
|
|
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,
|
|
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(
|
|
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
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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:
|
|
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
|
-
|
|
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:
|
|
60
|
+
descriptor: batchDescriptor,
|
|
60
61
|
});
|
|
61
|
-
|
|
62
|
+
return { descriptor: batchDescriptor, items };
|
|
63
|
+
}), batchesParallelism));
|
|
62
64
|
}
|
|
63
|
-
function
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
-
/**
|
|
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
|
-
|
|
107
|
-
|
|
108
|
-
const
|
|
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
|
|
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
|
-
|
|
157
|
+
JOIN IdSet(:elementIds) elementIds ON elementIds.id = e.ECInstanceId
|
|
113
158
|
GROUP BY e.ECClassId
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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
|
|
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
|
|
133
|
-
* be sequential, a batch is defined a list of from-to pairs.
|
|
134
|
-
*
|
|
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
|
|
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
|
-
|
|
148
|
-
|
|
149
|
-
|
|
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
|
-
|
|
155
|
-
return
|
|
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)((
|
|
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":"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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 { 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 -
|
|
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 -
|
|
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 -
|
|
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 -
|
|
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 -
|
|
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 -
|
|
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 -
|
|
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 -
|
|
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 -
|
|
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 -
|
|
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 -
|
|
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 -
|
|
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 -
|
|
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>;
|