@woltz/rich-domain 1.3.1 → 1.3.2
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/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +9 -11
- package/eslint.config.js +0 -57
- package/jest.config.js +0 -21
- package/src/aggregate-changes.ts +0 -444
- package/src/base-entity.ts +0 -410
- package/src/change-tracker.ts +0 -1123
- package/src/constants.ts +0 -81
- package/src/criteria.ts +0 -521
- package/src/crypto.ts +0 -31
- package/src/domain-event-bus.ts +0 -152
- package/src/domain-event.ts +0 -49
- package/src/entity-changes.ts +0 -146
- package/src/entity-schema-registry.ts +0 -505
- package/src/entity.ts +0 -5
- package/src/exceptions.ts +0 -435
- package/src/id.ts +0 -98
- package/src/index.ts +0 -52
- package/src/mapper.ts +0 -6
- package/src/paginated-result.ts +0 -250
- package/src/repository/base-repository.ts +0 -33
- package/src/repository/index.ts +0 -3
- package/src/repository/unit-of-work.ts +0 -76
- package/src/types/change-tracker.ts +0 -264
- package/src/types/criteria.ts +0 -159
- package/src/types/domain-event.ts +0 -38
- package/src/types/domain.ts +0 -33
- package/src/types/index.ts +0 -7
- package/src/types/standard-schema.ts +0 -19
- package/src/types/unit-of-work.ts +0 -46
- package/src/types/utils.ts +0 -20
- package/src/utils/criteria-operator-validation.ts +0 -209
- package/src/utils/helpers.ts +0 -34
- package/src/validation-error.ts +0 -141
- package/src/value-object.ts +0 -249
package/src/constants.ts
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ArrayOperators,
|
|
3
|
-
BooleanOperators,
|
|
4
|
-
DateOperators,
|
|
5
|
-
FilterOperator,
|
|
6
|
-
NumberOperators,
|
|
7
|
-
StringOperators,
|
|
8
|
-
ValidationConfig,
|
|
9
|
-
} from ".";
|
|
10
|
-
|
|
11
|
-
export const DEFAULT_VALIDATION_CONFIG: Required<ValidationConfig> = {
|
|
12
|
-
onCreate: true,
|
|
13
|
-
onUpdate: true,
|
|
14
|
-
throwOnError: true,
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export const ARRAY_OPERATORS: ArrayOperators[] = [
|
|
18
|
-
"in",
|
|
19
|
-
"notIn",
|
|
20
|
-
"isNull",
|
|
21
|
-
"isNotNull",
|
|
22
|
-
];
|
|
23
|
-
export const BOOLEAN_OPERATORS: BooleanOperators[] = [
|
|
24
|
-
"equals",
|
|
25
|
-
"notEquals",
|
|
26
|
-
"isNull",
|
|
27
|
-
"isNotNull",
|
|
28
|
-
];
|
|
29
|
-
export const DATE_OPERATORS: DateOperators[] = [
|
|
30
|
-
"equals",
|
|
31
|
-
"notEquals",
|
|
32
|
-
"greaterThan",
|
|
33
|
-
"greaterThanOrEqual",
|
|
34
|
-
"lessThan",
|
|
35
|
-
"lessThanOrEqual",
|
|
36
|
-
"in",
|
|
37
|
-
"notIn",
|
|
38
|
-
"between",
|
|
39
|
-
"isNull",
|
|
40
|
-
"isNotNull",
|
|
41
|
-
];
|
|
42
|
-
export const NUMBER_OPERATORS: NumberOperators[] = [
|
|
43
|
-
"equals",
|
|
44
|
-
"notEquals",
|
|
45
|
-
"greaterThan",
|
|
46
|
-
"greaterThanOrEqual",
|
|
47
|
-
"lessThan",
|
|
48
|
-
"lessThanOrEqual",
|
|
49
|
-
"in",
|
|
50
|
-
"notIn",
|
|
51
|
-
"between",
|
|
52
|
-
"isNull",
|
|
53
|
-
"isNotNull",
|
|
54
|
-
];
|
|
55
|
-
export const STRING_OPERATORS: StringOperators[] = [
|
|
56
|
-
"equals",
|
|
57
|
-
"notEquals",
|
|
58
|
-
"contains",
|
|
59
|
-
"startsWith",
|
|
60
|
-
"endsWith",
|
|
61
|
-
"in",
|
|
62
|
-
"notIn",
|
|
63
|
-
"isNull",
|
|
64
|
-
"isNotNull",
|
|
65
|
-
];
|
|
66
|
-
export const FILTER_OPERATORS: FilterOperator[] = [
|
|
67
|
-
"equals",
|
|
68
|
-
"notEquals",
|
|
69
|
-
"greaterThan",
|
|
70
|
-
"greaterThanOrEqual",
|
|
71
|
-
"lessThan",
|
|
72
|
-
"lessThanOrEqual",
|
|
73
|
-
"contains",
|
|
74
|
-
"startsWith",
|
|
75
|
-
"endsWith",
|
|
76
|
-
"in",
|
|
77
|
-
"notIn",
|
|
78
|
-
"between",
|
|
79
|
-
"isNull",
|
|
80
|
-
"isNotNull",
|
|
81
|
-
];
|
package/src/criteria.ts
DELETED
|
@@ -1,521 +0,0 @@
|
|
|
1
|
-
import { InvalidCriteriaError } from "./exceptions";
|
|
2
|
-
import {
|
|
3
|
-
CriteriaAdapter,
|
|
4
|
-
CriteriaOptions,
|
|
5
|
-
FieldPath,
|
|
6
|
-
Filter,
|
|
7
|
-
FilterOperator,
|
|
8
|
-
FilterValueFor,
|
|
9
|
-
OperatorsForType,
|
|
10
|
-
Order,
|
|
11
|
-
OrderDirection,
|
|
12
|
-
Pagination,
|
|
13
|
-
PathValue,
|
|
14
|
-
Search,
|
|
15
|
-
TypedFilter,
|
|
16
|
-
TypedOrder,
|
|
17
|
-
} from "./types";
|
|
18
|
-
import {
|
|
19
|
-
isValidOperatorForType,
|
|
20
|
-
getValidOperatorsForType,
|
|
21
|
-
isOperator,
|
|
22
|
-
sanitizeFieldValue,
|
|
23
|
-
} from "./utils/criteria-operator-validation";
|
|
24
|
-
import { parseQueryValue } from "./utils/helpers";
|
|
25
|
-
|
|
26
|
-
export class Criteria<T = any> {
|
|
27
|
-
private _filters: Filter<FieldPath<T>, any>[] = [];
|
|
28
|
-
private _orders: Order[] = [];
|
|
29
|
-
private _pagination: Pagination = { page: 1, limit: 20, offset: 0 };
|
|
30
|
-
private _search?: Search;
|
|
31
|
-
private _adapter?: CriteriaAdapter<any, any>;
|
|
32
|
-
|
|
33
|
-
private constructor() {}
|
|
34
|
-
|
|
35
|
-
static create<T = any>(): Criteria<T> {
|
|
36
|
-
return new Criteria<T>();
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
useAdapter<A extends CriteriaAdapter<any, any>>(map: A): this {
|
|
40
|
-
this._adapter = map;
|
|
41
|
-
return this;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
getAdapter(): CriteriaAdapter<any, any> | undefined {
|
|
45
|
-
return this._adapter;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
where<K extends FieldPath<T>>(
|
|
49
|
-
field: K,
|
|
50
|
-
operator: OperatorsForType<NonNullable<PathValue<T, K>>>,
|
|
51
|
-
value?: FilterValueFor<PathValue<T, K>>,
|
|
52
|
-
options?: CriteriaOptions
|
|
53
|
-
): this;
|
|
54
|
-
|
|
55
|
-
where<K extends FieldPath<T>>(
|
|
56
|
-
field: K,
|
|
57
|
-
operator: FilterOperator,
|
|
58
|
-
value?: FilterValueFor<PathValue<T, K>>,
|
|
59
|
-
options?: CriteriaOptions
|
|
60
|
-
): this {
|
|
61
|
-
this.validateOperator(operator, value);
|
|
62
|
-
|
|
63
|
-
this._filters.push({
|
|
64
|
-
field: this.resolveFieldPath(field),
|
|
65
|
-
operator,
|
|
66
|
-
value,
|
|
67
|
-
options,
|
|
68
|
-
});
|
|
69
|
-
return this;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
whereEquals<K extends FieldPath<T>>(field: K, value: PathValue<T, K>): this {
|
|
73
|
-
return this.where(
|
|
74
|
-
field,
|
|
75
|
-
"equals" as OperatorsForType<PathValue<T, K>>,
|
|
76
|
-
value
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
whereContains<K extends FieldPath<T>>(
|
|
81
|
-
field: K,
|
|
82
|
-
value: PathValue<T, K>
|
|
83
|
-
): this {
|
|
84
|
-
return this.where(
|
|
85
|
-
field,
|
|
86
|
-
"contains" as OperatorsForType<PathValue<T, K>>,
|
|
87
|
-
value
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
whereIn<K extends FieldPath<T>>(field: K, values: PathValue<T, K>[]): this {
|
|
92
|
-
return this.where(field, "in" as OperatorsForType<PathValue<T, K>>, values);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
whereBetween<K extends FieldPath<T>>(
|
|
96
|
-
field: K,
|
|
97
|
-
min: PathValue<T, K>,
|
|
98
|
-
max: PathValue<T, K>
|
|
99
|
-
): this {
|
|
100
|
-
return this.where(
|
|
101
|
-
field,
|
|
102
|
-
"between" as OperatorsForType<PathValue<T, K>>,
|
|
103
|
-
[min, max] as [PathValue<T, K>, PathValue<T, K>]
|
|
104
|
-
);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
whereNull<K extends FieldPath<T>>(field: K): this {
|
|
108
|
-
return this.where(field, "isNull" as OperatorsForType<PathValue<T, K>>);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
whereNotNull<K extends FieldPath<T>>(field: K): this {
|
|
112
|
-
return this.where(field, "isNotNull" as OperatorsForType<PathValue<T, K>>);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
whereSome<K extends FieldPath<T>>(
|
|
116
|
-
field: K,
|
|
117
|
-
operator: OperatorsForType<NonNullable<PathValue<T, K>>>,
|
|
118
|
-
value?: FilterValueFor<PathValue<T, K>>
|
|
119
|
-
): this {
|
|
120
|
-
return this.where(field, operator, value, { quantifier: "some" });
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
whereEvery<K extends FieldPath<T>>(
|
|
124
|
-
field: K,
|
|
125
|
-
operator: OperatorsForType<NonNullable<PathValue<T, K>>>,
|
|
126
|
-
value?: FilterValueFor<PathValue<T, K>>
|
|
127
|
-
): this {
|
|
128
|
-
return this.where(field, operator, value, { quantifier: "every" });
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
whereNone<K extends FieldPath<T>>(
|
|
132
|
-
field: K,
|
|
133
|
-
operator: OperatorsForType<NonNullable<PathValue<T, K>>>,
|
|
134
|
-
value?: FilterValueFor<PathValue<T, K>>
|
|
135
|
-
): this {
|
|
136
|
-
return this.where(field, operator, value, { quantifier: "none" });
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
orderBy<K extends FieldPath<T>>(
|
|
140
|
-
field: K,
|
|
141
|
-
direction: OrderDirection = "asc"
|
|
142
|
-
): this {
|
|
143
|
-
this._orders.push({
|
|
144
|
-
field: this.resolveFieldPath(field),
|
|
145
|
-
direction,
|
|
146
|
-
});
|
|
147
|
-
return this;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
orderByAsc<K extends FieldPath<T>>(field: K): this {
|
|
151
|
-
return this.orderBy(field, "asc");
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
orderByDesc<K extends FieldPath<T>>(field: K): this {
|
|
155
|
-
return this.orderBy(field, "desc");
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
search(value: string): this {
|
|
159
|
-
this._search = value;
|
|
160
|
-
return this;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
hasSearch(): boolean {
|
|
164
|
-
return !!this._search;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
getSearch(): Search | undefined {
|
|
168
|
-
return this._search;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
paginate(page: number, limit: number): this {
|
|
172
|
-
if (page < 1) page = 1;
|
|
173
|
-
if (limit < 1) limit = 10;
|
|
174
|
-
|
|
175
|
-
this._pagination = {
|
|
176
|
-
page,
|
|
177
|
-
limit,
|
|
178
|
-
offset: (page - 1) * limit,
|
|
179
|
-
};
|
|
180
|
-
return this;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
limit(limit: number): this {
|
|
184
|
-
return this.paginate(1, limit);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
getFilters(): Filter[] {
|
|
188
|
-
return this._filters.map((filter) => ({
|
|
189
|
-
field: this.resolveFieldPath(filter.field),
|
|
190
|
-
operator: filter.operator,
|
|
191
|
-
value: filter.value,
|
|
192
|
-
options: filter.options,
|
|
193
|
-
}));
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
getOrders(): Order[] {
|
|
197
|
-
return this._orders.map((order) => ({
|
|
198
|
-
field: this.resolveFieldPath(order.field as FieldPath<T>),
|
|
199
|
-
direction: order.direction,
|
|
200
|
-
}));
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
getPagination(): Pagination {
|
|
204
|
-
return this._pagination;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
hasFilters(): boolean {
|
|
208
|
-
return this._filters.length > 0;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
hasOrders(): boolean {
|
|
212
|
-
return this._orders.length > 0;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
hasPagination(): boolean {
|
|
216
|
-
return this._pagination !== undefined;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
clone(): Criteria<T> {
|
|
220
|
-
const cloned = Criteria.create<T>();
|
|
221
|
-
cloned._filters = [
|
|
222
|
-
...this._filters.map((filter) => ({
|
|
223
|
-
field: this.resolveFieldPath(filter.field),
|
|
224
|
-
operator: filter.operator,
|
|
225
|
-
value: filter.value,
|
|
226
|
-
options: filter.options,
|
|
227
|
-
})),
|
|
228
|
-
];
|
|
229
|
-
cloned._orders = [
|
|
230
|
-
...this._orders.map((order) => ({
|
|
231
|
-
field: this.resolveFieldPath(order.field as FieldPath<T>),
|
|
232
|
-
direction: order.direction,
|
|
233
|
-
})),
|
|
234
|
-
];
|
|
235
|
-
cloned._pagination = { ...this._pagination };
|
|
236
|
-
cloned._search = this._search;
|
|
237
|
-
|
|
238
|
-
if (this._adapter) {
|
|
239
|
-
cloned.useAdapter(this._adapter);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
return cloned;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
toJSON() {
|
|
246
|
-
return {
|
|
247
|
-
filters: this._filters.map((filter) => ({
|
|
248
|
-
field: this.resolveFieldPath(filter.field),
|
|
249
|
-
operator: filter.operator,
|
|
250
|
-
value: filter.value,
|
|
251
|
-
options: filter.options,
|
|
252
|
-
})),
|
|
253
|
-
orders: this._orders.map((order) => ({
|
|
254
|
-
field: this.resolveFieldPath(order.field as FieldPath<T>),
|
|
255
|
-
direction: order.direction,
|
|
256
|
-
})),
|
|
257
|
-
pagination: this._pagination,
|
|
258
|
-
search: this._search,
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
static fromObject<T>(
|
|
263
|
-
obj: {
|
|
264
|
-
filters?: TypedFilter<T>[];
|
|
265
|
-
orders?: TypedOrder<T>[];
|
|
266
|
-
pagination?: Pagination;
|
|
267
|
-
search?: Search;
|
|
268
|
-
},
|
|
269
|
-
adapter?: CriteriaAdapter<any, any>
|
|
270
|
-
): Criteria<T> {
|
|
271
|
-
const criteria = Criteria.create<T>();
|
|
272
|
-
|
|
273
|
-
if (adapter) {
|
|
274
|
-
criteria.useAdapter(adapter);
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
if (obj.filters) {
|
|
278
|
-
for (const filter of obj.filters) {
|
|
279
|
-
filter.field = criteria.resolveFieldPath(filter.field);
|
|
280
|
-
criteria.validateOperator(filter.operator, filter.value);
|
|
281
|
-
}
|
|
282
|
-
criteria._filters = [...obj.filters];
|
|
283
|
-
}
|
|
284
|
-
if (obj.orders)
|
|
285
|
-
criteria._orders = [
|
|
286
|
-
...obj.orders.map((order) => ({
|
|
287
|
-
field: criteria.resolveFieldPath(order.field as FieldPath<T>),
|
|
288
|
-
direction: order.direction,
|
|
289
|
-
})),
|
|
290
|
-
];
|
|
291
|
-
if (obj.pagination) criteria._pagination = { ...obj.pagination };
|
|
292
|
-
if (obj.search) criteria._search = obj.search;
|
|
293
|
-
|
|
294
|
-
return criteria;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
protected resolveFieldPath(field: FieldPath<T>): FieldPath<T> {
|
|
298
|
-
if (!this?._adapter) return field;
|
|
299
|
-
|
|
300
|
-
if (this._adapter[field]) {
|
|
301
|
-
return this._adapter[field] as FieldPath<T>;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
const parts = field.split(".");
|
|
305
|
-
for (let i = parts.length; i > 0; i--) {
|
|
306
|
-
const prefix = parts.slice(0, i).join(".");
|
|
307
|
-
if (this._adapter[prefix]) {
|
|
308
|
-
const rest = parts.slice(i).join(".");
|
|
309
|
-
return rest
|
|
310
|
-
? (`${this._adapter[prefix]}.${rest}` as FieldPath<T>)
|
|
311
|
-
: (this._adapter[prefix] as FieldPath<T>);
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
return field;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
static fromQueryParams<T = any>(
|
|
319
|
-
query: Record<string, any> | undefined,
|
|
320
|
-
adapter?: CriteriaAdapter<any, any>
|
|
321
|
-
): Criteria<T> {
|
|
322
|
-
if (!query) return Criteria.create<T>();
|
|
323
|
-
|
|
324
|
-
const criteria = Criteria.create<T>();
|
|
325
|
-
|
|
326
|
-
if (adapter) {
|
|
327
|
-
criteria.useAdapter(adapter);
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
for (const [key, value] of Object.entries(query)) {
|
|
331
|
-
if (key === "page") {
|
|
332
|
-
continue;
|
|
333
|
-
}
|
|
334
|
-
if (key === "limit") {
|
|
335
|
-
continue;
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
if (key === "filters") {
|
|
339
|
-
const filters: Record<string, any> = criteria.parseFilterValue(value);
|
|
340
|
-
|
|
341
|
-
for (let [filterKey, filterValue] of Object.entries(filters)) {
|
|
342
|
-
const [field, operatorWithQuantifier] = filterKey.split(":");
|
|
343
|
-
|
|
344
|
-
if (!operatorWithQuantifier || !field) continue;
|
|
345
|
-
|
|
346
|
-
const [operatorRaw, quantifierRaw] =
|
|
347
|
-
operatorWithQuantifier.split("@");
|
|
348
|
-
const operator = isOperator(operatorRaw) ? operatorRaw : null;
|
|
349
|
-
if (!operator) {
|
|
350
|
-
throw new InvalidCriteriaError(
|
|
351
|
-
`Invalid filter operator`,
|
|
352
|
-
operatorRaw
|
|
353
|
-
);
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
const validQuantifiers = ["some", "every", "none"];
|
|
357
|
-
const quantifier =
|
|
358
|
-
quantifierRaw && validQuantifiers.includes(quantifierRaw)
|
|
359
|
-
? (quantifierRaw as CriteriaOptions["quantifier"])
|
|
360
|
-
: undefined;
|
|
361
|
-
|
|
362
|
-
if (quantifierRaw && !quantifier) {
|
|
363
|
-
throw new InvalidCriteriaError(
|
|
364
|
-
`Invalid quantifier. Valid values: ${validQuantifiers.join(
|
|
365
|
-
", "
|
|
366
|
-
)}`,
|
|
367
|
-
quantifierRaw
|
|
368
|
-
);
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
const options: CriteriaOptions | undefined = quantifier
|
|
372
|
-
? { quantifier }
|
|
373
|
-
: undefined;
|
|
374
|
-
|
|
375
|
-
let parsedValue: any = filterValue;
|
|
376
|
-
|
|
377
|
-
const resolvedField = criteria.resolveFieldPath(
|
|
378
|
-
field as FieldPath<T>
|
|
379
|
-
);
|
|
380
|
-
|
|
381
|
-
if (operator === "between") {
|
|
382
|
-
parsedValue = criteria
|
|
383
|
-
.parseFilterValue(filterValue)
|
|
384
|
-
.map((v: any) => parseQueryValue(v.trim()));
|
|
385
|
-
|
|
386
|
-
if (parsedValue.length === 2) {
|
|
387
|
-
criteria.where(
|
|
388
|
-
resolvedField,
|
|
389
|
-
"between" as OperatorsForType<PathValue<T, FieldPath<T>>>,
|
|
390
|
-
[parsedValue[0], parsedValue[1]] as [
|
|
391
|
-
PathValue<T, FieldPath<T>>,
|
|
392
|
-
PathValue<T, FieldPath<T>>
|
|
393
|
-
],
|
|
394
|
-
options
|
|
395
|
-
);
|
|
396
|
-
}
|
|
397
|
-
continue;
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
if (operator === "in" || operator === "notIn") {
|
|
401
|
-
parsedValue = criteria
|
|
402
|
-
.parseFilterValue(filterValue)
|
|
403
|
-
.map(parseQueryValue);
|
|
404
|
-
|
|
405
|
-
criteria.where(
|
|
406
|
-
field as any,
|
|
407
|
-
operator as OperatorsForType<PathValue<T, FieldPath<T>>>,
|
|
408
|
-
parsedValue,
|
|
409
|
-
options
|
|
410
|
-
);
|
|
411
|
-
continue;
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
const parsedFinalValue = parseQueryValue(filterValue);
|
|
415
|
-
|
|
416
|
-
criteria.validateOperator(operator, parsedFinalValue);
|
|
417
|
-
|
|
418
|
-
criteria.where(
|
|
419
|
-
field as FieldPath<T>,
|
|
420
|
-
operator as OperatorsForType<PathValue<T, FieldPath<T>>>,
|
|
421
|
-
parsedFinalValue,
|
|
422
|
-
options
|
|
423
|
-
);
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
const page = query.page ? parseInt(query.page) : undefined;
|
|
429
|
-
const limit = query.limit ? parseInt(query.limit) : undefined;
|
|
430
|
-
|
|
431
|
-
if (page && limit) {
|
|
432
|
-
criteria.paginate(page, limit);
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
// 1. orderBy=["field:asc","field2:desc"]
|
|
436
|
-
if (query.orderBy) {
|
|
437
|
-
const orderByValue = query.orderBy;
|
|
438
|
-
|
|
439
|
-
if (
|
|
440
|
-
typeof orderByValue === "string" &&
|
|
441
|
-
orderByValue.trim().startsWith("[")
|
|
442
|
-
) {
|
|
443
|
-
try {
|
|
444
|
-
const orderArray = JSON.parse(orderByValue);
|
|
445
|
-
if (Array.isArray(orderArray)) {
|
|
446
|
-
orderArray.forEach((item: string) => {
|
|
447
|
-
const [field, direction] = item.split(":");
|
|
448
|
-
criteria.orderBy(
|
|
449
|
-
field as FieldPath<T>,
|
|
450
|
-
(direction as OrderDirection) || "asc"
|
|
451
|
-
);
|
|
452
|
-
});
|
|
453
|
-
}
|
|
454
|
-
} catch {
|
|
455
|
-
throw new InvalidCriteriaError(
|
|
456
|
-
"Invalid JSON array format for orderBy",
|
|
457
|
-
orderByValue
|
|
458
|
-
);
|
|
459
|
-
}
|
|
460
|
-
} else if (Array.isArray(orderByValue)) {
|
|
461
|
-
orderByValue.forEach((item: string) => {
|
|
462
|
-
const [field, direction] = item.split(":");
|
|
463
|
-
criteria.orderBy(
|
|
464
|
-
field as FieldPath<T>,
|
|
465
|
-
(direction as OrderDirection) || "asc"
|
|
466
|
-
);
|
|
467
|
-
});
|
|
468
|
-
}
|
|
469
|
-
// 2. orderBy="field:asc,field2:desc"
|
|
470
|
-
else if (typeof orderByValue === "string" && orderByValue.includes(":")) {
|
|
471
|
-
const sortParts = orderByValue.split(",");
|
|
472
|
-
sortParts.forEach((part: string) => {
|
|
473
|
-
const [field, direction] = part.split(":");
|
|
474
|
-
criteria.orderBy(
|
|
475
|
-
field as FieldPath<T>,
|
|
476
|
-
(direction as OrderDirection) || "asc"
|
|
477
|
-
);
|
|
478
|
-
});
|
|
479
|
-
}
|
|
480
|
-
// 3. orderBy="field" + orderDirection="asc"
|
|
481
|
-
else {
|
|
482
|
-
const direction = (query.orderDirection as OrderDirection) || "asc";
|
|
483
|
-
criteria.orderBy(orderByValue as FieldPath<T>, direction);
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
if (query.search && typeof query.search === "string") {
|
|
488
|
-
criteria.search(query.search);
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
return criteria;
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
private validateOperator(operator: FilterOperator, value: any): void {
|
|
495
|
-
const sanitizedValue = sanitizeFieldValue(value, operator);
|
|
496
|
-
|
|
497
|
-
if (
|
|
498
|
-
sanitizedValue !== undefined &&
|
|
499
|
-
!isValidOperatorForType(sanitizedValue, operator)
|
|
500
|
-
) {
|
|
501
|
-
const validOps = getValidOperatorsForType(sanitizedValue);
|
|
502
|
-
throw new InvalidCriteriaError(
|
|
503
|
-
`Operator "${operator}" is not valid for type "${typeof sanitizedValue}". Valid operators: ${validOps.join(
|
|
504
|
-
", "
|
|
505
|
-
)}`,
|
|
506
|
-
operator
|
|
507
|
-
);
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
private parseFilterValue(value: any) {
|
|
512
|
-
if (typeof value === "string") {
|
|
513
|
-
try {
|
|
514
|
-
return JSON.parse(value);
|
|
515
|
-
} catch {
|
|
516
|
-
throw new InvalidCriteriaError(`Invalid filter value`, value);
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
return parseQueryValue(value);
|
|
520
|
-
}
|
|
521
|
-
}
|
package/src/crypto.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
const customCrypto = {
|
|
2
|
-
randomUUID: () => {
|
|
3
|
-
if (
|
|
4
|
-
typeof globalThis !== "undefined" &&
|
|
5
|
-
globalThis?.crypto &&
|
|
6
|
-
typeof globalThis.crypto.randomUUID === "function"
|
|
7
|
-
) {
|
|
8
|
-
return globalThis.crypto.randomUUID();
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const hexChars = "0123456789abcdef";
|
|
12
|
-
let uuid = "";
|
|
13
|
-
|
|
14
|
-
for (let i = 0; i < 36; i++) {
|
|
15
|
-
if (i === 8 || i === 13 || i === 18 || i === 23) {
|
|
16
|
-
uuid += "-";
|
|
17
|
-
} else if (i === 14) {
|
|
18
|
-
uuid += "4";
|
|
19
|
-
} else if (i === 19) {
|
|
20
|
-
uuid += hexChars.charAt(Math.floor(Math.random() * 4) + 8);
|
|
21
|
-
} else {
|
|
22
|
-
uuid += hexChars.charAt(Math.floor(Math.random() * 16));
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return uuid;
|
|
27
|
-
},
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
export const UUID = customCrypto.randomUUID;
|
|
31
|
-
export default UUID;
|