UNPKG

8.65 kBPlain TextView Raw
1import { Repository, SelectQueryBuilder } from "typeorm";
2import { Request } from "express";
3
4export class Element {
5 _class: string;
6 text: string;
7}
8
9export class TableConfiguration {
10 _class: string = "";
11 ordersBy: Number[] = [];
12 header: Element[] = [];
13 data: Element[][] = [];
14
15 addClass(_class: string): TableConfiguration {
16 this._class += _class + " ";
17 return this;
18 }
19
20 addHeader(text: string, _class?: string): TableConfiguration {
21 this.header.push({ text: text, _class: _class ? _class : "" });
22 this.ordersBy.push(0);
23 return this;
24 }
25
26 addData(texts: string[], _classes?: string[]): TableConfiguration {
27 let c: Element[] = [];
28 for (let i = 0; i < texts.length; i++) {
29 c.push({
30 text: texts[i],
31 _class: _classes && _classes[i] ? _classes[i] : ""
32 });
33 }
34 this.data.push(c);
35 return this;
36 }
37}
38
39export class PaginationConfiguration {
40 total = 0;
41 pageSize = 10;
42 pageCount = 0;
43 currentPage = 0;
44 left = 0;
45 right = 0;
46 maxPages = 2;
47 _class: string = "";
48
49 calculate() {
50 this.pageCount = Math.ceil(this.total / this.pageSize);
51 this.left = Math.max(0, this.currentPage - this.maxPages);
52 this.right = Math.min(
53 this.pageCount,
54 this.currentPage + 1 + this.maxPages
55 );
56 }
57
58 addClass(_class: string): PaginationConfiguration {
59 this._class += _class + " ";
60 return this;
61 }
62}
63
64export class DatatableConfiguration {
65 private table: TableConfiguration = new TableConfiguration();
66 private repository: Repository<any>;
67 private req: Request;
68 protected urlNoPage: string;
69 protected urlNoOrder: string;
70 protected urlNoPageNoOrder: string;
71 protected urlNoFilter: string;
72 private map: string[];
73 private _classes: string[] = [];
74 private mapTransformers: any = {};
75 private pagination: PaginationConfiguration = new PaginationConfiguration();
76 private alias: string = "e";
77
78 constructor(repository: Repository<any>, req: Request, alias?: string) {
79 this.repository = repository;
80 this.req = req;
81 this.setupPageRequested();
82 this.urlNoPage = getUrlWithoutPage(this.req);
83 this.urlNoOrder = getUrlWithoutOrder(this.req);
84 this.urlNoPageNoOrder = getUrlWithoutPageOrOrder(this.req);
85 this.urlNoFilter = getUrlWithoutFilter(this.req);
86 if (alias) {
87 this.alias = alias;
88 }
89 }
90
91 public setPageSize(size: number) {
92 this.pagination.pageSize = size;
93 }
94
95 public addTableClass(_class: string): DatatableConfiguration {
96 this.table.addClass(_class);
97 return this;
98 }
99
100 public addTableHeader(
101 text: string,
102 _class?: string
103 ): DatatableConfiguration {
104 this.table.addHeader(text, _class);
105 return this;
106 }
107
108 public addDataMap(
109 map: string[],
110 _classes?: string[]
111 ): DatatableConfiguration {
112 this.map = map;
113 if (_classes) {
114 this._classes = _classes;
115 } else {
116 this._classes = [];
117 for (let i = 0; i < this.map.length; i++) {
118 this._classes.push("");
119 }
120 }
121 return this;
122 }
123
124 public addDataTransformer(
125 label: string,
126 exe: (value: any, entity: any) => any
127 ): DatatableConfiguration {
128 this.mapTransformers[label] = exe;
129 return this;
130 }
131
132 public addPaginationClass(_class: string): DatatableConfiguration {
133 this.pagination.addClass(_class);
134 return this;
135 }
136
137 private setupPageRequested() {
138 this.pagination.currentPage = 0;
139 if (this.req.query.page) {
140 this.pagination.currentPage = Number(this.req.query.page);
141 if (this.pagination.currentPage > 0) {
142 this.pagination.currentPage -= 1;
143 }
144 }
145 }
146
147 private getQueryValue(key: string): any[] {
148 for (let q in this.req.query) {
149 if (q.toLowerCase() !== key) {
150 continue;
151 }
152 if (this.req.query[q] instanceof Array) {
153 return this.req.query[q];
154 }
155 return [this.req.query[q]];
156 }
157 return [];
158 }
159
160 private addOrderBy(
161 query: SelectQueryBuilder<any>
162 ): SelectQueryBuilder<any> {
163 let ordersBy = this.getQueryValue("orderby");
164 if (ordersBy.length > 0) {
165 let order = ordersBy[0].split(":");
166 this.setOrderBy(order[0], order[1]);
167 query = query.orderBy(
168 this.alias + "." + order[0],
169 order[1] == "desc" ? "DESC" : "ASC"
170 );
171 for (let i = 1; i < ordersBy.length; i++) {
172 let order = ordersBy[i].split(":");
173 this.setOrderBy(order[0], order[1]);
174 query = query.addOrderBy(
175 this.alias + "." + order[0],
176 order[1] == "desc" ? "DESC" : "ASC"
177 );
178 }
179 }
180 return query;
181 }
182
183 private setOrderBy(column: string, order: string) {
184 for (let i = 0; i < this.map.length; i++) {
185 if (this.map[i] == column) {
186 this.table.ordersBy[i] = order == "desc" ? -1 : 1;
187 }
188 }
189 }
190
191 private addFilterBy(
192 query: SelectQueryBuilder<any>
193 ): SelectQueryBuilder<any> {
194 let filtersBy = this.getQueryValue("filterby");
195 if (filtersBy.length) {
196 let f = filtersBy[0].split(":");
197 let o: any = {};
198 o[f[0] + "_" + 0] = f[1];
199 query = query.where(this.alias + "." + f[0] + " = :" + f[0] + "_" + 0, o);
200 for (let i = 1; i < filtersBy.length; i++) {
201 let f = filtersBy[i].split(":");
202 let o: any = {};
203 o[f[0] + "_" + i] = f[1];
204 query = query.andWhere(
205 this.alias + "." + f[0] + " = :" + f[0] + "_" + i,
206 o
207 );
208 }
209 }
210 return query;
211 }
212
213 public async fetchData(query?: SelectQueryBuilder<any>): Promise<void> {
214 if (!query) {
215 let select: string[] = [];
216 this.map.forEach(v => {
217 if (!v.startsWith(":")) {
218 select.push(this.alias + "." + v.replace("-", ""));
219 }
220 });
221 query = this.repository.createQueryBuilder(this.alias).select(select);
222 }
223
224 query = this.addFilterBy(query);
225
226 this.pagination.total = await query.getCount();
227 this.pagination.calculate();
228
229 query = this.addOrderBy(query);
230
231 let skip = this.pagination.currentPage * this.pagination.pageSize;
232 query = query.skip(skip).take(this.pagination.pageSize);
233
234 let result = await query.getMany();
235
236 for (let r of result) {
237 let line: string[] = [];
238 for (let label of this.map) {
239 if (label.startsWith("-")) continue;
240 let cell = r[label];
241 if (this.mapTransformers[label]) {
242 cell = this.mapTransformers[label](cell, r);
243 }
244 line.push(cell);
245 }
246 this.table.addData(line, this._classes);
247 }
248 }
249}
250
251function getUrlWithoutPage(req: Request): string {
252 return getUrlWithoutParameter(req, ["page"]);
253}
254
255function getUrlWithoutOrder(req: Request): string {
256 return getUrlWithoutParameter(req, ["orderby"]);
257}
258
259function getUrlWithoutPageOrOrder(req: Request): string {
260 return getUrlWithoutParameter(req, ["orderby", "page"]);
261}
262
263function getUrlWithoutFilter(req: Request): string {
264 return getUrlWithoutParameter(req, ["filter", "filterby"]);
265}
266
267function getUrlWithoutParameter(req: Request, parameters: string[]): string {
268 let u = (req.baseUrl + req.path).replace(/\/$/, "") + "?";
269 for (let key in req.query) {
270 var found = false;
271 for (let p of parameters) {
272 if (key.toLowerCase() == p) {
273 found = true;
274 break;
275 }
276 }
277 if (found) {
278 continue;
279 }
280 u += generateQueryValue(key, req.query[key]);
281 }
282 return u;
283}
284
285function generateQueryValue(key: string, q: any): string {
286 let m = key + "=";
287 if (q instanceof Array) {
288 m += q[0] + "&";
289 for (let i = 1; i < q.length; i++) {
290 m += key + "=" + q[i] + "&";
291 }
292 return m;
293 }
294 return m + q + "&";
295}