Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

classIdPresentInChange should be true when ecClassId is present #6341

Merged
merged 4 commits into from
Jan 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@itwin/core-backend",
"comment": "",
"type": "none"
}
],
"packageName": "@itwin/core-backend"
}
57 changes: 52 additions & 5 deletions core/backend/src/ChangesetECAdaptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,44 @@ namespace DateTime {
export class PartialECChangeUnifier {
private _cache = new Map<string, ChangedECInstance>();
private _readonly = false;
/**
* Get root class id for a given class
* @param classId given class id
* @param db use to find root class
* @returns return root class id
*/
private static getRootClassId(classId: Id64String, db: AnyDb): Id64String | undefined {
const sql = `
WITH
[base_class]([classId], [baseClassId], [Level]) AS(
SELECT [ch].[ClassId], [ch].[BaseClassId], 0
FROM [ec_ClassHasBaseClasses] [ch] WHERE [ch].[ClassId] = ?
UNION ALL
SELECT [ch].[ClassId], [ch].[BaseClassId], [Level] + 1
FROM [ec_ClassHasBaseClasses] [ch], [base_class] [bc] WHERE [bc].[BaseClassId] = [ch].[ClassId]

)
SELECT FORMAT('0x%x', [bc].[BaseClassId]) rootClass
FROM [base_class] [bc]
WHERE [bc].[ClassId] <> [bc].[BaseClassId]
AND [bc].[BaseClassId] NOT IN (SELECT [ca].[ContainerId]
FROM [ec_CustomAttribute] [ca]
WHERE [ca].[ContainerType] = 30
AND [ca].[ClassId] IN (SELECT [cc].[Id]
FROM [ec_Class] [cc]
JOIN [ec_Schema] [ss] ON [ss].[Id] = [cc].[SchemaId]
WHERE [cc].[Name] = 'IsMixIn'
AND [ss].[Name] = 'CoreCustomAttributes'))
ORDER BY [Level] DESC`;

return db.withSqliteStatement(sql, (stmt) => {
stmt.bindId(1, classId);
if (stmt.step() === DbResult.BE_SQLITE_ROW && !stmt.isValueNull(0)) {
return stmt.getValueString(0);
}
return classId;
});
}
/**
* Combine partial instance with instance with same key if already exists.
* @param rhs partial instance
Expand All @@ -416,7 +454,7 @@ export class PartialECChangeUnifier {
if (!rhs.$meta) {
throw new Error("PartialECChange being combine must have '$meta' property");
}
const key = PartialECChangeUnifier.buildKey(rhs);
const key = PartialECChangeUnifier.buildKey(rhs, db);
const lhs = this._cache.get(key);
if (lhs) {
const { $meta: _, ...restOfRhs } = rhs;
Expand Down Expand Up @@ -450,8 +488,17 @@ export class PartialECChangeUnifier {
* @param change EC change
* @returns key created from EC change.
*/
private static buildKey(change: ChangedECInstance): string {
return `${change.ECClassId}-${change.ECInstanceId}-${change.$meta?.stage}`.toLowerCase();
private static buildKey(change: ChangedECInstance, db?: AnyDb): string {
let classId = change.ECClassId;
if (typeof classId === "undefined") {
if (db && change.$meta?.fallbackClassId) {
classId = this.getRootClassId(change.$meta.fallbackClassId, db);
}
if (typeof classId === "undefined") {
throw new Error(`unable to resolve ECClassId to root class id.`);
}
}
return `${change.ECInstanceId}-${classId}-${change.$meta?.stage}`.toLowerCase();
}
/**
* Append partial changes which will be combine using there instance key.
Expand Down Expand Up @@ -711,7 +758,7 @@ export class ChangesetECAdaptor implements IDisposable {
}

let ecClassId: Id64String | undefined = this.reader.op === "Inserted" ? change.inserted?.ECClassId : change.deleted?.ECClassId;
const classIdPresentInChange = !ecClassId;
const classIdPresentInChange = typeof ecClassId !== "undefined";
let classMap: IClassMap | undefined;
let fallbackClassId: Id64String | undefined;
if (table.isClassIdVirtual) {
Expand All @@ -737,7 +784,7 @@ export class ChangesetECAdaptor implements IDisposable {
if (!classMap)
throw new Error(`unable to load class map`);

if (!classIdPresentInChange && !ecClassId)
if (!classIdPresentInChange && !ecClassId && !fallbackClassId)
ecClassId = classMap.id;

if (this._allowedClasses.size !== 0) {
Expand Down
Loading