Dexie.js строится поверх IndexedDB и наследует его ключевую особенность — обязательное версионирование схемы базы данных. Любое изменение структуры хранилищ, индексов или первичных ключей должно сопровождаться увеличением версии базы. Эта модель исключает произвольную модификацию схемы «на лету» и переводит все изменения в контролируемые миграции.
Версия базы данных в Dexie.js представляет собой числовой идентификатор состояния схемы. Каждое увеличение версии сигнализирует движку IndexedDB о необходимости запуска процедуры обновления структуры, включающей создание, модификацию или удаление объектных хранилищ (object stores) и индексов.
В Dexie.js версия задаётся через метод version() у
экземпляра базы данных. Каждая версия описывает состояние схемы через
строку определения таблиц и их индексов.
const db = new Dexie("AppDatabase");
db.version(1).stores({
users: "++id, name, email"
});
Первая версия фиксирует начальную структуру. Строка схемы определяет:
users — имя таблицы++id — автоинкрементный первичный ключname, email — индексируемые поляЛюбое последующее изменение структуры требует новой версии.
После публикации версии её описание становится неизменяемым. Dexie.js рассматривает версии как исторические слепки схемы. Изменение ранее объявленной версии не допускается, поскольку IndexedDB опирается на строгую последовательность миграций.
Добавление новой таблицы или индекса осуществляется только через новую версию:
db.version(2).stores({
users: "++id, name, email, age",
orders: "++id, userId, total"
});
В этом примере расширена таблица users и добавлена новая
таблица orders. Dexie интерпретирует это как переход от
состояния версии 1 к версии 2.
При открытии базы данных Dexie сравнивает текущую версию хранилища в браузере с последней объявленной версией в коде. Если обнаруживается несоответствие, запускается процесс миграции.
Миграция проходит последовательно через все промежуточные версии, если их несколько. Например, при переходе с версии 1 на версию 3 будут выполнены шаги 1 → 2 → 3.
Каждый переход может сопровождаться функцией upgrade,
содержащей пользовательскую логику преобразования данных.
db.version(2).stores({
users: "++id, name, email, age"
}).upgrade(tx => {
return tx.table("users").toCollection().modify(user => {
user.age = 0;
});
});
Здесь добавление поля age сопровождается миграцией
существующих записей.
Определение версии включает два ключевых элемента:
stores()upgrade()Эти элементы связаны с конкретным номером версии и формируют атомарное описание состояния базы.
db.version(3)
.stores({
users: "++id, name, email, age, createdAt"
})
.upgrade(tx => {
return tx.table("users").toCollection().modify(user => {
user.createdAt = Date.now();
});
});
Dexie.js накладывает строгие ограничения на изменение схемы:
Каждое изменение трактуется как переход состояния, а не как патч существующей схемы.
Если код приложения содержит несколько объявлений одной и той же версии, применяется первое объявление в цепочке и фиксируется как финальное. Повторное определение версии игнорируется, поскольку Dexie формирует внутренний список версий при инициализации экземпляра базы данных.
При попытке уменьшения версии возникает ошибка, так как IndexedDB не поддерживает откат схемы.
Версии должны объявляться в возрастающем порядке. Dexie формирует цепочку миграций, упорядоченную по числовому значению версии:
db.version(1).stores({ users: "++id, name" });
db.version(2).stores({ users: "++id, name, email" });
db.version(3).stores({
users: "++id, name, email, age",
logs: "++id, type, createdAt"
});
Каждая новая версия расширяет или изменяет предыдущее состояние, но не заменяет его.
При вызове db.open() происходит анализ состояния:
В процессе обновления база может быть временно недоступна для операций чтения и записи, поскольку структура находится в переходном состоянии.
Во время миграции доступ к данным осуществляется через транзакции, привязанные к конкретной версии. Dexie обеспечивает консистентность данных, гарантируя, что изменения схемы и модификации записей выполняются атомарно в рамках одной миграционной операции.
Пример массового преобразования данных:
db.version(4).stores({
users: "++id, name, email, isActive"
}).upgrade(async tx => {
const users = tx.table("users");
await users.toCollection().modify(user => {
user.isActive = true;
});
});
Версионная система Dexie.js подчиняется ограничениям IndexedDB:
Эти ограничения формируют детерминированную модель управления структурой данных.
Dexie хранит список версий как упорядоченный набор описаний схем. Каждая запись содержит:
При инициализации формируется граф переходов между версиями, где каждая вершина представляет состояние схемы, а ребро — операцию миграции.
Версионная модель позволяет управлять изменениями структуры данных в долгоживущих приложениях. Каждое изменение схемы становится явным шагом эволюции, фиксируемым в коде. Это исключает рассинхронизацию между клиентскими экземплярами и гарантирует предсказуемость состояния базы при обновлениях приложения.