Skip to content

Commit 6e41926

Browse files
authored
refactor: upgrade rxdb (#47)
- move dump functionality to custom plugin to utilize rxdb hooks - remove decorator and use plain async on all collection methods, wait with `lastValueFrom` - remove config object, introduce function to create full config - remove custom pipe, use `ngrxLet` in demo application - remove pouchdb dependencies, fix tests, add plugin tests - add more tests, fix coverage exclude - update rxdb to v15 beta - add info, count, missing bulk methods - add clear method - remove separate interface for service, add doc strings - provide utils with namespace, simplify logger utility - allow logs to be enabled on prod - handle storage "migration" problem
1 parent 72bab67 commit 6e41926

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+3017
-3061
lines changed

.eslintrc.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
],
1414
"parser": "@typescript-eslint/parser",
1515
"parserOptions": {
16-
"project": "tsconfig.json",
16+
"project": "tsconfig.base.json",
1717
"sourceType": "module"
1818
},
1919
"plugins": [
@@ -45,7 +45,7 @@
4545
"jsdoc/require-returns-type": 0,
4646
"jsdoc/require-returns-description": 0,
4747
"jsdoc/require-jsdoc": [
48-
1,
48+
0,
4949
{
5050
"contexts": [
5151
"TSEnumDeclaration",

.github/workflows/main.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ jobs:
5757
- name: Install
5858
run: npm ci
5959
- name: Lint & Test
60-
run: npm run packages:lint && npm run packages:test
60+
run: npm run lint && npm run test
6161
env:
6262
CI: true
6363
# Save coverage report in Coveralls
@@ -72,7 +72,7 @@ jobs:
7272
# Build if release published
7373
- name: Build
7474
# if: github.event.release.published
75-
run: npm run packages:build
75+
run: npm run build
7676
- name: Archive production artifacts
7777
uses: actions/upload-artifact@v2
7878
with:

examples/demo/project.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@
3636
"maximumError": "4kb"
3737
}
3838
],
39-
"outputHashing": "all"
39+
"outputHashing": "all",
40+
"vendorChunk": true
4041
},
4142
"development": {
4243
"buildOptimizer": false,

examples/demo/src/app/app.module.ts

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,11 @@
11
import { NgModule } from '@angular/core';
22
import { BrowserModule } from '@angular/platform-browser';
3+
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
34
import { RouterModule, Routes } from '@angular/router';
4-
import { NgxRxdbConfig } from '@ngx-odm/rxdb/config';
55
import { NgxRxdbModule } from '@ngx-odm/rxdb';
6+
import { getRxDatabaseCreator } from '@ngx-odm/rxdb/config';
67
import { AppComponent } from './app.component';
78

8-
/** NgxRxdbConfig extends RxDatabaseCreator, will be merged with default config */
9-
const APP_RXDB_CONFIG: NgxRxdbConfig = {
10-
name: 'demo', // <- name (required, 'ngx')
11-
adapter: 'idb', // <- storage-adapter (required, default: 'idb')
12-
multiInstance: true,
13-
options: {
14-
// dumpPath: 'assets/data/db.dump.json', // <- remote url (optional)
15-
},
16-
};
17-
189
const routes: Routes = [
1910
{
2011
path: 'todos',
@@ -31,8 +22,20 @@ const routes: Routes = [
3122
declarations: [AppComponent],
3223
imports: [
3324
BrowserModule,
25+
BrowserAnimationsModule,
3426
RouterModule.forRoot(routes),
35-
NgxRxdbModule.forRoot(APP_RXDB_CONFIG),
27+
NgxRxdbModule.forRoot(
28+
getRxDatabaseCreator({
29+
name: 'demo',
30+
localDocuments: true,
31+
multiInstance: true,
32+
ignoreDuplicate: false,
33+
options: {
34+
storageType: localStorage['_ngx_rxdb_storage'] ?? 'dexie',
35+
dumpPath: 'assets/data/db.dump.json',
36+
},
37+
})
38+
),
3639
],
3740
providers: [],
3841
bootstrap: [AppComponent],

examples/demo/src/app/todos/components/todos/todos.component.html

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
<!-- https://angular.io/guide/template-typecheck#disabling-type-checking-using-any -->
22
<section
33
class="todoapp"
4-
*ngxLet="{
5-
todos: todos$ | asyncNoZone,
6-
count: count$ | async,
7-
remainig: remainig$ | async,
8-
filter: filter$ | async
4+
*ngrxLet="{
5+
todos: todos$,
6+
count: count$,
7+
filter: filter$
98
} as $"
109
>
1110
<header class="header">
@@ -15,7 +14,7 @@ <h1>todos</h1>
1514
placeholder="What needs to be done?"
1615
autofocus=""
1716
[(ngModel)]="newTodo"
18-
(keyup)="newTodoChange($event.target.value)"
17+
(keyup)="newTodoChange($any($event.target).value)"
1918
(keyup.enter)="!isAddTodoDisabled && addTodo()"
2019
(keyup.escape)="newTodoClear()"
2120
/>
@@ -30,9 +29,9 @@ <h1>todos</h1>
3029
[checked]="(filter$ | async) === 'ALL'"
3130
(click)="filterTodos('')"
3231
/> -->
33-
<ul class="todo-list">
32+
<ul [@listAnimation]="$.todos?.length" class="todo-list">
3433
<li
35-
*ngFor="let todo of $.todos"
34+
*ngFor="let todo of $.todos | byStatus: $.filter; trackBy: trackByFn"
3635
[class.completed]="todo.completed"
3736
[class.editing]="isEditing === todo.id"
3837
>
@@ -59,10 +58,14 @@ <h1>todos</h1>
5958
</li>
6059
</ul>
6160
</main>
62-
<footer class="footer" [hidden]="$.count === 0">
63-
<ng-container *ngIf="showRemainig($.remainig)">
64-
<span class="todo-count" [ngPlural]="$.remainig">
65-
<ng-template ngPluralCase="other">{{ $.remainig }} items left</ng-template>
61+
<footer
62+
class="footer"
63+
[hidden]="$.count === 0"
64+
*ngrxLet="($.todos | byStatus: 'ACTIVE')?.length; let remainig"
65+
>
66+
<ng-container *ngIf="showRemainig(remainig)">
67+
<span class="todo-count" [ngPlural]="remainig">
68+
<ng-template ngPluralCase="other">{{ remainig }} items left</ng-template>
6669
<ng-template ngPluralCase="=1">one item left</ng-template>
6770
<ng-template ngPluralCase="=0">no items left</ng-template>
6871
</span>
@@ -98,11 +101,11 @@ <h1>todos</h1>
98101
</ul>
99102
<button
100103
class="clear-completed"
101-
[disabled]="$.todos?.length - $.remainig < $.todos?.length"
104+
[disabled]="$.todos?.length - remainig < $.todos?.length"
102105
(click)="removeCompletedTodos()"
103106
style="z-index: 3"
104107
>
105-
Clear completed ({{ $.todos?.length - $.remainig }})
108+
Clear completed ({{ $.todos?.length - remainig }})
106109
</button>
107110
</footer>
108111
</section>

examples/demo/src/app/todos/components/todos/todos.component.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,46 @@
1+
import { trigger, transition, query, style, stagger, animate } from '@angular/animations';
12
import {
23
ChangeDetectionStrategy,
34
ChangeDetectorRef,
45
Component,
5-
ElementRef,
66
OnInit,
77
} from '@angular/core';
88
import { Observable } from 'rxjs';
99
import { Todo, TodosFilter } from '../../models';
1010
import { TodosService } from '../../services';
1111

12+
const listAnimation = trigger('listAnimation', [
13+
transition('* <=> *', [
14+
query(
15+
':enter',
16+
[
17+
style({ opacity: 0 }),
18+
stagger('100ms', animate('250ms ease-out', style({ opacity: 1 }))),
19+
],
20+
{ optional: true }
21+
),
22+
query(':leave', animate('250ms', style({ opacity: 0 })), { optional: true }),
23+
]),
24+
]);
25+
1226
@Component({
1327
selector: 'demo-todos',
1428
templateUrl: './todos.component.html',
1529
styleUrls: ['./todos.component.css'],
1630
changeDetection: ChangeDetectionStrategy.OnPush,
31+
animations: [listAnimation],
1732
})
1833
export class TodosComponent implements OnInit {
1934
filter$ = this.todosService.filter$;
20-
todos$: Observable<Todo[]> = this.todosService.select();
35+
todos$: Observable<Todo[]> = this.todosService.todos$;
2136
count$ = this.todosService.count$;
22-
remainig$: Observable<number> = this.todosService.remaining$;
2337
newTodo = '';
2438
isEditing = '';
2539

40+
trackByFn(index: number, item: Todo) {
41+
return item.id;
42+
}
43+
2644
constructor(
2745
private todosService: TodosService,
2846
private cdRef: ChangeDetectorRef
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { Pipe, PipeTransform } from '@angular/core';
2+
import { Todo, TodosFilter, TodosState } from '../../models';
3+
4+
@Pipe({ name: 'byStatus' })
5+
export class TodosPipe implements PipeTransform {
6+
transform(value: Todo[], status: TodosFilter): Todo[] {
7+
if (!value) {
8+
return value;
9+
}
10+
if (status === 'ALL') {
11+
return value;
12+
}
13+
return value.filter(todo => todo.completed === (status === 'COMPLETED'));
14+
}
15+
}

examples/demo/src/app/todos/models/todos.model.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export interface TodosState {
1212
filter: TodosFilter;
1313
}
1414

15-
export const initialState: TodosState = {
15+
export const TODOS_INITIAL_STATE: TodosState = {
1616
items: [
1717
{
1818
id: 'ac3ef2c6-c98b-43e1-9047-71d68b1f92f4',
Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { NgxRxdbCollectionConfig } from '@ngx-odm/rxdb/config';
2-
import { RxCollection } from 'rxdb';
3-
import { initialState } from './todos.model';
1+
import type { RxCollectionCreatorExtended } from '@ngx-odm/rxdb/config';
2+
import type { RxCollection } from 'rxdb';
3+
import { TODOS_INITIAL_STATE } from './todos.model';
44

55
export async function percentageCompletedFn() {
66
const allDocs = await (this as RxCollection).find().exec();
@@ -10,12 +10,13 @@ const collectionMethods = {
1010
percentageCompleted: percentageCompletedFn,
1111
};
1212

13-
export const TODOS_COLLECTION_CONFIG: NgxRxdbCollectionConfig = {
13+
export const TODOS_COLLECTION_CONFIG: RxCollectionCreatorExtended = {
1414
name: 'todo',
15-
// schema: todoSchema,
15+
localDocuments: true,
1616
statics: collectionMethods,
17+
schema: null,
1718
options: {
1819
schemaUrl: 'assets/data/todo.schema.json',
19-
initialDocs: initialState.items,
20+
initialDocs: TODOS_INITIAL_STATE.items,
2021
},
2122
};

examples/demo/src/app/todos/services/todos.service.ts

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,23 @@ import { Title } from '@angular/platform-browser';
55
import { NgxRxdbCollection, NgxRxdbCollectionService } from '@ngx-odm/rxdb/collection';
66
import { MangoQuery } from 'rxdb/dist/types/types';
77
import { Observable } from 'rxjs';
8-
import { distinctUntilChanged, startWith, switchMap, map, tap } from 'rxjs/operators';
8+
import { distinctUntilChanged, startWith, switchMap, tap } from 'rxjs/operators';
99
import { v4 as uuid } from 'uuid';
1010
import { Todo, TodosFilter } from '../models';
1111

1212
@Injectable()
1313
export class TodosService {
14-
filter$ = this.collectionService
14+
filter$: Observable<TodosFilter> = this.collectionService
1515
.getLocal('local', 'filterValue')
16-
.pipe(startWith('ALL'), distinctUntilChanged());
16+
.pipe(startWith('ALL'), distinctUntilChanged()) as Observable<TodosFilter>;
1717

1818
count$ = this.collectionService.count();
1919

20-
remaining$: Observable<number> = this.collectionService.docs().pipe(
21-
map(docs => {
20+
todos$: Observable<Todo[]> = this.collectionService.docs().pipe(
21+
tap(docs => {
2222
const total = docs.length;
2323
const remaining = docs.filter(doc => !doc.completed).length;
24-
2524
this.title.setTitle(`(${total - remaining}/${total}) Todos done`);
26-
27-
return remaining;
2825
})
2926
);
3027

@@ -34,11 +31,6 @@ export class TodosService {
3431
private title: Title
3532
) {}
3633

37-
async getCount() {
38-
const count = await this.collectionService.collection?.['countAllDocuments']?.();
39-
return count;
40-
}
41-
4234
select(completedOnly = false): Observable<Todo[]> {
4335
const queryObj = this.buildQueryObject(completedOnly);
4436
return this.filter$.pipe(
@@ -100,12 +92,8 @@ export class TodosService {
10092

10193
private buildQueryObject(completedOnly: boolean): MangoQuery<Todo> {
10294
const queryObj: MangoQuery<Todo> = {
103-
selector: {
104-
createdAt: {
105-
$gt: null,
106-
},
107-
},
108-
sort: [{ createdAt: 'desc' } as any],
95+
selector: {},
96+
sort: [{ createdAt: 'desc' }],
10997
};
11098
if (completedOnly) {
11199
Object.assign(queryObj.selector, {

0 commit comments

Comments
 (0)