Функция-трансформер в библиотеке idb-keyval — это механизм, позволяющий управлять процессом сериализации и десериализации данных при записи и чтении из IndexedDB. Она действует как промежуточный слой между приложением и базой данных, обеспечивая контроль над форматом хранимых данных, их типами и структурой.
Трансформер представляет собой объект с двумя обязательными методами:
serialize — вызывается при записи
значения в хранилище. Должен принимать любое значение и возвращать
объект вида { value: any, type: string }, где
value — сериализованное значение, а type —
строковый идентификатор типа данных.deserialize — вызывается при чтении
значения из хранилища. Принимает объект { value, type } и
возвращает восстановленное значение исходного типа.Контракт трансформера строго определяет, что сериализация и
десериализация должны быть взаимно обратимыми. Любое значение, которое
прошло через serialize, после применения
deserialize должно полностью соответствовать исходному.
interface Transformer {
serialize: (value: any) => { value: any, type: string };
deserialize: (record: { value: any, type: string }) => any;
}
Пояснения к сигнатурам:
value: any — любое значение JavaScript, включая
объекты, массивы, примитивы, Map, Set.type: string — уникальная строка, однозначно
идентифицирующая тип сериализованного объекта. Она необходима для
корректного восстановления объекта при десериализации.{ value, type } может содержать
любое внутреннее представление данных, главное — чтобы десериализатор
понимал, как его реконструировать.Обратимость: Для всех значений x
должно выполняться:
transformer.deserialize(transformer.serialize(x)) === x
Для сложных объектов обратимость может быть проверена через глубокое
сравнение (deepEqual).
Определённость типа: Каждый сериализованный
объект должен иметь чётко определённое поле type,
позволяющее десериализатору точно понять структуру данных.
Нейтральность к побочным эффектам: Методы
serialize и deserialize не должны изменять
исходные объекты. Они должны работать исключительно с копиями или
промежуточными представлениями.
const simpleTransformer = {
serialize(value) {
return { value, type: typeof value };
},
deserialize(record) {
return record.value;
}
};
В этом случае примитивные типы (string,
number, boolean) и объекты хранятся без
изменений, тип используется лишь для информационных целей.
Dateconst dateTransformer = {
serialize(value) {
if (value instanceof Date) {
return { value: value.toISOString(), type: 'date' };
}
return { value, type: typeof value };
},
deserialize(record) {
if (record.type === 'date') {
return new Date(record.value);
}
return record.value;
}
};
Этот трансформер обеспечивает безопасное хранение дат в виде строки
ISO и корректное восстановление объекта Date.
Map и Setconst collectionTransformer = {
serialize(value) {
if (value instanceof Map) {
return { value: Array.from(value.entries()), type: 'map' };
}
if (value instanceof Set) {
return { value: Array.from(value), type: 'set' };
}
return { value, type: typeof value };
},
deserialize(record) {
if (record.type === 'map') {
return new Map(record.value);
}
if (record.type === 'set') {
return new Set(record.value);
}
return record.value;
}
};
Такой подход позволяет хранить нестандартные структуры JavaScript без потери данных.
При создании нового хранилища через createStore или при
вызове методов get, set можно передать
трансформер:
import { createStore, set, get } from 'idb-keyval';
const store = createStore('my-database', 'my-store', {
transformer: dateTransformer
});
set('eventDate', new Date(), store);
get('eventDate', store).then(date => console.log(date instanceof Date)); // true
Ключевые моменты:
serialize и deserialize.type, даже если данные примитивные. Это облегчает отладку и
расширение трансформера.value и type, чтобы не
перегружать IndexedDB.Map внутри
Set, вложенные объекты) делать это рекурсивно внутри
serialize.Трансформер в idb-keyval является точкой расширения для:
Blob,
ArrayBuffer, TypedArray).msgpack, protobuf или
JSON.stringify для сложных объектов.Строгий контракт гарантирует, что любые данные, сериализованные через
serialize, всегда могут быть корректно восстановлены через
deserialize, что делает хранилище предсказуемым и
безопасным для сложных веб-приложений.