diff options
Diffstat (limited to 'apps/web/src/services/storage/migrations/runner.ts')
| -rw-r--r-- | apps/web/src/services/storage/migrations/runner.ts | 150 |
1 files changed, 53 insertions, 97 deletions
diff --git a/apps/web/src/services/storage/migrations/runner.ts b/apps/web/src/services/storage/migrations/runner.ts index cbc3739f..83e7edae 100644 --- a/apps/web/src/services/storage/migrations/runner.ts +++ b/apps/web/src/services/storage/migrations/runner.ts @@ -1,138 +1,94 @@ -import { IndexedDBAdapter } from "@/services/storage/indexeddb-adapter"; +import { + IndexedDBAdapter, + deleteDatabase, +} from "@/services/storage/indexeddb-adapter"; import type { StorageMigration } from "./base"; -import { StorageVersionManager } from "./version-manager"; +import type { ProjectRecord } from "./transformers/types"; +import { getProjectId } from "./transformers/utils"; export interface StorageMigrationResult { - fromVersion: number; - toVersion: number; - migrated: boolean; + migratedCount: number; } -export type StorageMigrationCallbacks = { - onMigrationStart?: ({ - fromVersion, - toVersion, - }: { - fromVersion: number; - toVersion: number; - }) => void; - onMigrationComplete?: ({ - fromVersion, - toVersion, - }: { - fromVersion: number; - toVersion: number; - }) => void; -}; - -type ProjectRecord = Record<string, unknown>; +let hasCleanedUpMetaDb = false; export async function runStorageMigrations({ migrations, - versionManager = new StorageVersionManager(), - callbacks, }: { migrations: StorageMigration[]; - versionManager?: StorageVersionManager; - callbacks?: StorageMigrationCallbacks; }): Promise<StorageMigrationResult> { - const versionRecord = await versionManager.getVersionRecord(); - const inferredVersion = versionRecord - ? null - : await inferStorageVersionFromProjects(); - const fromVersion = - versionRecord?.inProgress?.from ?? - versionRecord?.version ?? - inferredVersion ?? - 0; - - if (!versionRecord) { - await versionManager.setVersion({ version: fromVersion }); - } - - const orderedMigrations = [...migrations].sort((a, b) => a.from - b.from); - let currentVersion = fromVersion; - - for (const migration of orderedMigrations) { - if (migration.from !== currentVersion) { - continue; + // One-time cleanup: delete the old global version database + if (!hasCleanedUpMetaDb) { + try { + await deleteDatabase({ dbName: "video-editor-meta" }); + } catch { + // Ignore errors - DB might not exist } - - await versionManager.setInProgress({ - from: migration.from, - to: migration.to, - }); - callbacks?.onMigrationStart?.({ - fromVersion: migration.from, - toVersion: migration.to, - }); - await migration.run(); - currentVersion = migration.to; - await versionManager.setVersion({ version: currentVersion }); - await versionManager.clearInProgress(); - callbacks?.onMigrationComplete?.({ - fromVersion: migration.from, - toVersion: migration.to, - }); + hasCleanedUpMetaDb = true; } - return { - fromVersion, - toVersion: currentVersion, - migrated: currentVersion !== fromVersion, - }; -} - -async function inferStorageVersionFromProjects(): Promise<number> { - const projectsAdapter = new IndexedDBAdapter<unknown>( + const projectsAdapter = new IndexedDBAdapter<ProjectRecord>( "video-editor-projects", "projects", 1, ); const projects = await projectsAdapter.getAll(); - if (projects.length === 0) { - return 0; - } - - let lowestVersion = Number.POSITIVE_INFINITY; + const orderedMigrations = [...migrations].sort((a, b) => a.from - b.from); + let migratedCount = 0; for (const project of projects) { - const projectVersion = checkProjectVersion({ project }); - if (projectVersion < lowestVersion) { - lowestVersion = projectVersion; + if (typeof project !== "object" || project === null) { + continue; } - } - if (lowestVersion === Number.POSITIVE_INFINITY) { - return 0; - } + let projectRecord = project as ProjectRecord; + let currentVersion = getProjectVersion({ project: projectRecord }); - return lowestVersion; -} + // Apply migrations sequentially until project is up to date + for (const migration of orderedMigrations) { + if (migration.from !== currentVersion) { + continue; + } + + const result = await migration.transform(projectRecord); + + if (result.skipped) { + break; // Project is already at this version or higher + } + + // Update project with migrated version + const projectId = getProjectId({ project: result.project }); + if (!projectId) { + break; // Can't save without ID + } -function checkProjectVersion({ project }: { project: unknown }): number { - if (!isRecord(project)) { - return 0; + await projectsAdapter.set(projectId, result.project); + migratedCount++; + currentVersion = migration.to; + + // Use migrated project for next iteration + projectRecord = result.project; + } } + return { migratedCount }; +} + +function getProjectVersion({ project }: { project: ProjectRecord }): number { const versionValue = project.version; - // v2 and up + // v2 and up - has explicit version field if (typeof versionValue === "number") { return versionValue; } - // v1 (got scenes) + // v1 - has scenes array const scenesValue = project.scenes; if (Array.isArray(scenesValue) && scenesValue.length > 0) { return 1; } - // v0 (didn't have scenes) + // v0 - no scenes return 0; } - -function isRecord(value: unknown): value is ProjectRecord { - return typeof value === "object" && value !== null; -} |
