react-native-onyx 1.0.31 → 1.0.33
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/web.development.js +4330 -3057
- package/dist/web.development.js.map +1 -1
- package/dist/web.min.js +2 -1
- package/dist/web.min.js.LICENSE.txt +9 -0
- package/dist/web.min.js.map +1 -1
- package/lib/Onyx.js +5 -4
- package/lib/OnyxCache.js +2 -0
- package/lib/storage/NativeStorage.js +2 -2
- package/lib/storage/providers/SQLiteStorage.js +118 -0
- package/lib/storage/providers/__mocks__/SQLiteStorage.js +3 -0
- package/package.json +22 -10
package/lib/Onyx.js
CHANGED
|
@@ -799,8 +799,7 @@ function notifyCollectionSubscribersOnNextTick(key, value) {
|
|
|
799
799
|
* @return {Promise}
|
|
800
800
|
*/
|
|
801
801
|
function remove(key) {
|
|
802
|
-
|
|
803
|
-
cache.set(key, null);
|
|
802
|
+
cache.drop(key);
|
|
804
803
|
notifySubscribersOnNextTick(key, null);
|
|
805
804
|
return Storage.removeItem(key);
|
|
806
805
|
}
|
|
@@ -847,8 +846,9 @@ function evictStorageAndRetry(error, onyxMethod, ...args) {
|
|
|
847
846
|
* @returns {Promise}
|
|
848
847
|
*/
|
|
849
848
|
function set(key, value) {
|
|
850
|
-
|
|
851
|
-
|
|
849
|
+
if (_.isNull(value)) {
|
|
850
|
+
return remove(key);
|
|
851
|
+
}
|
|
852
852
|
|
|
853
853
|
// eslint-disable-next-line no-use-before-define
|
|
854
854
|
if (hasPendingMergeForKey(key)) {
|
|
@@ -1294,6 +1294,7 @@ const Onyx = {
|
|
|
1294
1294
|
mergeCollection,
|
|
1295
1295
|
update,
|
|
1296
1296
|
clear,
|
|
1297
|
+
getAllKeys,
|
|
1297
1298
|
init,
|
|
1298
1299
|
registerLogger: Logger.registerLogger,
|
|
1299
1300
|
addToEvictionBlockList,
|
package/lib/OnyxCache.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import
|
|
1
|
+
import SQLiteStorage from './providers/SQLiteStorage';
|
|
2
2
|
|
|
3
|
-
export default
|
|
3
|
+
export default SQLiteStorage;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The SQLiteStorage provider stores everything in a key/value store by
|
|
3
|
+
* converting the value to a JSON string
|
|
4
|
+
*/
|
|
5
|
+
import {open} from 'react-native-quick-sqlite';
|
|
6
|
+
import _ from 'underscore';
|
|
7
|
+
|
|
8
|
+
const DB_NAME = 'OnyxDB';
|
|
9
|
+
const db = open({name: DB_NAME});
|
|
10
|
+
|
|
11
|
+
db.execute('CREATE TABLE IF NOT EXISTS keyvaluepairs (record_key TEXT NOT NULL PRIMARY KEY , valueJSON JSON NOT NULL) WITHOUT ROWID;');
|
|
12
|
+
|
|
13
|
+
// All of the 3 pragmas below were suggested by SQLite team.
|
|
14
|
+
// You can find more info about them here: https://www.sqlite.org/pragma.html
|
|
15
|
+
db.execute('PRAGMA CACHE_SIZE=-20000;');
|
|
16
|
+
db.execute('PRAGMA synchronous=NORMAL;');
|
|
17
|
+
db.execute('PRAGMA journal_mode=WAL;');
|
|
18
|
+
|
|
19
|
+
const provider = {
|
|
20
|
+
/**
|
|
21
|
+
* Get the value of a given key or return `null` if it's not available in storage
|
|
22
|
+
* @param {String} key
|
|
23
|
+
* @return {Promise<*>}
|
|
24
|
+
*/
|
|
25
|
+
getItem(key) {
|
|
26
|
+
return db.executeAsync('SELECT record_key, valueJSON FROM keyvaluepairs WHERE record_key = ?;', [key]).then(({rows}) => {
|
|
27
|
+
if (rows.length === 0) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
const result = rows.item(0);
|
|
31
|
+
return JSON.parse(result.valueJSON);
|
|
32
|
+
});
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Get multiple key-value pairs for the given array of keys in a batch
|
|
37
|
+
* @param {String[]} keys
|
|
38
|
+
* @return {Promise<Array<[key, value]>>}
|
|
39
|
+
*/
|
|
40
|
+
multiGet(keys) {
|
|
41
|
+
const placeholders = _.map(keys, () => '?').join(',');
|
|
42
|
+
const command = `SELECT record_key, valueJSON FROM keyvaluepairs WHERE record_key IN (${placeholders});`;
|
|
43
|
+
return db.executeAsync(command, keys)
|
|
44
|
+
.then(({rows}) => {
|
|
45
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
46
|
+
const result = _.map(rows._array, row => [row.record_key, JSON.parse(row.valueJSON)]);
|
|
47
|
+
return result;
|
|
48
|
+
});
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Sets the value for a given key. The only requirement is that the value should be serializable to JSON string
|
|
53
|
+
* @param {String} key
|
|
54
|
+
* @param {*} value
|
|
55
|
+
* @return {Promise<void>}
|
|
56
|
+
*/
|
|
57
|
+
setItem(key, value) {
|
|
58
|
+
return db.executeAsync('REPLACE INTO keyvaluepairs (record_key, valueJSON) VALUES (?, ?);', [key, JSON.stringify(value)]);
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Stores multiple key-value pairs in a batch
|
|
63
|
+
* @param {Array<[key, value]>} pairs
|
|
64
|
+
* @return {Promise<void>}
|
|
65
|
+
*/
|
|
66
|
+
multiSet(pairs) {
|
|
67
|
+
const stringifiedPairs = _.map(pairs, pair => [
|
|
68
|
+
pair[0],
|
|
69
|
+
JSON.stringify(pair[1]),
|
|
70
|
+
]);
|
|
71
|
+
return db.executeBatchAsync([['REPLACE INTO keyvaluepairs (record_key, valueJSON) VALUES (?, json(?));', stringifiedPairs]]);
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Multiple merging of existing and new values in a batch
|
|
76
|
+
* @param {Array<[key, value]>} pairs
|
|
77
|
+
* @return {Promise<void>}
|
|
78
|
+
*/
|
|
79
|
+
multiMerge(pairs) {
|
|
80
|
+
// Note: We use `ON CONFLICT DO UPDATE` here instead of `INSERT OR REPLACE INTO`
|
|
81
|
+
// so the new JSON value is merged into the old one if there's an existing value
|
|
82
|
+
const query = `INSERT INTO keyvaluepairs (record_key, valueJSON)
|
|
83
|
+
VALUES (:key, JSON(:value))
|
|
84
|
+
ON CONFLICT DO UPDATE
|
|
85
|
+
SET valueJSON = JSON_PATCH(valueJSON, JSON(:value));
|
|
86
|
+
`;
|
|
87
|
+
const queryArguments = _.map(pairs, (pair) => {
|
|
88
|
+
const value = JSON.stringify(pair[1]);
|
|
89
|
+
return [pair[0], value];
|
|
90
|
+
});
|
|
91
|
+
return db.executeBatchAsync([[query, queryArguments]]);
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Returns all keys available in storage
|
|
96
|
+
* @returns {Promise<String[]>}
|
|
97
|
+
*/
|
|
98
|
+
getAllKeys: () => db.executeAsync('SELECT record_key FROM keyvaluepairs;').then(({rows}) => {
|
|
99
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
100
|
+
const result = _.map(rows._array, row => row.record_key);
|
|
101
|
+
return result;
|
|
102
|
+
}),
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Removes given key and it's value from storage
|
|
106
|
+
* @param {String} key
|
|
107
|
+
* @returns {Promise<void>}
|
|
108
|
+
*/
|
|
109
|
+
removeItem: key => db.executeAsync('DELETE FROM keyvaluepairs WHERE record_key = ?;', [key]),
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Clears absolutely everything from storage
|
|
113
|
+
* @returns {Promise<void>}
|
|
114
|
+
*/
|
|
115
|
+
clear: () => db.executeAsync('DELETE FROM keyvaluepairs;', []),
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
export default provider;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-onyx",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.33",
|
|
4
4
|
"author": "Expensify, Inc.",
|
|
5
5
|
"homepage": "https://expensify.com",
|
|
6
6
|
"description": "State management for React Native",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"@babel/core": "^7.17.10",
|
|
49
49
|
"@babel/plugin-proposal-class-properties": "^7.16.7",
|
|
50
50
|
"@babel/runtime": "^7.11.2",
|
|
51
|
-
"@react-native-async-storage/async-storage": "^1.
|
|
51
|
+
"@react-native-async-storage/async-storage": "^1.17.11",
|
|
52
52
|
"@react-native-community/eslint-config": "^2.0.0",
|
|
53
53
|
"@testing-library/jest-native": "^3.4.2",
|
|
54
54
|
"@testing-library/react-native": "^7.0.2",
|
|
@@ -60,27 +60,31 @@
|
|
|
60
60
|
"babel-plugin-transform-class-properties": "^6.24.1",
|
|
61
61
|
"eslint": "^7.6.0",
|
|
62
62
|
"eslint-config-expensify": "^2.0.24",
|
|
63
|
+
"eslint-plugin-jsx-a11y": "^6.6.1",
|
|
64
|
+
"eslint-plugin-react": "^7.31.10",
|
|
63
65
|
"expensify-common": "git+https://github.com/Expensify/expensify-common.git#427295da130a4eacc184d38693664280d020dffd",
|
|
64
66
|
"jest": "^26.5.2",
|
|
65
67
|
"jest-cli": "^26.5.2",
|
|
66
68
|
"jsdoc-to-markdown": "^7.1.0",
|
|
67
69
|
"localforage": "^1.10.0",
|
|
68
|
-
"metro-react-native-babel-preset": "^0.
|
|
70
|
+
"metro-react-native-babel-preset": "^0.72.3",
|
|
69
71
|
"prop-types": "^15.7.2",
|
|
70
|
-
"react": "
|
|
71
|
-
"react-native": "0.
|
|
72
|
+
"react": "18.1.0",
|
|
73
|
+
"react-native": "0.70.0",
|
|
72
74
|
"react-native-performance": "^2.0.0",
|
|
73
|
-
"react-
|
|
75
|
+
"react-native-quick-sqlite": "^5.0.3",
|
|
76
|
+
"react-test-renderer": "18.1.0",
|
|
74
77
|
"webpack": "^5.72.1",
|
|
75
78
|
"webpack-cli": "^4.9.2",
|
|
76
79
|
"webpack-merge": "^5.8.0"
|
|
77
80
|
},
|
|
78
81
|
"peerDependencies": {
|
|
79
|
-
"@react-native-async-storage/async-storage": "^1.
|
|
82
|
+
"@react-native-async-storage/async-storage": "^1.17.11",
|
|
80
83
|
"expensify-common": ">=1",
|
|
81
84
|
"localforage": "^1.10.0",
|
|
82
|
-
"react": ">=
|
|
83
|
-
"react-native-performance": "^
|
|
85
|
+
"react": ">=18.1.0",
|
|
86
|
+
"react-native-performance": "^4.0.0",
|
|
87
|
+
"react-native-quick-sqlite": "^5.0.3"
|
|
84
88
|
},
|
|
85
89
|
"peerDependenciesMeta": {
|
|
86
90
|
"react-native-performance": {
|
|
@@ -89,10 +93,17 @@
|
|
|
89
93
|
"@react-native-async-storage/async-storage": {
|
|
90
94
|
"optional": true
|
|
91
95
|
},
|
|
96
|
+
"react-native-quick-sqlite": {
|
|
97
|
+
"optional": true
|
|
98
|
+
},
|
|
92
99
|
"localforage": {
|
|
93
100
|
"optional": true
|
|
94
101
|
}
|
|
95
102
|
},
|
|
103
|
+
"engines": {
|
|
104
|
+
"node": "16.15.1",
|
|
105
|
+
"npm": "8.11.0"
|
|
106
|
+
},
|
|
96
107
|
"jest": {
|
|
97
108
|
"preset": "react-native",
|
|
98
109
|
"transform": {
|
|
@@ -116,7 +127,8 @@
|
|
|
116
127
|
"timers": "fake",
|
|
117
128
|
"testEnvironment": "jsdom",
|
|
118
129
|
"setupFilesAfterEnv": [
|
|
119
|
-
"@testing-library/jest-native/extend-expect"
|
|
130
|
+
"@testing-library/jest-native/extend-expect",
|
|
131
|
+
"./jestSetup.js"
|
|
120
132
|
]
|
|
121
133
|
},
|
|
122
134
|
"sideEffects": false
|