Pagination 分页

一般情况下,可用数据库操作进行分页。本篇仅以实现分页为演示,来进行 RxJS 操作说明。

一些无关紧要的类型定义:

export class Cat {
  id: number;
  name: string;
  age: number;
  breed: string;
}

export class PaginatorQueryDto {
  readonly limit?: number = 10;
  readonly offset?: number = 0;
}

export class CatPaginatorDto extends PaginatorQueryDto {
  readonly name?: string;
  readonly age?: number;
  readonly breed?: string;
}

实现部分代码:

import { from, iif, of, forkJoin, Observable } from 'rxjs';
import { mergeMap } from 'rxjs/operators';

pagination({ limit = 10, offset = 0, age, name = '', breed = '' }: CatPaginatorDto): Observable<{items: Cat[]}> {
  const items = from(Promise.resolve([
    // 模拟数据
    { id: 1, name: 'Kitty1', age: 1, breed: 'string' },
    { id: 2, name: 'Kitty2', age: 1, breed: 'string' },
    { id: 3, name: 'Kitty3', age: 1, breed: 'string' },
    { id: 4, name: 'Kitty4', age: 2, breed: 'string' },
    { id: 5, name: 'Kitty5', age: 2, breed: 'string' },
    { id: 6, name: 'Kitty6', age: 2, breed: 'string2' }
  ])).pipe(
    // 此处也仅用于作为 rxjs 的操作示例
    // Filter by Age
    mergeMap((cats: Cat[]) =>
      iif(
        //
        () => age >= 0,
        // Query 里的数值类型,如果没有默认值,实际为字符串类型
        of(cats.filter((cat) => `${cat.age}` === `${age}`)),
        of(cats)
      )
    ),
    // Filter by Name
    mergeMap((cats: Cat[]) =>
      iif(
        //
        () => name !== '',
        of(cats.filter((cat) => cat.name === name)),
        of(cats)
      )
    ),
    // Filter by Breed
    mergeMap((cats: Cat[]) =>
      iif(
        //
        () => breed !== '',
        of(cats.filter((cat) => cat.breed === breed)),
        of(cats)
      )
    ),
    // Pagination
    mergeMap((cats: Cat[]) => of(cats.slice(offset, offset + limit)))
  );
  return forkJoin({
    items
  });
}

其中,每个 mergeMap 都是一个独立的、特定的过滤操作,除了最后一步将结果进行分页,其他的步骤(如按类型、按年龄查询)均可以调换顺序,或者直接去除,也可以很方便地添加新的过滤字段。

在 GitHub 上编辑此页面 article.updatedAt Wed, Aug 11, 2021