forked from admin/french-vocab
fix: harden backup import typing
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import Dexie, { type Table } from 'dexie';
|
||||
import type { TtsSettings } from '../types/settings';
|
||||
import type { Word, StudyProgress, StudyStats } from '../types/vocabulary';
|
||||
|
||||
export interface WordEntry extends Word {
|
||||
@@ -9,11 +10,32 @@ export interface ProgressEntry extends StudyProgress {
|
||||
syncedAt?: Date;
|
||||
}
|
||||
|
||||
interface SettingsEntry {
|
||||
key: string;
|
||||
value: TtsSettings;
|
||||
}
|
||||
|
||||
type ImportedWordEntry = Omit<Word, 'addedAt'> & {
|
||||
addedAt?: Date | string;
|
||||
};
|
||||
|
||||
interface ImportedProgressEntry extends Omit<StudyProgress, 'nextReviewDate' | 'lastStudiedDate'> {
|
||||
nextReviewDate: Date | string;
|
||||
lastStudiedDate: Date | string;
|
||||
syncedAt?: Date | string;
|
||||
}
|
||||
|
||||
interface BackupPayload {
|
||||
words?: ImportedWordEntry[];
|
||||
progress?: ImportedProgressEntry[];
|
||||
stats?: StudyStats;
|
||||
}
|
||||
|
||||
export class FrenchVocabDB extends Dexie {
|
||||
words!: Table<WordEntry>;
|
||||
progress!: Table<ProgressEntry>;
|
||||
stats!: Table<StudyStats & { id: string }>;
|
||||
settings!: Table<{ key: string; value: any }>;
|
||||
settings!: Table<SettingsEntry>;
|
||||
|
||||
constructor() {
|
||||
super('FrenchVocabDB');
|
||||
@@ -564,16 +586,36 @@ export async function exportData() {
|
||||
}
|
||||
|
||||
// 导入数据
|
||||
export async function importData(data: any) {
|
||||
if (data.words) {
|
||||
const normalizeWordEntry = (word: ImportedWordEntry): WordEntry => ({
|
||||
...word,
|
||||
addedAt: word.addedAt ? new Date(word.addedAt) : new Date(),
|
||||
});
|
||||
|
||||
const normalizeProgressEntry = (progress: ImportedProgressEntry): ProgressEntry => ({
|
||||
...progress,
|
||||
nextReviewDate: new Date(progress.nextReviewDate),
|
||||
lastStudiedDate: new Date(progress.lastStudiedDate),
|
||||
syncedAt: progress.syncedAt ? new Date(progress.syncedAt) : undefined,
|
||||
});
|
||||
|
||||
export async function importData(data: unknown) {
|
||||
if (!data || typeof data !== 'object') {
|
||||
throw new Error('Invalid backup data.');
|
||||
}
|
||||
|
||||
const backup = data as BackupPayload;
|
||||
|
||||
if (Array.isArray(backup.words)) {
|
||||
await db.words.clear();
|
||||
await db.words.bulkAdd(data.words);
|
||||
await db.words.bulkAdd(backup.words.map(normalizeWordEntry));
|
||||
}
|
||||
if (data.progress) {
|
||||
|
||||
if (Array.isArray(backup.progress)) {
|
||||
await db.progress.clear();
|
||||
await db.progress.bulkAdd(data.progress);
|
||||
await db.progress.bulkAdd(backup.progress.map(normalizeProgressEntry));
|
||||
}
|
||||
if (data.stats) {
|
||||
await db.stats.put({ ...data.stats, id: 'main' });
|
||||
|
||||
if (backup.stats) {
|
||||
await db.stats.put({ ...backup.stats, id: 'main' });
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user