Browse Source

feat: add a service for easily querying lists

pull/3956/head
Arman Ozak 6 years ago
parent
commit
2d694e9e39
  1. 1
      npm/ng-packs/packages/core/src/lib/services/index.ts
  2. 96
      npm/ng-packs/packages/core/src/lib/services/list.service.ts
  3. 150
      npm/ng-packs/packages/core/src/lib/tests/list.service.spec.ts

1
npm/ng-packs/packages/core/src/lib/services/index.ts

@ -4,6 +4,7 @@ export * from './config-state.service';
export * from './content-projection.service';
export * from './dom-insertion.service';
export * from './lazy-load.service';
export * from './list.service';
export * from './localization.service';
export * from './profile-state.service';
export * from './profile.service';

96
npm/ng-packs/packages/core/src/lib/services/list.service.ts

@ -0,0 +1,96 @@
import { Inject, Injectable, Optional } from '@angular/core';
import { BehaviorSubject, Observable, ReplaySubject } from 'rxjs';
import { debounceTime, shareReplay, switchMap, tap } from 'rxjs/operators';
import { ABP } from '../models/common';
import { LIST_QUERY_DEBOUNCE_TIME } from '../tokens/list.token';
import { takeUntilDestroy } from '../utils/rxjs-utils';
@Injectable()
export class ListService {
private _filter = '';
set filter(value: string) {
this._filter = value;
this.get();
}
get filter(): string {
return this._filter;
}
private _maxResultCount = 10;
set maxResultCount(value: number) {
this._maxResultCount = value;
this.get();
}
get maxResultCount(): number {
return this._maxResultCount;
}
private _page = 1;
set page(value: number) {
this._page = value;
this.get();
}
get page(): number {
return this._page;
}
private _sortKey = '';
set sortKey(value: string) {
console.log(value);
this._sortKey = value;
this.get();
}
get sortKey(): string {
return this._sortKey;
}
private _sortOrder = '';
set sortOrder(value: string) {
this._sortOrder = value;
this.get();
}
get sortOrder(): string {
return this._sortOrder;
}
private _query$ = new ReplaySubject<ABP.PageQueryParams>(1);
get query$(): Observable<ABP.PageQueryParams> {
return this._query$
.asObservable()
.pipe(debounceTime(this.delay || 300), shareReplay({ bufferSize: 1, refCount: true }));
}
private _isLoading$ = new BehaviorSubject(false);
get isLoading$(): Observable<boolean> {
return this._isLoading$.asObservable();
}
constructor(@Optional() @Inject(LIST_QUERY_DEBOUNCE_TIME) private delay: number) {
this.get();
}
get() {
this._query$.next({
filter: this._filter || undefined,
maxResultCount: this._maxResultCount,
skipCount: (this._page - 1) * this._maxResultCount,
sorting: this._sortOrder ? `${this._sortKey} ${this._sortOrder}` : undefined,
});
}
hookToQuery<T extends any>(streamCreatorCallback: QueryStreamCreatorCallback<T>): Observable<T> {
this._isLoading$.next(true);
return this.query$.pipe(
switchMap(streamCreatorCallback),
tap(() => this._isLoading$.next(false)),
takeUntilDestroy(this),
);
}
ngOnDestroy() {}
}
export type QueryStreamCreatorCallback<T> = (query: ABP.PageQueryParams) => Observable<T>;

150
npm/ng-packs/packages/core/src/lib/tests/list.service.spec.ts

@ -0,0 +1,150 @@
import { createServiceFactory, SpectatorService } from '@ngneat/spectator/jest';
import { of } from 'rxjs';
import { bufferCount, take } from 'rxjs/operators';
import { ListService } from '../services/list.service';
import { LIST_QUERY_DEBOUNCE_TIME } from '../tokens';
describe('ListService', () => {
let spectator: SpectatorService<ListService>;
let service: ListService;
const createService = createServiceFactory({
service: ListService,
providers: [
{
provide: LIST_QUERY_DEBOUNCE_TIME,
useValue: 0,
},
],
});
beforeEach(() => {
spectator = createService();
service = spectator.service;
});
describe('#filter', () => {
it('should initially be empty string', () => {
expect(service.filter).toBe('');
});
it('should be changed', () => {
service.filter = 'foo';
expect(service.filter).toBe('foo');
});
});
describe('#maxResultCount', () => {
it('should initially be 10', () => {
expect(service.maxResultCount).toBe(10);
});
it('should be changed', () => {
service.maxResultCount = 20;
expect(service.maxResultCount).toBe(20);
});
});
describe('#page', () => {
it('should initially be 1', () => {
expect(service.page).toBe(1);
});
it('should be changed', () => {
service.page = 9;
expect(service.page).toBe(9);
});
});
describe('#sortKey', () => {
it('should initially be empty string', () => {
expect(service.sortKey).toBe('');
});
it('should be changed', () => {
service.sortKey = 'foo';
expect(service.sortKey).toBe('foo');
});
});
describe('#sortOrder', () => {
it('should initially be empty string', () => {
expect(service.sortOrder).toBe('');
});
it('should be changed', () => {
service.sortOrder = 'foo';
expect(service.sortOrder).toBe('foo');
});
});
describe('#query$', () => {
it('should initially emit default query', done => {
service.query$.pipe(take(1)).subscribe(query => {
expect(query).toEqual({
filter: undefined,
maxResultCount: 10,
skipCount: 0,
sorting: undefined,
});
done();
});
});
it('should emit a query based on params set', done => {
service.filter = 'foo';
service.sortKey = 'bar';
service.sortOrder = 'baz';
service.maxResultCount = 20;
service.page = 9;
service.query$.pipe(take(1)).subscribe(query => {
expect(query).toEqual({
filter: 'foo',
sorting: 'bar baz',
maxResultCount: 20,
skipCount: 160,
});
done();
});
});
});
describe('#hookToQuery', () => {
it('should call given callback with the query', done => {
const callback = query => of(query);
service.hookToQuery(callback).subscribe(query => {
expect(query).toEqual({
filter: undefined,
maxResultCount: 10,
skipCount: 0,
sorting: undefined,
});
done();
});
});
it('should emit isLoading as side effect', done => {
const callback = query => of(query);
service.isLoading$.pipe(bufferCount(3)).subscribe(([idle, init, end]) => {
expect(idle).toBe(false);
expect(init).toBe(true);
expect(end).toBe(false);
done();
});
service.hookToQuery(callback).subscribe();
});
});
});
Loading…
Cancel
Save