@woltz/rich-domain 1.3.0 → 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.
Files changed (76) hide show
  1. package/dist/aggregate-changes.js +1 -1
  2. package/dist/aggregate-changes.js.map +1 -1
  3. package/dist/base-entity.d.ts.map +1 -1
  4. package/dist/base-entity.js +17 -5
  5. package/dist/base-entity.js.map +1 -1
  6. package/dist/change-tracker.d.ts +1 -1
  7. package/dist/change-tracker.d.ts.map +1 -1
  8. package/dist/change-tracker.js +20 -8
  9. package/dist/change-tracker.js.map +1 -1
  10. package/dist/criteria.js +6 -5
  11. package/dist/criteria.js.map +1 -1
  12. package/dist/domain-event-bus.js +4 -4
  13. package/dist/domain-event-bus.js.map +1 -1
  14. package/dist/domain-event.js +3 -0
  15. package/dist/domain-event.js.map +1 -1
  16. package/dist/entity-changes.js +1 -0
  17. package/dist/entity-changes.js.map +1 -1
  18. package/dist/entity-schema-registry.d.ts +4 -0
  19. package/dist/entity-schema-registry.d.ts.map +1 -1
  20. package/dist/entity-schema-registry.js +8 -6
  21. package/dist/entity-schema-registry.js.map +1 -1
  22. package/dist/exceptions.js +26 -1
  23. package/dist/exceptions.js.map +1 -1
  24. package/dist/id.js +2 -0
  25. package/dist/id.js.map +1 -1
  26. package/dist/index.d.ts +1 -1
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js.map +1 -1
  29. package/dist/paginated-result.d.ts.map +1 -1
  30. package/dist/paginated-result.js +9 -0
  31. package/dist/paginated-result.js.map +1 -1
  32. package/dist/repository/unit-of-work.js +3 -7
  33. package/dist/repository/unit-of-work.js.map +1 -1
  34. package/dist/types/domain.d.ts +0 -1
  35. package/dist/types/domain.d.ts.map +1 -1
  36. package/dist/validation-error.d.ts +15 -1
  37. package/dist/validation-error.d.ts.map +1 -1
  38. package/dist/validation-error.js +46 -3
  39. package/dist/validation-error.js.map +1 -1
  40. package/dist/value-object.d.ts.map +1 -1
  41. package/dist/value-object.js +29 -1
  42. package/dist/value-object.js.map +1 -1
  43. package/package.json +9 -11
  44. package/eslint.config.js +0 -57
  45. package/jest.config.js +0 -21
  46. package/src/aggregate-changes.ts +0 -444
  47. package/src/base-entity.ts +0 -404
  48. package/src/change-tracker.ts +0 -1133
  49. package/src/constants.ts +0 -81
  50. package/src/criteria.ts +0 -521
  51. package/src/crypto.ts +0 -31
  52. package/src/domain-event-bus.ts +0 -152
  53. package/src/domain-event.ts +0 -49
  54. package/src/entity-changes.ts +0 -146
  55. package/src/entity-schema-registry.ts +0 -502
  56. package/src/entity.ts +0 -5
  57. package/src/exceptions.ts +0 -435
  58. package/src/id.ts +0 -98
  59. package/src/index.ts +0 -52
  60. package/src/mapper.ts +0 -6
  61. package/src/paginated-result.ts +0 -238
  62. package/src/repository/base-repository.ts +0 -33
  63. package/src/repository/index.ts +0 -3
  64. package/src/repository/unit-of-work.ts +0 -76
  65. package/src/types/change-tracker.ts +0 -264
  66. package/src/types/criteria.ts +0 -159
  67. package/src/types/domain-event.ts +0 -38
  68. package/src/types/domain.ts +0 -34
  69. package/src/types/index.ts +0 -7
  70. package/src/types/standard-schema.ts +0 -19
  71. package/src/types/unit-of-work.ts +0 -46
  72. package/src/types/utils.ts +0 -20
  73. package/src/utils/criteria-operator-validation.ts +0 -209
  74. package/src/utils/helpers.ts +0 -34
  75. package/src/validation-error.ts +0 -91
  76. package/src/value-object.ts +0 -244
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;