@itwin/imodel-transformer 2.0.0-dev.41 → 2.0.0-dev.42
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.
|
@@ -14,13 +14,9 @@ export interface ElementAspectExportProcessorHandler {
|
|
|
14
14
|
* @internal
|
|
15
15
|
*/
|
|
16
16
|
export declare class ElementAspectExportProcessor {
|
|
17
|
-
private readonly _aspectClasses;
|
|
18
17
|
/** ElementAspect classes excluded from source queries. */
|
|
19
18
|
private readonly _excludedElementAspectClassFullNames;
|
|
20
|
-
|
|
21
|
-
* declared subclasses.
|
|
22
|
-
*/
|
|
23
|
-
private _excludedClassIds;
|
|
19
|
+
private _hasExportableAspects;
|
|
24
20
|
private _aspectChanges;
|
|
25
21
|
/** ElementAspect class names excluded from source queries. */
|
|
26
22
|
get excludedElementAspectClassFullNames(): ReadonlySet<string>;
|
|
@@ -37,19 +33,11 @@ export declare class ElementAspectExportProcessor {
|
|
|
37
33
|
resetCaches(): void;
|
|
38
34
|
/** Excludes an ElementAspect class from subsequent queries and export callbacks. */
|
|
39
35
|
excludeElementAspectClass(classFullName: string): void;
|
|
40
|
-
private
|
|
36
|
+
private getExcludedClassFilter;
|
|
37
|
+
private getHasExportableAspects;
|
|
38
|
+
private queryHasExportableAspects;
|
|
39
|
+
private getAspectProps;
|
|
41
40
|
private queryAspects;
|
|
42
|
-
private getAspectClasses;
|
|
43
|
-
private queryAspectClasses;
|
|
44
|
-
private getExcludedClassIds;
|
|
45
|
-
/** Resolves every excluded class full name to the full set of ECClassIds it covers:
|
|
46
|
-
* the class itself plus every declared subclass. Reuses the same
|
|
47
|
-
* ECDbMeta.ClassHasAllBaseClasses shape as {@link queryAspectClasses}, rooted at
|
|
48
|
-
* each excluded class instead of at ElementUniqueAspect/ElementMultiAspect.
|
|
49
|
-
*/
|
|
50
|
-
private queryExcludedClassIds;
|
|
51
|
-
/** Scans which concrete subclasses of the given base aspect class have rows for the supplied owners. */
|
|
52
|
-
private queryPopulatedAspectClassIds;
|
|
53
41
|
}
|
|
54
42
|
export {};
|
|
55
43
|
//# sourceMappingURL=ElementAspectExportProcessor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ElementAspectExportProcessor.d.ts","sourceRoot":"","sources":["../../src/ElementAspectExportProcessor.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,mBAAmB,EACnB,QAAQ,EACT,MAAM,qBAAqB,CAAC;AAC7B,OAAO,
|
|
1
|
+
{"version":3,"file":"ElementAspectExportProcessor.d.ts","sourceRoot":"","sources":["../../src/ElementAspectExportProcessor.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,mBAAmB,EACnB,QAAQ,EACT,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAa,MAAM,qBAAqB,CAAC;AAS5D,UAAU,aAAa;IACrB,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,UAAU,CAAC,CAAC;IAC5C,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,UAAU,CAAC,CAAC;CAC7C;AAED,MAAM,WAAW,mCAAmC;IAClD,yBAAyB,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACnE,2BAA2B,CACzB,YAAY,EAAE,mBAAmB,EACjC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,GAC7B,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,2BAA2B,CACzB,YAAY,EAAE,kBAAkB,EAAE,GACjC,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACpC;AAED;;GAEG;AACH,qBAAa,4BAA4B;IACvC,0DAA0D;IAC1D,OAAO,CAAC,QAAQ,CAAC,oCAAoC,CAAqB;IAC1E,OAAO,CAAC,qBAAqB,CAA+B;IAC5D,OAAO,CAAC,cAAc,CAA4B;IAElD,8DAA8D;IAC9D,IAAW,mCAAmC,IAAI,WAAW,CAAC,MAAM,CAAC,CAEpE;IACD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAW;IACrC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsC;gBAG7D,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,mCAAmC;IAM9C;;OAEG;IACU,uBAAuB,CAClC,eAAe,EAAE,WAAW,CAAC,UAAU,CAAC,GACvC,OAAO,CAAC,IAAI,CAAC;IA6ChB,4GAA4G;IACrG,gBAAgB,CAAC,aAAa,CAAC,EAAE,aAAa,GAAG,IAAI;IAI5D,iFAAiF;IAC1E,WAAW,IAAI,IAAI;IAI1B,oFAAoF;IAC7E,yBAAyB,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI;IAM7D,OAAO,CAAC,sBAAsB;YAkBhB,uBAAuB;YAKvB,yBAAyB;IAuBvC,OAAO,CAAC,cAAc;YA4BP,YAAY;CAqC5B"}
|
|
@@ -6,19 +6,16 @@
|
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
exports.ElementAspectExportProcessor = void 0;
|
|
8
8
|
const core_backend_1 = require("@itwin/core-backend");
|
|
9
|
+
const core_bentley_1 = require("@itwin/core-bentley");
|
|
9
10
|
const ECSqlReaderAsyncIterableIteratorAdapter_1 = require("./ECSqlReaderAsyncIterableIteratorAdapter");
|
|
10
11
|
const core_common_1 = require("@itwin/core-common");
|
|
11
12
|
/** Queries and exports ElementAspects for accepted source owners, applying class and handler filters and grouping multi-aspects by owner.
|
|
12
13
|
* @internal
|
|
13
14
|
*/
|
|
14
15
|
class ElementAspectExportProcessor {
|
|
15
|
-
_aspectClasses = new Map();
|
|
16
16
|
/** ElementAspect classes excluded from source queries. */
|
|
17
17
|
_excludedElementAspectClassFullNames = new Set();
|
|
18
|
-
|
|
19
|
-
* declared subclasses.
|
|
20
|
-
*/
|
|
21
|
-
_excludedClassIds;
|
|
18
|
+
_hasExportableAspects;
|
|
22
19
|
_aspectChanges;
|
|
23
20
|
/** ElementAspect class names excluded from source queries. */
|
|
24
21
|
get excludedElementAspectClassFullNames() {
|
|
@@ -34,31 +31,43 @@ class ElementAspectExportProcessor {
|
|
|
34
31
|
* Multi-aspects are emitted in one callback group per owner.
|
|
35
32
|
*/
|
|
36
33
|
async exportAllElementAspects(ownerElementIds) {
|
|
37
|
-
if (ownerElementIds.size === 0)
|
|
34
|
+
if (ownerElementIds.size === 0 || !(await this.getHasExportableAspects()))
|
|
38
35
|
return;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
await this._handler.onExportElementUniqueAspect(uniqueAspect, isUpdate);
|
|
36
|
+
let multiAspectOwnerId;
|
|
37
|
+
let multiAspects = [];
|
|
38
|
+
const exportMultiAspects = async () => {
|
|
39
|
+
if (multiAspects.length === 0)
|
|
40
|
+
return;
|
|
41
|
+
await this._handler.onExportElementMultiAspects(multiAspects);
|
|
46
42
|
await this._handler.trackProgress();
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
if (
|
|
52
|
-
|
|
43
|
+
multiAspects = [];
|
|
44
|
+
multiAspectOwnerId = undefined;
|
|
45
|
+
};
|
|
46
|
+
for await (const aspect of this.queryAspects(ownerElementIds)) {
|
|
47
|
+
if (!(await this._handler.shouldExportElementAspect(aspect)))
|
|
48
|
+
continue;
|
|
49
|
+
if (multiAspectOwnerId !== undefined &&
|
|
50
|
+
multiAspectOwnerId !== aspect.element.id) {
|
|
51
|
+
await exportMultiAspects();
|
|
52
|
+
}
|
|
53
|
+
if (aspect instanceof core_backend_1.ElementUniqueAspect) {
|
|
54
|
+
const isUpdate = this._aspectChanges?.updateIds.has(aspect.id)
|
|
55
|
+
? true
|
|
56
|
+
: this._aspectChanges?.insertIds.has(aspect.id)
|
|
57
|
+
? false
|
|
58
|
+
: undefined;
|
|
59
|
+
await this._handler.onExportElementUniqueAspect(aspect, isUpdate);
|
|
60
|
+
await this._handler.trackProgress();
|
|
61
|
+
}
|
|
62
|
+
else if (aspect instanceof core_backend_1.ElementMultiAspect) {
|
|
63
|
+
multiAspectOwnerId = aspect.element.id;
|
|
64
|
+
multiAspects.push(aspect);
|
|
53
65
|
}
|
|
54
66
|
else {
|
|
55
|
-
|
|
67
|
+
throw new Error(`Unexpected ElementAspect type ${aspect.classFullName}`);
|
|
56
68
|
}
|
|
57
|
-
}, ownerElementIds);
|
|
58
|
-
for (const multiAspects of multiAspectsByOwner.values()) {
|
|
59
|
-
await this._handler.onExportElementMultiAspects(multiAspects);
|
|
60
|
-
await this._handler.trackProgress();
|
|
61
69
|
}
|
|
70
|
+
await exportMultiAspects();
|
|
62
71
|
}
|
|
63
72
|
/** Sets the aspect changes used to distinguish inserted and updated unique aspects during change export. */
|
|
64
73
|
setAspectChanges(aspectChanges) {
|
|
@@ -66,120 +75,92 @@ class ElementAspectExportProcessor {
|
|
|
66
75
|
}
|
|
67
76
|
/** Clears source schema and content caches at an outer export-scope boundary. */
|
|
68
77
|
resetCaches() {
|
|
69
|
-
this.
|
|
70
|
-
this._excludedClassIds = undefined;
|
|
78
|
+
this._hasExportableAspects = undefined;
|
|
71
79
|
}
|
|
72
80
|
/** Excludes an ElementAspect class from subsequent queries and export callbacks. */
|
|
73
81
|
excludeElementAspectClass(classFullName) {
|
|
74
|
-
this._excludedElementAspectClassFullNames.
|
|
75
|
-
this._excludedClassIds = undefined;
|
|
76
|
-
}
|
|
77
|
-
async exportAspectsLoop(baseAspectClass, exportAspect, ownerElementIds) {
|
|
78
|
-
for await (const aspect of this.queryAspects(baseAspectClass, ownerElementIds)) {
|
|
79
|
-
if (!(await this._handler.shouldExportElementAspect(aspect))) {
|
|
80
|
-
continue;
|
|
81
|
-
}
|
|
82
|
-
await exportAspect(aspect);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
async *queryAspects(baseElementAspectClassFullName, ownerElementIds) {
|
|
86
|
-
const queryOwnerElementIds = new Set(ownerElementIds);
|
|
87
|
-
const populatedClassIds = await this.queryPopulatedAspectClassIds(baseElementAspectClassFullName, queryOwnerElementIds);
|
|
88
|
-
if (populatedClassIds.size === 0)
|
|
82
|
+
if (this._excludedElementAspectClassFullNames.has(classFullName))
|
|
89
83
|
return;
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
for (const [classId, { schemaName, className }] of aspectClassNameIdMap) {
|
|
93
|
-
// Skip classes with no rows in the current owner scope: most schemas declare
|
|
94
|
-
// far more concrete aspect subclasses than a batch actually populates.
|
|
95
|
-
if (!populatedClassIds.has(classId))
|
|
96
|
-
continue;
|
|
97
|
-
// excludedClassIds is the excluded class plus every declared subclass.
|
|
98
|
-
if (excludedClassIds.has(classId))
|
|
99
|
-
continue;
|
|
100
|
-
const classFullName = `${schemaName}:${className}`;
|
|
101
|
-
const queryParams = new core_common_1.QueryBinder()
|
|
102
|
-
.bindId("classId", classId)
|
|
103
|
-
.bindIdSet("ownerElementIds", queryOwnerElementIds);
|
|
104
|
-
const aspectQueryReader = this._sourceDb.createQueryReader(`SELECT aspect.* FROM [${schemaName}]:[${className}] aspect
|
|
105
|
-
INNER JOIN IdSet(:ownerElementIds) ids ON ids.id = aspect.Element.Id
|
|
106
|
-
WHERE aspect.ECClassId = :classId
|
|
107
|
-
ORDER BY aspect.Element.Id, aspect.ECInstanceId OPTIONS ENABLE_EXPERIMENTAL_FEATURES`, queryParams,
|
|
108
|
-
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
109
|
-
{ rowFormat: core_common_1.QueryRowFormat.UseJsPropertyNames, usePrimaryConn: true });
|
|
110
|
-
for await (const rowProxy of (0, ECSqlReaderAsyncIterableIteratorAdapter_1.ensureECSqlReaderIsAsyncIterableIterator)(aspectQueryReader)) {
|
|
111
|
-
const { className: _className, ...aspectProps } = rowProxy.toRow();
|
|
112
|
-
aspectProps.classFullName = classFullName;
|
|
113
|
-
yield this._sourceDb.constructEntity(aspectProps);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
84
|
+
this._excludedElementAspectClassFullNames.add(classFullName);
|
|
85
|
+
this.resetCaches();
|
|
116
86
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
87
|
+
getExcludedClassFilter(queryParams) {
|
|
88
|
+
const excludedClassParameters = [];
|
|
89
|
+
let excludedClassIndex = 0;
|
|
90
|
+
for (const classFullName of this._excludedElementAspectClassFullNames) {
|
|
91
|
+
const parameterName = `excludedAspectClass${excludedClassIndex++}`;
|
|
92
|
+
excludedClassParameters.push(`ec_classid(:${parameterName})`);
|
|
93
|
+
queryParams.bindString(parameterName, classFullName.replace(".", ":"));
|
|
122
94
|
}
|
|
123
|
-
return
|
|
95
|
+
return excludedClassParameters.length === 0
|
|
96
|
+
? ""
|
|
97
|
+
: `AND NOT EXISTS (
|
|
98
|
+
SELECT 1 FROM meta.ClassHasAllBaseClasses excluded
|
|
99
|
+
WHERE excluded.SourceECInstanceId = aspect.ECClassId
|
|
100
|
+
AND excluded.TargetECInstanceId IN (${excludedClassParameters.join(",")})
|
|
101
|
+
)`;
|
|
124
102
|
}
|
|
125
|
-
async
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
SELECT c.ECInstanceId as classId,
|
|
129
|
-
(ec_className(c.ECInstanceId, 's')) as schemaName,
|
|
130
|
-
(ec_className(c.ECInstanceId, 'c')) as className
|
|
131
|
-
FROM ECDbMeta.ClassHasAllBaseClasses r
|
|
132
|
-
JOIN ECDbMeta.ECClassDef c ON c.ECInstanceId = r.SourceECInstanceId
|
|
133
|
-
WHERE r.TargetECInstanceId = ec_classId(:baseClassName)
|
|
134
|
-
ORDER BY schemaName, className
|
|
135
|
-
`, new core_common_1.QueryBinder().bindString("baseClassName", baseElementAspectClassFullName), { usePrimaryConn: true });
|
|
136
|
-
for await (const rowProxy of (0, ECSqlReaderAsyncIterableIteratorAdapter_1.ensureECSqlReaderIsAsyncIterableIterator)(aspectClassesQueryReader)) {
|
|
137
|
-
const row = rowProxy.toRow();
|
|
138
|
-
aspectClassNameIdMap.set(row.classId, {
|
|
139
|
-
schemaName: row.schemaName,
|
|
140
|
-
className: row.className,
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
return aspectClassNameIdMap;
|
|
103
|
+
async getHasExportableAspects() {
|
|
104
|
+
this._hasExportableAspects ??= this.queryHasExportableAspects();
|
|
105
|
+
return this._hasExportableAspects;
|
|
144
106
|
}
|
|
145
|
-
async
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
107
|
+
async queryHasExportableAspects() {
|
|
108
|
+
const queryParams = new core_common_1.QueryBinder();
|
|
109
|
+
const excludedClassFilter = this.getExcludedClassFilter(queryParams);
|
|
110
|
+
const reader = this._sourceDb.createQueryReader(`SELECT ECInstanceId FROM (
|
|
111
|
+
SELECT aspect.ECInstanceId
|
|
112
|
+
FROM Bis.ElementMultiAspect aspect
|
|
113
|
+
WHERE TRUE ${excludedClassFilter}
|
|
114
|
+
UNION ALL
|
|
115
|
+
SELECT aspect.ECInstanceId
|
|
116
|
+
FROM Bis.ElementUniqueAspect aspect
|
|
117
|
+
WHERE TRUE ${excludedClassFilter}
|
|
118
|
+
)
|
|
119
|
+
LIMIT 1`, queryParams, { usePrimaryConn: true });
|
|
120
|
+
for await (const _row of (0, ECSqlReaderAsyncIterableIteratorAdapter_1.ensureECSqlReaderIsAsyncIterableIterator)(reader))
|
|
121
|
+
return true;
|
|
122
|
+
return false;
|
|
150
123
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
const
|
|
158
|
-
for (const
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
FROM ECDbMeta.ClassHasAllBaseClasses r
|
|
162
|
-
JOIN ECDbMeta.ECClassDef c ON c.ECInstanceId = r.SourceECInstanceId
|
|
163
|
-
WHERE r.TargetECInstanceId = ec_classId(:excludedClassName)
|
|
164
|
-
`, new core_common_1.QueryBinder().bindString("excludedClassName", classFullName), { usePrimaryConn: true });
|
|
165
|
-
for await (const rowProxy of (0, ECSqlReaderAsyncIterableIteratorAdapter_1.ensureECSqlReaderIsAsyncIterableIterator)(excludedClassesQueryReader)) {
|
|
166
|
-
excludedClassIds.add(rowProxy.toRow().classId);
|
|
167
|
-
}
|
|
124
|
+
getAspectProps(rawInstance) {
|
|
125
|
+
const parsedRow = typeof rawInstance === "string"
|
|
126
|
+
? JSON.parse(rawInstance, core_common_1.Base64EncodedString.reviver)
|
|
127
|
+
: rawInstance;
|
|
128
|
+
if (!core_bentley_1.JsonUtils.isObject(parsedRow))
|
|
129
|
+
throw new Error("Expected an ElementAspect instance query to return an object");
|
|
130
|
+
const row = {};
|
|
131
|
+
for (const [key, value] of Object.entries(parsedRow)) {
|
|
132
|
+
const ecPropertyName = key.length === 0 ? key : key[0].toUpperCase() + key.substring(1);
|
|
133
|
+
row[core_common_1.ECJsNames.toJsName(ecPropertyName)] = value;
|
|
168
134
|
}
|
|
169
|
-
|
|
135
|
+
const className = row.className;
|
|
136
|
+
if (typeof className !== "string")
|
|
137
|
+
throw new Error("Expected an ElementAspect instance query to return a className");
|
|
138
|
+
row.classFullName = className.replace(".", ":");
|
|
139
|
+
delete row.className;
|
|
140
|
+
return row;
|
|
170
141
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
const
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
142
|
+
async *queryAspects(ownerElementIds) {
|
|
143
|
+
const queryParams = new core_common_1.QueryBinder().bindIdSet("ownerElementIds", ownerElementIds);
|
|
144
|
+
const excludedClassFilter = this.getExcludedClassFilter(queryParams);
|
|
145
|
+
const aspectQueryReader = this._sourceDb.createQueryReader(`WITH OwnerIds AS (SELECT id FROM IdSet(:ownerElementIds))
|
|
146
|
+
SELECT $ FROM (
|
|
147
|
+
SELECT aspect.ECInstanceId, aspect.ECClassId,
|
|
148
|
+
aspect.Element.Id AS OwnerId, 1 AS AspectKind
|
|
149
|
+
FROM OwnerIds owners
|
|
150
|
+
CROSS JOIN Bis.ElementMultiAspect aspect
|
|
151
|
+
WHERE aspect.Element.Id = owners.id ${excludedClassFilter}
|
|
152
|
+
UNION ALL
|
|
153
|
+
SELECT aspect.ECInstanceId, aspect.ECClassId,
|
|
154
|
+
aspect.Element.Id AS OwnerId, 0 AS AspectKind
|
|
155
|
+
FROM OwnerIds owners
|
|
156
|
+
CROSS JOIN Bis.ElementUniqueAspect aspect
|
|
157
|
+
WHERE aspect.Element.Id = owners.id ${excludedClassFilter}
|
|
158
|
+
)
|
|
159
|
+
ORDER BY AspectKind, OwnerId, ECClassId, ECInstanceId
|
|
160
|
+
OPTIONS USE_JS_PROP_NAMES DO_NOT_TRUNCATE_BLOB`, queryParams, { usePrimaryConn: true });
|
|
161
|
+
for await (const rowProxy of (0, ECSqlReaderAsyncIterableIteratorAdapter_1.ensureECSqlReaderIsAsyncIterableIterator)(aspectQueryReader)) {
|
|
162
|
+
yield this._sourceDb.constructEntity(this.getAspectProps(rowProxy[0]));
|
|
181
163
|
}
|
|
182
|
-
return populatedClassIds;
|
|
183
164
|
}
|
|
184
165
|
}
|
|
185
166
|
exports.ElementAspectExportProcessor = ElementAspectExportProcessor;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ElementAspectExportProcessor.js","sourceRoot":"","sources":["../../src/ElementAspectExportProcessor.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n * See LICENSE.md in the project root for license terms and full copyright notice.\n *--------------------------------------------------------------------------------------------*/\n\nimport {\n ElementAspect,\n ElementMultiAspect,\n ElementUniqueAspect,\n IModelDb,\n} from \"@itwin/core-backend\";\nimport { Id64Set, Id64String } from \"@itwin/core-bentley\";\nimport { ensureECSqlReaderIsAsyncIterableIterator } from \"./ECSqlReaderAsyncIterableIteratorAdapter\";\nimport {\n ElementAspectProps,\n QueryBinder,\n QueryRowFormat,\n} from \"@itwin/core-common\";\n\ninterface AspectChanges {\n readonly insertIds: ReadonlySet<Id64String>;\n readonly updateIds: ReadonlySet<Id64String>;\n}\n\nexport interface ElementAspectExportProcessorHandler {\n shouldExportElementAspect(aspect: ElementAspect): Promise<boolean>;\n onExportElementUniqueAspect(\n uniqueAspect: ElementUniqueAspect,\n isUpdate?: boolean | undefined\n ): Promise<void>;\n onExportElementMultiAspects(\n multiAspects: ElementMultiAspect[]\n ): Promise<void>;\n trackProgress: () => Promise<void>;\n}\n\n/** Queries and exports ElementAspects for accepted source owners, applying class and handler filters and grouping multi-aspects by owner.\n * @internal\n */\nexport class ElementAspectExportProcessor {\n private readonly _aspectClasses = new Map<\n string,\n Promise<ReadonlyMap<Id64String, { schemaName: string; className: string }>>\n >();\n /** ElementAspect classes excluded from source queries. */\n private readonly _excludedElementAspectClassFullNames = new Set<string>();\n /** ECClassIds excluded from source queries: every excluded class plus all of its\n * declared subclasses.\n */\n private _excludedClassIds: Promise<ReadonlySet<Id64String>> | undefined;\n private _aspectChanges: AspectChanges | undefined;\n\n /** ElementAspect class names excluded from source queries. */\n public get excludedElementAspectClassFullNames(): ReadonlySet<string> {\n return this._excludedElementAspectClassFullNames;\n }\n private readonly _sourceDb: IModelDb;\n private readonly _handler: ElementAspectExportProcessorHandler;\n\n public constructor(\n sourceDb: IModelDb,\n handler: ElementAspectExportProcessorHandler\n ) {\n this._sourceDb = sourceDb;\n this._handler = handler;\n }\n\n /** Exports ElementAspects owned by the supplied elements.\n * Multi-aspects are emitted in one callback group per owner.\n */\n public async exportAllElementAspects(\n ownerElementIds: ReadonlySet<Id64String>\n ): Promise<void> {\n if (ownerElementIds.size === 0) return;\n\n await this.exportAspectsLoop<ElementUniqueAspect>(\n ElementUniqueAspect.classFullName,\n async (uniqueAspect) => {\n const isUpdate = this._aspectChanges?.updateIds.has(uniqueAspect.id)\n ? true\n : this._aspectChanges?.insertIds.has(uniqueAspect.id)\n ? false\n : undefined;\n await this._handler.onExportElementUniqueAspect(uniqueAspect, isUpdate);\n await this._handler.trackProgress();\n },\n ownerElementIds\n );\n\n const multiAspectsByOwner = new Map<Id64String, ElementMultiAspect[]>();\n await this.exportAspectsLoop<ElementMultiAspect>(\n ElementMultiAspect.classFullName,\n async (multiAspect) => {\n const ownerAspects = multiAspectsByOwner.get(multiAspect.element.id);\n if (ownerAspects === undefined) {\n multiAspectsByOwner.set(multiAspect.element.id, [multiAspect]);\n } else {\n ownerAspects.push(multiAspect);\n }\n },\n ownerElementIds\n );\n\n for (const multiAspects of multiAspectsByOwner.values()) {\n await this._handler.onExportElementMultiAspects(multiAspects);\n await this._handler.trackProgress();\n }\n }\n\n /** Sets the aspect changes used to distinguish inserted and updated unique aspects during change export. */\n public setAspectChanges(aspectChanges?: AspectChanges): void {\n this._aspectChanges = aspectChanges;\n }\n\n /** Clears source schema and content caches at an outer export-scope boundary. */\n public resetCaches(): void {\n this._aspectClasses.clear();\n this._excludedClassIds = undefined;\n }\n\n /** Excludes an ElementAspect class from subsequent queries and export callbacks. */\n public excludeElementAspectClass(classFullName: string): void {\n this._excludedElementAspectClassFullNames.add(classFullName);\n this._excludedClassIds = undefined;\n }\n\n private async exportAspectsLoop<T extends ElementAspect>(\n baseAspectClass: string,\n exportAspect: (aspect: T) => Promise<void>,\n ownerElementIds: ReadonlySet<Id64String>\n ): Promise<void> {\n for await (const aspect of this.queryAspects<T>(\n baseAspectClass,\n ownerElementIds\n )) {\n if (!(await this._handler.shouldExportElementAspect(aspect))) {\n continue;\n }\n await exportAspect(aspect);\n }\n }\n\n private async *queryAspects<T extends ElementAspect>(\n baseElementAspectClassFullName: string,\n ownerElementIds: ReadonlySet<Id64String>\n ) {\n const queryOwnerElementIds = new Set(ownerElementIds) as Id64Set;\n const populatedClassIds = await this.queryPopulatedAspectClassIds(\n baseElementAspectClassFullName,\n queryOwnerElementIds\n );\n if (populatedClassIds.size === 0) return;\n\n const aspectClassNameIdMap = await this.getAspectClasses(\n baseElementAspectClassFullName\n );\n const excludedClassIds = await this.getExcludedClassIds();\n for (const [classId, { schemaName, className }] of aspectClassNameIdMap) {\n // Skip classes with no rows in the current owner scope: most schemas declare\n // far more concrete aspect subclasses than a batch actually populates.\n if (!populatedClassIds.has(classId)) continue;\n // excludedClassIds is the excluded class plus every declared subclass.\n if (excludedClassIds.has(classId)) continue;\n\n const classFullName = `${schemaName}:${className}`;\n const queryParams = new QueryBinder()\n .bindId(\"classId\", classId)\n .bindIdSet(\"ownerElementIds\", queryOwnerElementIds);\n const aspectQueryReader = this._sourceDb.createQueryReader(\n `SELECT aspect.* FROM [${schemaName}]:[${className}] aspect\n INNER JOIN IdSet(:ownerElementIds) ids ON ids.id = aspect.Element.Id\n WHERE aspect.ECClassId = :classId\n ORDER BY aspect.Element.Id, aspect.ECInstanceId OPTIONS ENABLE_EXPERIMENTAL_FEATURES`,\n queryParams,\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n { rowFormat: QueryRowFormat.UseJsPropertyNames, usePrimaryConn: true }\n );\n for await (const rowProxy of ensureECSqlReaderIsAsyncIterableIterator(\n aspectQueryReader\n )) {\n const { className: _className, ...aspectProps } =\n rowProxy.toRow() as ElementAspectProps & {\n className?: string;\n };\n aspectProps.classFullName = classFullName;\n yield this._sourceDb.constructEntity<T>(aspectProps);\n }\n }\n }\n\n private async getAspectClasses(\n baseElementAspectClassFullName: string\n ): Promise<\n ReadonlyMap<Id64String, { schemaName: string; className: string }>\n > {\n let aspectClasses = this._aspectClasses.get(baseElementAspectClassFullName);\n if (aspectClasses === undefined) {\n aspectClasses = this.queryAspectClasses(baseElementAspectClassFullName);\n this._aspectClasses.set(baseElementAspectClassFullName, aspectClasses);\n }\n return aspectClasses;\n }\n\n private async queryAspectClasses(\n baseElementAspectClassFullName: string\n ): Promise<\n ReadonlyMap<Id64String, { schemaName: string; className: string }>\n > {\n const aspectClassNameIdMap = new Map<\n Id64String,\n { schemaName: string; className: string }\n >();\n const aspectClassesQueryReader = this._sourceDb.createQueryReader(\n `\n SELECT c.ECInstanceId as classId,\n (ec_className(c.ECInstanceId, 's')) as schemaName,\n (ec_className(c.ECInstanceId, 'c')) as className\n FROM ECDbMeta.ClassHasAllBaseClasses r\n JOIN ECDbMeta.ECClassDef c ON c.ECInstanceId = r.SourceECInstanceId\n WHERE r.TargetECInstanceId = ec_classId(:baseClassName)\n ORDER BY schemaName, className\n `,\n new QueryBinder().bindString(\n \"baseClassName\",\n baseElementAspectClassFullName\n ),\n { usePrimaryConn: true }\n );\n for await (const rowProxy of ensureECSqlReaderIsAsyncIterableIterator(\n aspectClassesQueryReader\n )) {\n const row = rowProxy.toRow();\n aspectClassNameIdMap.set(row.classId, {\n schemaName: row.schemaName,\n className: row.className,\n });\n }\n return aspectClassNameIdMap;\n }\n\n private async getExcludedClassIds(): Promise<ReadonlySet<Id64String>> {\n if (this._excludedClassIds === undefined) {\n this._excludedClassIds = this.queryExcludedClassIds();\n }\n return this._excludedClassIds;\n }\n\n /** Resolves every excluded class full name to the full set of ECClassIds it covers:\n * the class itself plus every declared subclass. Reuses the same\n * ECDbMeta.ClassHasAllBaseClasses shape as {@link queryAspectClasses}, rooted at\n * each excluded class instead of at ElementUniqueAspect/ElementMultiAspect.\n */\n private async queryExcludedClassIds(): Promise<ReadonlySet<Id64String>> {\n const excludedClassIds = new Set<Id64String>();\n for (const classFullName of this._excludedElementAspectClassFullNames) {\n const excludedClassesQueryReader = this._sourceDb.createQueryReader(\n `\n SELECT c.ECInstanceId as classId\n FROM ECDbMeta.ClassHasAllBaseClasses r\n JOIN ECDbMeta.ECClassDef c ON c.ECInstanceId = r.SourceECInstanceId\n WHERE r.TargetECInstanceId = ec_classId(:excludedClassName)\n `,\n new QueryBinder().bindString(\"excludedClassName\", classFullName),\n { usePrimaryConn: true }\n );\n for await (const rowProxy of ensureECSqlReaderIsAsyncIterableIterator(\n excludedClassesQueryReader\n )) {\n excludedClassIds.add(rowProxy.toRow().classId);\n }\n }\n return excludedClassIds;\n }\n\n /** Scans which concrete subclasses of the given base aspect class have rows for the supplied owners. */\n private async queryPopulatedAspectClassIds(\n baseElementAspectClassFullName: string,\n ownerElementIds: Id64Set\n ): Promise<ReadonlySet<Id64String>> {\n const [schemaName, className] = baseElementAspectClassFullName.split(\":\");\n const populatedClassIds = new Set<Id64String>();\n const populatedClassesQueryReader = this._sourceDb.createQueryReader(\n `SELECT DISTINCT aspect.ECClassId as classId\n FROM [${schemaName}]:[${className}] aspect\n INNER JOIN IdSet(:ownerElementIds) ids ON ids.id = aspect.Element.Id\n OPTIONS ENABLE_EXPERIMENTAL_FEATURES`,\n new QueryBinder().bindIdSet(\"ownerElementIds\", ownerElementIds),\n { usePrimaryConn: true }\n );\n for await (const rowProxy of ensureECSqlReaderIsAsyncIterableIterator(\n populatedClassesQueryReader\n )) {\n populatedClassIds.add(rowProxy.toRow().classId);\n }\n return populatedClassIds;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ElementAspectExportProcessor.js","sourceRoot":"","sources":["../../src/ElementAspectExportProcessor.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n * See LICENSE.md in the project root for license terms and full copyright notice.\n *--------------------------------------------------------------------------------------------*/\n\nimport {\n ElementAspect,\n ElementMultiAspect,\n ElementUniqueAspect,\n IModelDb,\n} from \"@itwin/core-backend\";\nimport { Id64String, JsonUtils } from \"@itwin/core-bentley\";\nimport { ensureECSqlReaderIsAsyncIterableIterator } from \"./ECSqlReaderAsyncIterableIteratorAdapter\";\nimport {\n Base64EncodedString,\n ECJsNames,\n ElementAspectProps,\n QueryBinder,\n} from \"@itwin/core-common\";\n\ninterface AspectChanges {\n readonly insertIds: ReadonlySet<Id64String>;\n readonly updateIds: ReadonlySet<Id64String>;\n}\n\nexport interface ElementAspectExportProcessorHandler {\n shouldExportElementAspect(aspect: ElementAspect): Promise<boolean>;\n onExportElementUniqueAspect(\n uniqueAspect: ElementUniqueAspect,\n isUpdate?: boolean | undefined\n ): Promise<void>;\n onExportElementMultiAspects(\n multiAspects: ElementMultiAspect[]\n ): Promise<void>;\n trackProgress: () => Promise<void>;\n}\n\n/** Queries and exports ElementAspects for accepted source owners, applying class and handler filters and grouping multi-aspects by owner.\n * @internal\n */\nexport class ElementAspectExportProcessor {\n /** ElementAspect classes excluded from source queries. */\n private readonly _excludedElementAspectClassFullNames = new Set<string>();\n private _hasExportableAspects: Promise<boolean> | undefined;\n private _aspectChanges: AspectChanges | undefined;\n\n /** ElementAspect class names excluded from source queries. */\n public get excludedElementAspectClassFullNames(): ReadonlySet<string> {\n return this._excludedElementAspectClassFullNames;\n }\n private readonly _sourceDb: IModelDb;\n private readonly _handler: ElementAspectExportProcessorHandler;\n\n public constructor(\n sourceDb: IModelDb,\n handler: ElementAspectExportProcessorHandler\n ) {\n this._sourceDb = sourceDb;\n this._handler = handler;\n }\n\n /** Exports ElementAspects owned by the supplied elements.\n * Multi-aspects are emitted in one callback group per owner.\n */\n public async exportAllElementAspects(\n ownerElementIds: ReadonlySet<Id64String>\n ): Promise<void> {\n if (ownerElementIds.size === 0 || !(await this.getHasExportableAspects()))\n return;\n\n let multiAspectOwnerId: Id64String | undefined;\n let multiAspects: ElementMultiAspect[] = [];\n const exportMultiAspects = async () => {\n if (multiAspects.length === 0) return;\n await this._handler.onExportElementMultiAspects(multiAspects);\n await this._handler.trackProgress();\n multiAspects = [];\n multiAspectOwnerId = undefined;\n };\n\n for await (const aspect of this.queryAspects(ownerElementIds)) {\n if (!(await this._handler.shouldExportElementAspect(aspect))) continue;\n\n if (\n multiAspectOwnerId !== undefined &&\n multiAspectOwnerId !== aspect.element.id\n ) {\n await exportMultiAspects();\n }\n\n if (aspect instanceof ElementUniqueAspect) {\n const isUpdate = this._aspectChanges?.updateIds.has(aspect.id)\n ? true\n : this._aspectChanges?.insertIds.has(aspect.id)\n ? false\n : undefined;\n await this._handler.onExportElementUniqueAspect(aspect, isUpdate);\n await this._handler.trackProgress();\n } else if (aspect instanceof ElementMultiAspect) {\n multiAspectOwnerId = aspect.element.id;\n multiAspects.push(aspect);\n } else {\n throw new Error(\n `Unexpected ElementAspect type ${aspect.classFullName}`\n );\n }\n }\n\n await exportMultiAspects();\n }\n\n /** Sets the aspect changes used to distinguish inserted and updated unique aspects during change export. */\n public setAspectChanges(aspectChanges?: AspectChanges): void {\n this._aspectChanges = aspectChanges;\n }\n\n /** Clears source schema and content caches at an outer export-scope boundary. */\n public resetCaches(): void {\n this._hasExportableAspects = undefined;\n }\n\n /** Excludes an ElementAspect class from subsequent queries and export callbacks. */\n public excludeElementAspectClass(classFullName: string): void {\n if (this._excludedElementAspectClassFullNames.has(classFullName)) return;\n this._excludedElementAspectClassFullNames.add(classFullName);\n this.resetCaches();\n }\n\n private getExcludedClassFilter(queryParams: QueryBinder): string {\n const excludedClassParameters: string[] = [];\n let excludedClassIndex = 0;\n for (const classFullName of this._excludedElementAspectClassFullNames) {\n const parameterName = `excludedAspectClass${excludedClassIndex++}`;\n excludedClassParameters.push(`ec_classid(:${parameterName})`);\n queryParams.bindString(parameterName, classFullName.replace(\".\", \":\"));\n }\n\n return excludedClassParameters.length === 0\n ? \"\"\n : `AND NOT EXISTS (\n SELECT 1 FROM meta.ClassHasAllBaseClasses excluded\n WHERE excluded.SourceECInstanceId = aspect.ECClassId\n AND excluded.TargetECInstanceId IN (${excludedClassParameters.join(\",\")})\n )`;\n }\n\n private async getHasExportableAspects(): Promise<boolean> {\n this._hasExportableAspects ??= this.queryHasExportableAspects();\n return this._hasExportableAspects;\n }\n\n private async queryHasExportableAspects(): Promise<boolean> {\n const queryParams = new QueryBinder();\n const excludedClassFilter = this.getExcludedClassFilter(queryParams);\n const reader = this._sourceDb.createQueryReader(\n `SELECT ECInstanceId FROM (\n SELECT aspect.ECInstanceId\n FROM Bis.ElementMultiAspect aspect\n WHERE TRUE ${excludedClassFilter}\n UNION ALL\n SELECT aspect.ECInstanceId\n FROM Bis.ElementUniqueAspect aspect\n WHERE TRUE ${excludedClassFilter}\n )\n LIMIT 1`,\n queryParams,\n { usePrimaryConn: true }\n );\n\n for await (const _row of ensureECSqlReaderIsAsyncIterableIterator(reader))\n return true;\n return false;\n }\n\n private getAspectProps(rawInstance: unknown): ElementAspectProps {\n const parsedRow: unknown =\n typeof rawInstance === \"string\"\n ? JSON.parse(rawInstance, Base64EncodedString.reviver)\n : rawInstance;\n if (!JsonUtils.isObject(parsedRow))\n throw new Error(\n \"Expected an ElementAspect instance query to return an object\"\n );\n\n const row: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(parsedRow)) {\n const ecPropertyName =\n key.length === 0 ? key : key[0].toUpperCase() + key.substring(1);\n row[ECJsNames.toJsName(ecPropertyName)] = value;\n }\n\n const className = row.className;\n if (typeof className !== \"string\")\n throw new Error(\n \"Expected an ElementAspect instance query to return a className\"\n );\n\n row.classFullName = className.replace(\".\", \":\");\n delete row.className;\n return row as unknown as ElementAspectProps;\n }\n\n private async *queryAspects(\n ownerElementIds: ReadonlySet<Id64String>\n ): AsyncIterableIterator<ElementAspect> {\n const queryParams = new QueryBinder().bindIdSet(\n \"ownerElementIds\",\n ownerElementIds\n );\n const excludedClassFilter = this.getExcludedClassFilter(queryParams);\n const aspectQueryReader = this._sourceDb.createQueryReader(\n `WITH OwnerIds AS (SELECT id FROM IdSet(:ownerElementIds))\n SELECT $ FROM (\n SELECT aspect.ECInstanceId, aspect.ECClassId,\n aspect.Element.Id AS OwnerId, 1 AS AspectKind\n FROM OwnerIds owners\n CROSS JOIN Bis.ElementMultiAspect aspect\n WHERE aspect.Element.Id = owners.id ${excludedClassFilter}\n UNION ALL\n SELECT aspect.ECInstanceId, aspect.ECClassId,\n aspect.Element.Id AS OwnerId, 0 AS AspectKind\n FROM OwnerIds owners\n CROSS JOIN Bis.ElementUniqueAspect aspect\n WHERE aspect.Element.Id = owners.id ${excludedClassFilter}\n )\n ORDER BY AspectKind, OwnerId, ECClassId, ECInstanceId\n OPTIONS USE_JS_PROP_NAMES DO_NOT_TRUNCATE_BLOB`,\n queryParams,\n { usePrimaryConn: true }\n );\n\n for await (const rowProxy of ensureECSqlReaderIsAsyncIterableIterator(\n aspectQueryReader\n )) {\n yield this._sourceDb.constructEntity<ElementAspect>(\n this.getAspectProps(rowProxy[0])\n );\n }\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@itwin/imodel-transformer",
|
|
3
|
-
"version": "2.0.0-dev.
|
|
3
|
+
"version": "2.0.0-dev.42",
|
|
4
4
|
"description": "API for exporting an iModel's parts and also importing them into another iModel",
|
|
5
5
|
"main": "lib/cjs/imodel-transformer.js",
|
|
6
6
|
"typings": "lib/cjs/imodel-transformer",
|