@common-stack/store-mongo 7.1.1-alpha.8 → 7.1.1-alpha.9

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/lib/module.d.ts CHANGED
@@ -1,2 +1,3 @@
1
- declare const _default: any;
1
+ import { Feature } from '@common-stack/server-core';
2
+ declare const _default: Feature<import("@common-stack/server-core").ConfigurationScope, any>;
2
3
  export default _default;
@@ -0,0 +1,5 @@
1
+ export const SERVER_TYPES = {
2
+ BaseMongoRepository: Symbol.for('BaseMongoRepository'),
3
+ BaseMongoService: Symbol.for('BaseMongoService'),
4
+ BaseService: Symbol.for('BaseService'),
5
+ }
@@ -0,0 +1,13 @@
1
+
2
+ export interface IDatabaseMigration {
3
+
4
+ /**
5
+ * ID of the migration, and it should be changed inorder to overwrite previous migration
6
+ */
7
+ id: string;
8
+
9
+ up?(): Promise<void>;
10
+
11
+
12
+ down?(): Promise<void>;
13
+ }
@@ -0,0 +1,284 @@
1
+ /**
2
+ * @file BaseMongoRepository.ts
3
+ * @description Defines the IBaseMongoRepository interface that provides a standardized set of methods for interacting with MongoDB collections.
4
+ * This interface serves as a contract for repository implementations, ensuring consistent data access patterns across the application.
5
+ * It includes methods for CRUD operations, querying with filters, pagination, and aggregation pipelines.
6
+ *
7
+ * The interface is generic, accepting a SchemaType parameter that represents the Mongoose schema structure for the collection.
8
+ * Methods return domain objects (with 'id' instead of '_id') using the AsDomainType transformation.
9
+ *
10
+ * Key features:
11
+ * - Consistent data access patterns across different entity types
12
+ * - Type-safe operations with MongoDB collections
13
+ * - Support for pagination, filtering, and sorting
14
+ * - Aggregation pipeline integration for complex queries
15
+ * - Bulk operations for performance optimization
16
+ *
17
+ * This repository pattern creates a clean separation between the data access layer and business logic,
18
+ * making the codebase more maintainable and testable.
19
+ *
20
+ * @see IBaseService2 - Service layer that uses repositories for business logic
21
+ * @see IDataLoader2 - Efficient data loading pattern that can utilize repositories
22
+ * @see GetAllArgs - Common arguments for querying collections
23
+ */
24
+
25
+ import type { FilterQuery, Model, PipelineStage, UpdateQuery } from 'mongoose';
26
+ import { AsDomainType, CreateType, GetAllArgs, GetAllWithCountResult, UpdateType } from './dbCommonTypes';
27
+
28
+ export interface IBaseMongoRepository<SchemaType> {
29
+ /**
30
+ * The Mongoose model associated with this repository
31
+ * Used for direct database operations
32
+ */
33
+ model: Model<SchemaType>;
34
+
35
+ /**
36
+ * Counts documents matching the specified conditions
37
+ *
38
+ * @param conditions - Optional filter criteria to count specific documents
39
+ * @returns Promise resolving to the count of matching documents
40
+ *
41
+ * @example
42
+ * // Count all active users
43
+ * const activeUserCount = await userRepository.count({ active: true });
44
+ */
45
+ count(conditions?: FilterQuery<SchemaType>): Promise<number>;
46
+
47
+ /**
48
+ * Retrieves documents matching the specified options
49
+ *
50
+ * @param options - Query options including filtering, sorting, pagination, and field selection
51
+ * @returns Promise resolving to an array of domain objects
52
+ *
53
+ * @example
54
+ * // Get recently created users with pagination
55
+ * const users = await userRepository.getAll({
56
+ * criteria: { active: true },
57
+ * sort: { createdAt: -1 },
58
+ * skip: 0,
59
+ * limit: 10
60
+ * });
61
+ */
62
+ getAll(options: GetAllArgs<SchemaType>): Promise<AsDomainType<SchemaType>[]>;
63
+
64
+ /**
65
+ * Retrieves documents using a custom aggregation pipeline
66
+ *
67
+ * @param options - Base query options for filtering and pagination
68
+ * @param customPipeline - Optional MongoDB aggregation pipeline stages
69
+ * @returns Promise resolving to an array of domain objects
70
+ *
71
+ * @example
72
+ * // Get users with computed fields using aggregation
73
+ * const users = await userRepository.getAllWithPipeline(
74
+ * { limit: 10 },
75
+ * [
76
+ * { $lookup: { from: 'posts', localField: '_id', foreignField: 'userId', as: 'posts' } },
77
+ * { $addFields: { postCount: { $size: '$posts' } } }
78
+ * ]
79
+ * );
80
+ */
81
+ getAllWithPipeline(
82
+ options: GetAllArgs<SchemaType>,
83
+ customPipeline?: PipelineStage[],
84
+ ): Promise<AsDomainType<SchemaType>[]>;
85
+
86
+ /**
87
+ * Retrieves documents with pagination and total count
88
+ *
89
+ * @param options - Query options including filtering, sorting, pagination, and field selection
90
+ * @returns Promise resolving to object with data array and total count
91
+ *
92
+ * @example
93
+ * // Get paginated users with total count for UI pagination
94
+ * const { data, totalCount } = await userRepository.getAllWithCount({
95
+ * criteria: { role: 'user' },
96
+ * skip: 20,
97
+ * limit: 10
98
+ * });
99
+ */
100
+ getAllWithCount(options: GetAllArgs<SchemaType>): Promise<GetAllWithCountResult<SchemaType>>;
101
+
102
+ /**
103
+ * Retrieves documents with pagination, total count, and custom aggregation pipeline
104
+ *
105
+ * @param options - Base query options for filtering and pagination
106
+ * @param customPipeline - Optional MongoDB aggregation pipeline stages
107
+ * @returns Promise resolving to object with data array and total count
108
+ *
109
+ * @example
110
+ * // Get paginated users with related data and total count
111
+ * const result = await userRepository.getAllWithCountAndPipeline(
112
+ * { limit: 10, skip: 0 },
113
+ * [{ $lookup: { from: 'departments', localField: 'departmentId', foreignField: '_id', as: 'department' } }]
114
+ * );
115
+ */
116
+ getAllWithCountAndPipeline(
117
+ options: GetAllArgs<SchemaType>,
118
+ customPipeline?: PipelineStage[],
119
+ ): Promise<{
120
+ data: AsDomainType<SchemaType>[];
121
+ totalCount: number;
122
+ }>;
123
+
124
+ /**
125
+ * Retrieves a single document matching the specified conditions
126
+ *
127
+ * @param conditions - Filter criteria to find the document
128
+ * @param selectedFields - Optional space-separated string of fields to include
129
+ * @returns Promise resolving to a domain object or null if not found
130
+ *
131
+ * @example
132
+ * // Get user by email with selected fields
133
+ * const user = await userRepository.get({ email: 'user@example.com' }, 'name email role');
134
+ */
135
+ get(conditions?: FilterQuery<SchemaType>, selectedFields?: string): Promise<AsDomainType<SchemaType> | null>;
136
+
137
+ /**
138
+ * Finds a single document matching the specified conditions
139
+ * Similar to get() but with partial filter query support
140
+ *
141
+ * @param conditions - Partial filter criteria to find the document
142
+ * @param selectedFields - Optional space-separated string of fields to include
143
+ * @returns Promise resolving to a domain object or null if not found
144
+ *
145
+ * @example
146
+ * // Find user by partial match
147
+ * const user = await userRepository.find({ name: { $regex: 'John' } });
148
+ */
149
+ find(
150
+ conditions: Partial<FilterQuery<SchemaType>>,
151
+ selectedFields?: string,
152
+ ): Promise<AsDomainType<SchemaType> | null>;
153
+
154
+ /**
155
+ * Creates a new document
156
+ *
157
+ * @param data - Data for the new document
158
+ * @returns Promise resolving to the created domain object
159
+ *
160
+ * @example
161
+ * // Create a new user
162
+ * const newUser = await userRepository.create({
163
+ * name: 'John Doe',
164
+ * email: 'john@example.com',
165
+ * role: 'user'
166
+ * });
167
+ */
168
+ create<T = CreateType<SchemaType>>(data: T): Promise<AsDomainType<SchemaType>>;
169
+
170
+ /**
171
+ * Updates a document if it exists, otherwise creates it
172
+ *
173
+ * @param conditions - Filter criteria to find the document to update
174
+ * @param update - Data to update or create the document
175
+ * @param options - Optional MongoDB options for the operation
176
+ * @returns Promise resolving to the updated or created domain object
177
+ *
178
+ * @example
179
+ * // Upsert a user by email
180
+ * const user = await userRepository.upsert(
181
+ * { email: 'john@example.com' },
182
+ * { name: 'John Doe', role: 'admin' }
183
+ * );
184
+ */
185
+ upsert<T = UpdateType<SchemaType>>(
186
+ conditions: FilterQuery<SchemaType>,
187
+ update: T,
188
+ options?: Record<string, unknown>,
189
+ ): Promise<AsDomainType<SchemaType>>;
190
+
191
+ /**
192
+ * Updates a single document matching the criteria
193
+ *
194
+ * @param criteria - Filter criteria to find the document to update
195
+ * @param update - Data to update the document
196
+ * @param options - Optional MongoDB options for the operation
197
+ * @returns Promise resolving to the updated domain object
198
+ *
199
+ * @example
200
+ * // Update a user's role
201
+ * const updatedUser = await userRepository.update(
202
+ * { _id: userId },
203
+ * { role: 'admin' }
204
+ * );
205
+ */
206
+ update<T = UpdateType<SchemaType>>(
207
+ criteria: FilterQuery<SchemaType>,
208
+ update: T | UpdateQuery<SchemaType>,
209
+ options?: Record<string, unknown>,
210
+ ): Promise<AsDomainType<SchemaType>>;
211
+
212
+ /**
213
+ * Updates multiple documents matching the criteria
214
+ *
215
+ * @param criteria - Filter criteria to find documents to update
216
+ * @param update - Data to update the documents
217
+ * @param options - Optional MongoDB options for the operation
218
+ * @returns Promise resolving to an array of updated domain objects
219
+ *
220
+ * @example
221
+ * // Update all inactive users to active
222
+ * const updatedUsers = await userRepository.bulkUpdate(
223
+ * { active: false },
224
+ * { active: true }
225
+ * );
226
+ */
227
+ bulkUpdate<T = UpdateType<SchemaType>>(
228
+ criteria: FilterQuery<SchemaType>,
229
+ update: T | UpdateQuery<SchemaType>,
230
+ options?: Record<string, unknown>,
231
+ ): Promise<AsDomainType<SchemaType>[]>;
232
+
233
+ /**
234
+ * Deletes a document matching the criteria
235
+ *
236
+ * @param criteria - Filter criteria to find the document to delete
237
+ * @returns Promise resolving to boolean indicating success
238
+ *
239
+ * @example
240
+ * // Delete a user by ID
241
+ * const success = await userRepository.delete({ _id: userId });
242
+ */
243
+ delete(criteria: FilterQuery<SchemaType>): Promise<boolean>;
244
+
245
+ /**
246
+ * Retrieves multiple documents by their IDs
247
+ *
248
+ * @param ids - Array of document IDs to retrieve
249
+ * @param selectedFields - Optional space-separated string of fields to include
250
+ * @returns Promise resolving to an array of domain objects
251
+ *
252
+ * @example
253
+ * // Get multiple users by their IDs
254
+ * const users = await userRepository.bulkGet(['id1', 'id2', 'id3']);
255
+ */
256
+ bulkGet(ids: string[], selectedFields?: string): Promise<AsDomainType<SchemaType>[]>;
257
+
258
+ /**
259
+ * Creates multiple documents in a single operation
260
+ *
261
+ * @param data - Array of data for the new documents
262
+ * @returns Promise resolving to an array of created domain objects
263
+ *
264
+ * @example
265
+ * // Create multiple users at once
266
+ * const newUsers = await userRepository.bulkCreate([
267
+ * { name: 'John', email: 'john@example.com' },
268
+ * { name: 'Jane', email: 'jane@example.com' }
269
+ * ]);
270
+ */
271
+ bulkCreate<T = CreateType<SchemaType>>(data: T[]): Promise<AsDomainType<SchemaType>[]>;
272
+
273
+ /**
274
+ * Deletes multiple documents matching the criteria
275
+ *
276
+ * @param criteria - Filter criteria to find documents to delete
277
+ * @returns Promise resolving to the number of deleted documents
278
+ *
279
+ * @example
280
+ * // Delete all inactive users
281
+ * const deletedCount = await userRepository.bulkDelete({ active: false });
282
+ */
283
+ bulkDelete(criteria: FilterQuery<SchemaType>): Promise<number>;
284
+ }
@@ -0,0 +1,231 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ /**
3
+ * @file BaseService.ts
4
+ * @description Defines the IBaseService interface that provides a standardized set of service methods for business logic operations.
5
+ * This interface acts as an abstraction layer between controllers and repositories, implementing domain-specific logic.
6
+ * It offers methods for retrieving, creating, updating, and deleting domain entities, with support for filtering and pagination.
7
+ *
8
+ * The interface is generic, accepting a SchemaType parameter that represents the underlying data structure.
9
+ * Methods operate on and return domain objects (with 'id' instead of '_id') using the AsDomainType transformation.
10
+ *
11
+ * Key features:
12
+ * - Abstraction layer between controllers and repositories
13
+ * - Consistent API for business logic operations
14
+ * - Database-agnostic design
15
+ * - Domain-focused data manipulation
16
+ * - Support for single and bulk operations
17
+ * - Type-safe method signatures
18
+ *
19
+ * This service layer helps maintain separation of concerns and promotes code reusability across the application.
20
+ * Services typically use repositories for data access but add business rules, validation, and orchestration.
21
+ *
22
+ * @see IBaseMongoRepository - MongoDB data access layer used by services
23
+ * @see AsDomainType - Type transformation for domain objects
24
+ * @see GetAllArgs - Query options for retrieving collections
25
+ */
26
+
27
+ import { GetAllArgs, AsDomainType, CreateType, UpdateType, FilterCriteria } from './dbCommonTypes';
28
+
29
+ export interface IBaseService<SchemaType> {
30
+ /**
31
+ * Retrieves documents with pagination and total count
32
+ * Useful for implementing paginated UIs that need to know total pages
33
+ *
34
+ * @param options - Query options including filtering, sorting, pagination, and field selection
35
+ * @returns Promise resolving to object with data array and total count
36
+ *
37
+ * @example
38
+ * // Get paginated users with total count for UI pagination
39
+ * const { data, totalCount } = await userService.getAllWithCount({
40
+ * criteria: { role: 'user' },
41
+ * skip: 20,
42
+ * limit: 10,
43
+ * sort: { createdAt: -1 }
44
+ * });
45
+ */
46
+ getAllWithCount(options: GetAllArgs<SchemaType>): Promise<{
47
+ data: AsDomainType<SchemaType>[];
48
+ totalCount: number;
49
+ }>;
50
+
51
+ /**
52
+ * Counts documents matching the specified conditions
53
+ *
54
+ * @param conditions - Optional filter criteria to count specific documents
55
+ * @returns Promise resolving to the count of matching documents
56
+ *
57
+ * @example
58
+ * // Count all active users
59
+ * const activeUserCount = await userService.count({ active: true });
60
+ */
61
+ count(conditions?: FilterCriteria<SchemaType>): Promise<number>;
62
+
63
+ /**
64
+ * Retrieves a single document by ID or matching the specified conditions
65
+ *
66
+ * @param conditions - Document ID as string or filter criteria to find the document
67
+ * @returns Promise resolving to a domain object or null if not found
68
+ *
69
+ * @example
70
+ * // Get user by ID
71
+ * const user = await userService.get('60d21b4667d0d8992e610c85');
72
+ *
73
+ * // Get user by email
74
+ * const user = await userService.get({ email: 'user@example.com' });
75
+ */
76
+ get(conditions: string | FilterCriteria<SchemaType>): Promise<AsDomainType<SchemaType> | null>;
77
+
78
+ /**
79
+ * Retrieves a single document by name field
80
+ * Commonly used for entities that have a unique name identifier
81
+ *
82
+ * @param name - Name value to search for
83
+ * @returns Promise resolving to a domain object or null if not found
84
+ *
85
+ * @example
86
+ * // Get product by name
87
+ * const product = await productService.getByName('Premium Subscription');
88
+ */
89
+ getByName(name: string): Promise<AsDomainType<SchemaType> | null>;
90
+
91
+ /**
92
+ * Retrieves documents matching the specified options
93
+ *
94
+ * @param options - Query options including filtering, sorting, pagination, and field selection
95
+ * @returns Promise resolving to an array of domain objects
96
+ *
97
+ * @example
98
+ * // Get recently created users with pagination
99
+ * const users = await userService.getAll({
100
+ * criteria: { active: true },
101
+ * sort: { createdAt: -1 },
102
+ * skip: 0,
103
+ * limit: 10
104
+ * });
105
+ */
106
+ getAll(options: GetAllArgs<SchemaType>): Promise<AsDomainType<SchemaType>[]>;
107
+
108
+ /**
109
+ * Retrieves multiple documents by their IDs
110
+ *
111
+ * @param ids - Array of document IDs to retrieve
112
+ * @returns Promise resolving to an array of domain objects
113
+ *
114
+ * @example
115
+ * // Get multiple users by their IDs
116
+ * const users = await userService.getByIds(['id1', 'id2', 'id3']);
117
+ */
118
+ getByIds(ids: string[]): Promise<AsDomainType<SchemaType>[]>;
119
+
120
+ /**
121
+ * Creates a new document
122
+ *
123
+ * @param data - Data for the new document
124
+ * @returns Promise resolving to the created domain object
125
+ *
126
+ * @example
127
+ * // Create a new user
128
+ * const newUser = await userService.create({
129
+ * name: 'John Doe',
130
+ * email: 'john@example.com',
131
+ * role: 'user'
132
+ * });
133
+ */
134
+ create<T = CreateType<SchemaType>>(data: T): Promise<AsDomainType<SchemaType>>;
135
+
136
+ /**
137
+ * Creates multiple documents in a single operation
138
+ *
139
+ * @param data - Array of data for the new documents
140
+ * @returns Promise resolving to an array of created domain objects
141
+ *
142
+ * @example
143
+ * // Create multiple users at once
144
+ * const newUsers = await userService.bulkCreate([
145
+ * { name: 'John', email: 'john@example.com' },
146
+ * { name: 'Jane', email: 'jane@example.com' }
147
+ * ]);
148
+ */
149
+ bulkCreate<T = CreateType<SchemaType>>(data: T[]): Promise<AsDomainType<SchemaType>[]>;
150
+
151
+ /**
152
+ * Updates a document by ID
153
+ *
154
+ * @param id - ID of the document to update
155
+ * @param data - Data to update the document
156
+ * @param overwrite - Whether to completely replace the document (true) or merge with existing (false)
157
+ * @returns Promise resolving to the updated domain object
158
+ *
159
+ * @example
160
+ * // Update a user's role
161
+ * const updatedUser = await userService.update(
162
+ * 'user123',
163
+ * { role: 'admin', active: true }
164
+ * );
165
+ *
166
+ * // Replace a user document entirely
167
+ * const replacedUser = await userService.update(
168
+ * 'user123',
169
+ * { name: 'New Name', email: 'new@example.com', role: 'user' },
170
+ * true
171
+ * );
172
+ */
173
+ update<T = UpdateType<SchemaType>>(id: string, data: T, overwrite?: boolean): Promise<AsDomainType<SchemaType>>;
174
+
175
+ /**
176
+ * Creates a new document or updates it if ID is provided
177
+ * Useful for forms that handle both creation and updates
178
+ *
179
+ * @param data - Data for the new or updated document, optionally including an ID
180
+ * @param overwrite - Whether to completely replace the document (true) or merge with existing (false)
181
+ * @returns Promise resolving to the created or updated domain object
182
+ *
183
+ * @example
184
+ * // Create a new product
185
+ * const newProduct = await productService.insert({
186
+ * name: 'New Product',
187
+ * price: 99.99
188
+ * });
189
+ *
190
+ * // Update an existing product
191
+ * const updatedProduct = await productService.insert({
192
+ * id: 'product123',
193
+ * name: 'Updated Product',
194
+ * price: 129.99
195
+ * });
196
+ */
197
+ insert<T = CreateType<SchemaType>>(
198
+ data: T & { id?: string },
199
+ overwrite?: boolean,
200
+ ): Promise<AsDomainType<SchemaType>>;
201
+
202
+ /**
203
+ * Deletes a document by ID or matching criteria
204
+ *
205
+ * @param id - Document ID as string or filter criteria to find the document to delete
206
+ * @returns Promise resolving to boolean indicating success
207
+ *
208
+ * @example
209
+ * // Delete a user by ID
210
+ * const success = await userService.delete('user123');
211
+ *
212
+ * // Delete a user by email
213
+ * const success = await userService.delete({ email: 'user@example.com' });
214
+ */
215
+ delete(id: string | FilterCriteria<SchemaType>): Promise<boolean>;
216
+
217
+ /**
218
+ * Deletes multiple documents matching the criteria
219
+ *
220
+ * @param criteria - Filter criteria to find documents to delete
221
+ * @returns Promise resolving to the number of deleted documents
222
+ *
223
+ * @example
224
+ * // Delete all inactive users
225
+ * const deletedCount = await userService.bulkDelete({ active: false });
226
+ *
227
+ * // Delete users with a specific role
228
+ * const deletedCount = await userService.bulkDelete({ role: 'guest' });
229
+ */
230
+ bulkDelete(criteria: FilterCriteria<SchemaType>): Promise<number>;
231
+ }