From 50ca3e7da4977c0403f5fd89434e73c3c72d2bae Mon Sep 17 00:00:00 2001 From: Aaron Steinfeld Date: Thu, 7 Apr 2022 15:26:25 -0400 Subject: [PATCH 1/3] refactor: allow async config for storage --- projects/common/src/public-api.ts | 1 + .../browser/storage/abstract-storage.test.ts | 32 ++++++++++++------- .../browser/storage/abstract-storage.ts | 15 ++++++--- .../browser/storage/local-storage.ts | 9 +++--- .../browser/storage/session-storage.ts | 9 +++--- 5 files changed, 43 insertions(+), 23 deletions(-) diff --git a/projects/common/src/public-api.ts b/projects/common/src/public-api.ts index 8de3d2296..fff90aebd 100644 --- a/projects/common/src/public-api.ts +++ b/projects/common/src/public-api.ts @@ -9,6 +9,7 @@ export { DynamicComponentService } from './utilities/angular/dynamic-component.s // Browser export { CookieService } from './utilities/browser/cookies/cookie.service'; export { LocalStorage } from './utilities/browser/storage/local-storage'; +export * from './utilities/browser/storage/abstract-storage'; // Coercers export * from './utilities/coercers/boolean-coercer'; diff --git a/projects/common/src/utilities/browser/storage/abstract-storage.test.ts b/projects/common/src/utilities/browser/storage/abstract-storage.test.ts index 6cb87f972..c72d872cf 100644 --- a/projects/common/src/utilities/browser/storage/abstract-storage.test.ts +++ b/projects/common/src/utilities/browser/storage/abstract-storage.test.ts @@ -1,4 +1,5 @@ import { runFakeRxjs } from '@hypertrace/test-utils'; +import { of } from 'rxjs'; import { AbstractStorage } from './abstract-storage'; import { DictionaryStorageImpl } from './dictionary-storage-impl'; @@ -38,9 +39,12 @@ describe('Abstract storage', () => { test('should support scoped storage with no fallback', () => { const globalDictionary = new DictionaryStorageImpl({ foo: 'bad-foo' }); - const scopedStorage = new (class extends AbstractStorage {})(globalDictionary, { - scopeKey: 'test-scope' - }); + const scopedStorage = new (class extends AbstractStorage {})( + globalDictionary, + of({ + scopeKey: 'test-scope' + }) + ); expect(scopedStorage.get('foo')).toBeUndefined(); expect(scopedStorage.contains('foo')).toBe(false); @@ -58,10 +62,13 @@ describe('Abstract storage', () => { test('should support scoped storage with readonly fallback', () => { const globalDictionary = new DictionaryStorageImpl({ foo: 'original-foo' }); - const scopedStorage = new (class extends AbstractStorage {})(globalDictionary, { - scopeKey: 'test-scope', - fallbackPolicy: 'read-only' - }); + const scopedStorage = new (class extends AbstractStorage {})( + globalDictionary, + of({ + scopeKey: 'test-scope', + fallbackPolicy: 'read-only' + }) + ); expect(scopedStorage.get('foo')).toBe('original-foo'); expect(scopedStorage.contains('foo')).toBe(true); @@ -77,10 +84,13 @@ describe('Abstract storage', () => { test('should migrate on read if configured', () => { const globalDictionary = new DictionaryStorageImpl({ foo: 'original-foo' }); - const scopedStorage = new (class extends AbstractStorage {})(globalDictionary, { - scopeKey: 'test-scope', - fallbackPolicy: 'read-and-migrate' - }); + const scopedStorage = new (class extends AbstractStorage {})( + globalDictionary, + of({ + scopeKey: 'test-scope', + fallbackPolicy: 'read-and-migrate' + }) + ); expect(scopedStorage.get('foo')).toBe('original-foo'); expect(scopedStorage.contains('foo')).toBe(true); diff --git a/projects/common/src/utilities/browser/storage/abstract-storage.ts b/projects/common/src/utilities/browser/storage/abstract-storage.ts index 4be4bcf1e..01e4e14a4 100644 --- a/projects/common/src/utilities/browser/storage/abstract-storage.ts +++ b/projects/common/src/utilities/browser/storage/abstract-storage.ts @@ -5,11 +5,18 @@ import { DictionaryStorageImpl } from './dictionary-storage-impl'; // A small abstraction on browser's storage for mocking and cleaning up the API a bit export abstract class AbstractStorage { private readonly changeSubject: Subject = new Subject(); - private readonly scopedStorage?: DictionaryStorageImpl; + private scopeConfig?: ScopedStorageConfiguration; + private scopedStorage?: DictionaryStorageImpl; - public constructor(private readonly storage: Storage, private readonly scopeConfig?: ScopedStorageConfiguration) { - if (scopeConfig) { - this.scopedStorage = DictionaryStorageImpl.fromString(storage.getItem(scopeConfig.scopeKey) ?? '{}'); + public constructor( + private readonly storage: Storage, + private readonly scopeConfig$?: Observable + ) { + if (this.scopeConfig$) { + this.scopeConfig$.subscribe(scopeConfig => { + this.scopeConfig = scopeConfig; + this.scopedStorage = DictionaryStorageImpl.fromString(storage.getItem(scopeConfig.scopeKey) ?? '{}'); + }); } } diff --git a/projects/common/src/utilities/browser/storage/local-storage.ts b/projects/common/src/utilities/browser/storage/local-storage.ts index fd60fae80..e63119855 100644 --- a/projects/common/src/utilities/browser/storage/local-storage.ts +++ b/projects/common/src/utilities/browser/storage/local-storage.ts @@ -1,9 +1,10 @@ -import { Injectable } from '@angular/core'; -import { AbstractStorage } from './abstract-storage'; +import { Injectable, Optional } from '@angular/core'; +import { AbstractStorage, ScopedStorageConfiguration } from './abstract-storage'; +import { Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class LocalStorage extends AbstractStorage { - public constructor() { - super(localStorage); + public constructor(@Optional() scopeConfig$?: Observable) { + super(localStorage, scopeConfig$); } } diff --git a/projects/common/src/utilities/browser/storage/session-storage.ts b/projects/common/src/utilities/browser/storage/session-storage.ts index da1f9d1c9..a4f329e20 100644 --- a/projects/common/src/utilities/browser/storage/session-storage.ts +++ b/projects/common/src/utilities/browser/storage/session-storage.ts @@ -1,9 +1,10 @@ -import { Injectable } from '@angular/core'; -import { AbstractStorage } from './abstract-storage'; +import { Injectable, Optional } from '@angular/core'; +import { Observable } from 'rxjs'; +import { AbstractStorage, ScopedStorageConfiguration } from './abstract-storage'; @Injectable({ providedIn: 'root' }) export class SessionStorage extends AbstractStorage { - public constructor() { - super(sessionStorage); + public constructor(@Optional() scopeConfig$?: Observable) { + super(sessionStorage, scopeConfig$); } } From 1e8d30a0ca6ffa02315d4d08ff7008609b09cd69 Mon Sep 17 00:00:00 2001 From: Aaron Steinfeld Date: Thu, 7 Apr 2022 15:31:40 -0400 Subject: [PATCH 2/3] refactor: expose session storage --- projects/common/src/public-api.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/projects/common/src/public-api.ts b/projects/common/src/public-api.ts index fff90aebd..176e931e4 100644 --- a/projects/common/src/public-api.ts +++ b/projects/common/src/public-api.ts @@ -9,6 +9,7 @@ export { DynamicComponentService } from './utilities/angular/dynamic-component.s // Browser export { CookieService } from './utilities/browser/cookies/cookie.service'; export { LocalStorage } from './utilities/browser/storage/local-storage'; +export { SessionStorage } from './utilities/browser/storage/session-storage'; export * from './utilities/browser/storage/abstract-storage'; // Coercers From e6b42fd98edcc9288e6bc16fd4973b465e86197d Mon Sep 17 00:00:00 2001 From: Aaron Steinfeld Date: Thu, 7 Apr 2022 17:33:24 -0400 Subject: [PATCH 3/3] style: lint --- projects/common/src/utilities/browser/storage/local-storage.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/common/src/utilities/browser/storage/local-storage.ts b/projects/common/src/utilities/browser/storage/local-storage.ts index e63119855..0edd731f1 100644 --- a/projects/common/src/utilities/browser/storage/local-storage.ts +++ b/projects/common/src/utilities/browser/storage/local-storage.ts @@ -1,6 +1,6 @@ import { Injectable, Optional } from '@angular/core'; -import { AbstractStorage, ScopedStorageConfiguration } from './abstract-storage'; import { Observable } from 'rxjs'; +import { AbstractStorage, ScopedStorageConfiguration } from './abstract-storage'; @Injectable({ providedIn: 'root' }) export class LocalStorage extends AbstractStorage {