File size: 2,801 Bytes
4327358
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import { IJsonQuery } from '@waha/core/storage/sql/IJsonQuery';
import { PaginationParams, SortOrder } from '@waha/structures/pagination.dto';
import * as lodash from 'lodash';

export abstract class Paginator {
  constructor(protected readonly pagination: PaginationParams) {}

  apply<T>(data: T): T {
    if (lodash.isEmpty(this.pagination)) {
      return data;
    }
    return this.limit(this.sort(data));
  }

  protected abstract sort(data: any);

  protected abstract limit(data: any);
}

export class PaginatorInMemory extends Paginator {
  protected sort(data: any[]) {
    if (!this.pagination?.sortBy) {
      return data;
    }
    return lodash.orderBy(
      data,
      [this.NullLast(this.pagination.sortBy)],
      [this.pagination.sortOrder || 'asc'],
    );
  }

  protected limit(data: any[]) {
    if (!this.pagination?.limit) {
      return data;
    }
    const offset = this.pagination.offset || 0;
    const limit = this.pagination.limit || Infinity;
    return data.slice(offset, offset + limit);
  }

  NullLast(field) {
    return (item) => {
      const value = item?.[field];
      if (value == null) {
        return -Infinity;
      }
      return value;
    };
  }
}

export class KnexPaginator extends Paginator {
  indexes: string[] = [];
  dataField: string = 'data';

  constructor(
    pagination: PaginationParams,
    protected jsonQuery: IJsonQuery,
  ) {
    super(pagination);
  }

  protected sort(query: any) {
    if (!this.pagination?.sortBy) {
      return query;
    }
    const sortBy = this.pagination.sortBy;
    const direction = this.pagination.sortOrder || SortOrder.ASC;
    if (this.indexes.includes(sortBy)) {
      return query.orderBy(sortBy, direction);
    }

    // Make sure to sanitize sortBy to prevent SQL injection
    // sqlite3 doesn't support binding for column names and direction
    const sql = this.jsonQuery.sortBy(this.dataField, sortBy, direction);
    return query.orderByRaw(sql);
  }

  protected limit(query: any) {
    const limit = this.pagination.limit;
    const offset = this.pagination.offset;
    if (limit != null) {
      query = query.limit(limit);
    }
    if (offset != null) {
      query = query.offset(offset);
    }
    return query;
  }
}

export class MongoPaginator extends Paginator {
  protected sort(query: any) {
    if (!this.pagination?.sortBy) {
      return query;
    }
    const mongoDirection = this.pagination.sortOrder === 'asc' ? 1 : -1;
    return query.sort({ [this.pagination.sortBy]: mongoDirection });
  }

  protected limit(query: any) {
    const limit = this.pagination.limit;
    const offset = this.pagination.offset;
    if (limit != null) {
      query = query.limit(limit);
    }
    if (offset != null) {
      query = query.skip(offset);
    }
    return query;
  }
}