From a548a4022531e107f22e82d76eb6abb1ca0b1d34 Mon Sep 17 00:00:00 2001 From: DaddyWarbucks Date: Fri, 20 May 2022 22:35:41 -0500 Subject: [PATCH 1/3] Add support for strictStorage --- README.md | 3 ++- lib/index.js | 30 ++++++++++++++++++++---- test/index.test.js | 58 ++++++++++++++++++++++++++++++++++++++++++++++ types/index.d.ts | 3 +++ 4 files changed, 88 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 4edd216..7f550ce 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ app.use('/messages', service({ storage, id, startId, name, store, paginate })); __Options:__ - `storage` (**required**) - The local storage engine. You can pass in the browsers `window.localStorage`, React Native's `AsyncStorage` or a NodeJS localstorage module. -- `throttle` (*optional*, default `200`) - The minimum time (ms) before in-memory data is written to `storage`. Data is only written if changed since last write. +- `throttle` (*optional*, default `200`) - The minimum time (ms) before in-memory data is written to `storage`. - `id` (*optional*, default: `'id'`) - The name of the id field property. - `startId` (*optional*, default: `0`) - An id number to start with that will be incremented for new record. - `name` (*optional*, default: `'feathers'`) - The key to store data under in local or async storage. @@ -43,6 +43,7 @@ __Options:__ - `whitelist` (*optional*) - A list of additional query parameters to allow. - `multi` (*optional*) - Allow `create` with arrays and `update` and `remove` with `id` `null` to change multiple items. Can be `true` for all methods or an array of allowed methods (e.g. `[ 'remove', 'create' ]`). - `reuseKeys` (*optional*, default: `false`) Allow duplicate keys i.e. last definition wins. Mostly useful for demonstration and testing purposes. +- `strictStorage` (*optional*, default false) - When false, all storage data is held in memory after initialization. When true, the storage data is get/set on each method. ## Example diff --git a/lib/index.js b/lib/index.js index 85da79c..73c857a 100644 --- a/lib/index.js +++ b/lib/index.js @@ -8,6 +8,7 @@ class LocalStorage extends Service { this._storageKey = options.name || 'feathers'; this._storage = options.storage || (typeof window !== 'undefined' && window.localStorage); this._throttle = options.throttle || 200; + this._strictStorage = options.strictStorage || false; this._reuseKeys = options.reuseKeys || false; this.store = null; @@ -28,8 +29,8 @@ class LocalStorage extends Service { ready () { if (!this.store) { - return Promise.resolve(this._storage.getItem(this._storageKey)) - .then(str => JSON.parse(str || '{}')) + return Promise.resolve(this.getStorage()) + .then(store => store || {}) .then(store => { const keys = Object.keys(store); const last = store[keys[keys.length - 1]]; @@ -47,8 +48,11 @@ class LocalStorage extends Service { flush (data) { if (!this._timeout) { this._timeout = setTimeout(() => { - this._storage.setItem(this._storageKey, JSON.stringify(this.store)); + this.setStorage(this.store); delete this._timeout; + if (this._strictStorage) { + this.store = null; + } }, this._throttle); } @@ -61,11 +65,13 @@ class LocalStorage extends Service { } find (...args) { - return this.execute('find', ...args); + return this.execute('find', ...args) + .then(data => this._strictStorage ? this.flush(data) : data); } get (...args) { - return this.execute('get', ...args); + return this.execute('get', ...args) + .then(data => this._strictStorage ? this.flush(data) : data); } create (...args) { @@ -87,6 +93,20 @@ class LocalStorage extends Service { return this.execute('remove', ...args) .then(data => this.flush(data)); } + + getStorage(id) { + const storage = this._storage.getItem(this._storageKey); + const store = storage ? JSON.parse(storage) : null; + if (id && store) { + return store[id] || null; + } + return store; + } + + setStorage(store) { + this._storage.setItem(this._storageKey, JSON.stringify(store)); + return store; + } } module.exports = function init (options) { diff --git a/test/index.test.js b/test/index.test.js index 0fdf2a1..969eab4 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -205,6 +205,64 @@ describe('Feathers Localstorage Service', () => { done(); }); + it('clears memory when using strictStorage', () => { + const name = 'test-storage-8'; + + storage.setItem(name, '{ "0": { "id": 0, "text": "test 0" } }'); + + const app = feathers() + .use('/messages', service({ name, storage, strictStorage: true })); + + return app.service('messages').find() + .then(() => { + return new Promise((resolve) => { + setTimeout(() => { + assert.notStrictEqual(app.service('messages').store, null); + resolve(); + }, 100); + }); + }) + .then(() => { + return new Promise((resolve) => { + setTimeout(() => { + assert.strictEqual(app.service('messages').store, null); + resolve(); + }, 150); + }); + }); + }); + + it('sets data in storage manually', (done) => { + const name = 'test-storage-9'; + const data = { "0": { "id": 0, "text": "test 0" }}; + const app = feathers() + .use('/messages', service({ name, storage })); + + app.service('messages').setStorage(data); + const storageData = JSON.parse(storage.getItem(name)); + + assert.deepStrictEqual(data, storageData); + + done(); + }); + + it('gets data from storage manually', (done) => { + const name = 'test-storage-10'; + const data = { "0": { "id": 0, "text": "test 0" }}; + const app = feathers() + .use('/messages', service({ name, storage })); + + storage.setItem(name, JSON.stringify(data)); + + const storageData = app.service('messages').getStorage(); + assert.deepStrictEqual(data, storageData); + + const itemData = app.service('messages').getStorage("0"); + assert.deepStrictEqual(itemData, storageData["0"]); + + done(); + }); + testSuite(app, errors, 'people'); testSuite(app, errors, 'people-customid', 'customid'); }); diff --git a/types/index.d.ts b/types/index.d.ts index 34866fc..caac283 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -6,6 +6,7 @@ import { Service as MemoryService, MemoryServiceOptions, MemoryServiceStore } fr export interface LocalStorageServiceOptions extends MemoryServiceOptions { name: string; throttle: number; + strictStorage: boolean; } export class Service extends MemoryService { @@ -13,6 +14,8 @@ export class Service extends MemoryService { ready(): Promise; flush(data?: any): any; + setStorage(store: MemoryServiceStore): MemoryServiceStore; + getStorage(id?: any): MemoryServiceStore | any; } declare const localstorage: ((config?: Partial) => Service); From 89c0af1a7dac6624e12a3f3eb24de6e8c86b8b78 Mon Sep 17 00:00:00 2001 From: DaddyWarbucks Date: Fri, 20 May 2022 22:36:15 -0500 Subject: [PATCH 2/3] npm run lint --- lib/index.js | 4 ++-- test/index.test.js | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/index.js b/lib/index.js index 73c857a..b750e7e 100644 --- a/lib/index.js +++ b/lib/index.js @@ -94,7 +94,7 @@ class LocalStorage extends Service { .then(data => this.flush(data)); } - getStorage(id) { + getStorage (id) { const storage = this._storage.getItem(this._storageKey); const store = storage ? JSON.parse(storage) : null; if (id && store) { @@ -103,7 +103,7 @@ class LocalStorage extends Service { return store; } - setStorage(store) { + setStorage (store) { this._storage.setItem(this._storageKey, JSON.stringify(store)); return store; } diff --git a/test/index.test.js b/test/index.test.js index 969eab4..a64800e 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -234,7 +234,7 @@ describe('Feathers Localstorage Service', () => { it('sets data in storage manually', (done) => { const name = 'test-storage-9'; - const data = { "0": { "id": 0, "text": "test 0" }}; + const data = { 0: { id: 0, text: 'test 0' } }; const app = feathers() .use('/messages', service({ name, storage })); @@ -248,7 +248,7 @@ describe('Feathers Localstorage Service', () => { it('gets data from storage manually', (done) => { const name = 'test-storage-10'; - const data = { "0": { "id": 0, "text": "test 0" }}; + const data = { 0: { id: 0, text: 'test 0' } }; const app = feathers() .use('/messages', service({ name, storage })); @@ -257,8 +257,8 @@ describe('Feathers Localstorage Service', () => { const storageData = app.service('messages').getStorage(); assert.deepStrictEqual(data, storageData); - const itemData = app.service('messages').getStorage("0"); - assert.deepStrictEqual(itemData, storageData["0"]); + const itemData = app.service('messages').getStorage('0'); + assert.deepStrictEqual(itemData, storageData['0']); done(); }); From 26c9cd9c7e74acff78c96500aeab06bdce1da8b4 Mon Sep 17 00:00:00 2001 From: DaddyWarbucks Date: Thu, 22 Sep 2022 16:47:38 -0500 Subject: [PATCH 3/3] Remove unneeded code --- lib/index.js | 20 +++----------------- test/index.test.js | 31 ------------------------------- types/index.d.ts | 2 -- 3 files changed, 3 insertions(+), 50 deletions(-) diff --git a/lib/index.js b/lib/index.js index b750e7e..5c02f75 100644 --- a/lib/index.js +++ b/lib/index.js @@ -29,8 +29,8 @@ class LocalStorage extends Service { ready () { if (!this.store) { - return Promise.resolve(this.getStorage()) - .then(store => store || {}) + return Promise.resolve(this._storage.getItem(this._storageKey)) + .then(str => JSON.parse(str || '{}')) .then(store => { const keys = Object.keys(store); const last = store[keys[keys.length - 1]]; @@ -48,7 +48,7 @@ class LocalStorage extends Service { flush (data) { if (!this._timeout) { this._timeout = setTimeout(() => { - this.setStorage(this.store); + this._storage.setItem(this._storageKey, JSON.stringify(this.store)); delete this._timeout; if (this._strictStorage) { this.store = null; @@ -93,20 +93,6 @@ class LocalStorage extends Service { return this.execute('remove', ...args) .then(data => this.flush(data)); } - - getStorage (id) { - const storage = this._storage.getItem(this._storageKey); - const store = storage ? JSON.parse(storage) : null; - if (id && store) { - return store[id] || null; - } - return store; - } - - setStorage (store) { - this._storage.setItem(this._storageKey, JSON.stringify(store)); - return store; - } } module.exports = function init (options) { diff --git a/test/index.test.js b/test/index.test.js index a64800e..06dec19 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -232,37 +232,6 @@ describe('Feathers Localstorage Service', () => { }); }); - it('sets data in storage manually', (done) => { - const name = 'test-storage-9'; - const data = { 0: { id: 0, text: 'test 0' } }; - const app = feathers() - .use('/messages', service({ name, storage })); - - app.service('messages').setStorage(data); - const storageData = JSON.parse(storage.getItem(name)); - - assert.deepStrictEqual(data, storageData); - - done(); - }); - - it('gets data from storage manually', (done) => { - const name = 'test-storage-10'; - const data = { 0: { id: 0, text: 'test 0' } }; - const app = feathers() - .use('/messages', service({ name, storage })); - - storage.setItem(name, JSON.stringify(data)); - - const storageData = app.service('messages').getStorage(); - assert.deepStrictEqual(data, storageData); - - const itemData = app.service('messages').getStorage('0'); - assert.deepStrictEqual(itemData, storageData['0']); - - done(); - }); - testSuite(app, errors, 'people'); testSuite(app, errors, 'people-customid', 'customid'); }); diff --git a/types/index.d.ts b/types/index.d.ts index caac283..e092096 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -14,8 +14,6 @@ export class Service extends MemoryService { ready(): Promise; flush(data?: any): any; - setStorage(store: MemoryServiceStore): MemoryServiceStore; - getStorage(id?: any): MemoryServiceStore | any; } declare const localstorage: ((config?: Partial) => Service);