aggregate relations when seeing event target during back-pagination

This commit is contained in:
Bruno Windels 2021-06-16 17:40:29 +02:00
parent 9099a76f45
commit ce5409dc26
3 changed files with 46 additions and 6 deletions

View File

@ -119,13 +119,14 @@ export class GapWriter {
eventStorageEntry.displayName = member.displayName;
eventStorageEntry.avatarUrl = member.avatarUrl;
}
txn.timelineEvents.insert(eventStorageEntry);
const eventEntry = new EventEntry(eventStorageEntry, this._fragmentIdComparer);
directionalAppend(entries, eventEntry, direction);
const updatedRelationTargetEntries = await this._relationWriter.writeRelation(eventEntry, txn, log);
// this will modify eventStorageEntry if it is a relation target
const updatedRelationTargetEntries = await this._relationWriter.writeGapRelation(eventStorageEntry, direction, txn, log);
if (updatedRelationTargetEntries) {
updatedEntries.push(...updatedRelationTargetEntries);
}
txn.timelineEvents.insert(eventStorageEntry);
const eventEntry = new EventEntry(eventStorageEntry, this._fragmentIdComparer);
directionalAppend(entries, eventEntry, direction);
}
return {entries, updatedEntries};
}

View File

@ -44,10 +44,36 @@ export class RelationWriter {
}
}
}
// TODO: check if sourceEntry is in timelineRelations as a target, and if so reaggregate it
return null;
}
/**
* @param {Object} storageEntry the event object, as it will be stored in storage.
* Will be modified (but not written to storage) in case this event is
* a relation target for which we've previously received relations.
* @param {Direction} direction of the gap fill
* */
async writeGapRelation(storageEntry, direction, txn, log) {
const sourceEntry = new EventEntry(storageEntry, this._fragmentIdComparer);
const result = await this.writeRelation(sourceEntry, txn, log);
// when back-paginating, it can also happen that we've received relations
// for this event before, which now upon receiving the target need to be aggregated.
if (direction.isBackward) {
const relations = await txn.timelineRelations.getAllForTarget(this._roomId, sourceEntry.id);
if (relations.length) {
for (const r of relations) {
const relationStorageEntry = await txn.timelineEvents.getByEventId(this._roomId, r.sourceEventId);
if (relationStorageEntry) {
const relationEntry = new EventEntry(relationStorageEntry, this._fragmentIdComparer);
await this._applyRelation(relationEntry, storageEntry, txn, log);
}
}
}
}
return result;
}
/**
* @param {EventEntry} sourceEntry
* @param {Object} targetStorageEntry event entry as stored in the timelineEvents store

View File

@ -59,4 +59,17 @@ export class TimelineRelationStore {
const keys = await this._store.selectAll(range);
return keys.map(decodeKey);
}
async getAllForTarget(roomId, targetId) {
// exclude both keys as they are theoretical min and max,
// but we should't have a match for just the room id, or room id with max
const range = this._store.IDBKeyRange.bound(
encodeKey(roomId, targetId, MIN_UNICODE, MIN_UNICODE),
encodeKey(roomId, targetId, MAX_UNICODE, MAX_UNICODE),
true,
true
);
const keys = await this._store.selectAll(range);
return keys.map(decodeKey);
}
}