backend: enhance migration registries and improve type handling in migration service
This commit is contained in:
parent
696df4a7a2
commit
803e4b6704
@ -30,62 +30,75 @@ import { roomMigrations } from './room-migrations.js';
|
||||
import { userMigrations } from './user-migrations.js';
|
||||
|
||||
/**
|
||||
* Central registry of all collection migrations.
|
||||
* Defines the current version and migration map for each collection.
|
||||
*
|
||||
* Order matters: collections should be listed in dependency order.
|
||||
* For example, if recordings depend on rooms, rooms should come first.
|
||||
* Registry configuration for MeetGlobalConfig collection migrations.
|
||||
*/
|
||||
const migrationRegistry: [
|
||||
CollectionMigrationRegistry<MeetGlobalConfigDocument>,
|
||||
CollectionMigrationRegistry<MeetUserDocument>,
|
||||
CollectionMigrationRegistry<MeetApiKeyDocument>,
|
||||
CollectionMigrationRegistry<MeetRoomDocument>,
|
||||
CollectionMigrationRegistry<MeetRoomMemberDocument>,
|
||||
CollectionMigrationRegistry<MeetRecordingDocument>
|
||||
] = [
|
||||
// GlobalConfig - no dependencies, can run first
|
||||
{
|
||||
collectionName: meetGlobalConfigCollectionName,
|
||||
model: MeetGlobalConfigModel,
|
||||
currentVersion: INTERNAL_CONFIG.GLOBAL_CONFIG_SCHEMA_VERSION,
|
||||
migrations: globalConfigMigrations
|
||||
},
|
||||
// User - no dependencies
|
||||
{
|
||||
collectionName: meetUserCollectionName,
|
||||
model: MeetUserModel,
|
||||
currentVersion: INTERNAL_CONFIG.USER_SCHEMA_VERSION,
|
||||
migrations: userMigrations
|
||||
},
|
||||
// ApiKey - no dependencies
|
||||
{
|
||||
collectionName: meetApiKeyCollectionName,
|
||||
model: MeetApiKeyModel,
|
||||
currentVersion: INTERNAL_CONFIG.API_KEY_SCHEMA_VERSION,
|
||||
migrations: apiKeyMigrations
|
||||
},
|
||||
// Room - no dependencies on other collections
|
||||
{
|
||||
collectionName: meetRoomCollectionName,
|
||||
model: MeetRoomModel,
|
||||
currentVersion: INTERNAL_CONFIG.ROOM_SCHEMA_VERSION,
|
||||
migrations: roomMigrations
|
||||
},
|
||||
// RoomMember - depends on Room (references roomId)
|
||||
{
|
||||
collectionName: meetRoomMemberCollectionName,
|
||||
model: MeetRoomMemberModel,
|
||||
currentVersion: INTERNAL_CONFIG.ROOM_MEMBER_SCHEMA_VERSION,
|
||||
migrations: roomMemberMigrations
|
||||
},
|
||||
// Recording - depends on Room (references roomId)
|
||||
{
|
||||
collectionName: meetRecordingCollectionName,
|
||||
model: MeetRecordingModel,
|
||||
currentVersion: INTERNAL_CONFIG.RECORDING_SCHEMA_VERSION,
|
||||
migrations: recordingMigrations
|
||||
}
|
||||
const globalConfigMigrationRegistry: CollectionMigrationRegistry<MeetGlobalConfigDocument> = {
|
||||
collectionName: meetGlobalConfigCollectionName,
|
||||
model: MeetGlobalConfigModel,
|
||||
currentVersion: INTERNAL_CONFIG.GLOBAL_CONFIG_SCHEMA_VERSION,
|
||||
migrations: globalConfigMigrations
|
||||
};
|
||||
|
||||
/**
|
||||
* Registry configuration for MeetApiKey collection migrations.
|
||||
*/
|
||||
const apiKeyMigrationRegistry: CollectionMigrationRegistry<MeetApiKeyDocument> = {
|
||||
collectionName: meetApiKeyCollectionName,
|
||||
model: MeetApiKeyModel,
|
||||
currentVersion: INTERNAL_CONFIG.API_KEY_SCHEMA_VERSION,
|
||||
migrations: apiKeyMigrations
|
||||
};
|
||||
|
||||
/**
|
||||
* Registry configuration for MeetUser collection migrations.
|
||||
*/
|
||||
const userMigrationRegistry: CollectionMigrationRegistry<MeetUserDocument> = {
|
||||
collectionName: meetUserCollectionName,
|
||||
model: MeetUserModel,
|
||||
currentVersion: INTERNAL_CONFIG.USER_SCHEMA_VERSION,
|
||||
migrations: userMigrations
|
||||
};
|
||||
|
||||
/**
|
||||
* Registry configuration for MeetRoom collection migrations.
|
||||
*/
|
||||
const roomMigrationRegistry: CollectionMigrationRegistry<MeetRoomDocument> = {
|
||||
collectionName: meetRoomCollectionName,
|
||||
model: MeetRoomModel,
|
||||
currentVersion: INTERNAL_CONFIG.ROOM_SCHEMA_VERSION,
|
||||
migrations: roomMigrations
|
||||
};
|
||||
|
||||
/**
|
||||
* Registry configuration for MeetRoomMember collection migrations.
|
||||
*/
|
||||
const roomMemberMigrationRegistry: CollectionMigrationRegistry<MeetRoomMemberDocument> = {
|
||||
collectionName: meetRoomMemberCollectionName,
|
||||
model: MeetRoomMemberModel,
|
||||
currentVersion: INTERNAL_CONFIG.ROOM_MEMBER_SCHEMA_VERSION,
|
||||
migrations: roomMemberMigrations
|
||||
};
|
||||
|
||||
/**
|
||||
* Registry configuration for MeetRecording collection migrations.
|
||||
*/
|
||||
const recordingMigrationRegistry: CollectionMigrationRegistry<MeetRecordingDocument> = {
|
||||
collectionName: meetRecordingCollectionName,
|
||||
model: MeetRecordingModel,
|
||||
currentVersion: INTERNAL_CONFIG.RECORDING_SCHEMA_VERSION,
|
||||
migrations: recordingMigrations
|
||||
};
|
||||
|
||||
/**
|
||||
* Central registry of all collection migrations.
|
||||
*/
|
||||
const migrationRegistry = [
|
||||
globalConfigMigrationRegistry,
|
||||
apiKeyMigrationRegistry,
|
||||
userMigrationRegistry,
|
||||
roomMigrationRegistry,
|
||||
roomMemberMigrationRegistry,
|
||||
recordingMigrationRegistry
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@ -7,7 +7,7 @@ const userMigrationV1ToV2Name = generateSchemaMigrationName(meetUserCollectionNa
|
||||
const userMigrationV1ToV2Transform: SchemaTransform<MeetUserDocument> = (user: MeetUserDocument) => {
|
||||
const legacyUser = user as unknown as {
|
||||
username?: string;
|
||||
roles: unknown;
|
||||
roles?: unknown;
|
||||
};
|
||||
|
||||
// NOTE: This migration assumes that there is only one user in the system,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { Model } from 'mongoose';
|
||||
import { FilterQuery, Model, Require_id, Types } from 'mongoose';
|
||||
import ms from 'ms';
|
||||
import { MeetLock } from '../helpers/redis.helper.js';
|
||||
import { runtimeMigrationRegistry } from '../migrations/migration-registry.js';
|
||||
@ -270,7 +270,7 @@ export class MigrationService {
|
||||
let migratedCount = 0;
|
||||
let failedCount = 0;
|
||||
|
||||
const sourceVersionFilter = { schemaVersion: sourceSchemaVersion };
|
||||
const sourceVersionFilter: FilterQuery<TDocument> = { schemaVersion: sourceSchemaVersion };
|
||||
const totalSourceVersionDocuments = await model.countDocuments(sourceVersionFilter).exec();
|
||||
|
||||
if (totalSourceVersionDocuments === 0) {
|
||||
@ -282,18 +282,23 @@ export class MigrationService {
|
||||
}
|
||||
|
||||
let processedDocumentsCount = 0;
|
||||
let lastProcessedDocumentId: TDocument['_id'] | null = null;
|
||||
let lastProcessedDocumentId: Types.ObjectId | null = null;
|
||||
let hasMoreBatches = true;
|
||||
|
||||
while (hasMoreBatches) {
|
||||
const batchFilter =
|
||||
const batchFilter: FilterQuery<TDocument> =
|
||||
lastProcessedDocumentId === null
|
||||
? sourceVersionFilter
|
||||
: {
|
||||
...sourceVersionFilter,
|
||||
_id: { $gt: lastProcessedDocumentId }
|
||||
};
|
||||
const documents = await model.find(batchFilter).sort({ _id: 1 }).limit(batchSize).exec();
|
||||
const documents = (await model
|
||||
.find(batchFilter)
|
||||
.sort({ _id: 1 })
|
||||
.limit(batchSize)
|
||||
.lean()
|
||||
.exec()) as Require_id<TDocument>[];
|
||||
|
||||
if (documents.length === 0) {
|
||||
break;
|
||||
@ -302,8 +307,8 @@ export class MigrationService {
|
||||
const batchResults = await Promise.allSettled(
|
||||
documents.map(async (doc) => {
|
||||
const migratedDocument = this.applyTransformChain(doc, migrationChain, targetVersion);
|
||||
await migratedDocument.save();
|
||||
return String(doc._id);
|
||||
await model.replaceOne({ _id: doc._id }, migratedDocument).exec();
|
||||
return doc._id;
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user