backend: implement atomic update paths for recording and room repositories
This commit is contained in:
parent
2572fd3960
commit
54bb06adfd
@ -35,6 +35,16 @@ export abstract class BaseRepository<TDomain, TDocument extends TDomain = TDomai
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns document paths that must be updated atomically.
|
||||
*
|
||||
* Paths listed here are treated as leaf values during partial updates,
|
||||
* so nested properties are not flattened into dot notation.
|
||||
*/
|
||||
protected getAtomicUpdatePaths(): readonly string[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new document.
|
||||
*
|
||||
@ -338,6 +348,7 @@ export abstract class BaseRepository<TDomain, TDocument extends TDomain = TDomai
|
||||
protected buildUpdateQuery(partial: Partial<TDocument>): UpdateQuery<TDocument> {
|
||||
const $set: Record<string, unknown> = {};
|
||||
const $unset: Record<string, ''> = {};
|
||||
const atomicUpdatePaths = new Set(this.getAtomicUpdatePaths());
|
||||
|
||||
const buildUpdateQueryDeep = (input: Record<string, unknown>, prefix = ''): void => {
|
||||
for (const key in input) {
|
||||
@ -347,8 +358,8 @@ export abstract class BaseRepository<TDomain, TDocument extends TDomain = TDomai
|
||||
if (value === undefined) {
|
||||
// Mark field for unsetting if value is undefined
|
||||
$unset[path] = '';
|
||||
} else if (this.isPlainObject(value)) {
|
||||
// Recursively build update query for nested objects
|
||||
} else if (this.isPlainObject(value) && !atomicUpdatePaths.has(path)) {
|
||||
// Recursively build update query for nested objects that are not atomic paths
|
||||
buildUpdateQueryDeep(value, path);
|
||||
} else {
|
||||
// Set field value for $set operator
|
||||
|
||||
@ -38,6 +38,12 @@ export class RecordingRepository extends BaseRepository<MeetRecordingInfo, MeetR
|
||||
return MEET_RECORDING_DOCUMENT_ONLY_FIELDS;
|
||||
}
|
||||
|
||||
protected override getAtomicUpdatePaths(): readonly string[] {
|
||||
// Recording encoding must be treated as an atomic update path because
|
||||
// it can be either a string or an object, and we want to ensure it is fully replaced rather than partially updated.
|
||||
return ['encoding'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new recording with generated access secrets.
|
||||
*
|
||||
|
||||
@ -40,6 +40,12 @@ export class RoomRepository extends BaseRepository<MeetRoom, MeetRoomDocument> {
|
||||
return MEET_ROOM_DOCUMENT_ONLY_FIELDS;
|
||||
}
|
||||
|
||||
protected override getAtomicUpdatePaths(): readonly string[] {
|
||||
// Recording encoding must be treated as an atomic update path because
|
||||
// it can be either a string or an object, and we want to ensure it is fully replaced rather than partially updated.
|
||||
return ['config.recording.encoding'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new room.
|
||||
* URLs are stored in the database without the base URL.
|
||||
|
||||
@ -98,7 +98,7 @@ describe('Expired Rooms GC Tests', () => {
|
||||
expect(response.body).toHaveProperty('meetingEndAction', 'delete');
|
||||
|
||||
// End the meeting
|
||||
const { moderatorSecret } = MeetRoomHelper.extractSecretsFromRoom(room);
|
||||
const { moderatorSecret } = MeetRoomHelper.extractSecretsFromRoom(room.anonymous);
|
||||
const moderatorToken = await generateRoomMemberToken(room.roomId, { secret: moderatorSecret });
|
||||
await endMeeting(room.roomId, moderatorToken);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user