Skip to content

Commit 6be5040

Browse files
committed
feat(with-storage-sync): wip add local and session storage services
1 parent 91080d2 commit 6be5040

File tree

10 files changed

+124
-61
lines changed

10 files changed

+124
-61
lines changed

apps/demo/src/app/todo-storage-sync/synced-todo-store.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { patchState, signalStore, withHooks, withMethods } from '@ngrx/signals';
1+
import { patchState, signalStore, withMethods } from '@ngrx/signals';
22
import {
33
withEntities,
44
setEntity,
@@ -33,11 +33,11 @@ export const SyncedTodoStore = signalStore(
3333
);
3434
},
3535
};
36-
}),
37-
withHooks({
38-
// onInit(store, todoService = inject(TodoService)) {
39-
// const todos = todoService.getData();
40-
// todos.forEach((todo) => store.add(todo));
41-
// },
4236
})
37+
//withHooks({
38+
// onInit(store, todoService = inject(TodoService)) {
39+
// const todos = todoService.getData();
40+
// todos.forEach((todo) => store.add(todo));
41+
// },
42+
//})
4343
);

libs/ngrx-toolkit/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,7 @@ export * from './lib/with-undo-redo';
1919
export * from './lib/with-data-service';
2020
export * from './lib/with-pagination';
2121
export { withReset, setResetState } from './lib/with-reset';
22+
//export { withStorage } from './lib/storage-sync/features/with-storage';
23+
export { withIndexeddb } from './lib/storage-sync/features/with-indexeddb';
2224
export { withStorageSync, SyncConfig } from './lib/with-storage-sync';
2325
export { withImmutableState } from './lib/immutable-state/with-immutable-state';
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { IndexedDBService } from '../internal/indexeddb.service';
2+
import { StorageServiceFactory } from '../internal/storage.service';
3+
4+
export const withIndexeddb: () => StorageServiceFactory = () => {
5+
return () => IndexedDBService;
6+
};
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { StorageServiceFactory } from '../internal/storage.service';
2+
import { LocalStorageService } from '../internal/local-storage.service';
3+
4+
export const withLocalStorage: () => StorageServiceFactory = () => {
5+
return () => LocalStorageService;
6+
};
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { StorageServiceFactory } from '../internal/storage.service';
2+
import { SessionStorageService } from '../internal/session-storage.service';
3+
4+
export const withSessionStorage: () => StorageServiceFactory = () => {
5+
return () => SessionStorageService;
6+
};

libs/ngrx-toolkit/src/lib/storage-sync/internal/indexeddb.service.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Injectable } from '@angular/core';
2+
import { StorageService } from './storage.service';
23

34
export const dbName: string = 'ngrxToolkit' as const;
45

@@ -7,7 +8,7 @@ export const keyPath: string = 'ngrxToolkitId' as const;
78
export const VERSION: number = 1 as const;
89

910
@Injectable({ providedIn: 'root' })
10-
export class IndexedDBService {
11+
export class IndexedDBService implements StorageService {
1112
/**
1213
* open indexedDB
1314
* @param storeName
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { Injectable } from '@angular/core';
2+
import { StorageService } from './storage.service';
3+
4+
@Injectable({
5+
providedIn: 'root',
6+
})
7+
export class LocalStorageService implements StorageService {
8+
async getItem(key: string): Promise<string | null> {
9+
return localStorage.getItem(key);
10+
}
11+
12+
async setItem(key: string, data: string): Promise<void> {
13+
return localStorage.setItem(key, data);
14+
}
15+
16+
async clear(key: string): Promise<void> {
17+
return localStorage.removeItem(key);
18+
}
19+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { Injectable } from '@angular/core';
2+
import { StorageService } from './storage.service';
3+
4+
@Injectable({
5+
providedIn: 'root',
6+
})
7+
export class SessionStorageService implements StorageService {
8+
async getItem(key: string): Promise<string | null> {
9+
return sessionStorage.getItem(key);
10+
}
11+
12+
async setItem(key: string, data: string): Promise<void> {
13+
return sessionStorage.setItem(key, data);
14+
}
15+
16+
async clear(key: string): Promise<void> {
17+
return sessionStorage.removeItem(key);
18+
}
19+
}
Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,9 @@
1-
import { Injectable } from '@angular/core';
1+
import { Type } from '@angular/core';
22

3-
@Injectable({
4-
providedIn: 'root',
5-
})
6-
export class StorageService {
7-
// get item from storage(localStorage, sessionStorage)
8-
async getItem(storage: Storage, key: string): Promise<string | null> {
9-
return storage.getItem(key);
10-
}
11-
12-
// set item in storage(localStorage, sessionStorage)
13-
async setItem(storage: Storage, key: string, value: string): Promise<void> {
14-
return storage.setItem(key, value);
15-
}
16-
17-
// remove item from storage(localStorage, sessionStorage)
18-
async clear(storage: Storage, key: string): Promise<void> {
19-
return storage.removeItem(key);
20-
}
3+
export interface StorageService {
4+
clear(key: string): Promise<void>;
5+
getItem(key: string): Promise<string | null>;
6+
setItem(key: string, data: string): Promise<void>;
217
}
8+
9+
export type StorageServiceFactory = () => Type<StorageService>;

libs/ngrx-toolkit/src/lib/with-storage-sync.ts

Lines changed: 50 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import {
1616
SignalStoreFeatureResult,
1717
EmptyFeatureResult,
1818
} from '@ngrx/signals';
19+
import { withIndexeddb } from './storage-sync/features/with-indexeddb';
20+
import { StorageServiceFactory } from './storage-sync/internal/storage.service';
1921

2022
const NOOP = () => Promise.resolve();
2123

@@ -81,14 +83,22 @@ export type SyncConfig<State> = {
8183
export function withStorageSync<Input extends SignalStoreFeatureResult>(
8284
key: string
8385
): SignalStoreFeature<Input, WithStorageSyncFeatureResult>;
86+
8487
export function withStorageSync<Input extends SignalStoreFeatureResult>(
8588
config: SyncConfig<Input['state']>
8689
): SignalStoreFeature<Input, WithStorageSyncFeatureResult>;
90+
91+
export function withStorageSync<Input extends SignalStoreFeatureResult>(
92+
config: SyncConfig<Input['state']>,
93+
StorageServiceClass: StorageServiceFactory
94+
): SignalStoreFeature<Input, WithStorageSyncFeatureResult>;
95+
8796
export function withStorageSync<
8897
State extends object,
8998
Input extends SignalStoreFeatureResult
9099
>(
91-
configOrKey: SyncConfig<Input['state']> | string
100+
configOrKey: SyncConfig<Input['state']> | string,
101+
StorageServiceClass: StorageServiceFactory = withIndexeddb()
92102
): SignalStoreFeature<Input, WithStorageSyncFeatureResult> {
93103
const {
94104
key,
@@ -100,41 +110,47 @@ export function withStorageSync<
100110
} = typeof configOrKey === 'string' ? { key: configOrKey } : configOrKey;
101111

102112
return signalStoreFeature(
103-
withMethods((store, platformId = inject(PLATFORM_ID)) => {
104-
if (isPlatformServer(platformId)) {
105-
console.warn(
106-
`'withStorageSync' provides non-functional implementation due to server-side execution`
107-
);
108-
return StorageSyncStub;
109-
}
113+
withMethods(
114+
(
115+
store,
116+
platformId = inject(PLATFORM_ID),
117+
storageService = inject(StorageServiceClass)
118+
) => {
119+
if (isPlatformServer(platformId)) {
120+
console.warn(
121+
`'withStorageSync' provides non-functional implementation due to server-side execution`
122+
);
123+
return StorageSyncStub;
124+
}
110125

111-
const storage = storageFactory();
126+
const storage = storageFactory();
112127

113-
return {
114-
/**
115-
* Removes the item stored in storage.
116-
*/
117-
async clearStorage(): Promise<void> {
118-
storage.removeItem(key);
119-
},
120-
/**
121-
* Reads item from storage and patches the state.
122-
*/
123-
async readFromStorage(): Promise<void> {
124-
const stateString = storage.getItem(key);
125-
if (stateString) {
126-
patchState(store, parse(stateString));
127-
}
128-
},
129-
/**
130-
* Writes selected portion to storage.
131-
*/
132-
async writeToStorage(): Promise<void> {
133-
const slicedState = select(getState(store) as State);
134-
storage.setItem(key, stringify(slicedState));
135-
},
136-
};
137-
}),
128+
return {
129+
/**
130+
* Removes the item stored in storage.
131+
*/
132+
async clearStorage(): Promise<void> {
133+
storage.removeItem(key);
134+
},
135+
/**
136+
* Reads item from storage and patches the state.
137+
*/
138+
async readFromStorage(): Promise<void> {
139+
const stateString = storage.getItem(key);
140+
if (stateString) {
141+
patchState(store, parse(stateString));
142+
}
143+
},
144+
/**
145+
* Writes selected portion to storage.
146+
*/
147+
async writeToStorage(): Promise<void> {
148+
const slicedState = select(getState(store) as State);
149+
storage.setItem(key, stringify(slicedState));
150+
},
151+
};
152+
}
153+
),
138154
withHooks({
139155
onInit(
140156
store,

0 commit comments

Comments
 (0)