@decaf-ts/db-decorators 0.6.0 → 0.6.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 (141) hide show
  1. package/LICENSE.md +21 -157
  2. package/README.md +571 -10
  3. package/dist/db-decorators.cjs +1375 -327
  4. package/dist/db-decorators.esm.cjs +1375 -328
  5. package/lib/esm/identity/decorators.d.ts +7 -0
  6. package/lib/esm/identity/decorators.js +11 -4
  7. package/lib/esm/identity/index.js +3 -3
  8. package/lib/esm/identity/utils.d.ts +36 -23
  9. package/lib/esm/identity/utils.js +38 -25
  10. package/lib/esm/index.d.ts +12 -27
  11. package/lib/esm/index.js +13 -28
  12. package/lib/esm/interfaces/BulkCrudOperator.d.ts +39 -0
  13. package/lib/esm/interfaces/BulkCrudOperator.js +1 -1
  14. package/lib/esm/interfaces/Contextual.d.ts +19 -2
  15. package/lib/esm/interfaces/Contextual.js +1 -1
  16. package/lib/esm/interfaces/CrudOperator.d.ts +26 -23
  17. package/lib/esm/interfaces/CrudOperator.js +1 -1
  18. package/lib/esm/interfaces/IRepository.d.ts +10 -2
  19. package/lib/esm/interfaces/IRepository.js +1 -1
  20. package/lib/esm/interfaces/index.js +5 -5
  21. package/lib/esm/model/constants.d.ts +11 -13
  22. package/lib/esm/model/constants.js +12 -14
  23. package/lib/esm/model/decorators.d.ts +112 -23
  24. package/lib/esm/model/decorators.js +119 -29
  25. package/lib/esm/model/index.d.ts +1 -0
  26. package/lib/esm/model/index.js +7 -6
  27. package/lib/esm/model/model.d.ts +2 -141
  28. package/lib/esm/model/model.js +2 -13
  29. package/lib/esm/model/overrides.d.ts +1 -0
  30. package/lib/esm/model/overrides.js +23 -0
  31. package/lib/esm/model/utils.d.ts +39 -0
  32. package/lib/esm/model/utils.js +43 -4
  33. package/lib/esm/model/validation.d.ts +26 -8
  34. package/lib/esm/model/validation.js +29 -11
  35. package/lib/esm/operations/Operations.d.ts +65 -3
  36. package/lib/esm/operations/Operations.js +68 -6
  37. package/lib/esm/operations/OperationsRegistry.d.ts +44 -16
  38. package/lib/esm/operations/OperationsRegistry.js +46 -18
  39. package/lib/esm/operations/constants.d.ts +34 -8
  40. package/lib/esm/operations/constants.js +23 -9
  41. package/lib/esm/operations/decorators.d.ts +140 -134
  42. package/lib/esm/operations/decorators.js +152 -137
  43. package/lib/esm/operations/index.js +6 -6
  44. package/lib/esm/operations/types.d.ts +10 -0
  45. package/lib/esm/operations/types.js +1 -1
  46. package/lib/esm/repository/BaseRepository.d.ts +324 -0
  47. package/lib/esm/repository/BaseRepository.js +309 -9
  48. package/lib/esm/repository/Context.d.ts +153 -2
  49. package/lib/esm/repository/Context.js +154 -6
  50. package/lib/esm/repository/Repository.d.ts +89 -0
  51. package/lib/esm/repository/Repository.js +96 -7
  52. package/lib/esm/repository/constants.d.ts +7 -0
  53. package/lib/esm/repository/constants.js +9 -1
  54. package/lib/esm/repository/errors.d.ts +61 -34
  55. package/lib/esm/repository/errors.js +62 -35
  56. package/lib/esm/repository/index.js +9 -9
  57. package/lib/esm/repository/types.d.ts +26 -0
  58. package/lib/esm/repository/types.js +1 -1
  59. package/lib/esm/repository/utils.d.ts +11 -0
  60. package/lib/esm/repository/utils.js +7 -7
  61. package/lib/esm/repository/wrappers.d.ts +2 -2
  62. package/lib/esm/repository/wrappers.js +5 -5
  63. package/lib/esm/validation/constants.d.ts +20 -5
  64. package/lib/esm/validation/constants.js +22 -7
  65. package/lib/esm/validation/decorators.d.ts +101 -19
  66. package/lib/esm/validation/decorators.js +109 -27
  67. package/lib/esm/validation/index.js +5 -5
  68. package/lib/esm/validation/validation.js +10 -2
  69. package/lib/esm/validation/validators/ReadOnlyValidator.d.ts +32 -8
  70. package/lib/esm/validation/validators/ReadOnlyValidator.js +34 -10
  71. package/lib/esm/validation/validators/TimestampValidator.d.ts +37 -3
  72. package/lib/esm/validation/validators/TimestampValidator.js +39 -5
  73. package/lib/esm/validation/validators/UpdateValidator.d.ts +28 -11
  74. package/lib/esm/validation/validators/UpdateValidator.js +23 -8
  75. package/lib/esm/validation/validators/index.js +4 -4
  76. package/lib/identity/decorators.cjs +8 -1
  77. package/lib/identity/decorators.d.ts +7 -0
  78. package/lib/identity/utils.cjs +35 -22
  79. package/lib/identity/utils.d.ts +36 -23
  80. package/lib/index.cjs +14 -28
  81. package/lib/index.d.ts +12 -27
  82. package/lib/interfaces/BulkCrudOperator.cjs +1 -1
  83. package/lib/interfaces/BulkCrudOperator.d.ts +39 -0
  84. package/lib/interfaces/Contextual.cjs +1 -1
  85. package/lib/interfaces/Contextual.d.ts +19 -2
  86. package/lib/interfaces/CrudOperator.cjs +1 -1
  87. package/lib/interfaces/CrudOperator.d.ts +26 -23
  88. package/lib/interfaces/IRepository.cjs +1 -1
  89. package/lib/interfaces/IRepository.d.ts +10 -2
  90. package/lib/model/constants.cjs +12 -14
  91. package/lib/model/constants.d.ts +11 -13
  92. package/lib/model/decorators.cjs +114 -24
  93. package/lib/model/decorators.d.ts +112 -23
  94. package/lib/model/index.cjs +2 -1
  95. package/lib/model/index.d.ts +1 -0
  96. package/lib/model/model.cjs +1 -13
  97. package/lib/model/model.d.ts +2 -141
  98. package/lib/model/overrides.cjs +25 -0
  99. package/lib/model/overrides.d.ts +1 -0
  100. package/lib/model/utils.cjs +41 -2
  101. package/lib/model/utils.d.ts +39 -0
  102. package/lib/model/validation.cjs +27 -9
  103. package/lib/model/validation.d.ts +26 -8
  104. package/lib/operations/Operations.cjs +66 -4
  105. package/lib/operations/Operations.d.ts +65 -3
  106. package/lib/operations/OperationsRegistry.cjs +45 -17
  107. package/lib/operations/OperationsRegistry.d.ts +44 -16
  108. package/lib/operations/constants.cjs +24 -10
  109. package/lib/operations/constants.d.ts +34 -8
  110. package/lib/operations/decorators.cjs +150 -135
  111. package/lib/operations/decorators.d.ts +140 -134
  112. package/lib/operations/types.cjs +1 -1
  113. package/lib/operations/types.d.ts +10 -0
  114. package/lib/repository/BaseRepository.cjs +303 -3
  115. package/lib/repository/BaseRepository.d.ts +324 -0
  116. package/lib/repository/Context.cjs +153 -5
  117. package/lib/repository/Context.d.ts +153 -2
  118. package/lib/repository/Repository.cjs +90 -1
  119. package/lib/repository/Repository.d.ts +89 -0
  120. package/lib/repository/constants.cjs +9 -1
  121. package/lib/repository/constants.d.ts +7 -0
  122. package/lib/repository/errors.cjs +62 -35
  123. package/lib/repository/errors.d.ts +61 -34
  124. package/lib/repository/types.cjs +1 -1
  125. package/lib/repository/types.d.ts +26 -0
  126. package/lib/repository/utils.cjs +3 -3
  127. package/lib/repository/utils.d.ts +11 -0
  128. package/lib/repository/wrappers.cjs +3 -3
  129. package/lib/repository/wrappers.d.ts +2 -2
  130. package/lib/validation/constants.cjs +21 -6
  131. package/lib/validation/constants.d.ts +20 -5
  132. package/lib/validation/decorators.cjs +102 -20
  133. package/lib/validation/decorators.d.ts +101 -19
  134. package/lib/validation/validation.cjs +9 -1
  135. package/lib/validation/validators/ReadOnlyValidator.cjs +33 -9
  136. package/lib/validation/validators/ReadOnlyValidator.d.ts +32 -8
  137. package/lib/validation/validators/TimestampValidator.cjs +38 -4
  138. package/lib/validation/validators/TimestampValidator.d.ts +37 -3
  139. package/lib/validation/validators/UpdateValidator.cjs +23 -8
  140. package/lib/validation/validators/UpdateValidator.d.ts +28 -11
  141. package/package.json +2 -2
package/README.md CHANGED
@@ -1,7 +1,8 @@
1
1
  ![Banner](./workdocs/assets/Banner.png)
2
- ## DB Decorators
2
+ ### DB-Decorators: Database Operations Made Simple
3
+
4
+ The db-decorators library provides a comprehensive set of TypeScript decorators and utilities for database operations. It implements the repository pattern with support for model definition, validation, identity management, and operation hooks. The library enables developers to define database models with decorators, perform CRUD operations with validation, and customize behavior during database operations through operation hooks.
3
5
 
4
- Extension to Decorator Validation with common db functionalities
5
6
 
6
7
 
7
8
  ![Licence](https://img.shields.io/github/license/decaf-ts/db-decorators.svg?style=plastic)
@@ -27,15 +28,41 @@ Extension to Decorator Validation with common db functionalities
27
28
 
28
29
  Documentation available [here](https://decaf-ts.github.io/db-decorators/)
29
30
 
30
- ### Description
31
31
 
32
- Extension of `decorator-validation`, extends de validation api for the Model class:
33
- - update capable decorator based validation api with recursive validation;
34
- - implements configurable decorated based hooks for all CRUD operations:
35
- - on<operation>: hook will be called before the `operation`;
36
- - after<operation>: hook will be called after the `operation`;
37
- - Defines the abstract `Repository` class that calls the respective hooks for each CRUD operation:
38
- - Developers are responsible for implementing the actual CRUD methods for their storage systems;
32
+ ### DB-Decorators
33
+
34
+ The db-decorators library is a powerful TypeScript framework for database operations that leverages decorators to simplify database interactions. It provides a comprehensive solution for implementing the repository pattern with built-in support for model definition, validation, identity management, and operation hooks.
35
+
36
+ #### Key Features
37
+
38
+ 1. **Repository Pattern Implementation**
39
+ - Abstract `BaseRepository` class providing the foundation for CRUD operations
40
+ - Concrete `Repository` class with validation support
41
+ - Support for bulk operations through the `BulkCrudOperator` interface
42
+
43
+ 2. **Model Management**
44
+ - Model definition with TypeScript decorators
45
+ - Identity management with the `@id()` decorator
46
+ - Property composition with `@composed()` and `@composedFromKeys()` decorators
47
+ - Versioning support with the `@version()` decorator
48
+ - Transient properties with the `@transient()` decorator
49
+
50
+ 3. **Operation Hooks**
51
+ - Pre-operation hooks with `@on()`, `@onCreate()`, `@onUpdate()`, etc.
52
+ - Post-operation hooks with `@after()`, `@afterCreate()`, `@afterUpdate()`, etc.
53
+ - Custom operation handlers through the `Operations` registry
54
+
55
+ 4. **Context Management**
56
+ - Hierarchical context chains with parent-child relationships
57
+ - Context accumulation for state management
58
+ - Operation-specific context creation
59
+
60
+ 5. **Validation**
61
+ - Integration with decorator-validation library
62
+ - Automatic validation during CRUD operations
63
+ - Custom validation rules through decorators
64
+
65
+ The library is designed to be extensible and adaptable to different database backends, providing a consistent API regardless of the underlying storage mechanism.
39
66
 
40
67
 
41
68
  ### How to Use
@@ -43,6 +70,540 @@ Extension of `decorator-validation`, extends de validation api for the Model cla
43
70
  - [Initial Setup](../../workdocs/tutorials/For%20Developers.md#_initial-setup_)
44
71
  - [Installation](../../workdocs/tutorials/For%20Developers.md#installation)
45
72
 
73
+ ## DB-Decorators Examples
74
+
75
+ ### 1. Defining Models with Decorators
76
+
77
+ #### Basic Model Definition
78
+
79
+ Description: Create a User model with ID, name, email, and password fields. The ID is marked as required and readonly, the password is hashed, and the email is required.
80
+
81
+ ```typescript
82
+ import { Model } from "@decaf-ts/decorator-validation";
83
+ import { id, hash, version, transient } from "@decaf-ts/db-decorators";
84
+ import { required, minLength, email as emailValidator } from "@decaf-ts/decorator-validation";
85
+
86
+ class User extends Model {
87
+ @id()
88
+ id: string;
89
+
90
+ @required()
91
+ @minLength(3)
92
+ name: string;
93
+
94
+ @required()
95
+ @emailValidator()
96
+ email: string;
97
+
98
+ @required()
99
+ @minLength(8)
100
+ @hash()
101
+ password: string;
102
+
103
+ @version()
104
+ version: number;
105
+
106
+ @transient()
107
+ temporaryData: any;
108
+ }
109
+ ```
110
+
111
+ #### Composed Properties
112
+
113
+ Description: Create a Product model with a SKU that is automatically composed from other properties.
114
+
115
+ ```typescript
116
+ import { Model } from "@decaf-ts/decorator-validation";
117
+ import { id, composed, composedFromKeys } from "@decaf-ts/db-decorators";
118
+ import { required } from "@decaf-ts/decorator-validation";
119
+
120
+ class Product extends Model {
121
+ @id()
122
+ id: string;
123
+
124
+ @required()
125
+ category: string;
126
+
127
+ @required()
128
+ name: string;
129
+
130
+ @required()
131
+ variant: string;
132
+
133
+ @composed(['category', 'name', 'variant'], '-')
134
+ sku: string;
135
+
136
+ @composedFromKeys(['category', 'name'], '_', true, 'PROD_', '_KEY')
137
+ productKey: string;
138
+ }
139
+ ```
140
+
141
+ ### 2. Implementing Repositories
142
+
143
+ #### Basic Repository Implementation
144
+
145
+ Description: Create a repository for the User model that implements the required CRUD operations.
146
+
147
+ ```typescript
148
+ import { Repository } from "@decaf-ts/db-decorators";
149
+ import { User } from "./models/User";
150
+
151
+ class UserRepository extends Repository<User> {
152
+ constructor() {
153
+ super(User);
154
+ }
155
+
156
+ async create(model: User, ...args: any[]): Promise<User> {
157
+ // Implementation for creating a user in the database
158
+ console.log(`Creating user: ${model.name}`);
159
+ // Assign an ID if not already present
160
+ if (!model.id) {
161
+ model.id = Date.now().toString();
162
+ }
163
+ return model;
164
+ }
165
+
166
+ async read(key: string | number, ...args: any[]): Promise<User> {
167
+ // Implementation for reading a user from the database
168
+ console.log(`Reading user with ID: ${key}`);
169
+ return new User({ id: key, name: "Example User", email: "user@example.com" });
170
+ }
171
+
172
+ async update(model: User, ...args: any[]): Promise<User> {
173
+ // Implementation for updating a user in the database
174
+ console.log(`Updating user: ${model.name}`);
175
+ return model;
176
+ }
177
+
178
+ async delete(key: string | number, ...args: any[]): Promise<User> {
179
+ // Implementation for deleting a user from the database
180
+ console.log(`Deleting user with ID: ${key}`);
181
+ const user = await this.read(key);
182
+ return user;
183
+ }
184
+ }
185
+ ```
186
+
187
+ #### Using Bulk Operations
188
+
189
+ Description: Implement bulk operations for efficient batch processing of multiple models.
190
+
191
+ ```typescript
192
+ import { Repository } from "@decaf-ts/db-decorators";
193
+ import { Product } from "./models/Product";
194
+
195
+ class ProductRepository extends Repository<Product> {
196
+ constructor() {
197
+ super(Product);
198
+ }
199
+
200
+ // Implement required CRUD methods
201
+ async create(model: Product, ...args: any[]): Promise<Product> {
202
+ // Implementation
203
+ return model;
204
+ }
205
+
206
+ async read(key: string | number, ...args: any[]): Promise<Product> {
207
+ // Implementation
208
+ return new Product({ id: key });
209
+ }
210
+
211
+ async update(model: Product, ...args: any[]): Promise<Product> {
212
+ // Implementation
213
+ return model;
214
+ }
215
+
216
+ async delete(key: string | number, ...args: any[]): Promise<Product> {
217
+ // Implementation
218
+ return await this.read(key);
219
+ }
220
+
221
+ // Override bulk methods for optimized implementation
222
+ async createAll(models: Product[], ...args: any[]): Promise<Product[]> {
223
+ console.log(`Bulk creating ${models.length} products`);
224
+ // Custom implementation for bulk creation
225
+ return models.map(model => {
226
+ if (!model.id) {
227
+ model.id = Date.now().toString();
228
+ }
229
+ return model;
230
+ });
231
+ }
232
+
233
+ async readAll(keys: string[] | number[], ...args: any[]): Promise<Product[]> {
234
+ console.log(`Bulk reading ${keys.length} products`);
235
+ // Custom implementation for bulk reading
236
+ return keys.map(key => new Product({ id: key }));
237
+ }
238
+ }
239
+ ```
240
+
241
+ ### 3. Using Operation Hooks
242
+
243
+ #### Property Transformation Hooks
244
+
245
+ Description: Use operation hooks to transform property values during database operations.
246
+
247
+ ```typescript
248
+ import { Model } from "@decaf-ts/decorator-validation";
249
+ import { id, onCreate, onUpdate, onCreateUpdate } from "@decaf-ts/db-decorators";
250
+ import { required } from "@decaf-ts/decorator-validation";
251
+
252
+ // Handler function for setting creation timestamp
253
+ function setCreationTimestamp(repo, context, data, key, model) {
254
+ model[key] = new Date().toISOString();
255
+ }
256
+
257
+ // Handler function for setting update timestamp
258
+ function setUpdateTimestamp(repo, context, data, key, model) {
259
+ model[key] = new Date().toISOString();
260
+ }
261
+
262
+ // Handler function for normalizing email
263
+ function normalizeEmail(repo, context, data, key, model) {
264
+ if (model[key]) {
265
+ model[key] = model[key].toLowerCase().trim();
266
+ }
267
+ }
268
+
269
+ class User extends Model {
270
+ @id()
271
+ id: string;
272
+
273
+ @required()
274
+ name: string;
275
+
276
+ @required()
277
+ @onCreateUpdate(normalizeEmail)
278
+ email: string;
279
+
280
+ @onCreate(setCreationTimestamp)
281
+ createdAt: string;
282
+
283
+ @onUpdate(setUpdateTimestamp)
284
+ updatedAt: string;
285
+ }
286
+ ```
287
+
288
+ #### Post-Operation Hooks
289
+
290
+ Description: Use post-operation hooks to perform actions after database operations.
291
+
292
+ ```typescript
293
+ import { Model } from "@decaf-ts/decorator-validation";
294
+ import { id, afterCreate, afterUpdate, afterDelete } from "@decaf-ts/db-decorators";
295
+
296
+ // Handler function for logging after creation
297
+ function logCreation(repo, context, data, key, model) {
298
+ console.log(`User created: ${model.id} - ${model.name}`);
299
+ }
300
+
301
+ // Handler function for logging after update
302
+ function logUpdate(repo, context, data, key, model) {
303
+ console.log(`User updated: ${model.id} - ${model.name}`);
304
+ }
305
+
306
+ // Handler function for logging after deletion
307
+ function logDeletion(repo, context, data, key, model) {
308
+ console.log(`User deleted: ${model.id} - ${model.name}`);
309
+ }
310
+
311
+ class User extends Model {
312
+ @id()
313
+ id: string;
314
+
315
+ @required()
316
+ name: string;
317
+
318
+ @required()
319
+ email: string;
320
+
321
+ @afterCreate(logCreation)
322
+ @afterUpdate(logUpdate)
323
+ @afterDelete(logDeletion)
324
+ _log: any; // This property is just a placeholder for the decorators
325
+ }
326
+ ```
327
+
328
+ ### 4. Working with Contexts
329
+
330
+ #### Creating and Using Contexts
331
+
332
+ Description: Create and use contexts to manage operation state and configuration.
333
+
334
+ ```typescript
335
+ import { Context, Repository } from "@decaf-ts/db-decorators";
336
+ import { User } from "./models/User";
337
+
338
+ class UserRepository extends Repository<User> {
339
+ constructor() {
340
+ super(User);
341
+ }
342
+
343
+ // Implement required CRUD methods
344
+ async create(model: User, ...args: any[]): Promise<User> {
345
+ // Implementation
346
+ return model;
347
+ }
348
+
349
+ async read(key: string | number, ...args: any[]): Promise<User> {
350
+ // Implementation
351
+ return new User({ id: key });
352
+ }
353
+
354
+ async update(model: User, ...args: any[]): Promise<User> {
355
+ // Implementation
356
+ return model;
357
+ }
358
+
359
+ async delete(key: string | number, ...args: any[]): Promise<User> {
360
+ // Implementation
361
+ return await this.read(key);
362
+ }
363
+
364
+ // Example of using context
365
+ async createWithAudit(model: User, userId: string): Promise<User> {
366
+ // Create a context with audit information
367
+ const context = new Context().accumulate({
368
+ auditUser: userId,
369
+ auditTimestamp: new Date(),
370
+ skipValidation: false
371
+ });
372
+
373
+ // Pass the context to the create method
374
+ return this.create(model, context);
375
+ }
376
+ }
377
+
378
+ // Usage
379
+ const userRepo = new UserRepository();
380
+ const newUser = new User({ name: "John Doe", email: "john@example.com" });
381
+ const createdUser = await userRepo.createWithAudit(newUser, "admin123");
382
+ ```
383
+
384
+ #### Context Hierarchies
385
+
386
+ Description: Create hierarchical contexts for complex operations.
387
+
388
+ ```typescript
389
+ import { Context, OperationKeys } from "@decaf-ts/db-decorators";
390
+ import { User } from "./models/User";
391
+
392
+ // Create a parent context
393
+ const parentContext = new Context().accumulate({
394
+ transactionId: "tx123",
395
+ batchOperation: true
396
+ });
397
+
398
+ // Create a child context for a specific operation
399
+ const childContext = parentContext.child<User, Context<any>>(
400
+ OperationKeys.CREATE,
401
+ User
402
+ ).accumulate({
403
+ operationId: "op456",
404
+ validationLevel: "strict"
405
+ });
406
+
407
+ // Access values from the context hierarchy
408
+ console.log(childContext.get("transactionId")); // "tx123" (inherited from parent)
409
+ console.log(childContext.get("operationId")); // "op456" (from child)
410
+ ```
411
+
412
+ ### 5. Performing CRUD Operations
413
+
414
+ #### Basic CRUD Operations
415
+
416
+ Description: Perform basic CRUD operations using a repository.
417
+
418
+ ```typescript
419
+ import { User } from "./models/User";
420
+ import { UserRepository } from "./repositories/UserRepository";
421
+
422
+ async function userCrudExample() {
423
+ const userRepo = new UserRepository();
424
+
425
+ // Create a new user
426
+ const newUser = new User({
427
+ name: "Alice Smith",
428
+ email: "alice@example.com",
429
+ password: "securePassword123"
430
+ });
431
+ const createdUser = await userRepo.create(newUser);
432
+ console.log("Created user:", createdUser);
433
+
434
+ // Read a user
435
+ const userId = createdUser.id;
436
+ const retrievedUser = await userRepo.read(userId);
437
+ console.log("Retrieved user:", retrievedUser);
438
+
439
+ // Update a user
440
+ retrievedUser.name = "Alice Johnson";
441
+ const updatedUser = await userRepo.update(retrievedUser);
442
+ console.log("Updated user:", updatedUser);
443
+
444
+ // Delete a user
445
+ const deletedUser = await userRepo.delete(userId);
446
+ console.log("Deleted user:", deletedUser);
447
+ }
448
+ ```
449
+
450
+ #### Bulk Operations
451
+
452
+ Description: Perform bulk operations for efficient batch processing.
453
+
454
+ ```typescript
455
+ import { Product } from "./models/Product";
456
+ import { ProductRepository } from "./repositories/ProductRepository";
457
+
458
+ async function productBulkExample() {
459
+ const productRepo = new ProductRepository();
460
+
461
+ // Create multiple products
462
+ const products = [
463
+ new Product({ category: "Electronics", name: "Laptop", variant: "15-inch" }),
464
+ new Product({ category: "Electronics", name: "Laptop", variant: "13-inch" }),
465
+ new Product({ category: "Electronics", name: "Smartphone", variant: "Pro" })
466
+ ];
467
+ const createdProducts = await productRepo.createAll(products);
468
+ console.log("Created products:", createdProducts);
469
+
470
+ // Read multiple products
471
+ const productIds = createdProducts.map(p => p.id);
472
+ const retrievedProducts = await productRepo.readAll(productIds);
473
+ console.log("Retrieved products:", retrievedProducts);
474
+
475
+ // Update multiple products
476
+ const updatedProducts = retrievedProducts.map(p => {
477
+ p.name = p.name + " (Updated)";
478
+ return p;
479
+ });
480
+ const savedProducts = await productRepo.updateAll(updatedProducts);
481
+ console.log("Updated products:", savedProducts);
482
+
483
+ // Delete multiple products
484
+ const deletedProducts = await productRepo.deleteAll(productIds);
485
+ console.log("Deleted products:", deletedProducts);
486
+ }
487
+ ```
488
+
489
+ ### 6. Validation
490
+
491
+ #### Model Validation
492
+
493
+ Description: Validate models during CRUD operations to ensure data integrity.
494
+
495
+ ```typescript
496
+ import { Model, ModelErrorDefinition } from "@decaf-ts/decorator-validation";
497
+ import { id } from "@decaf-ts/db-decorators";
498
+ import { required, minLength, maxLength, email, pattern } from "@decaf-ts/decorator-validation";
499
+
500
+ class User extends Model {
501
+ @id()
502
+ id: string;
503
+
504
+ @required()
505
+ @minLength(2)
506
+ @maxLength(50)
507
+ name: string;
508
+
509
+ @required()
510
+ @email()
511
+ emailAddress: string;
512
+
513
+ @required()
514
+ @minLength(8)
515
+ @pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/,
516
+ "Password must contain at least one uppercase letter, one lowercase letter, one number, and one special character")
517
+ password: string;
518
+
519
+ // Manual validation example
520
+ hasErrors(): ModelErrorDefinition | undefined {
521
+ const errors = super.hasErrors();
522
+
523
+ // Add custom validation logic
524
+ if (this.name && this.name.includes('admin') && !this.emailAddress.includes('admin')) {
525
+ if (!errors) {
526
+ return {
527
+ name: ["Admin users must have an admin email address"]
528
+ };
529
+ }
530
+ errors.name = errors.name || [];
531
+ errors.name.push("Admin users must have an admin email address");
532
+ }
533
+
534
+ return errors;
535
+ }
536
+ }
537
+
538
+ // Usage in a repository
539
+ class UserRepository extends Repository<User> {
540
+ // ... other methods
541
+
542
+ async create(model: User, ...args: any[]): Promise<User> {
543
+ // The Repository class will automatically validate the model
544
+ // and throw a ValidationError if validation fails
545
+
546
+ // Custom validation can also be performed
547
+ const errors = model.hasErrors();
548
+ if (errors) {
549
+ throw new ValidationError(errors.toString());
550
+ }
551
+
552
+ // Proceed with creation if validation passes
553
+ return model;
554
+ }
555
+ }
556
+ ```
557
+
558
+ ### 7. Identity Management
559
+
560
+ #### Working with Model IDs
561
+
562
+ Description: Use the identity module to work with model IDs.
563
+
564
+ ```typescript
565
+ import { Model } from "@decaf-ts/decorator-validation";
566
+ import { id } from "@decaf-ts/db-decorators";
567
+ import { findPrimaryKey, findModelId } from "@decaf-ts/db-decorators";
568
+
569
+ class Document extends Model {
570
+ @id()
571
+ documentId: string;
572
+
573
+ title: string;
574
+ content: string;
575
+ }
576
+
577
+ // Create a document instance
578
+ const doc = new Document({
579
+ documentId: "doc-123",
580
+ title: "Sample Document",
581
+ content: "This is a sample document."
582
+ });
583
+
584
+ // Find the primary key property
585
+ const pkInfo = findPrimaryKey(doc);
586
+ console.log("Primary key property:", pkInfo.id); // "documentId"
587
+ console.log("Primary key metadata:", pkInfo.props);
588
+
589
+ // Get the primary key value
590
+ const docId = findModelId(doc);
591
+ console.log("Document ID:", docId); // "doc-123"
592
+
593
+ // Try to get ID from a model without an ID value
594
+ const emptyDoc = new Document();
595
+ try {
596
+ const id = findModelId(emptyDoc); // Will throw an error
597
+ } catch (error) {
598
+ console.error("Error:", error.message);
599
+ }
600
+
601
+ // Get ID with returnEmpty option
602
+ const emptyId = findModelId(emptyDoc, true); // Returns undefined instead of throwing
603
+ console.log("Empty ID:", emptyId);
604
+ ```
605
+
606
+
46
607
 
47
608
 
48
609