@react-native-ohos/react-native-mmkv-storage
Version:
This library aims to provide a fast & reliable solution for you data storage needs in react-native apps. It uses [MMKV](https://github.com/Tencent/MMKV) by Tencent under the hood on Android and iOS both that is used by their WeChat app(more than 1 Billion
595 lines (594 loc) • 22.7 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const encryption_1 = __importDefault(require("./encryption"));
const eventmanager_1 = __importDefault(require("./eventmanager"));
const handlers_1 = require("./handlers");
const indexer_1 = __importDefault(require("./indexer/indexer"));
const initializer_1 = require("./initializer");
const IDStore_1 = __importDefault(require("./mmkv/IDStore"));
const module_1 = __importDefault(require("./module"));
const transactions_1 = __importDefault(require("./transactions"));
const utils_1 = require("./utils");
function assert(type, value) {
if (type === 'array') {
if (!Array.isArray(value))
throw new Error(`Trying to set ${typeof value} as a ${type}.`);
}
else {
if (typeof value !== type)
throw new Error(`Trying to set ${typeof value} as a ${type}.`);
}
}
class MMKVInstance {
constructor(id) {
/**
* Set a string value to storage for the given key.
*/
this.setString = (key, value) => {
if (this.transactions.beforewrite['string']) {
value = this.transactions.transact('string', 'beforewrite', key, value);
}
if (this.handleNullOrUndefined(key, value))
return true;
assert('string', value);
let result = (0, handlers_1.handleAction)(module_1.default.setStringMMKV, key, value, this.instanceID);
if (result) {
if (this.isRegisterd(key)) {
this.ev.publish(`${key}:onwrite`, { key, value: value });
}
if (this.transactions.onwrite['string']) {
this.transactions.transact('string', 'onwrite', key, value);
}
}
return result;
};
/**
* Get the string value for the given key.
*/
this.getString = (key, callback) => {
let string = (0, handlers_1.handleAction)(module_1.default.getStringMMKV, key, this.instanceID);
if (this.transactions.onread['string']) {
string = this.transactions.transact('string', 'onread', key, string);
}
callback && callback(null, string);
return string;
};
/**
* Set a number value to storage for the given key.
*/
this.setInt = (key, value) => {
if (this.transactions.beforewrite['number']) {
value = this.transactions.transact('number', 'beforewrite', key, value);
}
if (this.handleNullOrUndefined(key, value))
return true;
assert('number', value);
let result = (0, handlers_1.handleAction)(module_1.default.setNumberMMKV, key, value, this.instanceID);
if (result) {
if (this.isRegisterd(key)) {
this.ev.publish(`${key}:onwrite`, { key, value: value });
}
this.transactions.transact('number', 'onwrite', key, value);
}
return result;
};
/**
* Get the number value for the given key
*/
this.getInt = (key, callback) => {
let int = (0, handlers_1.handleAction)(module_1.default.getNumberMMKV, key, this.instanceID);
if (this.transactions.onread['number']) {
int = this.transactions.transact('number', 'onread', key, int);
}
callback && callback(null, int);
return int;
};
/**
* Set a boolean value to storage for the given key
*/
this.setBool = (key, value) => {
if (this.transactions.beforewrite['boolean']) {
value = this.transactions.transact('boolean', 'beforewrite', key, value);
}
if (this.handleNullOrUndefined(key, value))
return true;
assert('boolean', value);
let result = (0, handlers_1.handleAction)(module_1.default.setBoolMMKV, key, value, this.instanceID);
if (result) {
if (this.isRegisterd(key)) {
this.ev.publish(`${key}:onwrite`, { key, value: value });
}
this.transactions.transact('boolean', 'onwrite', key, value);
}
return result;
};
/**
* Get the boolean value for the given key.
*/
this.getBool = (key, callback) => {
let bool = (0, handlers_1.handleAction)(module_1.default.getBoolMMKV, key, this.instanceID);
if (this.transactions.onread['boolean']) {
bool = this.transactions.transact('boolean', 'onread', key, bool);
}
callback && callback(null, bool);
return bool;
};
/**
* Set an Object to storage for a given key.
*
* Note that this function does **not** work with the Map data type
*/
this.setMap = (key, value) => {
if (this.transactions.beforewrite['object']) {
value = this.transactions.transact('object', 'beforewrite', key, value);
}
if (this.handleNullOrUndefined(key, value))
return true;
assert('object', value);
let result = (0, handlers_1.handleAction)(module_1.default.setMapMMKV, key, JSON.stringify(value), this.instanceID);
if (result) {
if (this.isRegisterd(key)) {
this.ev.publish(`${key}:onwrite`, { key, value: value });
}
if (this.transactions.onwrite['object']) {
this.transactions.transact('object', 'onwrite', key, value);
}
}
return result;
};
/**
* Get an Object from storage for a given key.
*/
this.getMap = (key, callback) => {
let json = (0, handlers_1.handleAction)(module_1.default.getMapMMKV, key, this.instanceID);
try {
if (json) {
let map = JSON.parse(json);
if (this.transactions.onread['object']) {
map = this.transactions.transact('object', 'onread', key, map);
}
callback && callback(null, map);
return map;
}
}
catch (e) { }
this.transactions.transact('object', 'onread', key);
callback && callback(null, null);
return null;
};
/**
* Set an array to storage for the given key.
*/
this.setArray = (key, value) => {
if (this.transactions.beforewrite['array']) {
value = this.transactions.transact('array', 'beforewrite', key, value);
}
if (this.handleNullOrUndefined(key, value))
return true;
assert('array', value);
let result = (0, handlers_1.handleAction)(module_1.default.setArrayMMKV, key, JSON.stringify(value), this.instanceID);
if (result) {
if (this.isRegisterd(key)) {
this.ev.publish(`${key}:onwrite`, { key, value: value });
}
if (this.transactions.onwrite['array']) {
this.transactions.transact('array', 'onwrite', key, value);
}
}
return result;
};
/**
* get an array from the storage for give key.
*/
this.getArray = (key, callback) => {
let json = (0, handlers_1.handleAction)(module_1.default.getMapMMKV, key, this.instanceID);
try {
if (json) {
let array = JSON.parse(json);
if (this.transactions.onread['array']) {
array = this.transactions.transact('array', 'onread', key, array);
}
callback && callback(null, array);
return array;
}
}
catch (e) { }
this.transactions.transact('array', 'onread', key);
callback && callback(null, null);
return null;
};
/**
* Retrieve multiple items for the given array of keys.
*
*/
this.getMultipleItems = (keys, type) => {
let items = [];
if (type === 'map')
type = 'object';
if (type === 'string') {
for (let i = 0; i < keys.length; i++) {
const item = [keys[i], this.getString(keys[i])];
if (this.transactions.onread[type]) {
item[1] = this.transactions.transact(type, 'onread', item[0], item[1]);
}
items.push(item);
}
return items;
}
else if (type === 'array') {
for (let i = 0; i < keys.length; i++) {
const item = [keys[i], this.getArray(keys[i])];
if (this.transactions.onread[type]) {
item[1] = this.transactions.transact(type, 'onread', item[0], item[1]);
}
items.push(item);
}
return items;
}
else if (type === 'object') {
for (let i = 0; i < keys.length; i++) {
const item = [keys[i], this.getMap(keys[i])];
if (this.transactions.onread[type]) {
item[1] = this.transactions.transact(type, 'onread', item[0], item[1]);
}
items.push(item);
}
return items;
}
else if (type === 'boolean') {
for (let i = 0; i < keys.length; i++) {
const item = [keys[i], this.getBool(keys[i])];
if (this.transactions.onread[type]) {
item[1] = this.transactions.transact(type, 'onread', item[0], item[1]);
}
items.push(item);
}
return items;
}
else if (type === 'number') {
for (let i = 0; i < keys.length; i++) {
const item = [keys[i], this.getInt(keys[i])];
if (this.transactions.onread[type]) {
item[1] = this.transactions.transact(type, 'onread', item[0], item[1]);
}
items.push(item);
}
return items;
}
};
this.instanceID = id;
this.encryption = new encryption_1.default(id);
this.indexer = new indexer_1.default(id);
this.ev = new eventmanager_1.default();
this.transactions = new transactions_1.default();
this.options = utils_1.options[id];
}
isRegisterd(key) {
return this.ev._registry[`${key}:onwrite`];
}
handleNullOrUndefined(key, value) {
if (value === null || value === undefined) {
this.removeItem(key);
return true;
}
return false;
}
/**
* Set a string value to storage for the given key.
* This method is added for redux-persist/zustand support.
*
*/
setItem(key, value, callback) {
return __awaiter(this, void 0, void 0, function* () {
return new Promise(resolve => {
const result = this.setString(key, value);
callback && callback(null);
resolve(result);
});
});
}
/**
* Get the string value for the given key.
* This method is added for redux-persist/zustand support.
*/
getItem(key, callback) {
return __awaiter(this, void 0, void 0, function* () {
return new Promise(resolve => {
resolve(this.getString(key, callback));
});
});
}
/**
* Set a string value to storage for the given key.
*/
setStringAsync(key, value) {
return new Promise(resolve => {
resolve(this.setString(key, value));
});
}
/**
* Get the string value for the given key.
*/
getStringAsync(key) {
return new Promise(resolve => {
resolve(this.getString(key));
});
}
/**
* Set a number value to storage for the given key.
*/
setIntAsync(key, value) {
return new Promise(resolve => {
resolve(this.setInt(key, value));
});
}
/**
* Get the number value for the given key.
*/
getIntAsync(key) {
return new Promise(resolve => {
resolve(this.getInt(key));
});
}
/**
* Set a boolean value to storage for the given key.
*
*/
setBoolAsync(key, value) {
return new Promise(resolve => {
resolve(this.setBool(key, value));
});
}
/**
* Get the boolean value for the given key.
*/
getBoolAsync(key) {
return new Promise(resolve => {
resolve(this.getBool(key));
});
}
/**
* Set an Object to storage for the given key.
*
* Note that this function does **not** work with the Map data type.
*
*/
setMapAsync(key, value) {
return new Promise(resolve => {
resolve(this.setMap(key, value));
});
}
/**
* Get then Object from storage for the given key.
*/
getMapAsync(key) {
return new Promise(resolve => {
resolve(this.getMap(key));
});
}
/**
* Set items in bulk of same type at once
*
* If a value against a key is null/undefined, it will be
* set as null.
*
* @param keys Array of keys
* @param values Array of values
* @param type
*/
setMultipleItemsAsync(items, type) {
return __awaiter(this, void 0, void 0, function* () {
if (type === 'object')
type = 'map';
let values = [];
if (type === 'string' || type === 'array' || type === 'map') {
values = items.map(item => {
let value = item[1];
if (this.transactions.beforewrite[type]) {
value = this.transactions.transact(type, 'beforewrite', item[0], value);
}
if (type === 'string')
return value;
return value ? JSON.stringify(value) : value;
});
(0, handlers_1.handleAction)(module_1.default.setMultiMMKV, items.map(item => item[0]), values, `${type}Index`, this.instanceID);
}
else {
if (type === 'boolean') {
for (let i = 0; i < items.length; i++) {
const item = items[i];
let value = item[1];
if (this.transactions.beforewrite[type]) {
value = this.transactions.transact(type, 'beforewrite', item[0], value);
}
values[i] = value;
this.setBool(item[0], value);
}
}
else if (type === 'number') {
for (let i = 0; i < items.length; i++) {
const item = items[i];
let value = item[1];
if (this.transactions.beforewrite[type]) {
value = this.transactions.transact(type, 'beforewrite', item[0], value);
}
values[i] = value;
this.setInt(item[0], value);
}
}
}
queueMicrotask(() => {
items === null || items === void 0 ? void 0 : items.forEach((item, index) => {
if (this.isRegisterd(item[0])) {
this.ev.publish(`${item[0]}:onwrite`, { key: item[0], value: values[index] });
}
if (this.transactions.onwrite[type]) {
this.transactions.transact(type, 'onwrite', item[0], values[index]);
}
});
});
return true;
});
}
/**
* Retrieve multiple items for the given array of keys
*/
getMultipleItemsAsync(keys, type) {
return __awaiter(this, void 0, void 0, function* () {
let items = [];
if (type === 'map')
type = 'object';
if (type === 'array' || type === 'string' || type === 'object') {
const result = (0, handlers_1.handleAction)(module_1.default.getMultiMMKV, keys, this.instanceID);
if (type === 'string')
return keys.map((key, index) => [key, result[index]]);
return keys.map((key, index) => {
let value = result[index] ? JSON.parse(result[index]) : result[index];
if (this.transactions.onread[type]) {
value = this.transactions.transact(type, 'onread', key, value);
}
return [key, value];
});
}
if (type === 'boolean') {
for (let i = 0; i < keys.length; i++) {
let value = this.getBool(keys[i]);
if (this.transactions.onread[type]) {
value = this.transactions.transact(type, 'onread', keys[i], value);
}
const item = [keys[i], value];
items.push(item);
}
return items;
}
else if (type === 'number') {
for (let i = 0; i < keys.length; i++) {
let value = this.getInt(keys[i]);
if (this.transactions.onread[type]) {
value = this.transactions.transact(type, 'onread', keys[i], value);
}
const item = [keys[i], value];
items.push(item);
}
return items;
}
});
}
/**
* Set an array to storage for the given key.
*/
setArrayAsync(key, value) {
return __awaiter(this, void 0, void 0, function* () {
return new Promise(resolve => {
resolve(this.setArray(key, value));
});
});
}
/**
* Get the array from the storage for the given key.
*/
getArrayAsync(key) {
return __awaiter(this, void 0, void 0, function* () {
return new Promise(resolve => {
resolve(this.getArray(key));
});
});
}
/**
*
* Get all Storage Instance IDs that are currently loaded.
*
*/
getCurrentMMKVInstanceIDs() {
return (0, initializer_1.getCurrentMMKVInstanceIDs)();
}
/**
*
* Get all Storage Instance IDs.
*
*/
getAllMMKVInstanceIDs() {
return IDStore_1.default.getAllMMKVInstanceIDs();
}
/**
* Remove an item from storage for a given key.
*
* If you are removing large number of keys, use `removeItems` instead.
*/
removeItem(key) {
let result = (0, handlers_1.handleAction)(module_1.default.removeValueMMKV, key, this.instanceID);
if (result) {
if (this.isRegisterd(key)) {
this.ev.publish(`${key}:onwrite`, { key, value: null });
}
}
if (this.transactions.ondelete) {
this.transactions.transact('string', 'ondelete', key);
}
return result;
}
/**
* Remove multiple items from storage for given keys
*
*/
removeItems(keys) {
let result = (0, handlers_1.handleAction)(module_1.default.removeValuesMMKV, keys.filter(key => key !== this.instanceID), this.instanceID);
for (const key of keys) {
if (result) {
if (this.isRegisterd(key)) {
this.ev.publish(`${key}:onwrite`, { key, value: null });
}
}
if (this.transactions.ondelete) {
this.transactions.transact('string', 'ondelete', key);
}
}
return result;
}
/**
* Remove all keys and values from storage.
*/
clearStore() {
let keys = (0, handlers_1.handleAction)(module_1.default.getAllKeysMMKV, this.instanceID);
let cleared = (0, handlers_1.handleAction)(module_1.default.clearMMKV, this.instanceID);
module_1.default.setBoolMMKV(this.instanceID, true, this.instanceID);
queueMicrotask(() => {
keys === null || keys === void 0 ? void 0 : keys.forEach((key) => {
if (this.isRegisterd(key)) {
this.ev.publish(`${key}:onwrite`, { key });
}
if (this.transactions.ondelete) {
this.transactions.transact('string', 'ondelete', key);
}
});
});
return cleared;
}
/**
* Get the key and alias for the encrypted storage
*/
getKey() {
let { alias, key } = utils_1.options[this.instanceID];
return { alias, key };
}
/**
* Clear memory cache of the current MMKV instance
*/
clearMemoryCache() {
let cleared = (0, handlers_1.handleAction)(module_1.default.clearMemoryCache, this.instanceID);
return cleared;
}
}
exports.default = MMKVInstance;