@woltz/rich-domain 1.7.0 → 1.8.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.
Files changed (204) hide show
  1. package/dist/cjs/core/aggregate-changes.d.ts +206 -0
  2. package/dist/cjs/core/aggregate-changes.d.ts.map +1 -0
  3. package/dist/cjs/core/aggregate-changes.js +365 -0
  4. package/dist/cjs/core/aggregate-changes.js.map +1 -0
  5. package/dist/cjs/core/base-entity.d.ts +88 -0
  6. package/dist/cjs/core/base-entity.d.ts.map +1 -0
  7. package/dist/cjs/core/base-entity.js +329 -0
  8. package/dist/cjs/core/base-entity.js.map +1 -0
  9. package/dist/cjs/core/change-tracker.d.ts +96 -0
  10. package/dist/cjs/core/change-tracker.d.ts.map +1 -0
  11. package/dist/cjs/core/change-tracker.js +789 -0
  12. package/dist/cjs/core/change-tracker.js.map +1 -0
  13. package/dist/cjs/core/domain-event.d.ts +23 -0
  14. package/dist/cjs/core/domain-event.d.ts.map +1 -0
  15. package/dist/cjs/core/domain-event.js +36 -0
  16. package/dist/cjs/core/domain-event.js.map +1 -0
  17. package/dist/cjs/core/entity-changes.d.ts +84 -0
  18. package/dist/cjs/core/entity-changes.d.ts.map +1 -0
  19. package/dist/cjs/core/entity-changes.js +136 -0
  20. package/dist/cjs/core/entity-changes.js.map +1 -0
  21. package/dist/cjs/core/entity.d.ts +7 -0
  22. package/dist/cjs/core/entity.d.ts.map +1 -0
  23. package/dist/cjs/core/entity.js +11 -0
  24. package/dist/cjs/core/entity.js.map +1 -0
  25. package/dist/cjs/core/id.d.ts +59 -0
  26. package/dist/cjs/core/id.d.ts.map +1 -0
  27. package/dist/cjs/core/id.js +92 -0
  28. package/dist/cjs/core/id.js.map +1 -0
  29. package/dist/cjs/core/index.d.ts +9 -0
  30. package/dist/cjs/core/index.d.ts.map +1 -0
  31. package/dist/cjs/core/index.js +25 -0
  32. package/dist/cjs/core/index.js.map +1 -0
  33. package/dist/cjs/core/value-object.d.ts +49 -0
  34. package/dist/cjs/core/value-object.d.ts.map +1 -0
  35. package/dist/cjs/core/value-object.js +129 -0
  36. package/dist/cjs/core/value-object.js.map +1 -0
  37. package/dist/cjs/index.d.ts +5 -11
  38. package/dist/cjs/index.d.ts.map +1 -1
  39. package/dist/cjs/index.js +21 -19
  40. package/dist/cjs/index.js.map +1 -1
  41. package/dist/cjs/repository/base-repository.d.ts +49 -3
  42. package/dist/cjs/repository/base-repository.d.ts.map +1 -1
  43. package/dist/cjs/repository/base-repository.js.map +1 -1
  44. package/dist/cjs/repository/entity-schema-registry.d.ts +281 -0
  45. package/dist/cjs/repository/entity-schema-registry.d.ts.map +1 -0
  46. package/dist/cjs/repository/entity-schema-registry.js +370 -0
  47. package/dist/cjs/repository/entity-schema-registry.js.map +1 -0
  48. package/dist/cjs/repository/index.d.ts +4 -2
  49. package/dist/cjs/repository/index.d.ts.map +1 -1
  50. package/dist/cjs/repository/index.js +4 -6
  51. package/dist/cjs/repository/index.js.map +1 -1
  52. package/dist/cjs/repository/mapper.d.ts +4 -0
  53. package/dist/cjs/repository/mapper.d.ts.map +1 -0
  54. package/dist/cjs/repository/mapper.js +7 -0
  55. package/dist/cjs/repository/mapper.js.map +1 -0
  56. package/dist/cjs/repository/paginated-result.d.ts +54 -0
  57. package/dist/cjs/repository/paginated-result.d.ts.map +1 -0
  58. package/dist/cjs/repository/paginated-result.js +197 -0
  59. package/dist/cjs/repository/paginated-result.js.map +1 -0
  60. package/dist/cjs/types/change-tracker.d.ts +1 -2
  61. package/dist/cjs/types/change-tracker.d.ts.map +1 -1
  62. package/dist/cjs/types/criteria.d.ts +13 -5
  63. package/dist/cjs/types/criteria.d.ts.map +1 -1
  64. package/dist/cjs/types/criteria.js +2 -2
  65. package/dist/cjs/types/criteria.js.map +1 -1
  66. package/dist/cjs/types/domain.d.ts +1 -1
  67. package/dist/cjs/types/domain.d.ts.map +1 -1
  68. package/dist/cjs/types/unit-of-work.d.ts +1 -1
  69. package/dist/cjs/types/unit-of-work.d.ts.map +1 -1
  70. package/dist/cjs/types/utils.d.ts +1 -2
  71. package/dist/cjs/types/utils.d.ts.map +1 -1
  72. package/dist/cjs/utils/criteria-operator-validation.d.ts.map +1 -1
  73. package/dist/cjs/utils/criteria-operator-validation.js +1 -1
  74. package/dist/cjs/utils/criteria-operator-validation.js.map +1 -1
  75. package/dist/cjs/utils/crypto.d.ts +3 -0
  76. package/dist/cjs/utils/crypto.d.ts.map +1 -0
  77. package/dist/cjs/utils/crypto.js +32 -0
  78. package/dist/cjs/utils/crypto.js.map +1 -0
  79. package/dist/esm/core/aggregate-changes.d.ts +206 -0
  80. package/dist/esm/core/aggregate-changes.d.ts.map +1 -0
  81. package/dist/esm/core/aggregate-changes.js +361 -0
  82. package/dist/esm/core/aggregate-changes.js.map +1 -0
  83. package/dist/esm/core/base-entity.d.ts +88 -0
  84. package/dist/esm/core/base-entity.d.ts.map +1 -0
  85. package/dist/esm/core/base-entity.js +325 -0
  86. package/dist/esm/core/base-entity.js.map +1 -0
  87. package/dist/esm/core/change-tracker.d.ts +96 -0
  88. package/dist/esm/core/change-tracker.d.ts.map +1 -0
  89. package/dist/esm/core/change-tracker.js +785 -0
  90. package/dist/esm/core/change-tracker.js.map +1 -0
  91. package/dist/esm/core/domain-event.d.ts +23 -0
  92. package/dist/esm/core/domain-event.d.ts.map +1 -0
  93. package/dist/esm/core/domain-event.js +32 -0
  94. package/dist/esm/core/domain-event.js.map +1 -0
  95. package/dist/esm/core/entity-changes.d.ts +84 -0
  96. package/dist/esm/core/entity-changes.d.ts.map +1 -0
  97. package/dist/esm/core/entity-changes.js +132 -0
  98. package/dist/esm/core/entity-changes.js.map +1 -0
  99. package/dist/esm/core/entity.d.ts +7 -0
  100. package/dist/esm/core/entity.d.ts.map +1 -0
  101. package/dist/esm/core/entity.js +6 -0
  102. package/dist/esm/core/entity.js.map +1 -0
  103. package/dist/esm/core/id.d.ts +59 -0
  104. package/dist/esm/core/id.d.ts.map +1 -0
  105. package/dist/esm/core/id.js +85 -0
  106. package/dist/esm/core/id.js.map +1 -0
  107. package/dist/esm/core/index.d.ts +9 -0
  108. package/dist/esm/core/index.d.ts.map +1 -0
  109. package/dist/esm/core/index.js +9 -0
  110. package/dist/esm/core/index.js.map +1 -0
  111. package/dist/esm/core/value-object.d.ts +49 -0
  112. package/dist/esm/core/value-object.d.ts.map +1 -0
  113. package/dist/esm/core/value-object.js +125 -0
  114. package/dist/esm/core/value-object.js.map +1 -0
  115. package/dist/esm/index.d.ts +5 -11
  116. package/dist/esm/index.d.ts.map +1 -1
  117. package/dist/esm/index.js +4 -10
  118. package/dist/esm/index.js.map +1 -1
  119. package/dist/esm/repository/base-repository.d.ts +49 -3
  120. package/dist/esm/repository/base-repository.d.ts.map +1 -1
  121. package/dist/esm/repository/base-repository.js.map +1 -1
  122. package/dist/esm/repository/entity-schema-registry.d.ts +281 -0
  123. package/dist/esm/repository/entity-schema-registry.d.ts.map +1 -0
  124. package/dist/esm/repository/entity-schema-registry.js +366 -0
  125. package/dist/esm/repository/entity-schema-registry.js.map +1 -0
  126. package/dist/esm/repository/index.d.ts +4 -2
  127. package/dist/esm/repository/index.d.ts.map +1 -1
  128. package/dist/esm/repository/index.js +4 -2
  129. package/dist/esm/repository/index.js.map +1 -1
  130. package/dist/esm/repository/mapper.d.ts +4 -0
  131. package/dist/esm/repository/mapper.d.ts.map +1 -0
  132. package/dist/esm/repository/mapper.js +3 -0
  133. package/dist/esm/repository/mapper.js.map +1 -0
  134. package/dist/esm/repository/paginated-result.d.ts +54 -0
  135. package/dist/esm/repository/paginated-result.d.ts.map +1 -0
  136. package/dist/esm/repository/paginated-result.js +193 -0
  137. package/dist/esm/repository/paginated-result.js.map +1 -0
  138. package/dist/esm/types/change-tracker.d.ts +1 -2
  139. package/dist/esm/types/change-tracker.d.ts.map +1 -1
  140. package/dist/esm/types/criteria.d.ts +13 -5
  141. package/dist/esm/types/criteria.d.ts.map +1 -1
  142. package/dist/esm/types/criteria.js +3 -1
  143. package/dist/esm/types/criteria.js.map +1 -1
  144. package/dist/esm/types/domain.d.ts +1 -1
  145. package/dist/esm/types/domain.d.ts.map +1 -1
  146. package/dist/esm/types/unit-of-work.d.ts +1 -1
  147. package/dist/esm/types/unit-of-work.d.ts.map +1 -1
  148. package/dist/esm/types/utils.d.ts +1 -2
  149. package/dist/esm/types/utils.d.ts.map +1 -1
  150. package/dist/esm/utils/criteria-operator-validation.d.ts.map +1 -1
  151. package/dist/esm/utils/criteria-operator-validation.js +1 -1
  152. package/dist/esm/utils/criteria-operator-validation.js.map +1 -1
  153. package/dist/esm/utils/crypto.d.ts +3 -0
  154. package/dist/esm/utils/crypto.d.ts.map +1 -0
  155. package/dist/esm/utils/crypto.js +29 -0
  156. package/dist/esm/utils/crypto.js.map +1 -0
  157. package/dist/tsconfig.cjs.tsbuildinfo +1 -1
  158. package/dist/tsconfig.esm.tsbuildinfo +1 -1
  159. package/dist/tsconfig.types.tsbuildinfo +1 -1
  160. package/dist/types/core/aggregate-changes.d.ts +206 -0
  161. package/dist/types/core/aggregate-changes.d.ts.map +1 -0
  162. package/dist/types/core/base-entity.d.ts +88 -0
  163. package/dist/types/core/base-entity.d.ts.map +1 -0
  164. package/dist/types/core/change-tracker.d.ts +96 -0
  165. package/dist/types/core/change-tracker.d.ts.map +1 -0
  166. package/dist/types/core/domain-event.d.ts +23 -0
  167. package/dist/types/core/domain-event.d.ts.map +1 -0
  168. package/dist/types/core/entity-changes.d.ts +84 -0
  169. package/dist/types/core/entity-changes.d.ts.map +1 -0
  170. package/dist/types/core/entity.d.ts +7 -0
  171. package/dist/types/core/entity.d.ts.map +1 -0
  172. package/dist/types/core/id.d.ts +59 -0
  173. package/dist/types/core/id.d.ts.map +1 -0
  174. package/dist/types/core/index.d.ts +9 -0
  175. package/dist/types/core/index.d.ts.map +1 -0
  176. package/dist/types/core/value-object.d.ts +49 -0
  177. package/dist/types/core/value-object.d.ts.map +1 -0
  178. package/dist/types/index.d.ts +5 -11
  179. package/dist/types/index.d.ts.map +1 -1
  180. package/dist/types/paginated-result.d.ts +54 -46
  181. package/dist/types/repository/base-repository.d.ts +49 -3
  182. package/dist/types/repository/base-repository.d.ts.map +1 -1
  183. package/dist/types/repository/entity-schema-registry.d.ts +281 -0
  184. package/dist/types/repository/entity-schema-registry.d.ts.map +1 -0
  185. package/dist/types/repository/index.d.ts +4 -2
  186. package/dist/types/repository/index.d.ts.map +1 -1
  187. package/dist/types/repository/mapper.d.ts +4 -0
  188. package/dist/types/repository/mapper.d.ts.map +1 -0
  189. package/dist/types/repository/paginated-result.d.ts +54 -0
  190. package/dist/types/repository/paginated-result.d.ts.map +1 -0
  191. package/dist/types/types/change-tracker.d.ts +1 -2
  192. package/dist/types/types/change-tracker.d.ts.map +1 -1
  193. package/dist/types/types/criteria.d.ts +13 -5
  194. package/dist/types/types/criteria.d.ts.map +1 -1
  195. package/dist/types/types/domain.d.ts +1 -1
  196. package/dist/types/types/domain.d.ts.map +1 -1
  197. package/dist/types/types/unit-of-work.d.ts +1 -1
  198. package/dist/types/types/unit-of-work.d.ts.map +1 -1
  199. package/dist/types/types/utils.d.ts +1 -2
  200. package/dist/types/types/utils.d.ts.map +1 -1
  201. package/dist/types/utils/criteria-operator-validation.d.ts.map +1 -1
  202. package/dist/types/utils/crypto.d.ts +3 -0
  203. package/dist/types/utils/crypto.d.ts.map +1 -0
  204. package/package.json +1 -1
@@ -0,0 +1,366 @@
1
+ import { Entity, ValueObject, Id } from "../core/index";
2
+ import { ConfigurationError } from "../exceptions.js";
3
+ import { levenshteinDistance } from "../utils/helpers.js";
4
+ /**
5
+ * Registry for mapping domain entities to database tables and fields.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * const registry = new EntitySchemaRegistry()
10
+ * .register({
11
+ * entity: 'User',
12
+ * table: 'users',
13
+ * fields: { email: 'user_email', name: 'user_name' },
14
+ * })
15
+ * .register({
16
+ * entity: 'Post',
17
+ * table: 'blog_posts',
18
+ * fields: { content: 'post_content' },
19
+ * parentFk: { field: 'author_id', parentEntity: 'User' },
20
+ * collections: {
21
+ * comments: { type: 'owned' },
22
+ * tags: { type: 'reference', entity: 'Tag' }
23
+ * }
24
+ * });
25
+ *
26
+ * const table = registry.getTable('Post'); // 'blog_posts'
27
+ * const tagConfig = registry.getCollectionConfig('Post', 'tags');
28
+ * // { type: 'reference', entity: 'Tag' }
29
+ * ```
30
+ */
31
+ export class EntitySchemaRegistry {
32
+ schemas = new Map();
33
+ /**
34
+ * Registers an entity schema.
35
+ * @param schema - Schema to be registered.
36
+ * @returns this (for chaining)
37
+ */
38
+ register(schema) {
39
+ if (this.schemas.has(schema.entity)) {
40
+ console.warn(`EntitySchemaRegistry: Schema for '${schema.entity}' is being overwritten`);
41
+ }
42
+ this.schemas.set(schema.entity, schema);
43
+ return this;
44
+ }
45
+ /**
46
+ * Registers multiple schemas at once.
47
+ * @param schemas - Array of schemas.
48
+ * @returns this (for chaining)
49
+ */
50
+ registerAll(schemas) {
51
+ schemas.forEach((schema) => this.register(schema));
52
+ return this;
53
+ }
54
+ /**
55
+ * Gets the schema of an entity.
56
+ * @param entity - Entity name.
57
+ * @throws Error if the entity is not registered.
58
+ */
59
+ getSchema(entity) {
60
+ const schema = this.schemas.get(entity);
61
+ if (!schema) {
62
+ throw new ConfigurationError(`EntitySchemaRegistry: No schema registered for entity '${entity}'. ` +
63
+ `Available entities: ${Array.from(this.schemas.keys()).join(", ") || "none"}`);
64
+ }
65
+ return schema;
66
+ }
67
+ /**
68
+ * Gets all registered schemas.
69
+ */
70
+ getAllSchemas() {
71
+ return Array.from(this.schemas.values());
72
+ }
73
+ /**
74
+ * Tries to get the schema of an entity, returns null if not found.
75
+ * @param entity - Entity name.
76
+ */
77
+ tryGetSchema(entity) {
78
+ return this.schemas.get(entity) ?? null;
79
+ }
80
+ /**
81
+ * Checks if an entity is registered.
82
+ * @param entity - Entity name.
83
+ */
84
+ has(entity) {
85
+ return this.schemas.has(entity);
86
+ }
87
+ /**
88
+ * Gets the table name for an entity.
89
+ * @param entity - Entity name.
90
+ */
91
+ getTable(entity) {
92
+ return this.getSchema(entity).table;
93
+ }
94
+ /**
95
+ * Gets the field mapping for an entity.
96
+ * @param entity - Entity name.
97
+ */
98
+ getFieldsMap(entity) {
99
+ return this.getSchema(entity).fields || {};
100
+ }
101
+ /**
102
+ * Maps a domain field name to the database field name.
103
+ * @param entity - Entity name.
104
+ * @param fieldName - Domain field name.
105
+ */
106
+ mapFieldName(entity, fieldName) {
107
+ const fields = this.getFieldsMap(entity);
108
+ return fields[fieldName] ?? fieldName;
109
+ }
110
+ /**
111
+ * Maps fields of a domain object to database field names.
112
+ * Ignores values that are Entity, ValueObject, or Arrays.
113
+ *
114
+ * @param entity - Entity name.
115
+ * @param data - Data to be mapped.
116
+ */
117
+ mapFields(entity, data) {
118
+ const fields = this.getFieldsMap(entity);
119
+ const result = {};
120
+ for (const [key, value] of Object.entries(data)) {
121
+ if (this.isEntityOrCollection(value))
122
+ continue;
123
+ const mappedKey = fields[key] ?? key;
124
+ result[mappedKey] = this.normalizeValue(value);
125
+ }
126
+ return result;
127
+ }
128
+ /**
129
+ * Maps a complete domain entity to database data.
130
+ * Used for CREATE operations.
131
+ *
132
+ * @param entity - Entity name.
133
+ * @param domainEntity - Domain entity instance.
134
+ */
135
+ mapEntity(entity, domainEntity) {
136
+ const fields = this.getFieldsMap(entity);
137
+ const result = {};
138
+ const hasId = domainEntity.id;
139
+ if (hasId) {
140
+ const idValue = hasId.value ?? hasId;
141
+ result["id"] = idValue;
142
+ }
143
+ const props = domainEntity.props || domainEntity;
144
+ for (const [key, value] of Object.entries(props)) {
145
+ if (key === "id")
146
+ continue;
147
+ if (this.isEntityOrCollection(value))
148
+ continue;
149
+ const mappedKey = fields[key] ?? key;
150
+ result[mappedKey] = this.normalizeValue(value);
151
+ }
152
+ return result;
153
+ }
154
+ /**
155
+ * Gets the FK object to relate with the parent.
156
+ *
157
+ * @param entity - Entity name.
158
+ * @param parentId - Parent ID.
159
+ * @returns Object with the FK field or null if there is no parent.
160
+ */
161
+ getParentFk(entity, parentId) {
162
+ const schema = this.getSchema(entity);
163
+ if (!schema.parentFk)
164
+ return null;
165
+ return { [schema.parentFk.field]: parentId };
166
+ }
167
+ /**
168
+ * Gets the name of the parent entity.
169
+ * @param entity - Entity name.
170
+ */
171
+ getParentEntity(entity) {
172
+ const schema = this.getSchema(entity);
173
+ return schema.parentFk?.parentEntity ?? null;
174
+ }
175
+ /**
176
+ * Gets the FK field name.
177
+ * @param entity - Entity name.
178
+ */
179
+ getParentFkField(entity) {
180
+ const schema = this.getSchema(entity);
181
+ return schema.parentFk?.field ?? null;
182
+ }
183
+ /**
184
+ * Gets the collection configuration for a specific field.
185
+ *
186
+ * @param entity - Parent entity name (e.g., 'Post')
187
+ * @param fieldName - Collection field name (e.g., 'tags')
188
+ * @returns CollectionConfig or null if not configured
189
+ *
190
+ * @example
191
+ * ```typescript
192
+ * const config = registry.getCollectionConfig('Post', 'tags');
193
+ * if (config?.type === 'reference') {
194
+ * // Handle N:N relation - use connect/disconnect
195
+ * } else {
196
+ * // Handle 1:N relation - use create/delete
197
+ * }
198
+ * ```
199
+ */
200
+ getCollectionConfig(entity, fieldName) {
201
+ const schema = this.tryGetSchema(entity);
202
+ if (!schema?.collections)
203
+ return null;
204
+ return schema.collections[fieldName] ?? null;
205
+ }
206
+ /**
207
+ * Checks if a collection is a reference type (N:N).
208
+ *
209
+ * @param entity - Parent entity name
210
+ * @param fieldName - Collection field name
211
+ * @returns true if the collection is a reference (N:N), false otherwise
212
+ *
213
+ * @example
214
+ * ```typescript
215
+ * if (registry.isReferenceCollection('Post', 'tags')) {
216
+ * // Use connect/disconnect instead of create/delete
217
+ * }
218
+ * ```
219
+ */
220
+ isReferenceCollection(entity, fieldName) {
221
+ const config = this.getCollectionConfig(entity, fieldName);
222
+ return config?.type === "reference";
223
+ }
224
+ /**
225
+ * Checks if a collection is owned (1:N).
226
+ * Returns true if explicitly configured as 'owned' or if not configured at all.
227
+ *
228
+ * @param entity - Parent entity name
229
+ * @param fieldName - Collection field name
230
+ * @returns true if the collection is owned (1:N), false if reference
231
+ */
232
+ isOwnedCollection(entity, fieldName) {
233
+ const config = this.getCollectionConfig(entity, fieldName);
234
+ // Default to owned if not configured
235
+ return config?.type !== "reference";
236
+ }
237
+ /**
238
+ * Gets all collections configured for an entity.
239
+ *
240
+ * @param entity - Entity name
241
+ * @returns Record of field names to collection configs, or empty object
242
+ */
243
+ getCollections(entity) {
244
+ const schema = this.tryGetSchema(entity);
245
+ return schema?.collections ?? {};
246
+ }
247
+ /**
248
+ * Gets all reference (N:N) collections for an entity.
249
+ *
250
+ * @param entity - Entity name
251
+ * @returns Array of field names that are reference collections
252
+ */
253
+ getReferenceCollections(entity) {
254
+ const collections = this.getCollections(entity);
255
+ return Object.entries(collections)
256
+ .filter(([_, config]) => config.type === "reference")
257
+ .map(([field]) => field);
258
+ }
259
+ /**
260
+ * Gets the junction table configuration for a reference collection.
261
+ *
262
+ * @param entity - Parent entity name
263
+ * @param fieldName - Collection field name
264
+ * @returns Junction config or null
265
+ */
266
+ getJunctionConfig(entity, fieldName) {
267
+ const config = this.getCollectionConfig(entity, fieldName);
268
+ return config?.junction ?? null;
269
+ }
270
+ /**
271
+ * Lists all registered entities.
272
+ */
273
+ getRegisteredEntities() {
274
+ return Array.from(this.schemas.keys());
275
+ }
276
+ /**
277
+ * Clears all registered schemas.
278
+ */
279
+ clear() {
280
+ this.schemas.clear();
281
+ }
282
+ /**
283
+ * Checks if a value is Entity, ValueObject, or Array.
284
+ */
285
+ isEntityOrCollection(value) {
286
+ if (value === null || value === undefined)
287
+ return false;
288
+ if (Array.isArray(value))
289
+ return true;
290
+ if (value instanceof Entity)
291
+ return true;
292
+ if (value instanceof ValueObject)
293
+ return true;
294
+ if (typeof value === "object" &&
295
+ value.id &&
296
+ typeof value.id === "object" &&
297
+ "value" in value.id) {
298
+ return true;
299
+ }
300
+ return false;
301
+ }
302
+ /**
303
+ * Normalizes a value for persistence.
304
+ */
305
+ normalizeValue(input) {
306
+ if (input === null || input === undefined)
307
+ return input;
308
+ if (input instanceof Id)
309
+ return input.value;
310
+ if (input instanceof ValueObject)
311
+ return input.value;
312
+ if (input instanceof Date)
313
+ return input;
314
+ if (typeof input === "object" && "value" in input) {
315
+ return input.value;
316
+ }
317
+ return input;
318
+ }
319
+ /**
320
+ * Validates that a relation field exists in the entity's collections.
321
+ *
322
+ * @param entity - Parent entity name
323
+ * @param relationField - Relation field to validate
324
+ * @throws ConfigurationError if the field doesn't exist
325
+ *
326
+ */
327
+ validateRelationField(entity, relationField) {
328
+ const schema = this.tryGetSchema(entity);
329
+ const uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
330
+ if (uuidPattern.test(entity)) {
331
+ throw new ConfigurationError(`EntitySchemaRegistry: Received an ID '${entity}' instead of an entity name. ` +
332
+ `This usually means 'parentEntity' is not being set correctly in the ChangeTracker. ` +
333
+ `Check that addDelete/addCreate are receiving the entity NAME (e.g., 'Post'), not the ID.`);
334
+ }
335
+ if (!schema) {
336
+ throw new ConfigurationError(`EntitySchemaRegistry: Cannot validate relation '${relationField}' - ` +
337
+ `entity '${entity}' is not registered. ` +
338
+ `Available entities: ${this.getRegisteredEntities().join(", ") || "none"}`);
339
+ }
340
+ const collections = schema.collections ?? {};
341
+ const availableCollections = Object.keys(collections);
342
+ if (availableCollections.length === 0) {
343
+ return;
344
+ }
345
+ if (!collections[relationField]) {
346
+ const suggestions = this.findSimilarNames(relationField, availableCollections);
347
+ const suggestionText = suggestions.length > 0
348
+ ? ` Did you mean: '${suggestions.join("' or '")}'?`
349
+ : "";
350
+ throw new ConfigurationError(`EntitySchemaRegistry: Unknown relation '${relationField}' for entity '${entity}'. ` +
351
+ `Available collections: ${availableCollections.join(", ")}.${suggestionText}`);
352
+ }
353
+ }
354
+ findSimilarNames(input, candidates) {
355
+ return candidates
356
+ .map((candidate) => ({
357
+ name: candidate,
358
+ distance: levenshteinDistance(input.toLowerCase(), candidate.toLowerCase()),
359
+ }))
360
+ .filter(({ distance }) => distance <= 3)
361
+ .sort((a, b) => a.distance - b.distance)
362
+ .slice(0, 2)
363
+ .map(({ name }) => name);
364
+ }
365
+ }
366
+ //# sourceMappingURL=entity-schema-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entity-schema-registry.js","sourceRoot":"","sources":["../../../src/repository/entity-schema-registry.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,6 @@
1
- export { Mapper } from "../mapper.js";
2
1
  export * from "./base-repository.js";
3
- export { UnitOfWork, BaseTransactionContext } from "./unit-of-work.js";
2
+ export * from "./mapper.js";
3
+ export * from "./unit-of-work.js";
4
+ export * from "./entity-schema-registry.js";
5
+ export * from "./paginated-result.js";
4
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/repository/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/repository/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,uBAAuB,CAAC"}
@@ -1,4 +1,6 @@
1
- export { Mapper } from "../mapper.js";
2
1
  export * from "./base-repository.js";
3
- export { UnitOfWork, BaseTransactionContext } from "./unit-of-work.js";
2
+ export * from "./mapper.js";
3
+ export * from "./unit-of-work.js";
4
+ export * from "./entity-schema-registry.js";
5
+ export * from "./paginated-result.js";
4
6
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/repository/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/repository/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,uBAAuB,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare abstract class Mapper<Input, Output> {
2
+ abstract build(input: Input, ...args: unknown[]): Output | Promise<Output>;
3
+ }
4
+ //# sourceMappingURL=mapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mapper.d.ts","sourceRoot":"","sources":["../../../src/repository/mapper.ts"],"names":[],"mappings":"AAAA,8BAAsB,MAAM,CAAC,KAAK,EAAE,MAAM;aACxB,KAAK,CACnB,KAAK,EAAE,KAAK,EACZ,GAAG,IAAI,EAAE,OAAO,EAAE,GACjB,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAC5B"}
@@ -0,0 +1,3 @@
1
+ export class Mapper {
2
+ }
3
+ //# sourceMappingURL=mapper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mapper.js","sourceRoot":"","sources":["../../../src/repository/mapper.ts"],"names":[],"mappings":"AAAA,MAAM,OAAgB,MAAM;CAK3B"}
@@ -0,0 +1,54 @@
1
+ import type { Criteria } from "../criteria.js";
2
+ import type { Pagination, PaginationMeta, DeepJsonResult } from "../types/index.js";
3
+ /**
4
+ * Type for the serialized result of PaginatedResult.toJSON()
5
+ * Uses DeepJsonResult to ensure all nested entities are converted to plain objects
6
+ */
7
+ export type PaginatedJsonResult<T> = {
8
+ data: DeepJsonResult<T>[];
9
+ meta: PaginationMeta;
10
+ };
11
+ export declare class PaginatedResult<T> {
12
+ readonly data: T[];
13
+ readonly meta: PaginationMeta;
14
+ constructor(data: T[], meta: PaginationMeta);
15
+ /**
16
+ * Creates a PaginatedResult with calculated metadata
17
+ */
18
+ static create<T>(data: T[], pagination: Pagination, total: number): PaginatedResult<T>;
19
+ /**
20
+ * Creates pagination metadata from total count
21
+ */
22
+ static createMeta(pagination: Pagination, total: number): PaginationMeta;
23
+ /**
24
+ * Applies criteria to an in-memory array (useful for testing)
25
+ */
26
+ static fromArray<T>(items: T[], criteria: Criteria<T>): PaginatedResult<T>;
27
+ /**
28
+ * Converts the result to JSON, deeply serializing all entities/aggregates/value objects
29
+ * - Entities/Aggregates → calls toJSON() recursively
30
+ * - Value Objects → converts to value
31
+ * - Id → converts to string
32
+ * - Arrays → maps recursively
33
+ * - Plain objects → serializes properties recursively
34
+ * - Primitives → returns as-is
35
+ */
36
+ toJSON(): PaginatedJsonResult<T>;
37
+ /**
38
+ * Deep serialization logic (similar to BaseEntity.deepToJson)
39
+ */
40
+ private deepSerialize;
41
+ /**
42
+ * Transform each item in the result using a mapper function
43
+ */
44
+ map<U>(fn: (item: T) => U): PaginatedResult<U>;
45
+ /**
46
+ * Check if result has no data
47
+ */
48
+ get isEmpty(): boolean;
49
+ /**
50
+ * Check if there are more pages available
51
+ */
52
+ get hasMore(): boolean;
53
+ }
54
+ //# sourceMappingURL=paginated-result.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paginated-result.d.ts","sourceRoot":"","sources":["../../../src/repository/paginated-result.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,EACV,UAAU,EACV,cAAc,EAEd,cAAc,EACf,MAAM,mBAAmB,CAAC;AAE3B;;;GAGG;AACH,MAAM,MAAM,mBAAmB,CAAC,CAAC,IAAI;IACnC,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1B,IAAI,EAAE,cAAc,CAAC;CACtB,CAAC;AAEF,qBAAa,eAAe,CAAC,CAAC;aAEV,IAAI,EAAE,CAAC,EAAE;aACT,IAAI,EAAE,cAAc;gBADpB,IAAI,EAAE,CAAC,EAAE,EACT,IAAI,EAAE,cAAc;IAGtC;;OAEG;IACH,MAAM,CAAC,MAAM,CAAC,CAAC,EACb,IAAI,EAAE,CAAC,EAAE,EACT,UAAU,EAAE,UAAU,EACtB,KAAK,EAAE,MAAM,GACZ,eAAe,CAAC,CAAC,CAAC;IAKrB;;OAEG;IACH,MAAM,CAAC,UAAU,CAAC,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,cAAc;IAaxE;;OAEG;IACH,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC;IA0C1E;;;;;;;;OAQG;IACH,MAAM,IAAI,mBAAmB,CAAC,CAAC,CAAC;IAShC;;OAEG;IACH,OAAO,CAAC,aAAa;IA2BrB;;OAEG;IACH,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC;IAI9C;;OAEG;IACH,IAAI,OAAO,IAAI,OAAO,CAErB;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,OAAO,CAErB;CACF"}
@@ -0,0 +1,193 @@
1
+ import { Id } from "../core/id.js";
2
+ import { ValueObject } from "../core/value-object.js";
3
+ export class PaginatedResult {
4
+ data;
5
+ meta;
6
+ constructor(data, meta) {
7
+ this.data = data;
8
+ this.meta = meta;
9
+ }
10
+ /**
11
+ * Creates a PaginatedResult with calculated metadata
12
+ */
13
+ static create(data, pagination, total) {
14
+ const meta = this.createMeta(pagination, total);
15
+ return new PaginatedResult(data, meta);
16
+ }
17
+ /**
18
+ * Creates pagination metadata from total count
19
+ */
20
+ static createMeta(pagination, total) {
21
+ const totalPages = Math.ceil(total / pagination.limit);
22
+ return {
23
+ page: pagination.page,
24
+ limit: pagination.limit,
25
+ total,
26
+ totalPages,
27
+ hasNext: pagination.page < totalPages,
28
+ hasPrevious: pagination.page > 1,
29
+ };
30
+ }
31
+ /**
32
+ * Applies criteria to an in-memory array (useful for testing)
33
+ */
34
+ static fromArray(items, criteria) {
35
+ let result = [...items];
36
+ let total = result.length;
37
+ for (const filter of criteria.getFilters()) {
38
+ result = result.filter((item) => applyFilter(item, filter));
39
+ total = result.length;
40
+ }
41
+ for (const order of criteria.getOrders().reverse()) {
42
+ result.sort((a, b) => {
43
+ const aVal = getNestedValue(a, order.field);
44
+ const bVal = getNestedValue(b, order.field);
45
+ let comparison = 0;
46
+ if (aVal < bVal)
47
+ comparison = -1;
48
+ if (aVal > bVal)
49
+ comparison = 1;
50
+ return order.direction === "desc" ? -comparison : comparison;
51
+ });
52
+ }
53
+ const pagination = criteria.getPagination();
54
+ result = result.slice(pagination.offset, pagination.offset + pagination.limit);
55
+ const search = criteria.getSearch();
56
+ if (search) {
57
+ result = result.filter((item) => {
58
+ const values = Object.values(item);
59
+ return values.some((val) => String(val).toLowerCase().includes(search.toLowerCase()));
60
+ });
61
+ }
62
+ return PaginatedResult.create(result, pagination, total);
63
+ }
64
+ /**
65
+ * Converts the result to JSON, deeply serializing all entities/aggregates/value objects
66
+ * - Entities/Aggregates → calls toJSON() recursively
67
+ * - Value Objects → converts to value
68
+ * - Id → converts to string
69
+ * - Arrays → maps recursively
70
+ * - Plain objects → serializes properties recursively
71
+ * - Primitives → returns as-is
72
+ */
73
+ toJSON() {
74
+ return {
75
+ data: this.data.map((item) => this.deepSerialize(item)),
76
+ meta: this.meta,
77
+ };
78
+ }
79
+ /**
80
+ * Deep serialization logic (similar to BaseEntity.deepToJson)
81
+ */
82
+ deepSerialize(obj) {
83
+ if (obj === null || obj === undefined)
84
+ return obj;
85
+ if (obj instanceof Id)
86
+ return obj.value;
87
+ if (obj instanceof ValueObject)
88
+ return obj.value;
89
+ if (Array.isArray(obj)) {
90
+ return obj.map((item) => this.deepSerialize(item));
91
+ }
92
+ if (obj && typeof obj.toJSON === "function") {
93
+ return obj.toJSON();
94
+ }
95
+ if (typeof obj === "object") {
96
+ const result = {};
97
+ for (const key in obj) {
98
+ if (obj.hasOwnProperty(key)) {
99
+ result[key] = this.deepSerialize(obj[key]);
100
+ }
101
+ }
102
+ return result;
103
+ }
104
+ return obj;
105
+ }
106
+ /**
107
+ * Transform each item in the result using a mapper function
108
+ */
109
+ map(fn) {
110
+ return new PaginatedResult(this.data.map(fn), this.meta);
111
+ }
112
+ /**
113
+ * Check if result has no data
114
+ */
115
+ get isEmpty() {
116
+ return this.data.length === 0;
117
+ }
118
+ /**
119
+ * Check if there are more pages available
120
+ */
121
+ get hasMore() {
122
+ return this.meta.hasNext;
123
+ }
124
+ }
125
+ function applyFilter(item, filter) {
126
+ const value = getNestedValue(item, filter.field);
127
+ const isValueDate = value instanceof Date;
128
+ const parseValue = (v) => {
129
+ if (isValueDate && typeof v === "string")
130
+ return new Date(v);
131
+ if (isValueDate && typeof v === "number")
132
+ return new Date(v);
133
+ return v;
134
+ };
135
+ switch (filter.operator) {
136
+ case "equals":
137
+ return value === filter.value;
138
+ case "notEquals":
139
+ return value !== filter.value;
140
+ case "greaterThan": {
141
+ const compareTo = parseValue(filter.value);
142
+ return isValueDate ? value > compareTo : value > filter.value;
143
+ }
144
+ case "greaterThanOrEqual": {
145
+ const compareTo = parseValue(filter.value);
146
+ return isValueDate ? value >= compareTo : value >= filter.value;
147
+ }
148
+ case "lessThan":
149
+ const lt = parseValue(filter.value);
150
+ return isValueDate ? value < lt : value < filter.value;
151
+ case "lessThanOrEqual":
152
+ const lte = parseValue(filter.value);
153
+ return isValueDate ? value <= lte : value <= filter.value;
154
+ case "contains":
155
+ return String(value)
156
+ .toLowerCase()
157
+ .includes(String(filter.value).toLowerCase());
158
+ case "startsWith":
159
+ return String(value)
160
+ .toLowerCase()
161
+ .startsWith(String(filter.value).toLowerCase());
162
+ case "endsWith":
163
+ return String(value)
164
+ .toLowerCase()
165
+ .endsWith(String(filter.value).toLowerCase());
166
+ case "in":
167
+ return Array.isArray(filter.value) && filter.value.includes(value);
168
+ case "notIn":
169
+ return Array.isArray(filter.value) && !filter.value.includes(value);
170
+ case "between":
171
+ if (Array.isArray(filter.value) && filter.value.length === 2) {
172
+ const [min, max] = filter.value.map(parseValue);
173
+ return isValueDate
174
+ ? value >= min && value <= max
175
+ : value >= filter.value[0] && value <= filter.value[1];
176
+ }
177
+ return false;
178
+ case "isNull":
179
+ return value === null || value === undefined;
180
+ case "isNotNull":
181
+ return value !== null && value !== undefined;
182
+ default:
183
+ return true;
184
+ }
185
+ }
186
+ function getNestedValue(obj, path) {
187
+ return path.split(".").reduce((current, key) => {
188
+ if (current === null || current === undefined)
189
+ return undefined;
190
+ return current[key];
191
+ }, obj);
192
+ }
193
+ //# sourceMappingURL=paginated-result.js.map