Skip to content

Commit 10002de

Browse files
authored
feat: Add IndexedDB Storage Controller (#1297)
* feat: Add IndexedDB Storage Controller * Add indexeddb polyfil * Revert "Add indexeddb polyfil" This reverts commit e101840. * Add indexedDB check
1 parent 4b4f3f6 commit 10002de

File tree

9 files changed

+172
-33
lines changed

9 files changed

+172
-33
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ const Parse = require('parse');
4444
import Parse from 'parse/dist/parse.min.js';
4545
```
4646

47+
For web worker or browser applications, indexedDB storage is available:
48+
49+
```js
50+
Parse.CoreManager.setStorageController(Parse.IndexedDB);
51+
```
52+
4753
For server-side applications or Node.js command line tools, include `'parse/node'`:
4854

4955
```js

package-lock.json

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@
2929
"react-native": false
3030
},
3131
"dependencies": {
32-
"@babel/runtime-corejs3": "7.12.5",
3332
"@babel/runtime": "7.12.5",
33+
"@babel/runtime-corejs3": "7.12.5",
34+
"idb-keyval": "5.0.2",
3435
"react-native-crypto-js": "1.0.0",
3536
"uuid": "3.4.0",
3637
"ws": "7.4.2",

src/IndexedDBStorageController.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* @flow
3+
*/
4+
5+
import { createStore, del, set, get, clear, keys } from 'idb-keyval';
6+
7+
try {
8+
const ParseStore = createStore('parseDB', 'parseStore');
9+
10+
const IndexedDBStorageController = {
11+
async: 1,
12+
getItemAsync(path: string) {
13+
return get(path, ParseStore);
14+
},
15+
setItemAsync(path: string, value: string) {
16+
return set(path, value, ParseStore);
17+
},
18+
removeItemAsync(path: string) {
19+
return del(path, ParseStore);
20+
},
21+
getAllKeysAsync() {
22+
return keys(ParseStore);
23+
},
24+
clear() {
25+
return clear(ParseStore);
26+
},
27+
};
28+
29+
module.exports = IndexedDBStorageController;
30+
} catch (e) {
31+
// IndexedDB not supported
32+
}

src/Parse.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ Parse.Storage = require('./Storage');
226226
Parse.User = require('./ParseUser').default;
227227
Parse.LiveQuery = require('./ParseLiveQuery').default;
228228
Parse.LiveQueryClient = require('./LiveQueryClient').default;
229+
Parse.IndexedDB = require('./IndexedDBStorageController');
229230

230231
Parse._request = function (...args) {
231232
return CoreManager.getRESTController().request.apply(null, args);

src/__tests__/Parse-test.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,4 +200,12 @@ describe('Parse module', () => {
200200
it('_encode', () => {
201201
expect(Parse._encode(12)).toBe(12);
202202
});
203+
204+
it('can get IndexedDB storage', () => {
205+
console.log(Parse.IndexedDB);
206+
expect(Parse.IndexedDB).toBeDefined();
207+
CoreManager.setStorageController(Parse.IndexedDB);
208+
const currentStorage = CoreManager.getStorageController();
209+
expect(currentStorage).toEqual(Parse.IndexedDB);
210+
});
203211
});

src/__tests__/Storage-test.js

Lines changed: 45 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -10,43 +10,16 @@
1010
jest.autoMockOff();
1111

1212
const mockRNStorageInterface = require('./test_helpers/mockRNStorage');
13+
const mockStorageInterface = require('./test_helpers/mockStorageInteface');
14+
const mockIndexedDB = require('./test_helpers/mockIndexedDB');
1315
const mockWeChat = require('./test_helpers/mockWeChat');
1416
const CoreManager = require('../CoreManager');
1517

1618
global.wx = mockWeChat;
17-
18-
let mockStorage = {};
19-
const mockStorageInterface = {
20-
getItem(path) {
21-
return mockStorage[path] || null;
22-
},
23-
24-
getItemAsync(path) {
25-
return Promise.resolve(mockStorageInterface.getItem(path));
26-
},
27-
28-
setItem(path, value) {
29-
mockStorage[path] = value;
30-
},
31-
32-
setItemAsync(path, value) {
33-
return Promise.resolve(mockStorageInterface.setItem(path, value));
34-
},
35-
36-
removeItem(path) {
37-
delete mockStorage[path];
38-
},
39-
40-
removeItemAsync(path) {
41-
return Promise.resolve(mockStorageInterface.removeItem(path));
42-
},
43-
44-
clear() {
45-
mockStorage = {};
46-
},
47-
};
48-
4919
global.localStorage = mockStorageInterface;
20+
jest.mock('idb-keyval', () => {
21+
return mockIndexedDB;
22+
});
5023

5124
const BrowserStorageController = require('../StorageController.browser');
5225

@@ -192,6 +165,46 @@ describe('React Native StorageController', () => {
192165
});
193166
});
194167

168+
const IndexedDBStorageController = require('../IndexedDBStorageController');
169+
170+
describe('React Native StorageController', () => {
171+
beforeEach(() => {
172+
IndexedDBStorageController.clear();
173+
});
174+
175+
it('is asynchronous', () => {
176+
expect(IndexedDBStorageController.async).toBe(1);
177+
expect(typeof IndexedDBStorageController.getItemAsync).toBe('function');
178+
expect(typeof IndexedDBStorageController.setItemAsync).toBe('function');
179+
expect(typeof IndexedDBStorageController.removeItemAsync).toBe('function');
180+
});
181+
182+
it('can store and retrieve values', async () => {
183+
let result = await IndexedDBStorageController.getItemAsync('myKey');
184+
expect(result).toBe(null);
185+
await IndexedDBStorageController.setItemAsync('myKey', 'myValue');
186+
result = await IndexedDBStorageController.getItemAsync('myKey');
187+
expect(result).toBe('myValue');
188+
});
189+
190+
it('can remove values', async () => {
191+
await IndexedDBStorageController.setItemAsync('myKey', 'myValue');
192+
let result = await IndexedDBStorageController.getItemAsync('myKey');
193+
expect(result).toBe('myValue');
194+
await IndexedDBStorageController.removeItemAsync('myKey');
195+
result = await IndexedDBStorageController.getItemAsync('myKey');
196+
expect(result).toBe(null);
197+
});
198+
199+
it('can getAllKeys', async () => {
200+
await IndexedDBStorageController.setItemAsync('myKey', 'myValue');
201+
const result = await IndexedDBStorageController.getItemAsync('myKey');
202+
expect(result).toBe('myValue');
203+
const keys = await IndexedDBStorageController.getAllKeysAsync();
204+
expect(keys[0]).toBe('myKey');
205+
});
206+
});
207+
195208
const DefaultStorageController = require('../StorageController.default');
196209

197210
describe('Default StorageController', () => {
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* Copyright (c) 2015-present, Parse, LLC.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
let mockStorage = {};
10+
const mockStorageInterface = {
11+
createStore() {},
12+
13+
async get(path) {
14+
return mockStorage[path] || null;
15+
},
16+
17+
async set(path, value) {
18+
mockStorage[path] = value;
19+
},
20+
21+
async del(path) {
22+
delete mockStorage[path];
23+
},
24+
25+
async keys() {
26+
return Object.keys(mockStorage);
27+
},
28+
29+
async clear() {
30+
mockStorage = {};
31+
},
32+
};
33+
34+
module.exports = mockStorageInterface;
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* Copyright (c) 2015-present, Parse, LLC.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
let mockStorage = {};
10+
const mockStorageInterface = {
11+
getItem(path) {
12+
return mockStorage[path] || null;
13+
},
14+
15+
getItemAsync(path) {
16+
return Promise.resolve(mockStorageInterface.getItem(path));
17+
},
18+
19+
setItem(path, value) {
20+
mockStorage[path] = value;
21+
},
22+
23+
setItemAsync(path, value) {
24+
return Promise.resolve(mockStorageInterface.setItem(path, value));
25+
},
26+
27+
removeItem(path) {
28+
delete mockStorage[path];
29+
},
30+
31+
removeItemAsync(path) {
32+
return Promise.resolve(mockStorageInterface.removeItem(path));
33+
},
34+
35+
clear() {
36+
mockStorage = {};
37+
},
38+
};
39+
module.exports = mockStorageInterface;

0 commit comments

Comments
 (0)