reslib 1.0.0
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 +298 -0
- package/build/auth/index.d.ts +2034 -0
- package/build/auth/index.js +5 -0
- package/build/auth/types.d.ts +465 -0
- package/build/auth/types.js +1 -0
- package/build/countries/countries.d.ts +1454 -0
- package/build/countries/countries.js +1 -0
- package/build/countries/index.d.ts +159 -0
- package/build/countries/index.js +5 -0
- package/build/countries/types.d.ts +65 -0
- package/build/countries/types.js +1 -0
- package/build/currency/currencies.d.ts +8 -0
- package/build/currency/currencies.js +1 -0
- package/build/currency/index.d.ts +51 -0
- package/build/currency/index.js +5 -0
- package/build/currency/session.d.ts +23 -0
- package/build/currency/session.js +5 -0
- package/build/currency/types.d.ts +1039 -0
- package/build/currency/types.js +1 -0
- package/build/currency/utils.d.ts +25 -0
- package/build/currency/utils.js +1 -0
- package/build/i18n/index.d.ts +640 -0
- package/build/i18n/index.js +5 -0
- package/build/inputFormatter/index.d.ts +396 -0
- package/build/inputFormatter/index.js +5 -0
- package/build/inputFormatter/types.d.ts +544 -0
- package/build/inputFormatter/types.js +1 -0
- package/build/logger/index.d.ts +235 -0
- package/build/logger/index.js +5 -0
- package/build/observable/index.d.ts +329 -0
- package/build/observable/index.js +1 -0
- package/build/platform/index.d.ts +32 -0
- package/build/platform/index.js +1 -0
- package/build/resources/ResourcePaginationHelper.d.ts +537 -0
- package/build/resources/ResourcePaginationHelper.js +2 -0
- package/build/resources/decorators/create.decorator.d.ts +20 -0
- package/build/resources/decorators/create.decorator.js +1 -0
- package/build/resources/decorators/index.d.ts +41 -0
- package/build/resources/decorators/index.js +1 -0
- package/build/resources/fields/index.d.ts +33 -0
- package/build/resources/fields/index.js +1 -0
- package/build/resources/filters.d.ts +62 -0
- package/build/resources/filters.js +1 -0
- package/build/resources/index.d.ts +854 -0
- package/build/resources/index.js +6 -0
- package/build/resources/types/filters.d.ts +508 -0
- package/build/resources/types/filters.js +1 -0
- package/build/resources/types/index.d.ts +4138 -0
- package/build/resources/types/index.js +1 -0
- package/build/session/index.d.ts +1474 -0
- package/build/session/index.js +1 -0
- package/build/translations/auth.en.d.ts +3 -0
- package/build/translations/auth.en.js +1 -0
- package/build/translations/countries.en.d.ts +6 -0
- package/build/translations/countries.en.js +1 -0
- package/build/translations/currencies.en.d.ts +5 -0
- package/build/translations/currencies.en.js +1 -0
- package/build/translations/date.en.d.ts +19 -0
- package/build/translations/date.en.js +1 -0
- package/build/translations/index.d.ts +1583 -0
- package/build/translations/index.js +5 -0
- package/build/translations/resources.en.d.ts +6 -0
- package/build/translations/resources.en.js +1 -0
- package/build/translations/validator.en.d.ts +104 -0
- package/build/translations/validator.en.js +5 -0
- package/build/types/date.d.ts +44 -0
- package/build/types/date.js +1 -0
- package/build/types/dictionary.d.ts +29 -0
- package/build/types/dictionary.js +1 -0
- package/build/types/i18n.d.ts +121 -0
- package/build/types/i18n.js +1 -0
- package/build/types/index.d.ts +145 -0
- package/build/types/index.js +1 -0
- package/build/utils/areEquals.d.ts +19 -0
- package/build/utils/areEquals.js +1 -0
- package/build/utils/date/dateHelper.d.ts +371 -0
- package/build/utils/date/dateHelper.js +5 -0
- package/build/utils/date/index.d.ts +212 -0
- package/build/utils/date/index.js +5 -0
- package/build/utils/date/isDateObj.d.ts +14 -0
- package/build/utils/date/isDateObj.js +1 -0
- package/build/utils/debounce.d.ts +52 -0
- package/build/utils/debounce.js +1 -0
- package/build/utils/defaultArray.d.ts +18 -0
- package/build/utils/defaultArray.js +1 -0
- package/build/utils/defaultBool.d.ts +14 -0
- package/build/utils/defaultBool.js +1 -0
- package/build/utils/defaultStr.d.ts +17 -0
- package/build/utils/defaultStr.js +1 -0
- package/build/utils/defaultVal.d.ts +18 -0
- package/build/utils/defaultVal.js +1 -0
- package/build/utils/dom/index.d.ts +65 -0
- package/build/utils/dom/index.js +1 -0
- package/build/utils/dom/isDOMElement.d.ts +11 -0
- package/build/utils/dom/isDOMElement.js +1 -0
- package/build/utils/file/index.d.ts +26 -0
- package/build/utils/file/index.js +1 -0
- package/build/utils/global.d.ts +53 -0
- package/build/utils/global.js +1 -0
- package/build/utils/image.d.ts +56 -0
- package/build/utils/image.js +1 -0
- package/build/utils/index.d.ts +39 -0
- package/build/utils/index.js +6 -0
- package/build/utils/interpolate.d.ts +105 -0
- package/build/utils/interpolate.js +1 -0
- package/build/utils/isEmail.d.ts +57 -0
- package/build/utils/isEmail.js +1 -0
- package/build/utils/isEmpty.d.ts +18 -0
- package/build/utils/isEmpty.js +1 -0
- package/build/utils/isNonNullString.d.ts +17 -0
- package/build/utils/isNonNullString.js +1 -0
- package/build/utils/isNullable.d.ts +7 -0
- package/build/utils/isNullable.js +1 -0
- package/build/utils/isNumber.d.ts +36 -0
- package/build/utils/isNumber.js +1 -0
- package/build/utils/isPrimitive.d.ts +16 -0
- package/build/utils/isPrimitive.js +1 -0
- package/build/utils/isPromise.d.ts +14 -0
- package/build/utils/isPromise.js +1 -0
- package/build/utils/isRegex.d.ts +15 -0
- package/build/utils/isRegex.js +1 -0
- package/build/utils/isTime.d.ts +18 -0
- package/build/utils/isTime.js +1 -0
- package/build/utils/json.d.ts +224 -0
- package/build/utils/json.js +1 -0
- package/build/utils/numbers.d.ts +148 -0
- package/build/utils/numbers.js +5 -0
- package/build/utils/object.d.ts +567 -0
- package/build/utils/object.js +1 -0
- package/build/utils/sort.d.ts +67 -0
- package/build/utils/sort.js +1 -0
- package/build/utils/string.d.ts +165 -0
- package/build/utils/string.js +1 -0
- package/build/utils/stringify.d.ts +23 -0
- package/build/utils/stringify.js +1 -0
- package/build/utils/uniqid.d.ts +18 -0
- package/build/utils/uniqid.js +1 -0
- package/build/utils/uri/index.d.ts +333 -0
- package/build/utils/uri/index.js +2 -0
- package/build/validator/index.d.ts +4 -0
- package/build/validator/index.js +6 -0
- package/build/validator/rules/array.d.ts +848 -0
- package/build/validator/rules/array.js +5 -0
- package/build/validator/rules/boolean.d.ts +87 -0
- package/build/validator/rules/boolean.js +5 -0
- package/build/validator/rules/date.d.ts +551 -0
- package/build/validator/rules/date.js +5 -0
- package/build/validator/rules/default.d.ts +367 -0
- package/build/validator/rules/default.js +5 -0
- package/build/validator/rules/enum.d.ts +155 -0
- package/build/validator/rules/enum.js +5 -0
- package/build/validator/rules/file.d.ts +356 -0
- package/build/validator/rules/file.js +5 -0
- package/build/validator/rules/format.d.ts +2825 -0
- package/build/validator/rules/format.js +6 -0
- package/build/validator/rules/index.d.ts +16 -0
- package/build/validator/rules/index.js +6 -0
- package/build/validator/rules/multiRules.d.ts +475 -0
- package/build/validator/rules/multiRules.js +5 -0
- package/build/validator/rules/numeric.d.ts +1135 -0
- package/build/validator/rules/numeric.js +5 -0
- package/build/validator/rules/string.d.ts +504 -0
- package/build/validator/rules/string.js +5 -0
- package/build/validator/rules/target.d.ts +137 -0
- package/build/validator/rules/target.js +5 -0
- package/build/validator/rules/utils.d.ts +1 -0
- package/build/validator/rules/utils.js +1 -0
- package/build/validator/rulesMarkers.d.ts +11 -0
- package/build/validator/rulesMarkers.js +1 -0
- package/build/validator/types.d.ts +2906 -0
- package/build/validator/types.js +1 -0
- package/build/validator/validator.d.ts +3692 -0
- package/build/validator/validator.js +5 -0
- package/lib/cjs/auth.js +1 -0
- package/lib/cjs/countries.js +1 -0
- package/lib/cjs/currency.js +1 -0
- package/lib/cjs/i18n.js +1 -0
- package/lib/cjs/inputFormatter.js +1 -0
- package/lib/cjs/logger.js +1 -0
- package/lib/cjs/observable.js +1 -0
- package/lib/cjs/platform.js +1 -0
- package/lib/cjs/resources.js +1 -0
- package/lib/cjs/session.js +1 -0
- package/lib/cjs/types.js +1 -0
- package/lib/cjs/utils.js +1 -0
- package/lib/cjs/validator.js +1 -0
- package/lib/esm/auth.mjs +1 -0
- package/lib/esm/countries.mjs +1 -0
- package/lib/esm/currency.mjs +1 -0
- package/lib/esm/i18n.mjs +1 -0
- package/lib/esm/inputFormatter.mjs +1 -0
- package/lib/esm/logger.mjs +1 -0
- package/lib/esm/observable.mjs +1 -0
- package/lib/esm/platform.mjs +1 -0
- package/lib/esm/resources.mjs +1 -0
- package/lib/esm/session.mjs +1 -0
- package/lib/esm/types.mjs +1 -0
- package/lib/esm/utils.mjs +1 -0
- package/lib/esm/validator.mjs +1 -0
- package/package.json +244 -0
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
import { Dictionary } from '../types';
|
|
2
|
+
import { NestedPaths, ResourcePaginationMeta, ResourceQueryOptions, ResourceQueryOrderBy } from './types';
|
|
3
|
+
export declare class ResourcePaginationHelper {
|
|
4
|
+
/**
|
|
5
|
+
* Normalizes pagination parameters into a consistent format, calculating missing values and ensuring valid pagination state.
|
|
6
|
+
*
|
|
7
|
+
* This method takes pagination options and normalizes them by calculating the missing pagination parameters
|
|
8
|
+
* (`page`, `skip`, `limit`) based on the provided values. It handles the relationship between page-based
|
|
9
|
+
* and offset-based pagination, ensuring that all three parameters are consistent and valid.
|
|
10
|
+
*
|
|
11
|
+
* **Normalization Logic:**
|
|
12
|
+
* - If `limit` is not a valid number, returns an empty object (no pagination)
|
|
13
|
+
* - If `skip` is provided, calculates the corresponding `page` number
|
|
14
|
+
* - If `page` is provided, calculates the corresponding `skip` offset
|
|
15
|
+
* - If neither `skip` nor `page` are provided, defaults to page 1 with skip 0
|
|
16
|
+
* - Ensures all returned values are valid numbers
|
|
17
|
+
*
|
|
18
|
+
* **Parameter Relationships:**
|
|
19
|
+
* - `page`: 1-based page number (first page = 1)
|
|
20
|
+
* - `skip`: 0-based offset (number of records to skip)
|
|
21
|
+
* - `limit`: Maximum records per page
|
|
22
|
+
* - Formula: `skip = (page - 1) * limit`
|
|
23
|
+
*
|
|
24
|
+
* @template DataType - The resource data type (used for type consistency with ResourceQueryOptions)
|
|
25
|
+
* @param {ResourceQueryOptions<DataType>} [options] - Pagination options containing page, skip, and/or limit
|
|
26
|
+
* @param {number} [options.page] - The page number (1-based)
|
|
27
|
+
* @param {number} [options.skip] - The number of records to skip (0-based offset)
|
|
28
|
+
* @param {number} [options.limit] - The maximum number of records per page
|
|
29
|
+
* @returns {{page?: number, skip?: number, limit?: number}} Normalized pagination parameters:
|
|
30
|
+
* - `page`: Calculated or provided page number
|
|
31
|
+
* - `skip`: Calculated or provided skip offset
|
|
32
|
+
* - `limit`: The limit value (unchanged if valid, omitted if invalid)
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* // Page-based pagination - calculates skip automatically
|
|
37
|
+
* const result = ResourcePaginationHelper.normalizePagination({
|
|
38
|
+
* page: 3,
|
|
39
|
+
* limit: 10
|
|
40
|
+
* });
|
|
41
|
+
* // Result: { page: 3, skip: 20, limit: 10 }
|
|
42
|
+
* // (skip = (3-1) * 10 = 20)
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* // Offset-based pagination - calculates page automatically
|
|
48
|
+
* const result = ResourcePaginationHelper.normalizePagination({
|
|
49
|
+
* skip: 50,
|
|
50
|
+
* limit: 25
|
|
51
|
+
* });
|
|
52
|
+
* // Result: { page: 3, skip: 50, limit: 25 }
|
|
53
|
+
* // (page = floor(50/25) + 1 = 3)
|
|
54
|
+
* ```
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* // Default pagination - no parameters provided
|
|
59
|
+
* const result = ResourcePaginationHelper.normalizePagination({
|
|
60
|
+
* limit: 20
|
|
61
|
+
* });
|
|
62
|
+
* // Result: { page: 1, skip: 0, limit: 20 }
|
|
63
|
+
* ```
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```typescript
|
|
67
|
+
* // Invalid limit - returns empty object (no pagination)
|
|
68
|
+
* const result = ResourcePaginationHelper.normalizePagination({
|
|
69
|
+
* page: 2,
|
|
70
|
+
* limit: "invalid"
|
|
71
|
+
* });
|
|
72
|
+
* // Result: {}
|
|
73
|
+
* ```
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* // Zero or negative values - defaults to first page
|
|
78
|
+
* const result = ResourcePaginationHelper.normalizePagination({
|
|
79
|
+
* page: 0,
|
|
80
|
+
* limit: 15
|
|
81
|
+
* });
|
|
82
|
+
* // Result: { page: 1, skip: 0, limit: 15 }
|
|
83
|
+
* ```
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```typescript
|
|
87
|
+
* // Large skip values
|
|
88
|
+
* const result = ResourcePaginationHelper.normalizePagination({
|
|
89
|
+
* skip: 1000,
|
|
90
|
+
* limit: 50
|
|
91
|
+
* });
|
|
92
|
+
* // Result: { page: 21, skip: 1000, limit: 50 }
|
|
93
|
+
* // (page = floor(1000/50) + 1 = 21)
|
|
94
|
+
* ```
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```typescript
|
|
98
|
+
* // Fractional skip values (floor operation)
|
|
99
|
+
* const result = ResourcePaginationHelper.normalizePagination({
|
|
100
|
+
* skip: 37,
|
|
101
|
+
* limit: 10
|
|
102
|
+
* });
|
|
103
|
+
* // Result: { page: 4, skip: 37, limit: 10 }
|
|
104
|
+
* // (page = floor(37/10) + 1 = 4)
|
|
105
|
+
* ```
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```typescript
|
|
109
|
+
* // Mixed parameters - skip takes precedence over page
|
|
110
|
+
* const result = ResourcePaginationHelper.normalizePagination({
|
|
111
|
+
* page: 2,
|
|
112
|
+
* skip: 30,
|
|
113
|
+
* limit: 15
|
|
114
|
+
* });
|
|
115
|
+
* // Result: { page: 3, skip: 30, limit: 15 }
|
|
116
|
+
* // (skip provided, so page is recalculated from skip)
|
|
117
|
+
* ```
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* ```typescript
|
|
121
|
+
* // Database cursor scenario
|
|
122
|
+
* const result = ResourcePaginationHelper.normalizePagination({
|
|
123
|
+
* skip: 500,
|
|
124
|
+
* limit: 100
|
|
125
|
+
* });
|
|
126
|
+
* // Result: { page: 6, skip: 500, limit: 100 }
|
|
127
|
+
* // Useful for database queries with OFFSET
|
|
128
|
+
* ```
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```typescript
|
|
132
|
+
* // API pagination with user input
|
|
133
|
+
* const userOptions = { page: 5, limit: 20 };
|
|
134
|
+
* const result = ResourcePaginationHelper.normalizePagination(userOptions);
|
|
135
|
+
* // Result: { page: 5, skip: 80, limit: 20 }
|
|
136
|
+
* // Ready for database query: LIMIT 20 OFFSET 80
|
|
137
|
+
* ```
|
|
138
|
+
*
|
|
139
|
+
* @remarks
|
|
140
|
+
* - Page numbers are 1-based (first page = 1, not 0)
|
|
141
|
+
* - Skip values are 0-based (skip 0 = first record)
|
|
142
|
+
* - Invalid limit values disable pagination entirely
|
|
143
|
+
* - When both page and skip are provided, skip takes precedence for page calculation
|
|
144
|
+
* - Negative or zero page values default to page 1
|
|
145
|
+
* - Fractional skip values are floored when calculating page numbers
|
|
146
|
+
*/
|
|
147
|
+
static normalizePagination<DataType = unknown>(options?: ResourceQueryOptions<DataType>): {
|
|
148
|
+
page?: undefined;
|
|
149
|
+
skip?: undefined;
|
|
150
|
+
limit?: undefined;
|
|
151
|
+
} | {
|
|
152
|
+
page: number;
|
|
153
|
+
skip: number;
|
|
154
|
+
limit: number;
|
|
155
|
+
};
|
|
156
|
+
/**
|
|
157
|
+
* Normalizes orderBy parameters into a structured object format.
|
|
158
|
+
*
|
|
159
|
+
* This method takes various input formats for sorting criteria and converts them into a consistent
|
|
160
|
+
* object where keys are valid nested property paths and values are sort directions ("asc" or "desc").
|
|
161
|
+
* It handles single strings, arrays of strings, and undefined inputs gracefully.
|
|
162
|
+
*
|
|
163
|
+
* @template T - The resource type to validate paths against
|
|
164
|
+
* @param orderBy - The orderBy specification in various formats:
|
|
165
|
+
* - `string`: Single field like "name" (ascending) or "-name" (descending)
|
|
166
|
+
* - `string[]`: Multiple fields like ["name", "-age", "createdAt"]
|
|
167
|
+
* - `undefined`: No sorting specified
|
|
168
|
+
* @returns A partial record mapping valid nested paths to sort directions
|
|
169
|
+
*
|
|
170
|
+
* @example
|
|
171
|
+
* ```typescript
|
|
172
|
+
* interface User {
|
|
173
|
+
* id: number;
|
|
174
|
+
* name: string;
|
|
175
|
+
* profile: { age: number; address: { city: string } };
|
|
176
|
+
* }
|
|
177
|
+
*
|
|
178
|
+
* // Single ascending field
|
|
179
|
+
* normalizeOrderBy<User>("name")
|
|
180
|
+
* // Returns: { "name": "asc" }
|
|
181
|
+
*
|
|
182
|
+
* // Single descending field
|
|
183
|
+
* normalizeOrderBy<User>("-profile.age")
|
|
184
|
+
* // Returns: { "profile.age": "desc" }
|
|
185
|
+
*
|
|
186
|
+
* // Multiple fields
|
|
187
|
+
* normalizeOrderBy<User>(["name", "-profile.age", "profile.address.city"])
|
|
188
|
+
* // Returns: { "name": "asc", "profile.age": "desc", "profile.address.city": "asc" }
|
|
189
|
+
*
|
|
190
|
+
* // Invalid input (filtered out)
|
|
191
|
+
* normalizeOrderBy<User>([null, "", "name", undefined])
|
|
192
|
+
* // Returns: { "name": "asc" }
|
|
193
|
+
* ```
|
|
194
|
+
*
|
|
195
|
+
* @remarks
|
|
196
|
+
* - Fields starting with "-" are treated as descending order
|
|
197
|
+
* - Invalid or empty strings are silently filtered out
|
|
198
|
+
* - Duplicate fields will log a warning and use the last occurrence
|
|
199
|
+
* - The method performs type assertion to `NestedPaths<T>` - ensure input paths are valid at call site
|
|
200
|
+
*/
|
|
201
|
+
static normalizeOrderBy<T = unknown>(orderBy?: ResourceQueryOrderBy<T>): Partial<Record<NestedPaths<T>, SortOrder>>;
|
|
202
|
+
/***
|
|
203
|
+
* Determines if result can be paginated based on the provided query options.
|
|
204
|
+
* It checks if the query options have a `limit` property of type number.
|
|
205
|
+
* @template DataType The type of resource data.
|
|
206
|
+
* @param {ResourceQueryOptions} queryOptions - The query options.
|
|
207
|
+
* @returns {boolean} Whether the result can be paginated.
|
|
208
|
+
*
|
|
209
|
+
* @example
|
|
210
|
+
* canPaginateResult({ limit: undefined }); //false
|
|
211
|
+
* canPaginateResult({ limit: 10, skip: 20 }); // true
|
|
212
|
+
* canPaginateResult({ page: 3, limit: 10 }); // true
|
|
213
|
+
* canPaginateResult({ page: 3, skip: 20 }); // true
|
|
214
|
+
*/
|
|
215
|
+
static canPaginateResult<DataType = unknown>(queryOptions: ResourceQueryOptions<DataType>): boolean;
|
|
216
|
+
static getPaginationMetaData<DataType = unknown>(count: number, queryOptions?: ResourceQueryOptions<DataType>): ResourcePaginationMeta;
|
|
217
|
+
/**
|
|
218
|
+
* Paginates an array of data based on the provided query options and total count.
|
|
219
|
+
*
|
|
220
|
+
* This method applies pagination logic to slice the data array according to the specified
|
|
221
|
+
* page size and current page, while also generating comprehensive pagination metadata.
|
|
222
|
+
* It's designed to work seamlessly with database query results and API responses.
|
|
223
|
+
*
|
|
224
|
+
* **Pagination Logic:**
|
|
225
|
+
* - Calculates the correct slice of data based on `page` and `limit` parameters
|
|
226
|
+
* - Generates metadata including total pages, current page, navigation flags, etc.
|
|
227
|
+
* - Handles edge cases like invalid page numbers or missing pagination parameters
|
|
228
|
+
*
|
|
229
|
+
* **Data Slicing:**
|
|
230
|
+
* - Uses zero-based indexing for array slicing
|
|
231
|
+
* - Ensures start/end indices are within array bounds
|
|
232
|
+
* - Returns empty array if pagination parameters are invalid
|
|
233
|
+
*
|
|
234
|
+
* @template DataType - The type of individual data items in the array
|
|
235
|
+
* @param {DataType[]} data - The complete array of data to be paginated
|
|
236
|
+
* @param {number} count - The total number of records available (may be different from data.length for database queries)
|
|
237
|
+
* @param {ResourceQueryOptions<DataType>} [options] - Pagination and query options
|
|
238
|
+
* @returns {{
|
|
239
|
+
* data: DataType[],
|
|
240
|
+
* total: number,
|
|
241
|
+
* meta: ResourcePaginationMeta
|
|
242
|
+
* }} An object containing:
|
|
243
|
+
* - `data`: The paginated slice of the original data array
|
|
244
|
+
* - `total`: The total count of records (unchanged from input)
|
|
245
|
+
* - `meta`: Comprehensive pagination metadata
|
|
246
|
+
*
|
|
247
|
+
* @example
|
|
248
|
+
* ```typescript
|
|
249
|
+
* // Basic pagination - page 1 with 10 items per page
|
|
250
|
+
* const users = [{id: 1}, {id: 2}, ..., {id: 25}]; // 25 total users
|
|
251
|
+
* const result = ResourcePaginationHelper.paginate(users, 25, {
|
|
252
|
+
* page: 1,
|
|
253
|
+
* limit: 10
|
|
254
|
+
* });
|
|
255
|
+
* // Result:
|
|
256
|
+
* // {
|
|
257
|
+
* // data: [{id: 1}, {id: 2}, ..., {id: 10}], // First 10 users
|
|
258
|
+
* // total: 25,
|
|
259
|
+
* // meta: {
|
|
260
|
+
* // total: 25,
|
|
261
|
+
* // currentPage: 1,
|
|
262
|
+
* // pageSize: 10,
|
|
263
|
+
* // totalPages: 3,
|
|
264
|
+
* // hasNextPage: true,
|
|
265
|
+
* // hasPreviousPage: false,
|
|
266
|
+
* // nextPage: 2,
|
|
267
|
+
* // previousPage: undefined,
|
|
268
|
+
* // lastPage: 3
|
|
269
|
+
* // }
|
|
270
|
+
* // }
|
|
271
|
+
* ```
|
|
272
|
+
*
|
|
273
|
+
* @example
|
|
274
|
+
* ```typescript
|
|
275
|
+
* // Middle page pagination
|
|
276
|
+
* const result = ResourcePaginationHelper.paginate(users, 25, {
|
|
277
|
+
* page: 2,
|
|
278
|
+
* limit: 10
|
|
279
|
+
* });
|
|
280
|
+
* // Result: data contains items 11-20, meta shows navigation to pages 1 and 3
|
|
281
|
+
* ```
|
|
282
|
+
*
|
|
283
|
+
* @example
|
|
284
|
+
* ```typescript
|
|
285
|
+
* // Last page with fewer items
|
|
286
|
+
* const result = ResourcePaginationHelper.paginate(users, 25, {
|
|
287
|
+
* page: 3,
|
|
288
|
+
* limit: 10
|
|
289
|
+
* });
|
|
290
|
+
* // Result: data contains items 21-25 (5 items), meta shows no next page
|
|
291
|
+
* ```
|
|
292
|
+
*
|
|
293
|
+
* @example
|
|
294
|
+
* ```typescript
|
|
295
|
+
* // Using skip instead of page
|
|
296
|
+
* const result = ResourcePaginationHelper.paginate(users, 25, {
|
|
297
|
+
* skip: 15,
|
|
298
|
+
* limit: 5
|
|
299
|
+
* });
|
|
300
|
+
* // Result: data contains items 16-20, meta shows currentPage: 4
|
|
301
|
+
* ```
|
|
302
|
+
*
|
|
303
|
+
* @example
|
|
304
|
+
* ```typescript
|
|
305
|
+
* // No pagination options - returns all data
|
|
306
|
+
* const result = ResourcePaginationHelper.paginate(users, 25);
|
|
307
|
+
* // Result: data contains all 25 users, meta is minimal (only total)
|
|
308
|
+
* ```
|
|
309
|
+
*
|
|
310
|
+
* @example
|
|
311
|
+
* ```typescript
|
|
312
|
+
* // Invalid page number - clamps to valid range
|
|
313
|
+
* const result = ResourcePaginationHelper.paginate(users, 25, {
|
|
314
|
+
* page: 999,
|
|
315
|
+
* limit: 10
|
|
316
|
+
* });
|
|
317
|
+
* // Result: data is empty array, meta shows page: 999 but no valid data slice
|
|
318
|
+
* ```
|
|
319
|
+
*
|
|
320
|
+
* @example
|
|
321
|
+
* ```typescript
|
|
322
|
+
* // Database scenario - data array smaller than total count
|
|
323
|
+
* const dbResult = [{id: 101}, {id: 102}, {id: 103}]; // Only 3 records from DB
|
|
324
|
+
* const result = ResourcePaginationHelper.paginate(dbResult, 150, {
|
|
325
|
+
* page: 34,
|
|
326
|
+
* limit: 3
|
|
327
|
+
* });
|
|
328
|
+
* // Result: data contains the 3 DB records, total: 150, meta shows page 34 of ~50
|
|
329
|
+
* ```
|
|
330
|
+
*
|
|
331
|
+
* @example
|
|
332
|
+
* ```typescript
|
|
333
|
+
* // Empty data array
|
|
334
|
+
* const result = ResourcePaginationHelper.paginate([], 0, {
|
|
335
|
+
* page: 1,
|
|
336
|
+
* limit: 10
|
|
337
|
+
* });
|
|
338
|
+
* // Result: data is empty array, total: 0, meta shows single empty page
|
|
339
|
+
* ```
|
|
340
|
+
*
|
|
341
|
+
* @example
|
|
342
|
+
* ```typescript
|
|
343
|
+
* // Large dataset pagination
|
|
344
|
+
* const largeDataset = Array.from({length: 10000}, (_, i) => ({id: i + 1}));
|
|
345
|
+
* const result = ResourcePaginationHelper.paginate(largeDataset, 10000, {
|
|
346
|
+
* page: 500,
|
|
347
|
+
* limit: 20
|
|
348
|
+
* });
|
|
349
|
+
* // Result: data contains items 9981-10000, meta shows page 500 of 500
|
|
350
|
+
* ```
|
|
351
|
+
*/
|
|
352
|
+
static paginate<DataType = unknown>(data: DataType[], count: number, options?: ResourceQueryOptions<DataType>): {
|
|
353
|
+
data: DataType[];
|
|
354
|
+
total: number;
|
|
355
|
+
meta: ResourcePaginationMeta;
|
|
356
|
+
};
|
|
357
|
+
/**
|
|
358
|
+
* Parses query options from HTTP request data, extracting and normalizing parameters from multiple sources.
|
|
359
|
+
*
|
|
360
|
+
* This method consolidates query parameters from URL query strings, request headers, route parameters,
|
|
361
|
+
* and custom filters into a standardized `ResourceQueryOptions` object. It's designed for REST API
|
|
362
|
+
* endpoints that need to handle complex query parameters for filtering, sorting, pagination, and more.
|
|
363
|
+
*
|
|
364
|
+
* **Parameter Sources (in precedence order):**
|
|
365
|
+
* 1. URL query parameters (`req.url`)
|
|
366
|
+
* 2. Route parameters (`req.params`)
|
|
367
|
+
* 3. X-Filters header (`req.headers['x-filters']`)
|
|
368
|
+
* 4. Custom filters (`req.filters`)
|
|
369
|
+
*
|
|
370
|
+
* **Supported Parameters:**
|
|
371
|
+
* - **Pagination**: `limit`, `skip`, `page`
|
|
372
|
+
* - **Sorting**: `orderBy` (string, array, or object)
|
|
373
|
+
* - **Filtering**: `where` (object, array, or string conditions)
|
|
374
|
+
* - **Relations**: `include`, `relations` (related data to load)
|
|
375
|
+
* - **Caching**: `cache`, `cacheTTL`
|
|
376
|
+
* - **Soft Deletes**: `includeDeleted`
|
|
377
|
+
* - **Distinct**: `distinct` (unique results)
|
|
378
|
+
*
|
|
379
|
+
* @template T - The resource data type for type-safe query options
|
|
380
|
+
* @param {Object} req - The request object containing query data from multiple sources
|
|
381
|
+
* @param {string} req.url - The request URL containing query parameters
|
|
382
|
+
* @param {Dictionary} req.headers - Request headers (may include 'x-filters')
|
|
383
|
+
* @param {Dictionary} [req.params] - Route parameters from URL path
|
|
384
|
+
* @param {Dictionary} [req.filters] - Custom filter object
|
|
385
|
+
* @returns {ResourceQueryOptions<T> & {queryParams: Dictionary}} Normalized query options with:
|
|
386
|
+
* - All standard `ResourceQueryOptions<T>` properties
|
|
387
|
+
* - `queryParams`: Raw parsed query parameters for reference
|
|
388
|
+
*
|
|
389
|
+
* @example
|
|
390
|
+
* ```typescript
|
|
391
|
+
* // Basic pagination from URL query
|
|
392
|
+
* const req = {
|
|
393
|
+
* url: '/api/users?limit=10&page=2',
|
|
394
|
+
* headers: {}
|
|
395
|
+
* };
|
|
396
|
+
* const options = ResourcePaginationHelper.parseQueryOptions(req);
|
|
397
|
+
* // Result: { limit: 10, page: 2, skip: 10, queryParams: { limit: '10', page: '2' } }
|
|
398
|
+
* ```
|
|
399
|
+
*
|
|
400
|
+
* @example
|
|
401
|
+
* ```typescript
|
|
402
|
+
* // Complex query with multiple sources
|
|
403
|
+
* const req = {
|
|
404
|
+
* url: '/api/users?limit=20&orderBy=name',
|
|
405
|
+
* headers: {
|
|
406
|
+
* 'x-filters': {
|
|
407
|
+
* where: { active: true },
|
|
408
|
+
* include: ['profile', 'roles']
|
|
409
|
+
* }
|
|
410
|
+
* },
|
|
411
|
+
* params: { userId: '123' },
|
|
412
|
+
* filters: { cache: true }
|
|
413
|
+
* };
|
|
414
|
+
* const options = ResourcePaginationHelper.parseQueryOptions(req);
|
|
415
|
+
* // Result includes all merged parameters with proper precedence
|
|
416
|
+
* ```
|
|
417
|
+
*
|
|
418
|
+
* @example
|
|
419
|
+
* ```typescript
|
|
420
|
+
* // Sorting with multiple fields
|
|
421
|
+
* const req = {
|
|
422
|
+
* url: '/api/users?orderBy[]=name&orderBy[]=-createdAt',
|
|
423
|
+
* headers: {}
|
|
424
|
+
* };
|
|
425
|
+
* const options = ResourcePaginationHelper.parseQueryOptions(req);
|
|
426
|
+
* // Result: { orderBy: { name: 'asc', createdAt: 'desc' }, ... }
|
|
427
|
+
* ```
|
|
428
|
+
*
|
|
429
|
+
* @example
|
|
430
|
+
* ```typescript
|
|
431
|
+
* // Filtering with complex where conditions
|
|
432
|
+
* const req = {
|
|
433
|
+
* url: '/api/users',
|
|
434
|
+
* headers: {
|
|
435
|
+
* 'x-filters': {
|
|
436
|
+
* where: {
|
|
437
|
+
* age: { $gte: 18 },
|
|
438
|
+
* status: 'active',
|
|
439
|
+
* $or: [{ role: 'admin' }, { role: 'moderator' }]
|
|
440
|
+
* }
|
|
441
|
+
* }
|
|
442
|
+
* }
|
|
443
|
+
* };
|
|
444
|
+
* const options = ResourcePaginationHelper.parseQueryOptions(req);
|
|
445
|
+
* // Result includes complex where conditions for database queries
|
|
446
|
+
* ```
|
|
447
|
+
*
|
|
448
|
+
* @example
|
|
449
|
+
* ```typescript
|
|
450
|
+
* // Including related data
|
|
451
|
+
* const req = {
|
|
452
|
+
* url: '/api/posts?include[]=author&include[]=comments',
|
|
453
|
+
* headers: {
|
|
454
|
+
* 'x-filters': {
|
|
455
|
+
* relations: ['tags', 'categories']
|
|
456
|
+
* }
|
|
457
|
+
* }
|
|
458
|
+
* };
|
|
459
|
+
* const options = ResourcePaginationHelper.parseQueryOptions(req);
|
|
460
|
+
* // Result: { include: ['author', 'comments'], relations: ['tags', 'categories'], ... }
|
|
461
|
+
* ```
|
|
462
|
+
*
|
|
463
|
+
* @example
|
|
464
|
+
* ```typescript
|
|
465
|
+
* // Caching configuration
|
|
466
|
+
* const req = {
|
|
467
|
+
* url: '/api/users?cache=1&cacheTTL=300',
|
|
468
|
+
* headers: {}
|
|
469
|
+
* };
|
|
470
|
+
* const options = ResourcePaginationHelper.parseQueryOptions(req);
|
|
471
|
+
* // Result: { cache: true, cacheTTL: 300, ... }
|
|
472
|
+
* ```
|
|
473
|
+
*
|
|
474
|
+
* @example
|
|
475
|
+
* ```typescript
|
|
476
|
+
* // Distinct results and soft deletes
|
|
477
|
+
* const req = {
|
|
478
|
+
* url: '/api/users?distinct=1&includeDeleted=true',
|
|
479
|
+
* headers: {}
|
|
480
|
+
* };
|
|
481
|
+
* const options = ResourcePaginationHelper.parseQueryOptions(req);
|
|
482
|
+
* // Result: { distinct: true, includeDeleted: true, ... }
|
|
483
|
+
* ```
|
|
484
|
+
*
|
|
485
|
+
* @example
|
|
486
|
+
* ```typescript
|
|
487
|
+
* // Express.js style request object
|
|
488
|
+
* const expressReq = {
|
|
489
|
+
* url: '/api/users?limit=5&page=1&orderBy=name',
|
|
490
|
+
* headers: {
|
|
491
|
+
* 'x-filters': JSON.stringify({ where: { active: true } })
|
|
492
|
+
* },
|
|
493
|
+
* params: { tenantId: 'abc123' },
|
|
494
|
+
* query: { search: 'john' } // Additional query params
|
|
495
|
+
* };
|
|
496
|
+
* const options = ResourcePaginationHelper.parseQueryOptions(expressReq);
|
|
497
|
+
* // Handles all Express.js request formats automatically
|
|
498
|
+
* ```
|
|
499
|
+
*
|
|
500
|
+
* @example
|
|
501
|
+
* ```typescript
|
|
502
|
+
* // Minimal request - only URL parameters
|
|
503
|
+
* const req = {
|
|
504
|
+
* url: '/api/users',
|
|
505
|
+
* headers: {}
|
|
506
|
+
* };
|
|
507
|
+
* const options = ResourcePaginationHelper.parseQueryOptions(req);
|
|
508
|
+
* // Result: { queryParams: {} } - minimal options, no pagination/sorting
|
|
509
|
+
* ```
|
|
510
|
+
*
|
|
511
|
+
* @example
|
|
512
|
+
* ```typescript
|
|
513
|
+
* // Mixed data types and type coercion
|
|
514
|
+
* const req = {
|
|
515
|
+
* url: '/api/users?limit=10&page=2&cache=true&includeDeleted=0',
|
|
516
|
+
* headers: {
|
|
517
|
+
* 'x-filters': {
|
|
518
|
+
* distinct: '1', // String '1' becomes boolean true
|
|
519
|
+
* cacheTTL: '600' // String '600' becomes number 600
|
|
520
|
+
* }
|
|
521
|
+
* }
|
|
522
|
+
* };
|
|
523
|
+
* const options = ResourcePaginationHelper.parseQueryOptions(req);
|
|
524
|
+
* // Result: proper type coercion for all parameters
|
|
525
|
+
* ```
|
|
526
|
+
*/
|
|
527
|
+
static parseQueryOptions<T = unknown>(req: {
|
|
528
|
+
url: string;
|
|
529
|
+
headers: Dictionary;
|
|
530
|
+
params?: Dictionary;
|
|
531
|
+
filters?: Dictionary;
|
|
532
|
+
}): ResourceQueryOptions<T> & {
|
|
533
|
+
queryParams: Dictionary;
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
type SortOrder = 'asc' | 'desc';
|
|
537
|
+
export {};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
'use strict';var _=require('qs');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var ___default=/*#__PURE__*/_interopDefault(_);var Q=Object.defineProperty,W=Object.defineProperties;var K=Object.getOwnPropertyDescriptors;var M=Object.getOwnPropertySymbols;var v=Object.prototype.hasOwnProperty,F=Object.prototype.propertyIsEnumerable;var U=(t,e,n)=>e in t?Q(t,e,{enumerable:true,configurable:true,writable:true,value:n}):t[e]=n,A=(t,e)=>{for(var n in e||(e={}))v.call(e,n)&&U(t,n,e[n]);if(M)for(var n of M(e))F.call(e,n)&&U(t,n,e[n]);return t},k=(t,e)=>W(t,K(e));function w(...t){if(t.length===1)return Array.isArray(t[0])?t[0]:[];let e=null;for(var n in t){let r=t[n];if(Array.isArray(r)){if(r.length)return r;e||(e=r);}}return e||[]}function u(t){return !!(t&&typeof t=="string")}function O(t){return typeof t=="number"&&!isNaN(t)&&isFinite(t)}function R(t){return !t||typeof t!="object"?false:t instanceof Date?true:typeof t.getTime!="function"?false:!(Object.prototype.toString.call(t)!=="[object Date]"||isNaN(t.getTime()))}function N(t){return typeof window!="object"||!window||typeof document=="undefined"||typeof HTMLElement=="undefined"||!HTMLElement?false:t===document?true:"HTMLElement"in window?!!t&&t instanceof HTMLElement:!!t&&typeof t=="object"&&t.nodeType===1&&!!t.nodeName}function D(t){return t==null||typeof t=="string"||typeof t=="number"||typeof t=="boolean"}function j(t){if(t instanceof RegExp)return true;if(!t||typeof t!="object"||!Object.prototype.toString.call(t).includes("RegExp"))return false;try{return new RegExp(t),!0}catch(e){return false}}function y(t){if(t===null||typeof t!="object"||N(t)||R(t)||j(t)||D(t))return false;let e=Object.getPrototypeOf(t);if(e===null)return true;let n=e.constructor;if(typeof n!="function")return false;if(n===Object)return true;let r=n.prototype;return typeof r!="object"?false:r===Object.prototype?true:typeof e.hasOwnProperty=="function"&&Object.prototype.hasOwnProperty.call(e,"isPrototypeOf")&&typeof e.isPrototypeOf=="function"}function C(t){if(Array.isArray(t)){let r=[];for(var e=0;e<t.length;e++)r[e]=C(t[e]);return r}else if(y(t)&&t){let r={};for(var n in t)t.hasOwnProperty(n)&&(r[n]=C(t[n]));return r}else return t}Object.getSize=function(t,e=false){if(!t||typeof t!="object")return 0;if(Array.isArray(t))return t.length;typeof e!="boolean"&&(e=false);let n=0;for(let r in t)if(Object.prototype.hasOwnProperty.call(t,r)&&(n++,e===true))return n;return n};function x(t,...e){let n=Array.isArray(t),r=y(t);(t==null||!n&&!r)&&(t={});for(let i=0;i<e.length;i++){let s=e[i];if(s==null)continue;let o=y(s),c=Array.isArray(s);if(!(!o&&!c)){if(n){c&&L(t,s);continue}else if(c)continue;for(let a in s){let f=s[a];if(f==null)continue;if(f===s){t[a]=t;continue}let p=t[a],m=Array.isArray(p),h=Array.isArray(f);if(m){h?L(t[a],f):t[a]=f;continue}else if(!y(p)){t[a]=f;continue}if(h||!y(f)){t[a]=f;continue}t[a]=x({},p,f);}}}return t}var L=(t,e)=>{let n=e.length,r=0;for(let i=0;i<t.length;i++){let s=t[i],o=e[i];if(i<n){let c=Array.isArray(s),a=Array.isArray(o),f=y(s),p=y(o);c&&a||f&&p?(t[r]=x(c?[]:{},s,o),r++):o!=null?(t[r]=o,r++):s!=null&&(t[r]=s,r++);}}for(let i=t.length;i<n;i++)e[i]!==void 0&&e[i]!==null&&t.push(e[i]);return t};function Z(t,e){return P(t,"",{},e)}function P(t,e="",n={},r){if(n=y(n)?n:{},D(t)||R(t)||j(t)||Array.isArray(t)&&(r!=null&&r.skipArrays))return e&&(n[e]=t),n;if(typeof t=="function"||typeof t=="object"&&!y(t)&&!H(t))return n;if(t instanceof Map||t instanceof WeakMap)return Array.from(t.entries()).forEach(([i,s])=>{let o=e?`${e}[${String(i)}]`:String(i);P(s,o,n,r);}),n;if(Array.isArray(t)||t instanceof Set||t instanceof WeakSet)return (Array.isArray(t)?t:Array.from(t)).forEach((s,o)=>{let c=e?`${e}[${o}]`:String(o);P(s,c,n,r);}),n;if(y(t))for(let i in t){if(!Object.prototype.hasOwnProperty.call(t,i))continue;let s=t[i],o=e?e.endsWith("]")?`${e}.${i}`:`${e}.${i}`:i;P(s,o,n,r);}return n}function H(t){return Array.isArray(t)||t instanceof Set||t instanceof Map||t instanceof WeakMap||t instanceof WeakSet}function V(t){return Object.entries(t)}Object.typedEntries=V;Object.flatten=Z;Object.clone=C;var S=function(t,e=""){if(!t||typeof t!="string")return "";if(!e||typeof e!="string")return t.trim();let n=t.length;for(;t.startsWith(e)&&n>=0;)t=t.slice(e.length),--n;return t.toString()},$=function(t,e=""){if(!t||typeof t!="string")return "";if(!e||typeof e!="string")return t.trim();let n=t.length;for(;t.endsWith(e)&&n>=0;)t=t.slice(0,-e.length),--n;return t.toString()},I=(t,e=true)=>typeof t!="string"?false:e!==false?/^\d*\.?\d+$/.test(t):/^\d+$/.test(t);String.prototype.ltrim=function(t){return S(this.toString(),t)};String.prototype.rtrim=function(t){return $(this.toString(),t)};String.prototype.isNumber=function(t=true){return I(this.toString(),t)};String.prototype.replaceAll=function(t,e){return !u(t)||!u(e)?this.toString():this.toString().split(t).join(e)};var G=t=>u(t)?(t=t.trim(),t.replace(/(.)([A-Z][a-z]+)/,"$1_$2").replace(/([a-z0-9])([A-Z])/,"$1_$2").toUpperCase()):"";String.prototype.toSnakeCase=function(){return G(this.toString())};var J=t=>u(t)?(t=t.trim(),t.charAt(0)+t.replace(/(_\w)/g,e=>e[1].toUpperCase()).substring(1)):"";String.prototype.toCamelCase=function(){return J(this.toString())};var X=function(t){return !t||typeof t!="string"?"":(t=t.trim(),t.charAt(0).toUpperCase()+t.slice(1))};String.prototype.upperFirst=function(){return X(this.toString())};var Y=function(t){return !t||typeof t!="string"?"":(t=t.trim(),t.charAt(0).toLowerCase()+t.slice(1))};String.prototype.lowerFirst=function(){return Y(this.toString())};var q=(t,e=true)=>{if(typeof t!="string")return "";let n=tt(t);return t=typeof n.search=="string"?n.search:"",e&&t?"?"+S(t,"?"):(t=$(S(t.trim(),"?"),"?"),t)},E=function(t,e={}){return typeof t!="string"?{}:___default.default.parse(q(t,false),A({allowSparse:true,decoder:n=>decodeURIComponent(n.replace(/\+/g," "))},Object.assign({},e)))};var tt=t=>{if(typeof t!="string")return {};if(typeof URL!="undefined"&&URL&&et(t))try{return new URL(t)}catch(r){}t=nt(t)?decodeURIComponent(t):t;var e=t.match(/^(([^:\\/?#]+:)?(?:\/\/((?:([^\\/?#:]*):([^\\/?#:]*)@)?([^\\/?#:]*)(?::([^\\/?#:]*))?)))?([^?#]*)(\?[^#]*)?(#.*)?$/);let n=e?{hash:e[10]||"",host:e[3]||"",hostname:e[6]||"",href:e[0]||"",origin:e[1]||"",pathname:e[8]||(e[1]?"/":""),port:e[7]||"",protocol:e[2]||"",search:e[9]||"",username:e[4]||"",password:e[5]||""}:{};return n.protocol&&n.protocol.length==2&&(n.protocol="file:///"+n.protocol.toUpperCase(),n.origin=n.protocol+"//"+n.host),n.protocol&&(n.href=n.origin+n.pathname+n.search+n.hash),n};function et(t,e={}){let{requireHost:n=true,allowedProtocols:r}=Object.assign({},e);if(!u(t)||!u(t.trim()))return false;let i=t;if(typeof URL!="undefined"&&URL)try{let s=new URL(i);if(!s.protocol||s.protocol===":")return !1;let o=s.protocol.slice(0,-1);if(r&&r.length>0&&!r.includes(o))return !1;if(n)if(["http","https","ftp","ftps","ws","wss"].includes(o)){if(!u(s.hostname)||!s.hostname.trim()||!u(s.host)||!s.host.trim())return !1;let a=`${o}://`;if(!i.startsWith(a)||i.slice(a.length).startsWith("/"))return !1;let p=/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/,m=s.hostname.match(p);if(m&&!m.slice(1,5).map(Number).every(l=>l>=0&&l<=255))return !1}else return !1;return !0}catch(s){return false}if(n){let s=i.indexOf("://");if(s===-1)return false;let o=i.slice(0,s);if(!o||r&&r.length>0&&!r.includes(o))return false;let c=i.slice(s+3);if(c==="")return false;let a=c.indexOf("@"),f=a>=0?c.slice(a+1):c;if(f===""||f.startsWith("/"))return false;let p=f.indexOf("/"),m=f.indexOf("?"),h=f.indexOf("#"),T=Math.min(p>=0?p:f.length,m>=0?m:f.length,h>=0?h:f.length),l=f.slice(0,T);if(!l)return false;let d=l;if(l.startsWith("[")){let g=l.indexOf("]");if(g===-1)return false;d=l.slice(0,g+1);let b=l.slice(g+1);if(b&&!b.startsWith(":"))return false}else {let g=l.indexOf(":");g>=0&&(d=l.slice(0,g));}if(!d)return false;if(d==="localhost")return true;if(/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(d))return !d.split(".").map(Number).some(b=>b>255||b<0);if(/^\[.*\]$/.test(d)){let g=d.slice(1,-1);return !(!g||g.includes(":::"))}return !!(/^[a-zA-Z\d-]*(\.[a-zA-Z\d-]+)*$/.test(d)&&d!=="")}else {let s="[a-zA-Z][a-zA-Z\\d+\\-.]*";return r&&r.length>0&&(s=`(?:${r.join("|")})`),new RegExp(`^(${s}):.+$`).test(i)}}var nt=t=>{if(!u(t)||!t.includes("%"))return false;let e=/%[0-9A-Fa-f]{2}/g;if(!t.match(e))return false;try{let r=decodeURIComponent(t);if(r!==t)return !0;try{if(decodeURIComponent(r)!==r)return !0}catch(i){return !0}}catch(r){return false}return false};var B=class t{static normalizePagination(e){let{page:n,skip:r,limit:i}=Object.assign({},e);return O(i)?(O(r)&&r>0?n=Math.floor(r/i)+1:O(n)&&n>0?r=(n-1)*i:(n=1,r=0),{page:n,skip:r,limit:i}):{}}static normalizeOrderBy(e){let n=Array.isArray(e)?e:u(e)?[e]:[],r={};return n.forEach(i=>{if(!u(i)||String(i).trim()==="")return;let s=String(i).startsWith("-"),o=s?"desc":"asc",c=s?String(i).slice(1):i,a=c;r[a]!==void 0&&console.warn(`Duplicate orderBy field: ${c}. Using last occurrence.`),r[a]=o;}),r}static canPaginateResult(e){return y(e)?O(e.limit):false}static getPaginationMetaData(e,n){let{limit:r,page:i,skip:s}=t.normalizePagination(n);e=O(e)?e:0;let o={total:e};return typeof r=="number"&&r>0&&typeof i=="number"&&i>=0&&(o.currentPage=i,o.pageSize=r,o.totalPages=Math.ceil(e/r),o.hasNextPage=o.currentPage<o.totalPages,o.hasPreviousPage=o.currentPage>1,o.nextPage=o.hasNextPage?o.currentPage+1:void 0,o.previousPage=o.hasPreviousPage?o.currentPage-1:void 0,o.lastPage=o.totalPages),o}static paginate(e,n,r){let i=t.getPaginationMetaData(n,r),{currentPage:s,pageSize:o,totalPages:c}=i;if(Array.isArray(e)&&O(s)&&O(o)&&O(c)){let a=Math.max(0,s-1)*o,f=a+o;e=e.slice(a,f);}return {data:e,total:n,meta:i}}static parseQueryOptions(e){var b;let n=x({},e==null?void 0:e.params,E(e==null?void 0:e.url)),r=x({},n,(b=e==null?void 0:e.headers)==null?void 0:b["x-filters"],e==null?void 0:e.filters),i=z(r.limit),s=z(r.skip),o=z(r.page),c=t.normalizePagination({limit:i,skip:s,page:o}),a=r.distinct;typeof a=="number"&&(a=!!a),(typeof a=="boolean"||Array.isArray(a)&&a.length)&&(c.distinct=a);let f=r.orderBy,p=t.normalizeOrderBy(f);p&&Object.getSize(p,true)>0&&(c.orderBy=p);let m=w(r.include);m.length&&(c.include=m);let h=r.cache;h!==void 0&&(c.cache=!!h);let T=r.cacheTTL;T!==void 0&&(c.cacheTTL=T);let l=rt(r.where);y(l)&&Object.getSize(l,true)&&(c.where=l);let d=r.includeDeleted;typeof d=="boolean"&&(c.includeDeleted=d);let g=w(r.relations);return g.length&&(c.relations=g),k(A({},c),{queryParams:n})}},rt=(...t)=>{for(let e of t)if(Array.isArray(e)&&e.length||u(e)||y(e)&&Object.getSize(e,true))return e},z=t=>{if(I(t))return Number(t);if(typeof t=="number")return t};
|
|
2
|
+
exports.ResourcePaginationHelper=B;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a decorator that can be applied to class properties or methods.
|
|
3
|
+
*
|
|
4
|
+
* This function takes a key of type KeyType (defaulting to any) and returns a function that takes a value of type ValueType (defaulting to any).
|
|
5
|
+
* The returned function is a decorator that can be applied to class properties or methods.
|
|
6
|
+
*
|
|
7
|
+
* @template KeyType - The type of the key used to store metadata.
|
|
8
|
+
* @template ValueType - The type of the value associated with the key.
|
|
9
|
+
* @param {KeyType} key - The key under which the metadata will be stored.
|
|
10
|
+
* @returns {(value: ValueType) => (target: Object, propertyKey: string) => void} A function that takes a value and returns the decorator function.
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const myDecorator = createDecorator('myKey')('myValue');
|
|
14
|
+
* class MyClass {
|
|
15
|
+
* @myDecorator
|
|
16
|
+
* myProperty: string;
|
|
17
|
+
* }
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare function createDecorator<ValueType = unknown, KeyType = unknown>(key: KeyType): (value: ValueType) => (target: object, propertyKey: string | symbol) => void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
'use strict';function o(e){return t=>(n,r)=>{Reflect.defineMetadata(e,t,n,r);}}exports.createDecorator=o;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { ClassConstructor } from '../../types';
|
|
3
|
+
/**
|
|
4
|
+
* Creates a property decorator that stores metadata without making the property readonly
|
|
5
|
+
@template MetadataType - The type of the metadata
|
|
6
|
+
@template PropertyKeyType - The type of the property key
|
|
7
|
+
* @param metadataKey - The key to store the metadata under
|
|
8
|
+
@param metadata - The metadata to store, or a function that returns the metadata
|
|
9
|
+
* @returns PropertyDecorator
|
|
10
|
+
*/
|
|
11
|
+
export declare function buildPropertyDecorator<MetadataType = unknown, PropertyKeyType extends MetadataPropertyKey = MetadataPropertyKey>(metadataKey: any,
|
|
12
|
+
/**
|
|
13
|
+
Retrieves the metadata for a property
|
|
14
|
+
@param {Object} target - The class constructor
|
|
15
|
+
@param {PropertyKeyType} propertyKey - The property key
|
|
16
|
+
@param {MetadataType} existingMetaData - The existing metadata for the property
|
|
17
|
+
@param {Record<PropertyKeyType, MetadataType>} allExistingMetadata - All existing metadata for the class
|
|
18
|
+
@returns {MetadataType} The metadata for the property
|
|
19
|
+
|
|
20
|
+
*/
|
|
21
|
+
metadata: ((existingMetaData: MetadataType, allExistingMetadata: Record<PropertyKeyType, MetadataType>, target: object, propertyKey: MetadataPropertyKey) => MetadataType) | MetadataType): PropertyDecorator;
|
|
22
|
+
/**
|
|
23
|
+
* Retrieves all properties of a class that have been decorated with a specific metadata key.
|
|
24
|
+
@template MetaDataType - The type of the metadata
|
|
25
|
+
@template PropertyKeyType - The type of the property key
|
|
26
|
+
* @param target The class to retrieve decorated properties from.
|
|
27
|
+
* @param metadataKey The metadata key.
|
|
28
|
+
* @returns Record of property names and their metadata
|
|
29
|
+
*/
|
|
30
|
+
export declare function getDecoratedProperties<MetaDataType = any, PropertyKeyType extends MetadataPropertyKey = MetadataPropertyKey>(target: ClassConstructor, metadataKey: any): Record<PropertyKeyType, MetaDataType>;
|
|
31
|
+
/**
|
|
32
|
+
* Retrieves metadata for a specific property.
|
|
33
|
+
* @template MetaDataType - The type of the metadata
|
|
34
|
+
* @param target - target The class or object containing the property.
|
|
35
|
+
* @param metadataKey - The key to retrieve metadata for
|
|
36
|
+
*@param propertyKey - The name of the propertyfor which metadata is being retrieved.
|
|
37
|
+
* @returns {MetaDataType} The metadata value for the property.
|
|
38
|
+
*/
|
|
39
|
+
export declare function getDecoratedProperty<MetaDataType = unknown>(target: ClassConstructor, metadataKey: MetadataPropertyKey, propertyKey: MetadataPropertyKey): MetaDataType;
|
|
40
|
+
type MetadataPropertyKey = string | symbol | number;
|
|
41
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
'use strict';require('reflect-metadata');function d(t,e){return (a,o)=>{let y=a==null?void 0:a.constructor,r=Object.assign({},Reflect.getMetadata(t,y)),n=r[o],p=typeof e=="function"?e(n,r,a,o):e;r[o]=p,Reflect.defineMetadata(t,r,y),Reflect.defineMetadata(t,e,a,o);}}function s(t,e){return Object.assign({},Object.assign({},Reflect.getMetadata(e,t)),Object.assign({},Reflect.getMetadata(e,t.prototype)))}function M(t,e,a){return s(t,e)[a]}exports.buildPropertyDecorator=d;exports.getDecoratedProperties=s;exports.getDecoratedProperty=M;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { ClassConstructor } from '../../types';
|
|
2
|
+
import 'reflect-metadata';
|
|
3
|
+
import { Field, FieldType } from '../types';
|
|
4
|
+
export declare const fieldsMetaData: unique symbol;
|
|
5
|
+
export declare function FieldMeta<T extends FieldType = FieldType>(options: Field<T>): PropertyDecorator;
|
|
6
|
+
/**
|
|
7
|
+
* Retrieves the fields metadata from a class target.
|
|
8
|
+
*
|
|
9
|
+
* This function uses reflection to access the metadata associated with the given target class.
|
|
10
|
+
* It returns an object where the keys are property names, and the values are objects containing the type, name, and any additional options defined in the field metadata.
|
|
11
|
+
*
|
|
12
|
+
* @param {any} target - The target class or instance from which to retrieve the metadata.
|
|
13
|
+
* @returns {Record<string, ({ name: string } & Field)>} An object mapping property names to their corresponding metadata, which includes the type and other options.
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* class MyClass {
|
|
17
|
+
* @FieldMeta({ type: 'string' }) myField: string;
|
|
18
|
+
* }
|
|
19
|
+
* const fields = getFieldsFromTarget(MyClass);
|
|
20
|
+
* console.log(fields); // Output: { myField: { name: 'myField', type: 'string' } }
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare function getFieldsFromTarget(target: ClassConstructor): Record<string, {
|
|
24
|
+
name: string;
|
|
25
|
+
} & Field>;
|
|
26
|
+
/***
|
|
27
|
+
* Retrieves the fields metadata from a class instance.
|
|
28
|
+
* @param {T} instance - The instance of the class from which to retrieve the metadata.
|
|
29
|
+
* @returns {Record<string, ({ name: string } & Field)>} An object mapping property names to their corresponding metadata, which includes the type and other options.
|
|
30
|
+
*/
|
|
31
|
+
export declare function getFields<T extends ClassConstructor>(instance: InstanceType<T>): Record<string, {
|
|
32
|
+
name: string;
|
|
33
|
+
} & Field>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
'use strict';require('reflect-metadata');var l=Object.defineProperty;var r=Object.getOwnPropertySymbols;var f=Object.prototype.hasOwnProperty,g=Object.prototype.propertyIsEnumerable;var d=(t,e,s)=>e in t?l(t,e,{enumerable:true,configurable:true,writable:true,value:s}):t[e]=s,c=(t,e)=>{for(var s in e||(e={}))f.call(e,s)&&d(t,s,e[s]);if(r)for(var s of r(e))g.call(e,s)&&d(t,s,e[s]);return t};var n=Symbol("fieldsResourcesMetadata");function p(t){return function(e,s){var o;let a=Object.assign({},Reflect.getMetadata(n,e)||{}),i=String((o=Reflect.getMetadata("design:type",e,s))==null?void 0:o.name).toLowerCase();t.type===void 0&&(t.type=["string","number","boolean","date"].includes(i)?i:"text"),a[s]=c({name:s},Object.assign({},t)),Reflect.defineMetadata(n,a,e);}}function F(t){let e=Reflect.getMetadata(n,t.prototype);return Object.assign({},e)}function y(t){let e=Reflect.getMetadata(n,Object.getPrototypeOf(t).constructor);return Object.assign({},e)}exports.FieldMeta=p;exports.fieldsMetaData=n;exports.getFields=y;exports.getFieldsFromTarget=F;
|