versioned-storage
Version:
Local storage with versioning.
104 lines (103 loc) • 3.27 kB
JavaScript
function withLocalStorage(fn) {
try {
return fn();
}
catch {
throw new Error('localStorage not accessible');
}
}
function get(key) {
return withLocalStorage(() => globalThis.localStorage.getItem(key));
}
function set(key, value) {
withLocalStorage(() => globalThis.localStorage.setItem(key, value));
}
function remove(key) {
withLocalStorage(() => globalThis.localStorage.removeItem(key));
}
function clear() {
withLocalStorage(() => globalThis.localStorage.clear());
}
/**
* A class that can be instantiated into a storage with a specific name and version.
* Type T stands for the type of the value that is stored in the storage. It has to be serializable to JSON.
*/
export class Storage {
/**
* Name of the storage.
*/
name;
/**
* Version of the storage with this particular name.
*/
version;
/**
* Create or retrieve the storage with the given name and version.
* If the version is omitted, it will use the existing version of the storage with the given name.
* If there is no existing storage with the given name, it will throw an error.
* @param name Name of the storage.
* @param version Version of the storage. It has to be a positive integer.
*/
constructor(name, version) {
if (version !== undefined) {
const parsedVersion = parseInt(`${version}`, 10);
if (Number.isNaN(parsedVersion) || parsedVersion <= 0) {
throw new Error('version has to be a positive integer');
}
this.name = name;
this.version = parsedVersion;
const previousVersion = parseInt(`${get(name)}`, 10) || 0;
if (parsedVersion > previousVersion) {
remove(`${name}:${previousVersion}`);
set(name, version.toString(10));
}
}
else {
const existingVersion = parseInt(`${get(name)}`, 10) || 0;
if (!existingVersion) {
throw new Error(`There is no existing storage named ${name}`);
}
this.name = name;
this.version = existingVersion;
}
}
/**
* Read the value from the storage.
* @returns The value that is stored in the storage. If there is no value, it returns null.
*/
read() {
const key = `${this.name}:${this.version}`;
const jsonString = get(key);
let value = null;
if (jsonString) {
try {
value = JSON.parse(jsonString);
}
catch {
// Remove corrupted item
remove(key);
}
}
return value;
}
/**
* Write the value to the storage.
* @param value The value to be stored in the storage.
*/
write(value) {
const key = `${this.name}:${this.version}`;
const jsonString = JSON.stringify(value);
if (jsonString === undefined) {
remove(key);
}
else {
set(key, jsonString);
}
}
/**
* Reset all storages. (It even wipes out other localStorage content that are not written by this class.)
*/
static reset() {
clear();
}
}