Idb-keyval — это легковесная обёртка над IndexedDB, предназначенная для удобного асинхронного хранения ключ-значение в браузере. Одной из задач при использовании Idb-keyval является миграция данных между версиями приложения, особенно когда требуется изменение структуры или формата значений. Стратегия миграции с трансформацией значений позволяет безопасно преобразовать старые данные в новый формат без потери информации.
Миграция данных в контексте Idb-keyval обычно включает три шага:
Идентификация ключей, требующих трансформации
Необходимо определить, какие ключи хранят устаревшие или несовместимые
значения. Например, ключ userSettings в версии 1 приложения
может содержать объект вида:
{
"theme": "dark",
"notifications": true
}
В новой версии требуется хранить:
{
"appearance": { "theme": "dark" },
"notifications": { "enabled": true }
}Определение функции трансформации Функция трансформации принимает старое значение и возвращает новое. В примере выше функция может быть такой:
function transformUserSettings(oldValue) {
return {
appearance: { theme: oldValue.theme },
notifications: { enabled: oldValue.notifications }
};
}
Ключевой момент: функция должна быть детерминированной и безопасно обрабатывать отсутствующие или частично повреждённые данные.
Применение трансформации и сохранение результата Для каждого выбранного ключа выполняется извлечение значения, его преобразование и запись обратно в хранилище:
import { get, set } from 'idb-keyval';
async function migrateUserSettings() {
const oldValue = await get('userSettings');
if (oldValue) {
const newValue = transformUserSettings(oldValue);
await set('userSettings', newValue);
}
}Когда структура приложения предполагает множество ключей, ручная
трансформация каждого ключа становится неудобной. Для этого используется
итерация по ключам с использованием метода keys() из
Idb-keyval:
import { keys, get, set } from 'idb-keyval';
async function migrateAll(transformMap) {
const allKeys = await keys();
for (const key of allKeys) {
if (transformMap[key]) {
const oldValue = await get(key);
if (oldValue !== undefined) {
const newValue = transformMap[key](oldValue);
await set(key, newValue);
}
}
}
}
transformMap — объект, где ключи соответствуют ключам
хранилища, а значения — функции трансформации:
const transformMap = {
userSettings: transformUserSettings,
appData: transformAppData
};
Такой подход позволяет централизованно управлять миграцией и легко добавлять новые правила трансформации.
При работе с IndexedDB возможны сбои: данные могут быть повреждены, база может быть недоступна или процесс прерван. Для минимизации риска следует:
get на
undefined или null.try/catch для каждой операции записи.async function safeMigrate(key, transform) {
try {
const oldValue = await get(key);
if (oldValue !== undefined) {
const backupKey = `${key}_backup`;
await set(backupKey, oldValue);
const newValue = transform(oldValue);
await set(key, newValue);
}
} catch (error) {
console.error(`Ошибка миграции ключа ${key}:`, error);
}
}
Это позволяет при сбое восстановить исходное состояние, сохраняя целостность данных.
Для крупных приложений целесообразно внедрять версионирование хранилища:
import { get, set } from 'idb-keyval';
async function migrateStorage(currentVersion) {
const storedVersion = await get('dbVersion') || 0;
if (storedVersion < currentVersion) {
if (storedVersion < 1) {
await migrateAll(version1Transforms);
}
if (storedVersion < 2) {
await migrateAll(version2Transforms);
}
await set('dbVersion', currentVersion);
}
}
Преимущества:
Стратегия миграции с трансформацией значений в Idb-keyval обеспечивает безопасное и управляемое обновление структуры данных, поддерживает версионирование и позволяет масштабировать процесс для сложных приложений, где количество ключей и зависимостей может быть большим.