react-native-onyx 3.0.26 → 3.0.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/OnyxUtils.js +3 -2
- package/dist/storage/InstanceSync/index.web.d.ts +1 -1
- package/dist/storage/__mocks__/index.d.ts +0 -1
- package/dist/storage/__mocks__/index.js +0 -1
- package/dist/storage/index.d.ts +2 -2
- package/dist/storage/providers/IDBKeyValProvider/createStore.js +36 -3
- package/dist/storage/providers/IDBKeyValProvider/index.d.ts +2 -1
- package/dist/storage/providers/IDBKeyValProvider/index.js +120 -43
- package/dist/storage/providers/MemoryOnlyProvider.d.ts +4 -4
- package/dist/storage/providers/MemoryOnlyProvider.js +22 -14
- package/dist/storage/providers/NoopProvider.d.ts +1 -1
- package/dist/storage/providers/NoopProvider.js +1 -0
- package/dist/storage/providers/SQLiteProvider.d.ts +6 -1
- package/dist/storage/providers/SQLiteProvider.js +58 -22
- package/dist/storage/providers/types.d.ts +2 -1
- package/dist/utils.js +2 -2
- package/package.json +2 -1
package/dist/OnyxUtils.js
CHANGED
|
@@ -699,7 +699,7 @@ function addKeyToRecentlyAccessedIfNeeded(key) {
|
|
|
699
699
|
function getCollectionDataAndSendAsObject(matchingKeys, mapping) {
|
|
700
700
|
multiGet(matchingKeys).then((dataMap) => {
|
|
701
701
|
const data = Object.fromEntries(dataMap.entries());
|
|
702
|
-
sendDataToConnection(mapping, data,
|
|
702
|
+
sendDataToConnection(mapping, data, mapping.key);
|
|
703
703
|
});
|
|
704
704
|
}
|
|
705
705
|
/**
|
|
@@ -961,9 +961,10 @@ function subscribeToKey(connectOptions) {
|
|
|
961
961
|
if (mapping.key) {
|
|
962
962
|
OnyxCache_1.default.addNullishStorageKey(mapping.key);
|
|
963
963
|
}
|
|
964
|
+
const matchedKey = isCollectionKey(mapping.key) && mapping.waitForCollectionCallback ? mapping.key : undefined;
|
|
964
965
|
// Here we cannot use batching because the nullish value is expected to be set immediately for default props
|
|
965
966
|
// or they will be undefined.
|
|
966
|
-
sendDataToConnection(mapping, null,
|
|
967
|
+
sendDataToConnection(mapping, null, matchedKey);
|
|
967
968
|
return;
|
|
968
969
|
}
|
|
969
970
|
// When using a callback subscriber we will either trigger the provided callback for each key we find or combine all values
|
|
@@ -17,7 +17,7 @@ declare const InstanceSync: {
|
|
|
17
17
|
/**
|
|
18
18
|
* @param {Function} onStorageKeyChanged Storage synchronization mechanism keeping all opened tabs in sync
|
|
19
19
|
*/
|
|
20
|
-
init: (onStorageKeyChanged: OnStorageKeyChanged, store: StorageProvider) => void;
|
|
20
|
+
init: (onStorageKeyChanged: OnStorageKeyChanged, store: StorageProvider<unknown>) => void;
|
|
21
21
|
setItem: typeof raiseStorageSyncEvent;
|
|
22
22
|
removeItem: typeof raiseStorageSyncEvent;
|
|
23
23
|
removeItems: typeof raiseStorageSyncManyKeysEvent;
|
|
@@ -15,7 +15,6 @@ declare const StorageMock: {
|
|
|
15
15
|
bytesRemaining: number;
|
|
16
16
|
}>, [], any>;
|
|
17
17
|
keepInstancesSync: jest.Mock<any, any, any>;
|
|
18
|
-
mockSet: (key: import("../..").OnyxKey, value: import("../..").OnyxValue<import("../..").OnyxKey>) => Promise<unknown>;
|
|
19
18
|
getMockStore: jest.Mock<{
|
|
20
19
|
[x: string]: unknown;
|
|
21
20
|
}, [], any>;
|
|
@@ -50,7 +50,6 @@ const StorageMock = {
|
|
|
50
50
|
getAllKeys: jest.fn(MemoryOnlyProvider_1.default.getAllKeys),
|
|
51
51
|
getDatabaseSize: jest.fn(MemoryOnlyProvider_1.default.getDatabaseSize),
|
|
52
52
|
keepInstancesSync: jest.fn(),
|
|
53
|
-
mockSet: MemoryOnlyProvider_1.mockSet,
|
|
54
53
|
getMockStore: jest.fn(() => MemoryOnlyProvider_1.mockStore),
|
|
55
54
|
setMockStore: jest.fn((data) => (0, MemoryOnlyProvider_1.setMockStore)(data)),
|
|
56
55
|
};
|
package/dist/storage/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type StorageProvider from './providers/types';
|
|
2
2
|
type Storage = {
|
|
3
|
-
getStorageProvider: () => StorageProvider
|
|
4
|
-
} & Omit<StorageProvider
|
|
3
|
+
getStorageProvider: () => StorageProvider<unknown>;
|
|
4
|
+
} & Omit<StorageProvider<unknown>, 'name' | 'store'>;
|
|
5
5
|
declare const storage: Storage;
|
|
6
6
|
export default storage;
|
|
@@ -1,6 +1,39 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const
|
|
36
|
+
const IDB = __importStar(require("idb-keyval"));
|
|
4
37
|
const Logger_1 = require("../../../Logger");
|
|
5
38
|
// This is a copy of the createStore function from idb-keyval, we need a custom implementation
|
|
6
39
|
// because we need to create the database manually in order to ensure that the store exists before we use it.
|
|
@@ -13,7 +46,7 @@ function createStore(dbName, storeName) {
|
|
|
13
46
|
return dbp;
|
|
14
47
|
const request = indexedDB.open(dbName);
|
|
15
48
|
request.onupgradeneeded = () => request.result.createObjectStore(storeName);
|
|
16
|
-
dbp =
|
|
49
|
+
dbp = IDB.promisifyRequest(request);
|
|
17
50
|
dbp.then((db) => {
|
|
18
51
|
// It seems like Safari sometimes likes to just close the connection.
|
|
19
52
|
// It's supposed to fire this event when that happens. Let's hope it does!
|
|
@@ -42,7 +75,7 @@ function createStore(dbName, storeName) {
|
|
|
42
75
|
(0, Logger_1.logInfo)(`Creating store ${storeName} in database ${dbName}.`);
|
|
43
76
|
updatedDatabase.createObjectStore(storeName);
|
|
44
77
|
};
|
|
45
|
-
dbp =
|
|
78
|
+
dbp = IDB.promisifyRequest(request);
|
|
46
79
|
return dbp;
|
|
47
80
|
};
|
|
48
81
|
return (txMode, callback) => getDB()
|
|
@@ -1,17 +1,50 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
37
|
};
|
|
5
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const
|
|
39
|
+
const IDB = __importStar(require("idb-keyval"));
|
|
7
40
|
const utils_1 = __importDefault(require("../../../utils"));
|
|
8
41
|
const createStore_1 = __importDefault(require("./createStore"));
|
|
9
|
-
// We don't want to initialize the store while the JS bundle loads as idb-keyval will try to use global.indexedDB
|
|
10
|
-
// which might not be available in certain environments that load the bundle (e.g. electron main process).
|
|
11
|
-
let idbKeyValStore;
|
|
12
42
|
const DB_NAME = 'OnyxDB';
|
|
13
43
|
const STORE_NAME = 'keyvaluepairs';
|
|
14
44
|
const provider = {
|
|
45
|
+
// We don't want to initialize the store while the JS bundle loads as idb-keyval will try to use global.indexedDB
|
|
46
|
+
// which might not be available in certain environments that load the bundle (e.g. electron main process).
|
|
47
|
+
store: undefined,
|
|
15
48
|
/**
|
|
16
49
|
* The name of the provider that can be printed to the logs
|
|
17
50
|
*/
|
|
@@ -24,60 +57,104 @@ const provider = {
|
|
|
24
57
|
if (newIdbKeyValStore == null) {
|
|
25
58
|
throw Error('IDBKeyVal store could not be created');
|
|
26
59
|
}
|
|
27
|
-
|
|
60
|
+
provider.store = newIdbKeyValStore;
|
|
28
61
|
},
|
|
29
|
-
setItem
|
|
62
|
+
setItem(key, value) {
|
|
63
|
+
if (!provider.store) {
|
|
64
|
+
throw new Error('Store not initialized!');
|
|
65
|
+
}
|
|
30
66
|
if (value === null) {
|
|
31
|
-
provider.removeItem(key);
|
|
67
|
+
return provider.removeItem(key);
|
|
32
68
|
}
|
|
33
|
-
return
|
|
69
|
+
return IDB.set(key, value, provider.store);
|
|
34
70
|
},
|
|
35
|
-
multiGet
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
71
|
+
multiGet(keysParam) {
|
|
72
|
+
if (!provider.store) {
|
|
73
|
+
throw new Error('Store not initialized!');
|
|
74
|
+
}
|
|
75
|
+
return IDB.getMany(keysParam, provider.store).then((values) => values.map((value, index) => [keysParam[index], value]));
|
|
76
|
+
},
|
|
77
|
+
multiMerge(pairs) {
|
|
78
|
+
if (!provider.store) {
|
|
79
|
+
throw new Error('Store not initialized!');
|
|
80
|
+
}
|
|
81
|
+
return provider.store('readwrite', (store) => {
|
|
82
|
+
// Note: we are using the manual store transaction here, to fit the read and update
|
|
83
|
+
// of the items in one transaction to achieve best performance.
|
|
84
|
+
const getValues = Promise.all(pairs.map(([key]) => IDB.promisifyRequest(store.get(key))));
|
|
85
|
+
return getValues.then((values) => {
|
|
86
|
+
for (const [index, [key, value]] of pairs.entries()) {
|
|
87
|
+
if (value === null) {
|
|
88
|
+
store.delete(key);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
const newValue = utils_1.default.fastMerge(values[index], value, {
|
|
92
|
+
shouldRemoveNestedNulls: true,
|
|
93
|
+
objectRemovalMode: 'replace',
|
|
94
|
+
}).result;
|
|
95
|
+
store.put(newValue, key);
|
|
96
|
+
}
|
|
45
97
|
}
|
|
46
|
-
return
|
|
47
|
-
});
|
|
48
|
-
const upsertMany = pairsWithoutNull.map(([key, value], index) => {
|
|
49
|
-
const prev = values[index];
|
|
50
|
-
const newValue = utils_1.default.fastMerge(prev, value, {
|
|
51
|
-
shouldRemoveNestedNulls: true,
|
|
52
|
-
objectRemovalMode: 'replace',
|
|
53
|
-
}).result;
|
|
54
|
-
return (0, idb_keyval_1.promisifyRequest)(store.put(newValue, key));
|
|
98
|
+
return IDB.promisifyRequest(store.transaction);
|
|
55
99
|
});
|
|
56
|
-
return Promise.all(upsertMany);
|
|
57
100
|
});
|
|
58
|
-
}
|
|
101
|
+
},
|
|
59
102
|
mergeItem(key, change) {
|
|
60
103
|
// Since Onyx already merged the existing value with the changes, we can just set the value directly.
|
|
61
104
|
return provider.multiMerge([[key, change]]);
|
|
62
105
|
},
|
|
63
|
-
multiSet
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
106
|
+
multiSet(pairs) {
|
|
107
|
+
if (!provider.store) {
|
|
108
|
+
throw new Error('Store not initialized!');
|
|
109
|
+
}
|
|
110
|
+
return provider.store('readwrite', (store) => {
|
|
111
|
+
for (const [key, value] of pairs) {
|
|
112
|
+
if (value === null) {
|
|
113
|
+
store.delete(key);
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
store.put(value, key);
|
|
117
|
+
}
|
|
68
118
|
}
|
|
69
|
-
return
|
|
119
|
+
return IDB.promisifyRequest(store.transaction);
|
|
70
120
|
});
|
|
71
|
-
return (0, idb_keyval_1.setMany)(pairsWithoutNull, idbKeyValStore);
|
|
72
121
|
},
|
|
73
|
-
clear
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
.
|
|
78
|
-
|
|
79
|
-
|
|
122
|
+
clear() {
|
|
123
|
+
if (!provider.store) {
|
|
124
|
+
throw new Error('Store not initialized!');
|
|
125
|
+
}
|
|
126
|
+
return IDB.clear(provider.store);
|
|
127
|
+
},
|
|
128
|
+
getAllKeys() {
|
|
129
|
+
if (!provider.store) {
|
|
130
|
+
throw new Error('Store not initialized!');
|
|
131
|
+
}
|
|
132
|
+
return IDB.keys(provider.store);
|
|
133
|
+
},
|
|
134
|
+
getItem(key) {
|
|
135
|
+
if (!provider.store) {
|
|
136
|
+
throw new Error('Store not initialized!');
|
|
137
|
+
}
|
|
138
|
+
return (IDB.get(key, provider.store)
|
|
139
|
+
// idb-keyval returns undefined for missing items, but this needs to return null so that idb-keyval does the same thing as SQLiteStorage.
|
|
140
|
+
.then((val) => (val === undefined ? null : val)));
|
|
141
|
+
},
|
|
142
|
+
removeItem(key) {
|
|
143
|
+
if (!provider.store) {
|
|
144
|
+
throw new Error('Store not initialized!');
|
|
145
|
+
}
|
|
146
|
+
return IDB.del(key, provider.store);
|
|
147
|
+
},
|
|
148
|
+
removeItems(keysParam) {
|
|
149
|
+
if (!provider.store) {
|
|
150
|
+
throw new Error('Store not initialized!');
|
|
151
|
+
}
|
|
152
|
+
return IDB.delMany(keysParam, provider.store);
|
|
153
|
+
},
|
|
80
154
|
getDatabaseSize() {
|
|
155
|
+
if (!provider.store) {
|
|
156
|
+
throw new Error('Store is not initialized!');
|
|
157
|
+
}
|
|
81
158
|
if (!window.navigator || !window.navigator.storage) {
|
|
82
159
|
throw new Error('StorageManager browser API unavailable');
|
|
83
160
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type StorageProvider from './types';
|
|
2
1
|
import type { OnyxKey, OnyxValue } from '../../types';
|
|
2
|
+
import type StorageProvider from './types';
|
|
3
3
|
type Store = Record<OnyxKey, OnyxValue<OnyxKey>>;
|
|
4
|
-
declare
|
|
4
|
+
declare const storeInternal: Store;
|
|
5
5
|
declare const set: (key: OnyxKey, value: OnyxValue<OnyxKey>) => Promise<unknown>;
|
|
6
|
-
declare const provider: StorageProvider
|
|
6
|
+
declare const provider: StorageProvider<Store>;
|
|
7
7
|
declare const setMockStore: (data: Store) => void;
|
|
8
8
|
export default provider;
|
|
9
|
-
export {
|
|
9
|
+
export { set as mockSet, storeInternal as mockStore, setMockStore };
|
|
@@ -3,20 +3,21 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.setMockStore = exports.
|
|
6
|
+
exports.setMockStore = exports.mockStore = exports.mockSet = void 0;
|
|
7
7
|
const underscore_1 = __importDefault(require("underscore"));
|
|
8
8
|
const utils_1 = __importDefault(require("../../utils"));
|
|
9
9
|
// eslint-disable-next-line import/no-mutable-exports
|
|
10
|
-
|
|
11
|
-
exports.mockStore =
|
|
10
|
+
const storeInternal = {};
|
|
11
|
+
exports.mockStore = storeInternal;
|
|
12
12
|
const setInternal = (key, value) => {
|
|
13
|
-
|
|
13
|
+
storeInternal[key] = value;
|
|
14
14
|
return Promise.resolve(value);
|
|
15
15
|
};
|
|
16
16
|
const isJestRunning = typeof jest !== 'undefined';
|
|
17
17
|
const set = isJestRunning ? jest.fn(setInternal) : setInternal;
|
|
18
18
|
exports.mockSet = set;
|
|
19
19
|
const provider = {
|
|
20
|
+
store: storeInternal,
|
|
20
21
|
/**
|
|
21
22
|
* The name of the provider that can be printed to the logs
|
|
22
23
|
*/
|
|
@@ -31,7 +32,7 @@ const provider = {
|
|
|
31
32
|
* Get the value of a given key or return `null` if it's not available in memory
|
|
32
33
|
*/
|
|
33
34
|
getItem(key) {
|
|
34
|
-
const value = store[key];
|
|
35
|
+
const value = provider.store[key];
|
|
35
36
|
return Promise.resolve(value === undefined ? null : value);
|
|
36
37
|
},
|
|
37
38
|
/**
|
|
@@ -39,7 +40,7 @@ const provider = {
|
|
|
39
40
|
*/
|
|
40
41
|
multiGet(keys) {
|
|
41
42
|
const getPromises = underscore_1.default.map(keys, (key) => new Promise((resolve) => {
|
|
42
|
-
|
|
43
|
+
provider.getItem(key).then((value) => resolve([key, value]));
|
|
43
44
|
}));
|
|
44
45
|
return Promise.all(getPromises);
|
|
45
46
|
},
|
|
@@ -54,7 +55,7 @@ const provider = {
|
|
|
54
55
|
* Stores multiple key-value pairs in a batch
|
|
55
56
|
*/
|
|
56
57
|
multiSet(pairs) {
|
|
57
|
-
const setPromises = underscore_1.default.map(pairs, ([key, value]) =>
|
|
58
|
+
const setPromises = underscore_1.default.map(pairs, ([key, value]) => provider.setItem(key, value));
|
|
58
59
|
return Promise.all(setPromises).then(() => undefined);
|
|
59
60
|
},
|
|
60
61
|
/**
|
|
@@ -62,7 +63,7 @@ const provider = {
|
|
|
62
63
|
*/
|
|
63
64
|
mergeItem(key, change) {
|
|
64
65
|
// Since Onyx already merged the existing value with the changes, we can just set the value directly.
|
|
65
|
-
return
|
|
66
|
+
return provider.multiMerge([[key, change]]);
|
|
66
67
|
},
|
|
67
68
|
/**
|
|
68
69
|
* Multiple merging of existing and new values in a batch
|
|
@@ -70,7 +71,7 @@ const provider = {
|
|
|
70
71
|
*/
|
|
71
72
|
multiMerge(pairs) {
|
|
72
73
|
underscore_1.default.forEach(pairs, ([key, value]) => {
|
|
73
|
-
const existingValue = store[key];
|
|
74
|
+
const existingValue = provider.store[key];
|
|
74
75
|
const newValue = utils_1.default.fastMerge(existingValue, value, {
|
|
75
76
|
shouldRemoveNestedNulls: true,
|
|
76
77
|
objectRemovalMode: 'replace',
|
|
@@ -83,7 +84,7 @@ const provider = {
|
|
|
83
84
|
* Remove given key and it's value from memory
|
|
84
85
|
*/
|
|
85
86
|
removeItem(key) {
|
|
86
|
-
delete store[key];
|
|
87
|
+
delete provider.store[key];
|
|
87
88
|
return Promise.resolve();
|
|
88
89
|
},
|
|
89
90
|
/**
|
|
@@ -91,7 +92,7 @@ const provider = {
|
|
|
91
92
|
*/
|
|
92
93
|
removeItems(keys) {
|
|
93
94
|
underscore_1.default.each(keys, (key) => {
|
|
94
|
-
delete store[key];
|
|
95
|
+
delete provider.store[key];
|
|
95
96
|
});
|
|
96
97
|
return Promise.resolve();
|
|
97
98
|
},
|
|
@@ -99,14 +100,17 @@ const provider = {
|
|
|
99
100
|
* Clear everything from memory
|
|
100
101
|
*/
|
|
101
102
|
clear() {
|
|
102
|
-
|
|
103
|
+
// Remove all keys without changing the root object reference.
|
|
104
|
+
for (const key of Object.keys(provider.store)) {
|
|
105
|
+
delete provider.store[key];
|
|
106
|
+
}
|
|
103
107
|
return Promise.resolve();
|
|
104
108
|
},
|
|
105
109
|
/**
|
|
106
110
|
* Returns all keys available in memory
|
|
107
111
|
*/
|
|
108
112
|
getAllKeys() {
|
|
109
|
-
return Promise.resolve(underscore_1.default.keys(store));
|
|
113
|
+
return Promise.resolve(underscore_1.default.keys(provider.store));
|
|
110
114
|
},
|
|
111
115
|
/**
|
|
112
116
|
* Gets the total bytes of the store.
|
|
@@ -117,7 +121,11 @@ const provider = {
|
|
|
117
121
|
},
|
|
118
122
|
};
|
|
119
123
|
const setMockStore = (data) => {
|
|
120
|
-
|
|
124
|
+
// Replace keys without changing the root object reference.
|
|
125
|
+
for (const key of Object.keys(storeInternal)) {
|
|
126
|
+
delete storeInternal[key];
|
|
127
|
+
}
|
|
128
|
+
Object.assign(storeInternal, data);
|
|
121
129
|
};
|
|
122
130
|
exports.setMockStore = setMockStore;
|
|
123
131
|
exports.default = provider;
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The SQLiteStorage provider stores everything in a key/value store by
|
|
3
|
+
* converting the value to a JSON string
|
|
4
|
+
*/
|
|
5
|
+
import type { NitroSQLiteConnection } from 'react-native-nitro-sqlite';
|
|
1
6
|
import type StorageProvider from './types';
|
|
2
7
|
/**
|
|
3
8
|
* The type of the key-value pair stored in the SQLite database
|
|
@@ -8,6 +13,6 @@ type OnyxSQLiteKeyValuePair = {
|
|
|
8
13
|
record_key: string;
|
|
9
14
|
valueJSON: string;
|
|
10
15
|
};
|
|
11
|
-
declare const provider: StorageProvider
|
|
16
|
+
declare const provider: StorageProvider<NitroSQLiteConnection | undefined>;
|
|
12
17
|
export default provider;
|
|
13
18
|
export type { OnyxSQLiteKeyValuePair };
|
|
@@ -13,7 +13,6 @@ const utils_1 = __importDefault(require("../../utils"));
|
|
|
13
13
|
// https://github.com/margelo/react-native-nitro-sqlite#sending-and-receiving-nullish-values
|
|
14
14
|
(0, react_native_nitro_sqlite_1.enableSimpleNullHandling)();
|
|
15
15
|
const DB_NAME = 'OnyxDB';
|
|
16
|
-
let db;
|
|
17
16
|
/**
|
|
18
17
|
* Prevents the stringifying of the object markers.
|
|
19
18
|
*/
|
|
@@ -33,6 +32,7 @@ function generateJSONReplaceSQLQueries(key, patches) {
|
|
|
33
32
|
return queries;
|
|
34
33
|
}
|
|
35
34
|
const provider = {
|
|
35
|
+
store: undefined,
|
|
36
36
|
/**
|
|
37
37
|
* The name of the provider that can be printed to the logs
|
|
38
38
|
*/
|
|
@@ -41,16 +41,19 @@ const provider = {
|
|
|
41
41
|
* Initializes the storage provider
|
|
42
42
|
*/
|
|
43
43
|
init() {
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
provider.store = (0, react_native_nitro_sqlite_1.open)({ name: DB_NAME });
|
|
45
|
+
provider.store.execute('CREATE TABLE IF NOT EXISTS keyvaluepairs (record_key TEXT NOT NULL PRIMARY KEY , valueJSON JSON NOT NULL) WITHOUT ROWID;');
|
|
46
46
|
// All of the 3 pragmas below were suggested by SQLite team.
|
|
47
47
|
// You can find more info about them here: https://www.sqlite.org/pragma.html
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
provider.store.execute('PRAGMA CACHE_SIZE=-20000;');
|
|
49
|
+
provider.store.execute('PRAGMA synchronous=NORMAL;');
|
|
50
|
+
provider.store.execute('PRAGMA journal_mode=WAL;');
|
|
51
51
|
},
|
|
52
52
|
getItem(key) {
|
|
53
|
-
|
|
53
|
+
if (!provider.store) {
|
|
54
|
+
throw new Error('Store is not initialized!');
|
|
55
|
+
}
|
|
56
|
+
return provider.store.executeAsync('SELECT record_key, valueJSON FROM keyvaluepairs WHERE record_key = ?;', [key]).then(({ rows }) => {
|
|
54
57
|
if (!rows || (rows === null || rows === void 0 ? void 0 : rows.length) === 0) {
|
|
55
58
|
return null;
|
|
56
59
|
}
|
|
@@ -62,26 +65,38 @@ const provider = {
|
|
|
62
65
|
});
|
|
63
66
|
},
|
|
64
67
|
multiGet(keys) {
|
|
68
|
+
if (!provider.store) {
|
|
69
|
+
throw new Error('Store is not initialized!');
|
|
70
|
+
}
|
|
65
71
|
const placeholders = keys.map(() => '?').join(',');
|
|
66
72
|
const command = `SELECT record_key, valueJSON FROM keyvaluepairs WHERE record_key IN (${placeholders});`;
|
|
67
|
-
return
|
|
73
|
+
return provider.store.executeAsync(command, keys).then(({ rows }) => {
|
|
68
74
|
// eslint-disable-next-line no-underscore-dangle
|
|
69
75
|
const result = rows === null || rows === void 0 ? void 0 : rows._array.map((row) => [row.record_key, JSON.parse(row.valueJSON)]);
|
|
70
76
|
return (result !== null && result !== void 0 ? result : []);
|
|
71
77
|
});
|
|
72
78
|
},
|
|
73
79
|
setItem(key, value) {
|
|
74
|
-
|
|
80
|
+
if (!provider.store) {
|
|
81
|
+
throw new Error('Store is not initialized!');
|
|
82
|
+
}
|
|
83
|
+
return provider.store.executeAsync('REPLACE INTO keyvaluepairs (record_key, valueJSON) VALUES (?, ?);', [key, JSON.stringify(value)]).then(() => undefined);
|
|
75
84
|
},
|
|
76
85
|
multiSet(pairs) {
|
|
86
|
+
if (!provider.store) {
|
|
87
|
+
throw new Error('Store is not initialized!');
|
|
88
|
+
}
|
|
77
89
|
const query = 'REPLACE INTO keyvaluepairs (record_key, valueJSON) VALUES (?, json(?));';
|
|
78
90
|
const params = pairs.map((pair) => [pair[0], JSON.stringify(pair[1] === undefined ? null : pair[1])]);
|
|
79
91
|
if (utils_1.default.isEmptyObject(params)) {
|
|
80
92
|
return Promise.resolve();
|
|
81
93
|
}
|
|
82
|
-
return
|
|
94
|
+
return provider.store.executeBatchAsync([{ query, params }]).then(() => undefined);
|
|
83
95
|
},
|
|
84
96
|
multiMerge(pairs) {
|
|
97
|
+
if (!provider.store) {
|
|
98
|
+
throw new Error('Store is not initialized!');
|
|
99
|
+
}
|
|
85
100
|
const commands = [];
|
|
86
101
|
// Query to merge the change into the DB value.
|
|
87
102
|
const patchQuery = `INSERT INTO keyvaluepairs (record_key, valueJSON)
|
|
@@ -112,26 +127,47 @@ const provider = {
|
|
|
112
127
|
if (replaceQueryArguments.length > 0) {
|
|
113
128
|
commands.push({ query: replaceQuery, params: replaceQueryArguments });
|
|
114
129
|
}
|
|
115
|
-
return
|
|
130
|
+
return provider.store.executeBatchAsync(commands).then(() => undefined);
|
|
116
131
|
},
|
|
117
132
|
mergeItem(key, change, replaceNullPatches) {
|
|
118
133
|
// Since Onyx already merged the existing value with the changes, we can just set the value directly.
|
|
119
|
-
return
|
|
134
|
+
return provider.multiMerge([[key, change, replaceNullPatches]]);
|
|
135
|
+
},
|
|
136
|
+
getAllKeys() {
|
|
137
|
+
if (!provider.store) {
|
|
138
|
+
throw new Error('Store is not initialized!');
|
|
139
|
+
}
|
|
140
|
+
return provider.store.executeAsync('SELECT record_key FROM keyvaluepairs;').then(({ rows }) => {
|
|
141
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
142
|
+
const result = rows === null || rows === void 0 ? void 0 : rows._array.map((row) => row.record_key);
|
|
143
|
+
return (result !== null && result !== void 0 ? result : []);
|
|
144
|
+
});
|
|
145
|
+
},
|
|
146
|
+
removeItem(key) {
|
|
147
|
+
if (!provider.store) {
|
|
148
|
+
throw new Error('Store is not initialized!');
|
|
149
|
+
}
|
|
150
|
+
return provider.store.executeAsync('DELETE FROM keyvaluepairs WHERE record_key = ?;', [key]).then(() => undefined);
|
|
120
151
|
},
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}),
|
|
126
|
-
removeItem: (key) => db.executeAsync('DELETE FROM keyvaluepairs WHERE record_key = ?;', [key]).then(() => undefined),
|
|
127
|
-
removeItems: (keys) => {
|
|
152
|
+
removeItems(keys) {
|
|
153
|
+
if (!provider.store) {
|
|
154
|
+
throw new Error('Store is not initialized!');
|
|
155
|
+
}
|
|
128
156
|
const placeholders = keys.map(() => '?').join(',');
|
|
129
157
|
const query = `DELETE FROM keyvaluepairs WHERE record_key IN (${placeholders});`;
|
|
130
|
-
return
|
|
158
|
+
return provider.store.executeAsync(query, keys).then(() => undefined);
|
|
159
|
+
},
|
|
160
|
+
clear() {
|
|
161
|
+
if (!provider.store) {
|
|
162
|
+
throw new Error('Store is not initialized!');
|
|
163
|
+
}
|
|
164
|
+
return provider.store.executeAsync('DELETE FROM keyvaluepairs;', []).then(() => undefined);
|
|
131
165
|
},
|
|
132
|
-
clear: () => db.executeAsync('DELETE FROM keyvaluepairs;', []).then(() => undefined),
|
|
133
166
|
getDatabaseSize() {
|
|
134
|
-
|
|
167
|
+
if (!provider.store) {
|
|
168
|
+
throw new Error('Store is not initialized!');
|
|
169
|
+
}
|
|
170
|
+
return Promise.all([provider.store.executeAsync('PRAGMA page_size;'), provider.store.executeAsync('PRAGMA page_count;'), (0, react_native_device_info_1.getFreeDiskStorage)()]).then(([pageSizeResult, pageCountResult, bytesRemaining]) => {
|
|
135
171
|
var _a, _b, _c, _d, _e, _f;
|
|
136
172
|
const pageSize = (_c = (_b = (_a = pageSizeResult.rows) === null || _a === void 0 ? void 0 : _a.item(0)) === null || _b === void 0 ? void 0 : _b.page_size) !== null && _c !== void 0 ? _c : 0;
|
|
137
173
|
const pageCount = (_f = (_e = (_d = pageCountResult.rows) === null || _d === void 0 ? void 0 : _d.item(0)) === null || _e === void 0 ? void 0 : _e.page_count) !== null && _f !== void 0 ? _f : 0;
|
|
@@ -7,7 +7,8 @@ type DatabaseSize = {
|
|
|
7
7
|
bytesRemaining: number;
|
|
8
8
|
};
|
|
9
9
|
type OnStorageKeyChanged = <TKey extends OnyxKey>(key: TKey, value: OnyxValue<TKey>) => void;
|
|
10
|
-
type StorageProvider = {
|
|
10
|
+
type StorageProvider<TStore> = {
|
|
11
|
+
store: TStore;
|
|
11
12
|
/**
|
|
12
13
|
* The name of the provider that can be printed to the logs
|
|
13
14
|
*/
|
package/dist/utils.js
CHANGED
|
@@ -14,10 +14,10 @@ function fastMerge(target, source, options, metadata, basePath = []) {
|
|
|
14
14
|
replaceNullPatches: [],
|
|
15
15
|
};
|
|
16
16
|
}
|
|
17
|
-
// We have to ignore arrays and nullish values here,
|
|
17
|
+
// We have to ignore arrays, primitives and nullish values here,
|
|
18
18
|
// otherwise "mergeObject" will throw an error,
|
|
19
19
|
// because it expects an object as "source"
|
|
20
|
-
if (
|
|
20
|
+
if (!isMergeableObject(source)) {
|
|
21
21
|
return { result: source, replaceNullPatches: metadata.replaceNullPatches };
|
|
22
22
|
}
|
|
23
23
|
const optionsWithDefaults = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-onyx",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.28",
|
|
4
4
|
"author": "Expensify, Inc.",
|
|
5
5
|
"homepage": "https://expensify.com",
|
|
6
6
|
"description": "State management for React Native",
|
|
@@ -78,6 +78,7 @@
|
|
|
78
78
|
"eslint-plugin-import": "^2.29.1",
|
|
79
79
|
"eslint-plugin-jsx-a11y": "^6.8.0",
|
|
80
80
|
"eslint-plugin-react": "^7.31.10",
|
|
81
|
+
"fake-indexeddb": "^6.2.5",
|
|
81
82
|
"idb-keyval": "^6.2.1",
|
|
82
83
|
"jest": "^29.7.0",
|
|
83
84
|
"jest-cli": "^29.7.0",
|