-
Notifications
You must be signed in to change notification settings - Fork 0
/
mango-parser.mixin.ts
127 lines (115 loc) · 3.93 KB
/
mango-parser.mixin.ts
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import type {
CustomQSMongoParser,
IMangoParser,
MangoParserOptions,
QueryCriteriaOptions
} from '@/interfaces'
import type { MangoParsedUrlQuery, MangoSearchParams } from '@/types'
import { ExceptionStatusCode } from '@flex-development/exceptions/enums'
import Exception from '@flex-development/exceptions/exceptions/base.exception'
import type {
ObjectPlain,
ObjectUnknown,
OneOrMany
} from '@flex-development/tutils'
import qsm from 'qs-to-mongo'
import type { ParsedOptions } from 'qs-to-mongo/lib/query/options-to-mongo'
/**
* @file Mixin - MangoParser
* @module mixins/MangoParser
*/
/**
* Converts Mongo URL queries into search parameters objects.
*
* See:
*
* - https://github.com/fox1t/qs-to-mongo
*
* @template D - Document (collection object)
*
* @class
* @implements {IMangoParser<D>}
*/
export default class MangoParser<D extends ObjectPlain = ObjectUnknown>
implements IMangoParser<D> {
/**
* @readonly
* @instance
* @property {typeof qsm} parser - `qs-to-mongo` module
* @see https://github.com/fox1t/qs-to-mongo
*/
readonly parser: typeof qsm = qsm
/**
* @readonly
* @instance
* @property {MangoParserOptions<D>} options - `qs-to-mongo` module options
*/
readonly options: MangoParserOptions<D>
/**
* Creates a new `MangoParser` client.
*
* Converts MongoDB query objects and strings into search parameters objects,
* and formats query criteria objects.
*
* - https://github.com/fox1t/qs-to-mongo
* - https://github.com/kofrasa/mingo
*
* @param {MangoParserOptions<D>} [options] - Parser options
* @param {OneOrMany<string>} [options.dateFields] - Fields that will be
* converted to `Date`; if no fields are passed, any valid date string will be
* converted to an ISO-8601 string
* @param {OneOrMany<string>} [options.fullTextFields] - Fields that will be
* used as criteria when passing `text` query parameter
* @param {OneOrMany<string>} [options.ignoredFields] - Array of query
* parameters that are ignored, in addition to the defaults (`fields`,
* `limit`, `offset`, `omit`, `sort`, `text`)
* @param {number} [options.maxLimit] - Max that can be passed to limit option
* @param {CustomQSMongoParser} [options.parser] - Custom query parser
* @param {any} [options.parserOptions] - Custom query parser options
*/
constructor(options: MangoParserOptions<D> = {}) {
const parser_options = Object.assign({}, options)
Reflect.deleteProperty(parser_options, 'objectIdFields')
Reflect.deleteProperty(parser_options, 'parameters')
this.options = parser_options
}
/**
* Convert URL query objects and strings into a search parameters objects.
*
* @param {MangoParsedUrlQuery<D> | string} [query] - Query object or string
* @return {MangoSearchParams<D>} Mango search parameters object
* @throws {Exception}
*/
params(query: MangoParsedUrlQuery<D> | string = ''): MangoSearchParams<D> {
let build: ObjectPlain = {}
try {
// @ts-expect-error `dateFields` and `fullTextFields` mapped to document
build = this.parser(query, this.options)
} catch ({ message, stack }) {
const code = ExceptionStatusCode.BAD_REQUEST
const data = { parser_options: this.options, query }
throw new Exception(code, message, data, stack)
}
return {
...build.criteria,
options: this.queryCriteriaOptions(build.options)
} as MangoSearchParams<D>
}
/**
* Converts parsed URL query criteria options into `QueryCriteriaOptions`
* objects.
*
* @param {Partial<ParsedOptions>} [base] - Parsed query criteria options
* @return {QueryCriteriaOptions<D>} Query criteria options
*/
queryCriteriaOptions(
base: Partial<ParsedOptions> = {}
): QueryCriteriaOptions<D> {
const { projection, sort, ...rest } = base
return {
...rest,
$project: projection as QueryCriteriaOptions<D>['$project'],
sort: sort as QueryCriteriaOptions<D>['sort']
}
}
}