core-express 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/lib/GenericController.js +224 -131
- package/lib/GenericSearchController.js +58 -37
- package/lib/HealthController.js +16 -58
- package/lib/LoadController.js +71 -46
- package/lib/LoadSearchController.js +113 -41
- package/lib/LogController.js +89 -0
- package/lib/LowCodeController.js +100 -0
- package/lib/SearchController.js +32 -25
- package/lib/access.js +34 -0
- package/lib/client.js +80 -0
- package/lib/edit.js +99 -84
- package/lib/health.js +157 -76
- package/lib/http.js +316 -0
- package/lib/index.js +488 -16
- package/lib/log.js +242 -0
- package/lib/resources.js +106 -6
- package/lib/search.js +766 -160
- package/lib/view.js +48 -34
- package/package.json +8 -4
- package/src/GenericController.ts +217 -106
- package/src/GenericSearchController.ts +38 -21
- package/src/HealthController.ts +9 -9
- package/src/LoadController.ts +70 -40
- package/src/LoadSearchController.ts +114 -21
- package/src/LogController.ts +137 -0
- package/src/LowCodeController.ts +88 -0
- package/src/SearchController.ts +28 -17
- package/src/access.ts +42 -0
- package/src/client.ts +69 -0
- package/src/edit.ts +93 -61
- package/src/health.ts +27 -28
- package/src/http.ts +295 -0
- package/src/index.ts +464 -13
- package/src/log.ts +245 -0
- package/src/metadata.ts +34 -23
- package/src/resources.ts +143 -4
- package/src/search.ts +782 -198
- package/src/view.ts +44 -30
- package/tsconfig.json +1 -0
- package/lib/response.js +0 -12
- package/src/response.ts +0 -10
package/src/search.ts
CHANGED
|
@@ -1,270 +1,854 @@
|
|
|
1
|
-
import {Request, Response} from
|
|
1
|
+
import { Request, Response } from "express"
|
|
2
|
+
import { minimizeArray, query, queryNumber } from "./http"
|
|
3
|
+
import { ViewService } from "./LoadController"
|
|
4
|
+
import { Attribute, Attributes } from "./metadata"
|
|
5
|
+
import { resources, StringMap } from "./resources"
|
|
2
6
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
7
|
+
const et = ""
|
|
8
|
+
|
|
9
|
+
export interface Filter {
|
|
10
|
+
page?: number
|
|
11
|
+
limit?: number
|
|
6
12
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
sort?: string;
|
|
13
|
+
fields?: string[]
|
|
14
|
+
sort?: string
|
|
10
15
|
|
|
11
|
-
|
|
12
|
-
excluding?: ArrayMap;
|
|
16
|
+
q?: string
|
|
13
17
|
}
|
|
14
18
|
export interface SearchConfig {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
excluding?: string
|
|
20
|
+
// fields?: string
|
|
21
|
+
list?: string
|
|
22
|
+
total?: string
|
|
23
|
+
token?: string
|
|
24
|
+
// last?: string
|
|
25
|
+
csv?: boolean
|
|
26
|
+
// page?: string
|
|
27
|
+
// limit?: string
|
|
28
|
+
// skip?: string
|
|
29
|
+
// refId?: string;
|
|
30
|
+
// firstLimit?: string
|
|
20
31
|
}
|
|
21
32
|
export interface SearchResult<T> {
|
|
22
|
-
list: T[]
|
|
23
|
-
total?: number
|
|
24
|
-
|
|
33
|
+
list: T[]
|
|
34
|
+
total?: number
|
|
35
|
+
nextPageToken?: string
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function getPage<F extends Filter>(req: Request, filter?: F): number {
|
|
39
|
+
if (filter) {
|
|
40
|
+
const v0 = (filter as any)[resources.page]
|
|
41
|
+
if (v0 == undefined) {
|
|
42
|
+
const field = req.query[resources.page]
|
|
43
|
+
const v = field ? field.toString() : undefined
|
|
44
|
+
if (!v || v.length === 0) {
|
|
45
|
+
;(filter as any)[resources.page] = 1
|
|
46
|
+
return 1
|
|
47
|
+
}
|
|
48
|
+
if (isNaN(v as any)) {
|
|
49
|
+
;(filter as any)[resources.page] = 1
|
|
50
|
+
return 1
|
|
51
|
+
} else {
|
|
52
|
+
let n = parseFloat(v)
|
|
53
|
+
if (n < 1) {
|
|
54
|
+
n = 1
|
|
55
|
+
}
|
|
56
|
+
;(filter as any)[resources.page] = n
|
|
57
|
+
return n
|
|
58
|
+
}
|
|
59
|
+
} else if (typeof v0 === "number") {
|
|
60
|
+
if (v0 > 0) {
|
|
61
|
+
return v0
|
|
62
|
+
} else {
|
|
63
|
+
;(filter as any)[resources.page] = 1
|
|
64
|
+
return 1
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const field = req.query[resources.page]
|
|
69
|
+
const v = field ? field.toString() : undefined
|
|
70
|
+
if (!v || v.length === 0) {
|
|
71
|
+
if (filter) {
|
|
72
|
+
;(filter as any)[resources.page] = 1
|
|
73
|
+
}
|
|
74
|
+
return 1
|
|
75
|
+
}
|
|
76
|
+
if (isNaN(v as any)) {
|
|
77
|
+
if (filter) {
|
|
78
|
+
;(filter as any)[resources.page] = 1
|
|
79
|
+
}
|
|
80
|
+
return 1
|
|
81
|
+
}
|
|
82
|
+
let n = parseFloat(v)
|
|
83
|
+
if (n < 1) {
|
|
84
|
+
n = 1
|
|
85
|
+
}
|
|
86
|
+
if (filter) {
|
|
87
|
+
;(filter as any)[resources.page] = n
|
|
88
|
+
}
|
|
89
|
+
return n
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function getLimit<F extends Filter>(req: Request, filter?: F): number {
|
|
93
|
+
if (filter) {
|
|
94
|
+
const v0 = (filter as any)[resources.limit]
|
|
95
|
+
if (v0 == undefined) {
|
|
96
|
+
const field = req.query[resources.limit]
|
|
97
|
+
const v = field ? field.toString() : undefined
|
|
98
|
+
if (!v || v.length === 0) {
|
|
99
|
+
;(filter as any)[resources.limit] = resources.defaultLimit
|
|
100
|
+
return resources.defaultLimit
|
|
101
|
+
}
|
|
102
|
+
if (isNaN(v as any)) {
|
|
103
|
+
;(filter as any)[resources.limit] = resources.defaultLimit
|
|
104
|
+
return 1
|
|
105
|
+
} else {
|
|
106
|
+
let n = parseFloat(v)
|
|
107
|
+
if (n < 1) {
|
|
108
|
+
n = resources.defaultLimit
|
|
109
|
+
}
|
|
110
|
+
;(filter as any)[resources.limit] = n
|
|
111
|
+
return n
|
|
112
|
+
}
|
|
113
|
+
} else if (typeof v0 === "number") {
|
|
114
|
+
if (v0 > 0) {
|
|
115
|
+
return v0
|
|
116
|
+
} else {
|
|
117
|
+
;(filter as any)[resources.limit] = resources.defaultLimit
|
|
118
|
+
return resources.defaultLimit
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
const field = req.query[resources.limit]
|
|
123
|
+
const v = field ? field.toString() : undefined
|
|
124
|
+
if (!v || v.length === 0) {
|
|
125
|
+
if (filter) {
|
|
126
|
+
;(filter as any)[resources.limit] = resources.defaultLimit
|
|
127
|
+
}
|
|
128
|
+
return resources.defaultLimit
|
|
129
|
+
}
|
|
130
|
+
if (isNaN(v as any)) {
|
|
131
|
+
if (filter) {
|
|
132
|
+
;(filter as any)[resources.limit] = resources.defaultLimit
|
|
133
|
+
}
|
|
134
|
+
return resources.defaultLimit
|
|
135
|
+
}
|
|
136
|
+
let n = parseFloat(v)
|
|
137
|
+
if (n < 1) {
|
|
138
|
+
n = resources.defaultLimit
|
|
139
|
+
}
|
|
140
|
+
if (filter) {
|
|
141
|
+
;(filter as any)[resources.limit] = n
|
|
142
|
+
}
|
|
143
|
+
return n
|
|
144
|
+
}
|
|
145
|
+
export function queryLimit(req: Request): number {
|
|
146
|
+
return queryNumber(req, resources.limit, resources.defaultLimit)
|
|
147
|
+
}
|
|
148
|
+
export function queryPage<F extends Filter>(req: Request, filter?: F): number {
|
|
149
|
+
const field = req.query[resources.page]
|
|
150
|
+
const v = field ? field.toString() : undefined
|
|
151
|
+
if (!v || v.length === 0) {
|
|
152
|
+
;(filter as any)[resources.page] = 1
|
|
153
|
+
return 1
|
|
154
|
+
}
|
|
155
|
+
if (isNaN(v as any)) {
|
|
156
|
+
;(filter as any)[resources.page] = 1
|
|
157
|
+
return 1
|
|
158
|
+
}
|
|
159
|
+
const n = parseFloat(v)
|
|
160
|
+
;(filter as any)[resources.page] = n
|
|
161
|
+
return n
|
|
162
|
+
}
|
|
163
|
+
export function getOffset(limit: number, page?: number): number {
|
|
164
|
+
return !page || page <= 1 || limit <= 0 ? 0 : limit * (page - 1)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export function getPageTotal(pageSize?: number, total?: number): number {
|
|
168
|
+
if (!pageSize || pageSize <= 0) {
|
|
169
|
+
return 1
|
|
170
|
+
} else {
|
|
171
|
+
if (!total) {
|
|
172
|
+
total = 0
|
|
173
|
+
}
|
|
174
|
+
if (total % pageSize === 0) {
|
|
175
|
+
return Math.floor(total / pageSize)
|
|
176
|
+
}
|
|
177
|
+
return Math.floor(total / pageSize + 1)
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
export function formatText(...args: any[]): string {
|
|
181
|
+
let formatted = args[0]
|
|
182
|
+
if (!formatted || formatted === "") {
|
|
183
|
+
return ""
|
|
184
|
+
}
|
|
185
|
+
if (args.length > 1 && Array.isArray(args[1])) {
|
|
186
|
+
const params = args[1]
|
|
187
|
+
for (let i = 0; i < params.length; i++) {
|
|
188
|
+
const regexp = new RegExp("\\{" + i + "\\}", "gi")
|
|
189
|
+
formatted = formatted.replace(regexp, params[i])
|
|
190
|
+
}
|
|
191
|
+
} else {
|
|
192
|
+
for (let i = 1; i < args.length; i++) {
|
|
193
|
+
const regexp = new RegExp("\\{" + (i - 1) + "\\}", "gi")
|
|
194
|
+
formatted = formatted.replace(regexp, args[i])
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return formatted
|
|
198
|
+
}
|
|
199
|
+
export function buildMessage<T>(resource: StringMap, results: T[], limit: number, page: number | undefined, total?: number): string {
|
|
200
|
+
if (!results || results.length === 0) {
|
|
201
|
+
return resource.msg_no_data_found
|
|
202
|
+
} else {
|
|
203
|
+
if (!page) {
|
|
204
|
+
page = 1
|
|
205
|
+
}
|
|
206
|
+
const fromIndex = (page - 1) * limit + 1
|
|
207
|
+
const toIndex = fromIndex + results.length - 1
|
|
208
|
+
const pageTotal = getPageTotal(limit, total)
|
|
209
|
+
if (pageTotal > 1) {
|
|
210
|
+
const msg2 = formatText(resource.msg_search_result_page_sequence, fromIndex, toIndex, total, page, pageTotal)
|
|
211
|
+
return msg2
|
|
212
|
+
} else {
|
|
213
|
+
const msg3 = formatText(resource.msg_search_result_sequence, fromIndex, toIndex)
|
|
214
|
+
return msg3
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
export function buildPages(pageSize?: number, total?: number): number[] {
|
|
219
|
+
const pageTotal = getPageTotal(pageSize, total)
|
|
220
|
+
if (pageTotal <= 1) {
|
|
221
|
+
return [1]
|
|
222
|
+
}
|
|
223
|
+
const arr: number[] = []
|
|
224
|
+
for (let i = 1; i <= pageTotal; i++) {
|
|
225
|
+
arr.push(i)
|
|
226
|
+
}
|
|
227
|
+
return arr
|
|
25
228
|
}
|
|
26
229
|
|
|
230
|
+
export function hasSearch(req: Request): boolean {
|
|
231
|
+
return req.url.indexOf("?") >= 0
|
|
232
|
+
}
|
|
233
|
+
export function getSearch(url: string): string {
|
|
234
|
+
const i = url.indexOf("?")
|
|
235
|
+
return i < 0 ? et : url.substring(i + 1)
|
|
236
|
+
}
|
|
237
|
+
export function getField(search: string, fieldName: string): string {
|
|
238
|
+
let i = search.indexOf(fieldName + "=")
|
|
239
|
+
if (i < 0) {
|
|
240
|
+
return ""
|
|
241
|
+
}
|
|
242
|
+
if (i > 0) {
|
|
243
|
+
if (search.substring(i - 1, 1) != "&") {
|
|
244
|
+
i = search.indexOf("&" + fieldName + "=")
|
|
245
|
+
if (i < 0) {
|
|
246
|
+
return search
|
|
247
|
+
}
|
|
248
|
+
i = i + 1
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
const j = search.indexOf("&", i + fieldName.length)
|
|
252
|
+
return j >= 0 ? search.substring(i, j) : search.substring(i)
|
|
253
|
+
}
|
|
254
|
+
export function removeField(search: string, fieldName: string): string {
|
|
255
|
+
let i = search.indexOf(fieldName + "=")
|
|
256
|
+
if (i < 0) {
|
|
257
|
+
return search
|
|
258
|
+
}
|
|
259
|
+
if (i > 0) {
|
|
260
|
+
if (search.substring(i - 1, 1) != "&") {
|
|
261
|
+
i = search.indexOf("&" + fieldName + "=")
|
|
262
|
+
if (i < 0) {
|
|
263
|
+
return search
|
|
264
|
+
}
|
|
265
|
+
i = i + 1
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
const j = search.indexOf("&", i + fieldName.length)
|
|
269
|
+
return j >= 0 ? search.substring(0, i) + search.substring(j + 1) : search.substring(0, i - 1)
|
|
270
|
+
}
|
|
271
|
+
export function removePage(search: string): string {
|
|
272
|
+
search = removeField(search, resources.page)
|
|
273
|
+
search = removeField(search, resources.partial)
|
|
274
|
+
return search
|
|
275
|
+
}
|
|
276
|
+
export function buildPageSearch(search: string): string {
|
|
277
|
+
const sr = removePage(search)
|
|
278
|
+
return sr.length == 0 ? sr : "&" + sr
|
|
279
|
+
}
|
|
280
|
+
export function buildPageSearchFromUrl(url: string): string {
|
|
281
|
+
const search = getSearch(url)
|
|
282
|
+
return buildPageSearch(search)
|
|
283
|
+
}
|
|
284
|
+
export function removeSort(search: string): string {
|
|
285
|
+
search = removeField(search, resources.sort)
|
|
286
|
+
search = removeField(search, resources.partial)
|
|
287
|
+
return search
|
|
288
|
+
}
|
|
289
|
+
export interface Sort {
|
|
290
|
+
field?: string
|
|
291
|
+
type?: string
|
|
292
|
+
}
|
|
293
|
+
export interface SortType {
|
|
294
|
+
url: string
|
|
295
|
+
tag: string
|
|
296
|
+
}
|
|
297
|
+
export interface SortMap {
|
|
298
|
+
[key: string]: SortType
|
|
299
|
+
}
|
|
300
|
+
export function getSortString(field: string, sort: Sort): string {
|
|
301
|
+
if (field === sort.field) {
|
|
302
|
+
return sort.type === "-" ? field : "-" + field
|
|
303
|
+
}
|
|
304
|
+
return field
|
|
305
|
+
}
|
|
306
|
+
export function buildSort(s?: string): Sort {
|
|
307
|
+
if (!s || s.indexOf(",") >= 0) {
|
|
308
|
+
return {} as Sort
|
|
309
|
+
}
|
|
310
|
+
if (s.startsWith("-")) {
|
|
311
|
+
return { field: s.substring(1), type: "-" }
|
|
312
|
+
} else {
|
|
313
|
+
return { field: s.startsWith("+") ? s.substring(1) : s, type: "+" }
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
export function buildSortFromRequest(req: Request): Sort {
|
|
317
|
+
const s = query(req, resources.sort)
|
|
318
|
+
return buildSort(s)
|
|
319
|
+
}
|
|
320
|
+
export function renderSort(field: string, sort: Sort): string {
|
|
321
|
+
if (field === sort.field) {
|
|
322
|
+
return sort.type === "-" ? "<i class='sort-down'></i>" : "<i class='sort-up'></i>"
|
|
323
|
+
}
|
|
324
|
+
return et
|
|
325
|
+
}
|
|
326
|
+
export function buildSortSearch(search: string, fields: string[], sortStr?: string): SortMap {
|
|
327
|
+
const sort = buildSort(sortStr)
|
|
328
|
+
search = removeSort(search)
|
|
329
|
+
let sorts: SortMap = {}
|
|
330
|
+
const prefix = search.length > 0 ? "?" + search + "&" : "?"
|
|
331
|
+
for (let i = 0; i < fields.length; i++) {
|
|
332
|
+
sorts[fields[i]] = {
|
|
333
|
+
url: prefix + resources.sort + "=" + getSortString(fields[i], sort),
|
|
334
|
+
tag: renderSort(fields[i], sort),
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
return sorts
|
|
338
|
+
}
|
|
339
|
+
export function clone(obj: any): any {
|
|
340
|
+
if (!obj) {
|
|
341
|
+
return obj
|
|
342
|
+
}
|
|
343
|
+
if (obj instanceof Date) {
|
|
344
|
+
return new Date(obj.getTime())
|
|
345
|
+
}
|
|
346
|
+
if (typeof obj !== "object") {
|
|
347
|
+
return obj
|
|
348
|
+
}
|
|
349
|
+
if (Array.isArray(obj)) {
|
|
350
|
+
const arr = []
|
|
351
|
+
for (const sub of obj) {
|
|
352
|
+
const c = clone(sub)
|
|
353
|
+
arr.push(c)
|
|
354
|
+
}
|
|
355
|
+
return arr
|
|
356
|
+
}
|
|
357
|
+
const x: any = {}
|
|
358
|
+
const keys = Object.keys(obj)
|
|
359
|
+
for (const k of keys) {
|
|
360
|
+
const v = obj[k]
|
|
361
|
+
if (v instanceof Date) {
|
|
362
|
+
x[k] = new Date(v.getTime())
|
|
363
|
+
} else {
|
|
364
|
+
switch (typeof v) {
|
|
365
|
+
case "object":
|
|
366
|
+
x[k] = clone(v)
|
|
367
|
+
break
|
|
368
|
+
default:
|
|
369
|
+
x[k] = v
|
|
370
|
+
break
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
return x
|
|
375
|
+
}
|
|
376
|
+
export function cloneFilter<F extends Filter>(obj: F, limit: number, page: number): F {
|
|
377
|
+
const f = clone(obj)
|
|
378
|
+
if (!obj.hasOwnProperty(resources.page)) {
|
|
379
|
+
;(obj as any)[resources.page] = page
|
|
380
|
+
}
|
|
381
|
+
if (!obj.hasOwnProperty(resources.limit)) {
|
|
382
|
+
;(obj as any)[resources.limit] = limit
|
|
383
|
+
}
|
|
384
|
+
return f
|
|
385
|
+
}
|
|
386
|
+
export function addSequence<T>(list: T[], offset: number, name?: string): T[] {
|
|
387
|
+
const n = name ? name : "sequence"
|
|
388
|
+
const l = list.length
|
|
389
|
+
for (let i = 0; i < l; i++) {
|
|
390
|
+
;(list[i] as any)[n] = offset + i + 1
|
|
391
|
+
}
|
|
392
|
+
return list
|
|
393
|
+
}
|
|
27
394
|
export function jsonResult<T>(res: Response, result: SearchResult<T>, quick?: boolean, fields?: string[], config?: SearchConfig): void {
|
|
28
395
|
if (quick && fields && fields.length > 0) {
|
|
29
|
-
res.status(200).json(toCsv(fields, result))
|
|
396
|
+
res.status(200).json(toCsv(fields, result)).end()
|
|
30
397
|
} else {
|
|
31
|
-
res.status(200).json(buildResult(result, config))
|
|
398
|
+
res.status(200).json(buildResult(result, config)).end()
|
|
32
399
|
}
|
|
33
400
|
}
|
|
34
401
|
export function buildResult<T>(r: SearchResult<T>, conf?: SearchConfig): any {
|
|
35
402
|
if (!conf) {
|
|
36
|
-
return r
|
|
403
|
+
return r
|
|
37
404
|
}
|
|
38
|
-
const x: any = {}
|
|
39
|
-
|
|
40
|
-
x[
|
|
41
|
-
|
|
42
|
-
|
|
405
|
+
const x: any = {}
|
|
406
|
+
const li = conf.list ? conf.list : "list"
|
|
407
|
+
x[li] = minimizeArray(r.list)
|
|
408
|
+
const to = conf.total ? conf.total : "total"
|
|
409
|
+
x[to] = r.total
|
|
410
|
+
if (r.nextPageToken && r.nextPageToken.length > 0) {
|
|
411
|
+
const t = conf.token ? conf.token : "token"
|
|
412
|
+
x[t] = r.nextPageToken
|
|
43
413
|
}
|
|
44
|
-
return x
|
|
414
|
+
return x
|
|
45
415
|
}
|
|
46
|
-
export function initializeConfig(conf
|
|
416
|
+
export function initializeConfig(conf?: SearchConfig): SearchConfig | undefined {
|
|
47
417
|
if (!conf) {
|
|
48
|
-
return undefined
|
|
418
|
+
return undefined
|
|
49
419
|
}
|
|
50
|
-
const c = {
|
|
420
|
+
const c: SearchConfig = {
|
|
421
|
+
excluding: conf.excluding,
|
|
51
422
|
list: conf.list,
|
|
52
423
|
total: conf.total,
|
|
53
424
|
token: conf.token,
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
425
|
+
csv: conf.csv,
|
|
426
|
+
}
|
|
427
|
+
if (!c.excluding || c.excluding.length === 0) {
|
|
428
|
+
c.excluding = "excluding"
|
|
429
|
+
}
|
|
57
430
|
if (!c.list || c.list.length === 0) {
|
|
58
|
-
c.list =
|
|
431
|
+
c.list = "list"
|
|
59
432
|
}
|
|
60
433
|
if (!c.total || c.total.length === 0) {
|
|
61
|
-
c.
|
|
434
|
+
c.total = "total"
|
|
435
|
+
}
|
|
436
|
+
if (!c.token || c.token.length === 0) {
|
|
437
|
+
c.token = "nextPageToken"
|
|
438
|
+
}
|
|
439
|
+
return c
|
|
440
|
+
}
|
|
441
|
+
export function fromRequest<S>(req: Request, arr?: string[]): S {
|
|
442
|
+
const s: any = req.method === "GET" ? fromUrl(req, arr) : req.body
|
|
443
|
+
const page = s[resources.page]
|
|
444
|
+
if (page) {
|
|
445
|
+
if (isNaN(page as any)) {
|
|
446
|
+
s[resources.page] = 1
|
|
447
|
+
} else {
|
|
448
|
+
let n = parseFloat(page)
|
|
449
|
+
if (n < 1) {
|
|
450
|
+
n = 1
|
|
451
|
+
}
|
|
452
|
+
s[resources.page] = n
|
|
453
|
+
}
|
|
454
|
+
} else {
|
|
455
|
+
s[resources.page] = 1
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
const limit = s[resources.limit]
|
|
459
|
+
if (limit) {
|
|
460
|
+
if (isNaN(limit as any)) {
|
|
461
|
+
s[resources.limit] = resources.defaultLimit
|
|
462
|
+
} else {
|
|
463
|
+
let n = parseFloat(limit)
|
|
464
|
+
if (n < 1) {
|
|
465
|
+
n = resources.defaultLimit
|
|
466
|
+
}
|
|
467
|
+
s[resources.limit] = n
|
|
468
|
+
}
|
|
469
|
+
} else {
|
|
470
|
+
s[resources.limit] = resources.defaultLimit
|
|
62
471
|
}
|
|
63
|
-
if (
|
|
64
|
-
|
|
472
|
+
if (resources.partial.length > 0) {
|
|
473
|
+
delete s[resources.partial]
|
|
65
474
|
}
|
|
66
|
-
return
|
|
475
|
+
return s
|
|
67
476
|
}
|
|
68
|
-
export function
|
|
69
|
-
const
|
|
70
|
-
|
|
477
|
+
export function buildArray(arr?: string[], s0?: string, s1?: string, s2?: string): string[] {
|
|
478
|
+
const r: string[] = []
|
|
479
|
+
if (arr && arr.length > 0) {
|
|
480
|
+
for (const a of arr) {
|
|
481
|
+
r.push(a)
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
if (s0 && s0.length > 0) {
|
|
485
|
+
r.push(s0)
|
|
486
|
+
}
|
|
487
|
+
if (s1 && s1.length > 0) {
|
|
488
|
+
r.push(s1)
|
|
489
|
+
}
|
|
490
|
+
if (s2 && s2.length > 0) {
|
|
491
|
+
r.push(s2)
|
|
492
|
+
}
|
|
493
|
+
return r
|
|
71
494
|
}
|
|
72
|
-
export function
|
|
73
|
-
|
|
74
|
-
if (!
|
|
75
|
-
|
|
495
|
+
export function fromUrl<S>(req: Request, arr?: string[]): S {
|
|
496
|
+
/*
|
|
497
|
+
if (!fields || fields.length === 0) {
|
|
498
|
+
fields = 'fields';
|
|
76
499
|
}
|
|
77
|
-
|
|
500
|
+
*/
|
|
501
|
+
const s: any = {}
|
|
502
|
+
const obj = req.query
|
|
503
|
+
const keys = Object.keys(obj)
|
|
504
|
+
for (const key of keys) {
|
|
505
|
+
if (inArray(key, arr)) {
|
|
506
|
+
const x = (obj[key] as string).split(",")
|
|
507
|
+
setValue(s, key, x)
|
|
508
|
+
} else {
|
|
509
|
+
setValue(s, key, obj[key] as string)
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
return s
|
|
78
513
|
}
|
|
79
|
-
export function
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
514
|
+
export function inArray(s: string, arr?: string[]): boolean {
|
|
515
|
+
if (!arr || arr.length === 0) {
|
|
516
|
+
return false
|
|
517
|
+
}
|
|
518
|
+
for (const a of arr) {
|
|
519
|
+
if (s === a) {
|
|
520
|
+
return true
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
return false
|
|
524
|
+
}
|
|
525
|
+
/*
|
|
526
|
+
export function setValue<T>(obj: T, path: string, value: string): void {
|
|
527
|
+
const paths = path.split('.');
|
|
528
|
+
if (paths.length === 1) {
|
|
529
|
+
obj[path] = value;
|
|
530
|
+
} else {
|
|
531
|
+
let current: any = obj;
|
|
532
|
+
const l = paths.length - 1;
|
|
533
|
+
for (let i = 0; i < l; i++) {
|
|
534
|
+
const sub = paths[i];
|
|
535
|
+
if (!obj[sub]) {
|
|
536
|
+
obj[sub] = {};
|
|
89
537
|
}
|
|
538
|
+
current = obj[sub];
|
|
90
539
|
}
|
|
91
|
-
|
|
92
|
-
|
|
540
|
+
current[paths[paths.length - 1]] = value;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
*/
|
|
544
|
+
export function setValue<T, V>(o: T, key: string, value: V): any {
|
|
545
|
+
const obj: any = o
|
|
546
|
+
let replaceKey = key.replace(/\[/g, ".[").replace(/\.\./g, ".")
|
|
547
|
+
if (replaceKey.indexOf(".") === 0) {
|
|
548
|
+
replaceKey = replaceKey.slice(1, replaceKey.length)
|
|
549
|
+
}
|
|
550
|
+
const keys = replaceKey.split(".")
|
|
551
|
+
const firstKey = keys.shift()
|
|
552
|
+
if (!firstKey) {
|
|
553
|
+
return
|
|
554
|
+
}
|
|
555
|
+
const isArrayKey = /\[([0-9]+)\]/.test(firstKey)
|
|
556
|
+
if (keys.length > 0) {
|
|
557
|
+
const firstKeyValue = obj[firstKey] || {}
|
|
558
|
+
const returnValue = setValue(firstKeyValue, keys.join("."), value)
|
|
559
|
+
return setKey(obj, isArrayKey, firstKey, returnValue)
|
|
560
|
+
}
|
|
561
|
+
return setKey(obj, isArrayKey, firstKey, value)
|
|
562
|
+
}
|
|
563
|
+
const setKey = (_object: any, _isArrayKey: boolean, _key: string, _nextValue: any) => {
|
|
564
|
+
if (_isArrayKey) {
|
|
565
|
+
if (_object.length > _key) {
|
|
566
|
+
_object[_key] = _nextValue
|
|
567
|
+
} else {
|
|
568
|
+
_object.push(_nextValue)
|
|
93
569
|
}
|
|
94
|
-
|
|
570
|
+
} else {
|
|
571
|
+
_object[_key] = _nextValue
|
|
572
|
+
}
|
|
573
|
+
return _object
|
|
95
574
|
}
|
|
96
575
|
export interface Limit {
|
|
97
|
-
limit
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
if (
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
return {limit: ipageSize, skip: iskip};
|
|
119
|
-
}
|
|
576
|
+
limit: number
|
|
577
|
+
page?: number
|
|
578
|
+
nextPageToken?: string
|
|
579
|
+
fields?: string[]
|
|
580
|
+
pageOrNextPageToken?: string | number
|
|
581
|
+
}
|
|
582
|
+
export function getParameters<T>(obj: T): Limit {
|
|
583
|
+
const o: any = obj
|
|
584
|
+
let fields: string[] | undefined
|
|
585
|
+
const fs = o[resources.fields]
|
|
586
|
+
if (fs && Array.isArray(fs)) {
|
|
587
|
+
fields = fs
|
|
588
|
+
}
|
|
589
|
+
let nextPageToken: string | undefined = o[resources.nextPageToken]
|
|
590
|
+
let page = 1
|
|
591
|
+
let spage = o[resources.page]
|
|
592
|
+
if (spage && typeof spage === "string") {
|
|
593
|
+
if (!isNaN(spage as any)) {
|
|
594
|
+
const ipage = Math.floor(parseFloat(spage))
|
|
595
|
+
if (ipage > 1) {
|
|
596
|
+
page = ipage
|
|
120
597
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
let limit = resources.defaultLimit
|
|
601
|
+
let slimit = o[resources.limit]
|
|
602
|
+
if (slimit && typeof slimit === "string") {
|
|
603
|
+
if (!isNaN(slimit as any)) {
|
|
604
|
+
const ilimit = Math.floor(parseFloat(slimit))
|
|
605
|
+
if (ilimit > 0) {
|
|
606
|
+
limit = ilimit
|
|
127
607
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
const r: Limit = { limit: limit, fields, page, nextPageToken, pageOrNextPageToken: page }
|
|
611
|
+
if (r.nextPageToken && r.nextPageToken.length > 0) {
|
|
612
|
+
r.pageOrNextPageToken = r.nextPageToken
|
|
613
|
+
}
|
|
614
|
+
deletePageInfo(o)
|
|
615
|
+
return r
|
|
616
|
+
}
|
|
617
|
+
// tslint:disable-next-line:array-type
|
|
618
|
+
export function deletePageInfo(obj: any, arr?: Array<string | undefined>): void {
|
|
619
|
+
if (!arr || arr.length === 0) {
|
|
620
|
+
delete obj[resources.fields]
|
|
621
|
+
delete obj[resources.limit]
|
|
622
|
+
delete obj[resources.page]
|
|
623
|
+
if (resources.nextPageToken && resources.nextPageToken.length > 0) {
|
|
624
|
+
delete obj[resources.nextPageToken]
|
|
625
|
+
}
|
|
626
|
+
if (resources.partial && resources.partial.length > 0) {
|
|
627
|
+
delete obj[resources.partial]
|
|
628
|
+
}
|
|
629
|
+
} else {
|
|
630
|
+
for (const o of arr) {
|
|
631
|
+
if (o && o.length > 0) {
|
|
632
|
+
delete obj[o]
|
|
149
633
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
return {limit: undefined, skip: undefined, refId};
|
|
155
|
-
}
|
|
156
|
-
export function deletePageInfo(obj: any): void {
|
|
157
|
-
delete obj['limit'];
|
|
158
|
-
delete obj['firstLimit'];
|
|
159
|
-
delete obj['skip'];
|
|
160
|
-
delete obj['page'];
|
|
161
|
-
delete obj['pageNo'];
|
|
162
|
-
delete obj['pageIndex'];
|
|
163
|
-
delete obj['pageSize'];
|
|
164
|
-
delete obj['initPageSize'];
|
|
165
|
-
delete obj['firstPageSize'];
|
|
166
|
-
delete obj['refId'];
|
|
167
|
-
delete obj['refId'];
|
|
168
|
-
delete obj['nextPageToken'];
|
|
169
|
-
}
|
|
170
|
-
const re = /"/g;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
const re = /"/g
|
|
171
638
|
export function toCsv<T>(fields: string[], r: SearchResult<T>): string {
|
|
172
639
|
if (!r || r.list.length === 0) {
|
|
173
|
-
return
|
|
640
|
+
return "0"
|
|
174
641
|
} else {
|
|
175
|
-
const e =
|
|
176
|
-
const s =
|
|
177
|
-
const n =
|
|
178
|
-
const b = '""'
|
|
179
|
-
const rows: string[] = []
|
|
180
|
-
rows.push(
|
|
642
|
+
const e = ""
|
|
643
|
+
const s = "string"
|
|
644
|
+
const n = "number"
|
|
645
|
+
const b = '""'
|
|
646
|
+
const rows: string[] = []
|
|
647
|
+
rows.push("" + (r.total ? r.total : "") + "," + (r.nextPageToken ? r.nextPageToken : ""))
|
|
181
648
|
for (const item of r.list) {
|
|
182
|
-
const cols: string[] = []
|
|
649
|
+
const cols: string[] = []
|
|
183
650
|
for (const name of fields) {
|
|
184
|
-
const v = item[name]
|
|
651
|
+
const v = (item as any)[name]
|
|
185
652
|
if (!v) {
|
|
186
|
-
cols.push(e)
|
|
653
|
+
cols.push(e)
|
|
187
654
|
} else {
|
|
188
655
|
if (typeof v === s) {
|
|
189
|
-
if (s.indexOf(
|
|
190
|
-
cols.push('"' + v.replace(re, b) + '"')
|
|
656
|
+
if (s.indexOf(",") >= 0) {
|
|
657
|
+
cols.push('"' + v.replace(re, b) + '"')
|
|
191
658
|
} else {
|
|
192
|
-
cols.push(v)
|
|
659
|
+
cols.push(v)
|
|
193
660
|
}
|
|
194
661
|
} else if (v instanceof Date) {
|
|
195
|
-
cols.push(v.toISOString())
|
|
662
|
+
cols.push(v.toISOString())
|
|
196
663
|
} else if (typeof v === n) {
|
|
197
|
-
cols.push(v.toString())
|
|
664
|
+
cols.push(v.toString())
|
|
198
665
|
} else {
|
|
199
|
-
cols.push(
|
|
666
|
+
cols.push("")
|
|
200
667
|
}
|
|
201
668
|
}
|
|
202
669
|
}
|
|
203
|
-
rows.push(cols.join(
|
|
670
|
+
rows.push(cols.join(","))
|
|
204
671
|
}
|
|
205
|
-
return rows.join(
|
|
672
|
+
return rows.join("\n")
|
|
206
673
|
}
|
|
207
674
|
}
|
|
208
|
-
|
|
209
|
-
export interface
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
675
|
+
|
|
676
|
+
export interface DateRange {
|
|
677
|
+
startDate?: Date
|
|
678
|
+
endDate?: Date
|
|
679
|
+
startTime?: Date
|
|
680
|
+
endTime?: Date
|
|
681
|
+
min?: Date
|
|
682
|
+
max?: Date
|
|
683
|
+
upper?: Date
|
|
684
|
+
}
|
|
685
|
+
export interface NumberRange {
|
|
686
|
+
min?: number
|
|
687
|
+
max?: number
|
|
688
|
+
lower?: number
|
|
689
|
+
upper?: number
|
|
690
|
+
}
|
|
691
|
+
export interface Metadata {
|
|
692
|
+
dates?: string[]
|
|
693
|
+
numbers?: string[]
|
|
694
|
+
}
|
|
695
|
+
export function buildMetadata(attributes: Attributes, includeDate?: boolean): Metadata {
|
|
696
|
+
const keys: string[] = Object.keys(attributes)
|
|
697
|
+
const dates: string[] = []
|
|
698
|
+
const numbers: string[] = []
|
|
699
|
+
for (const key of keys) {
|
|
700
|
+
const attr: Attribute = attributes[key]
|
|
701
|
+
if (attr.type === "number" || attr.type === "integer") {
|
|
702
|
+
numbers.push(key)
|
|
703
|
+
} else if (attr.type === "datetime" || (includeDate === true && attr.type === "date")) {
|
|
704
|
+
dates.push(key)
|
|
231
705
|
}
|
|
232
|
-
return s;
|
|
233
706
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
return s;
|
|
707
|
+
const m: Metadata = {}
|
|
708
|
+
if (dates.length > 0) {
|
|
709
|
+
m.dates = dates
|
|
710
|
+
}
|
|
711
|
+
if (numbers.length > 0) {
|
|
712
|
+
m.numbers = numbers
|
|
241
713
|
}
|
|
714
|
+
return m
|
|
242
715
|
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
716
|
+
|
|
717
|
+
const _datereg = "/Date("
|
|
718
|
+
const _re = /-?\d+/
|
|
719
|
+
function toDate(v: any): Date | null | undefined {
|
|
720
|
+
if (!v) {
|
|
721
|
+
return null
|
|
246
722
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
s.limit = (isNaN(pageSize) ? 0 : Math.floor(parseFloat(pageSize)));
|
|
723
|
+
if (v instanceof Date) {
|
|
724
|
+
return v
|
|
725
|
+
} else if (typeof v === "number") {
|
|
726
|
+
return new Date(v)
|
|
252
727
|
}
|
|
253
|
-
|
|
254
|
-
|
|
728
|
+
const i = v.indexOf(_datereg)
|
|
729
|
+
if (i >= 0) {
|
|
730
|
+
const m = _re.exec(v)
|
|
731
|
+
if (m !== null) {
|
|
732
|
+
const d = parseInt(m[0], 10)
|
|
733
|
+
return new Date(d)
|
|
734
|
+
} else {
|
|
735
|
+
return null
|
|
736
|
+
}
|
|
737
|
+
} else {
|
|
738
|
+
if (isNaN(v)) {
|
|
739
|
+
return new Date(v)
|
|
740
|
+
} else {
|
|
741
|
+
const d = parseInt(v, 10)
|
|
742
|
+
return new Date(d)
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
export function format<T>(obj: T, dates?: string[], nums?: string[]): T {
|
|
748
|
+
const o: any = obj
|
|
749
|
+
if (dates && dates.length > 0) {
|
|
750
|
+
for (const s of dates) {
|
|
751
|
+
const v = o[s]
|
|
752
|
+
if (v) {
|
|
753
|
+
if (v instanceof Date) {
|
|
754
|
+
continue
|
|
755
|
+
}
|
|
756
|
+
if (typeof v === "string" || typeof v === "number") {
|
|
757
|
+
const d = toDate(v)
|
|
758
|
+
if (d) {
|
|
759
|
+
if (!(d instanceof Date) || d.toString() === "Invalid Date") {
|
|
760
|
+
delete o[s]
|
|
761
|
+
} else {
|
|
762
|
+
o[s] = d
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
} else if (typeof v === "object") {
|
|
766
|
+
const keys = Object.keys(v)
|
|
767
|
+
for (const key of keys) {
|
|
768
|
+
const v2 = v[key]
|
|
769
|
+
if (v2 instanceof Date) {
|
|
770
|
+
continue
|
|
771
|
+
}
|
|
772
|
+
if (typeof v2 === "string" || typeof v2 === "number") {
|
|
773
|
+
const d2 = toDate(v2)
|
|
774
|
+
if (d2) {
|
|
775
|
+
if (!(d2 instanceof Date) || d2.toString() === "Invalid Date") {
|
|
776
|
+
delete v[key]
|
|
777
|
+
} else {
|
|
778
|
+
v[key] = d2
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
}
|
|
255
786
|
}
|
|
256
|
-
if (
|
|
257
|
-
|
|
787
|
+
if (nums && nums.length > 0) {
|
|
788
|
+
for (const s of nums) {
|
|
789
|
+
const v = o[s]
|
|
790
|
+
if (v) {
|
|
791
|
+
if (v instanceof Date) {
|
|
792
|
+
delete o[s]
|
|
793
|
+
continue
|
|
794
|
+
}
|
|
795
|
+
if (typeof v === "number") {
|
|
796
|
+
continue
|
|
797
|
+
}
|
|
798
|
+
if (typeof v === "string") {
|
|
799
|
+
if (!isNaN(v as any)) {
|
|
800
|
+
delete o[s]
|
|
801
|
+
continue
|
|
802
|
+
} else {
|
|
803
|
+
const i = parseFloat(v)
|
|
804
|
+
o[s] = i
|
|
805
|
+
}
|
|
806
|
+
} else if (typeof v === "object") {
|
|
807
|
+
const keys = Object.keys(v)
|
|
808
|
+
for (const key of keys) {
|
|
809
|
+
const v2 = v[key]
|
|
810
|
+
if (v2 instanceof Date) {
|
|
811
|
+
delete o[key]
|
|
812
|
+
continue
|
|
813
|
+
}
|
|
814
|
+
if (typeof v2 === "number") {
|
|
815
|
+
continue
|
|
816
|
+
}
|
|
817
|
+
if (typeof v2 === "string") {
|
|
818
|
+
if (!isNaN(v2 as any)) {
|
|
819
|
+
delete v[key]
|
|
820
|
+
} else {
|
|
821
|
+
const i = parseFloat(v2)
|
|
822
|
+
v[key] = i
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
}
|
|
258
829
|
}
|
|
259
|
-
|
|
260
|
-
|
|
830
|
+
return o
|
|
831
|
+
}
|
|
832
|
+
export function getMetadataFunc<T, ID>(
|
|
833
|
+
viewService: ViewService<T, ID> | ((id: ID, ctx?: any) => Promise<T>),
|
|
834
|
+
dates?: string[],
|
|
835
|
+
numbers?: string[],
|
|
836
|
+
keys?: Attributes | Attribute[] | string[],
|
|
837
|
+
): Metadata | undefined {
|
|
838
|
+
const m: Metadata = { dates, numbers }
|
|
839
|
+
if ((m.dates && m.dates.length > 0) || (m.numbers && m.numbers.length > 0)) {
|
|
840
|
+
return m
|
|
261
841
|
}
|
|
262
|
-
if (
|
|
263
|
-
|
|
842
|
+
if (keys) {
|
|
843
|
+
if (!Array.isArray(keys)) {
|
|
844
|
+
return buildMetadata(keys)
|
|
845
|
+
}
|
|
264
846
|
}
|
|
265
|
-
if (
|
|
266
|
-
|
|
847
|
+
if (typeof viewService !== "function" && viewService.metadata) {
|
|
848
|
+
const metadata = viewService.metadata()
|
|
849
|
+
if (metadata) {
|
|
850
|
+
return buildMetadata(metadata)
|
|
851
|
+
}
|
|
267
852
|
}
|
|
268
|
-
return
|
|
853
|
+
return undefined
|
|
269
854
|
}
|
|
270
|
-
*/
|