Skip to content

Commit 9f93cbd

Browse files
committed
refactor(example): remove @ngrx/db
add localStorage replacement
1 parent 78e237c commit 9f93cbd

File tree

11 files changed

+297
-80
lines changed

11 files changed

+297
-80
lines changed

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@
9494
"@angular/router": "^7.0.1",
9595
"@applitools/eyes-cypress": "^3.4.12",
9696
"@bazel/buildifier": "^0.22.0",
97-
"@ngrx/db": "^2.2.0-beta.0",
9897
"core-js": "^2.5.4",
9998
"hammerjs": "^2.0.8",
10099
"opencollective": "^1.0.3",

projects/example-app-cypress/integration/round-trip.spec.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,34 @@
1+
let LOCAL_STORAGE_MEMORY = {};
2+
3+
Cypress.Commands.add('saveLocalStorage', () => {
4+
Object.keys(localStorage).forEach(key => {
5+
LOCAL_STORAGE_MEMORY[key] = localStorage[key];
6+
});
7+
});
8+
9+
Cypress.Commands.add('restoreLocalStorage', () => {
10+
Object.keys(LOCAL_STORAGE_MEMORY).forEach(key => {
11+
localStorage.setItem(key, LOCAL_STORAGE_MEMORY[key]);
12+
});
13+
});
14+
115
context('Full round trip', () => {
216
before(() => {
317
(cy as any).eyesOpen({
418
appName: 'books_app',
519
testName: 'round-trip',
620
browser: { width: 800, height: 600 },
721
});
8-
window.indexedDB.deleteDatabase('books_app');
22+
window.localStorage.removeItem('books_app');
923
cy.visit('/');
1024
});
25+
beforeEach(() => {
26+
(cy as any).restoreLocalStorage();
27+
});
1128

29+
afterEach(() => {
30+
(cy as any).saveLocalStorage();
31+
});
1232
after(() => {
1333
(cy as any).eyesClose();
1434
});

projects/example-app/README.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33
Example application utilizing @ngrx libraries, showcasing common patterns and best practices. Try it on [StackBlitz](https://ngrx.github.io/platform/stackblitz.html).
44

55
This app is a book collection manager. The user can authenticate, use the Google Books API to search for
6-
books and add them to their collection. This application utilizes [@ngrx/db](https://github.com/ngrx/db)
7-
to persist the collection across sessions; [@ngrx/store](../../docs/store/README.md) to manage
6+
books and add them to their collection. This application utilizes [@ngrx/store](../../docs/store/README.md to manage
87
the state of the app and to cache requests made to the Google Books API;
98
[@ngrx/effects](../../docs/effects/README.md) to isolate side effects; [@angular/router](https://github.com/angular/angular) to manage navigation between routes; [@angular/material](https://github.com/angular/material2) to provide design and styling.
109

@@ -17,7 +16,6 @@ Built with [@angular/cli](https://github.com/angular/angular-cli)
1716
- [@ngrx/router-store](../../docs/router-store/README.md) - Bindings to connect the Angular Router to @ngrx/store
1817
- [@ngrx/entity](../../docs/entity/README.md) - Entity State adapter for managing record collections.
1918
- [@ngrx/store-devtools](../../docs/store-devtools/README.md) - Instrumentation for @ngrx/store enabling time-travel debugging
20-
- [@ngrx/db](https://github.com/ngrx/db) - RxJS powered IndexedDB for Angular apps
2119
- [@angular/router](https://github.com/angular/angular) - Angular Router
2220
- [@angular/material](https://github.com/angular/material2) - Angular Material
2321
- [jest](https://facebook.github.io/jest/) - JavaScript test runner with easy setup, isolated browser testing and snapshot testing

projects/example-app/src/app/app.module.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,13 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
66

77
import { StoreModule } from '@ngrx/store';
88
import { EffectsModule } from '@ngrx/effects';
9-
import { DBModule } from '@ngrx/db';
109
import { StoreRouterConnectingModule } from '@ngrx/router-store';
1110
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
1211

1312
import { CoreModule } from '@example-app/core/core.module';
1413
import { AuthModule } from '@example-app/auth/auth.module';
1514

1615
import { reducers, metaReducers } from '@example-app/reducers';
17-
import { schema } from '@example-app/db';
1816

1917
import { AppComponent } from '@example-app/core/containers/app.component';
2018
import { AppRoutingModule } from '@example-app/app-routing.module';
@@ -68,12 +66,6 @@ import { AppRoutingModule } from '@example-app/app-routing.module';
6866
*/
6967
EffectsModule.forRoot([]),
7068

71-
/**
72-
* `provideDB` sets up @ngrx/db with the provided schema and makes the Database
73-
* service available.
74-
*/
75-
DBModule.provideDB(schema),
76-
7769
CoreModule,
7870
],
7971
bootstrap: [AppComponent],

projects/example-app/src/app/books/effects/collection.effects.spec.ts

Lines changed: 38 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,24 @@
11
import { TestBed } from '@angular/core/testing';
2-
import { Database } from '@ngrx/db';
32
import { Actions } from '@ngrx/effects';
43
import { provideMockActions } from '@ngrx/effects/testing';
54
import { cold, hot } from 'jasmine-marbles';
6-
import { empty, Observable } from 'rxjs';
5+
import { Observable } from 'rxjs';
76

87
import {
98
CollectionApiActions,
109
SelectedBookPageActions,
1110
CollectionPageActions,
1211
} from '@example-app/books/actions';
1312
import { Book } from '@example-app/books/models/book';
14-
import { CollectionEffects } from '@example-app/books/effects/collection.effects';
13+
import { CollectionEffects } from './collection.effects';
14+
import {
15+
IBookStorageService,
16+
BookStorageService,
17+
LOCAL_STORAGE_TOKEN,
18+
} from '@example-app/core/services/book-storage.service';
1519

1620
describe('CollectionEffects', () => {
17-
let db: any;
21+
let db: IBookStorageService;
1822
let effects: CollectionEffects;
1923
let actions$: Observable<any>;
2024

@@ -26,30 +30,37 @@ describe('CollectionEffects', () => {
2630
providers: [
2731
CollectionEffects,
2832
{
29-
provide: Database,
33+
provide: BookStorageService,
34+
useValue: {
35+
supported: jest.fn(),
36+
deleteStoredCollection: jest.fn(),
37+
addToCollection: jest.fn(),
38+
getCollection: jest.fn(),
39+
removeFromCollection: jest.fn(),
40+
},
41+
},
42+
{
43+
provide: LOCAL_STORAGE_TOKEN,
3044
useValue: {
31-
open: jest.fn(),
32-
query: jest.fn(),
33-
insert: jest.fn(),
34-
executeWrite: jest.fn(),
45+
removeItem: jest.fn(),
46+
setItem: jest.fn(),
47+
getItem: jest.fn(_ => JSON.stringify([])),
3548
},
3649
},
3750
provideMockActions(() => actions$),
3851
],
3952
});
4053

41-
db = TestBed.get(Database);
54+
db = TestBed.get(BookStorageService);
4255
effects = TestBed.get(CollectionEffects);
4356
actions$ = TestBed.get(Actions);
4457
});
45-
46-
describe('openDB$', () => {
47-
it('should call db.open when initially subscribed to', () => {
48-
effects.openDB$.subscribe();
49-
expect(db.open).toHaveBeenCalledWith('books_app');
58+
describe('checkStorageSupport$', () => {
59+
it('should call db.checkStorageSupport when initially subscribed to', () => {
60+
effects.checkStorageSupport$.subscribe();
61+
expect(db.supported).toHaveBeenCalled();
5062
});
5163
});
52-
5364
describe('loadCollection$', () => {
5465
it('should return a collection.LoadSuccess, with the books, on success', () => {
5566
const action = CollectionPageActions.loadCollection();
@@ -58,9 +69,9 @@ describe('CollectionEffects', () => {
5869
});
5970

6071
actions$ = hot('-a', { a: action });
61-
const response = cold('-a-b|', { a: book1, b: book2 });
62-
const expected = cold('-----c', { c: completion });
63-
db.query = jest.fn(() => response);
72+
const response = cold('-a|', { a: [book1, book2] });
73+
const expected = cold('--c', { c: completion });
74+
db.getCollection = jest.fn(() => response);
6475

6576
expect(effects.loadCollection$).toBeObservable(expected);
6677
});
@@ -73,7 +84,7 @@ describe('CollectionEffects', () => {
7384
actions$ = hot('-a', { a: action });
7485
const response = cold('-#', {}, error);
7586
const expected = cold('--c', { c: completion });
76-
db.query = jest.fn(() => response);
87+
db.getCollection = jest.fn(() => response);
7788

7889
expect(effects.loadCollection$).toBeObservable(expected);
7990
});
@@ -87,10 +98,10 @@ describe('CollectionEffects', () => {
8798
actions$ = hot('-a', { a: action });
8899
const response = cold('-b', { b: true });
89100
const expected = cold('--c', { c: completion });
90-
db.insert = jest.fn(() => response);
101+
db.addToCollection = jest.fn(() => response);
91102

92103
expect(effects.addBookToCollection$).toBeObservable(expected);
93-
expect(db.insert).toHaveBeenCalledWith('books', [book1]);
104+
expect(db.addToCollection).toHaveBeenCalledWith([book1]);
94105
});
95106

96107
it('should return a collection.AddBookFail, with the book, when the db insert throws', () => {
@@ -101,7 +112,7 @@ describe('CollectionEffects', () => {
101112
actions$ = hot('-a', { a: action });
102113
const response = cold('-#', {}, error);
103114
const expected = cold('--c', { c: completion });
104-
db.insert = jest.fn(() => response);
115+
db.addToCollection = jest.fn(() => response);
105116

106117
expect(effects.addBookToCollection$).toBeObservable(expected);
107118
});
@@ -116,12 +127,10 @@ describe('CollectionEffects', () => {
116127
actions$ = hot('-a', { a: action });
117128
const response = cold('-b', { b: true });
118129
const expected = cold('--c', { c: completion });
119-
db.executeWrite = jest.fn(() => response);
130+
db.removeFromCollection = jest.fn(() => response);
120131

121132
expect(effects.removeBookFromCollection$).toBeObservable(expected);
122-
expect(db.executeWrite).toHaveBeenCalledWith('books', 'delete', [
123-
book1.id,
124-
]);
133+
expect(db.removeFromCollection).toHaveBeenCalledWith([book1.id]);
125134
});
126135

127136
it('should return a collection.RemoveBookFail, with the book, when the db insert throws', () => {
@@ -134,12 +143,10 @@ describe('CollectionEffects', () => {
134143
actions$ = hot('-a', { a: action });
135144
const response = cold('-#', {}, error);
136145
const expected = cold('--c', { c: completion });
137-
db.executeWrite = jest.fn(() => response);
146+
db.removeFromCollection = jest.fn(() => response);
138147

139148
expect(effects.removeBookFromCollection$).toBeObservable(expected);
140-
expect(db.executeWrite).toHaveBeenCalledWith('books', 'delete', [
141-
book1.id,
142-
]);
149+
expect(db.removeFromCollection).toHaveBeenCalledWith([book1.id]);
143150
});
144151
});
145152
});

projects/example-app/src/app/books/effects/collection.effects.ts

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
import { Injectable } from '@angular/core';
2-
import { Database } from '@ngrx/db';
3-
import { Actions, Effect, ofType } from '@ngrx/effects';
4-
import { Action } from '@ngrx/store';
5-
import { defer, Observable, of } from 'rxjs';
6-
import { catchError, map, mergeMap, switchMap, toArray } from 'rxjs/operators';
7-
8-
import { Book } from '@example-app/books/models/book';
92
import {
10-
SelectedBookPageActions,
11-
CollectionPageActions,
123
CollectionApiActions,
4+
CollectionPageActions,
5+
SelectedBookPageActions,
136
} from '@example-app/books/actions';
7+
import { Book } from '@example-app/books/models/book';
8+
import { BookStorageService } from '@example-app/core/services/book-storage.service';
9+
import { Actions, Effect, ofType } from '@ngrx/effects';
10+
import { Action } from '@ngrx/store';
11+
import { defer, Observable, of } from 'rxjs';
12+
import { catchError, map, mergeMap, switchMap } from 'rxjs/operators';
1413

1514
@Injectable()
1615
export class CollectionEffects {
@@ -25,16 +24,15 @@ export class CollectionEffects {
2524
* effect easier to test.
2625
*/
2726
@Effect({ dispatch: false })
28-
openDB$: Observable<any> = defer(() => {
29-
return this.db.open('books_app');
30-
});
27+
checkStorageSupport$: Observable<any> = defer(() =>
28+
this.storageService.supported()
29+
);
3130

3231
@Effect()
3332
loadCollection$: Observable<Action> = this.actions$.pipe(
3433
ofType(CollectionPageActions.loadCollection.type),
3534
switchMap(() =>
36-
this.db.query('books').pipe(
37-
toArray(),
35+
this.storageService.getCollection().pipe(
3836
map((books: Book[]) =>
3937
CollectionApiActions.loadBooksSuccess({ books })
4038
),
@@ -49,7 +47,7 @@ export class CollectionEffects {
4947
addBookToCollection$: Observable<Action> = this.actions$.pipe(
5048
ofType(SelectedBookPageActions.addBook.type),
5149
mergeMap(({ book }) =>
52-
this.db.insert('books', [book]).pipe(
50+
this.storageService.addToCollection([book]).pipe(
5351
map(() => CollectionApiActions.addBookSuccess({ book })),
5452
catchError(() => of(CollectionApiActions.addBookFailure({ book })))
5553
)
@@ -60,7 +58,7 @@ export class CollectionEffects {
6058
removeBookFromCollection$: Observable<Action> = this.actions$.pipe(
6159
ofType(SelectedBookPageActions.removeBook.type),
6260
mergeMap(({ book }) =>
63-
this.db.executeWrite('books', 'delete', [book.id]).pipe(
61+
this.storageService.removeFromCollection([book.id]).pipe(
6462
map(() => CollectionApiActions.removeBookSuccess({ book })),
6563
catchError(() => of(CollectionApiActions.removeBookFailure({ book })))
6664
)
@@ -71,6 +69,6 @@ export class CollectionEffects {
7169
private actions$: Actions<
7270
SelectedBookPageActions.SelectedBookPageActionsUnion
7371
>,
74-
private db: Database
72+
private storageService: BookStorageService
7573
) {}
7674
}

projects/example-app/src/app/core/core.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { NavItemComponent } from '@example-app/core/components/nav-item.componen
99
import { SidenavComponent } from '@example-app/core/components/sidenav.component';
1010
import { ToolbarComponent } from '@example-app/core/components/toolbar.component';
1111
import { MaterialModule } from '@example-app/material';
12+
import { LOCAL_STORAGE_PROVIDERS } from './services/book-storage.service';
1213

1314
export const COMPONENTS = [
1415
AppComponent,
@@ -21,6 +22,7 @@ export const COMPONENTS = [
2122

2223
@NgModule({
2324
imports: [CommonModule, RouterModule, MaterialModule],
25+
providers: [LOCAL_STORAGE_PROVIDERS],
2426
declarations: COMPONENTS,
2527
exports: COMPONENTS,
2628
})

0 commit comments

Comments
 (0)