@classytic/mongokit 2.0.0 → 3.0.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.
- package/README.md +221 -7
- package/dist/actions/index.d.ts +3 -0
- package/dist/actions/index.js +473 -0
- package/dist/actions/index.js.map +1 -0
- package/dist/index-CgOJ2pqz.d.ts +337 -0
- package/dist/index.d.ts +239 -0
- package/dist/index.js +2108 -0
- package/dist/index.js.map +1 -0
- package/dist/memory-cache-DG2oSSbx.d.ts +142 -0
- package/dist/pagination/PaginationEngine.d.ts +117 -0
- package/dist/pagination/PaginationEngine.js +369 -0
- package/dist/pagination/PaginationEngine.js.map +1 -0
- package/dist/plugins/index.d.ts +275 -0
- package/dist/plugins/index.js +857 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/types-Nxhmi1aI.d.ts +510 -0
- package/dist/utils/index.d.ts +189 -0
- package/dist/utils/index.js +643 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +38 -21
- package/src/Repository.js +0 -296
- package/src/actions/aggregate.js +0 -266
- package/src/actions/create.js +0 -59
- package/src/actions/delete.js +0 -88
- package/src/actions/index.js +0 -11
- package/src/actions/read.js +0 -188
- package/src/actions/update.js +0 -176
- package/src/hooks/lifecycle.js +0 -146
- package/src/index.js +0 -71
- package/src/pagination/PaginationEngine.js +0 -348
- package/src/pagination/utils/cursor.js +0 -119
- package/src/pagination/utils/filter.js +0 -42
- package/src/pagination/utils/limits.js +0 -82
- package/src/pagination/utils/sort.js +0 -101
- package/src/plugins/aggregate-helpers.plugin.js +0 -71
- package/src/plugins/audit-log.plugin.js +0 -60
- package/src/plugins/batch-operations.plugin.js +0 -66
- package/src/plugins/field-filter.plugin.js +0 -27
- package/src/plugins/index.js +0 -19
- package/src/plugins/method-registry.plugin.js +0 -140
- package/src/plugins/mongo-operations.plugin.js +0 -317
- package/src/plugins/soft-delete.plugin.js +0 -46
- package/src/plugins/subdocument.plugin.js +0 -66
- package/src/plugins/timestamp.plugin.js +0 -19
- package/src/plugins/validation-chain.plugin.js +0 -145
- package/src/types.d.ts +0 -87
- package/src/utils/error.js +0 -12
- package/src/utils/field-selection.js +0 -156
- package/src/utils/index.js +0 -12
- package/types/Repository.d.ts +0 -95
- package/types/Repository.d.ts.map +0 -1
- package/types/actions/aggregate.d.ts +0 -112
- package/types/actions/aggregate.d.ts.map +0 -1
- package/types/actions/create.d.ts +0 -21
- package/types/actions/create.d.ts.map +0 -1
- package/types/actions/delete.d.ts +0 -37
- package/types/actions/delete.d.ts.map +0 -1
- package/types/actions/index.d.ts +0 -6
- package/types/actions/index.d.ts.map +0 -1
- package/types/actions/read.d.ts +0 -135
- package/types/actions/read.d.ts.map +0 -1
- package/types/actions/update.d.ts +0 -58
- package/types/actions/update.d.ts.map +0 -1
- package/types/hooks/lifecycle.d.ts +0 -44
- package/types/hooks/lifecycle.d.ts.map +0 -1
- package/types/index.d.ts +0 -25
- package/types/index.d.ts.map +0 -1
- package/types/pagination/PaginationEngine.d.ts +0 -386
- package/types/pagination/PaginationEngine.d.ts.map +0 -1
- package/types/pagination/utils/cursor.d.ts +0 -40
- package/types/pagination/utils/cursor.d.ts.map +0 -1
- package/types/pagination/utils/filter.d.ts +0 -28
- package/types/pagination/utils/filter.d.ts.map +0 -1
- package/types/pagination/utils/limits.d.ts +0 -64
- package/types/pagination/utils/limits.d.ts.map +0 -1
- package/types/pagination/utils/sort.d.ts +0 -41
- package/types/pagination/utils/sort.d.ts.map +0 -1
- package/types/plugins/aggregate-helpers.plugin.d.ts +0 -6
- package/types/plugins/aggregate-helpers.plugin.d.ts.map +0 -1
- package/types/plugins/audit-log.plugin.d.ts +0 -6
- package/types/plugins/audit-log.plugin.d.ts.map +0 -1
- package/types/plugins/batch-operations.plugin.d.ts +0 -6
- package/types/plugins/batch-operations.plugin.d.ts.map +0 -1
- package/types/plugins/field-filter.plugin.d.ts +0 -6
- package/types/plugins/field-filter.plugin.d.ts.map +0 -1
- package/types/plugins/index.d.ts +0 -11
- package/types/plugins/index.d.ts.map +0 -1
- package/types/plugins/method-registry.plugin.d.ts +0 -3
- package/types/plugins/method-registry.plugin.d.ts.map +0 -1
- package/types/plugins/mongo-operations.plugin.d.ts +0 -4
- package/types/plugins/mongo-operations.plugin.d.ts.map +0 -1
- package/types/plugins/soft-delete.plugin.d.ts +0 -6
- package/types/plugins/soft-delete.plugin.d.ts.map +0 -1
- package/types/plugins/subdocument.plugin.d.ts +0 -6
- package/types/plugins/subdocument.plugin.d.ts.map +0 -1
- package/types/plugins/timestamp.plugin.d.ts +0 -6
- package/types/plugins/timestamp.plugin.d.ts.map +0 -1
- package/types/plugins/validation-chain.plugin.d.ts +0 -31
- package/types/plugins/validation-chain.plugin.d.ts.map +0 -1
- package/types/utils/error.d.ts +0 -11
- package/types/utils/error.d.ts.map +0 -1
- package/types/utils/field-selection.d.ts +0 -9
- package/types/utils/field-selection.d.ts.map +0 -1
- package/types/utils/index.d.ts +0 -2
- package/types/utils/index.d.ts.map +0 -1
package/src/actions/aggregate.js
DELETED
|
@@ -1,266 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Aggregate Actions
|
|
3
|
-
* MongoDB aggregation pipeline operations
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* @typedef {import('mongoose').Model} Model
|
|
8
|
-
* @typedef {import('mongoose').ClientSession} ClientSession
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Execute aggregation pipeline
|
|
13
|
-
*
|
|
14
|
-
* @param {Model} Model - Mongoose model
|
|
15
|
-
* @param {any[]} pipeline - Aggregation pipeline stages
|
|
16
|
-
* @param {Object} [options={}] - Aggregation options
|
|
17
|
-
* @param {ClientSession} [options.session] - MongoDB session
|
|
18
|
-
* @returns {Promise<any[]>} Aggregation results
|
|
19
|
-
*/
|
|
20
|
-
export async function aggregate(Model, pipeline, options = {}) {
|
|
21
|
-
const aggregation = Model.aggregate(pipeline);
|
|
22
|
-
|
|
23
|
-
if (options.session) {
|
|
24
|
-
aggregation.session(options.session);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return aggregation.exec();
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Aggregate with pagination using native MongoDB $facet
|
|
32
|
-
* WARNING: $facet results must be <16MB. For larger results (limit >1000),
|
|
33
|
-
* consider using Repository.aggregatePaginate() or splitting into separate queries.
|
|
34
|
-
*
|
|
35
|
-
* @param {Model} Model - Mongoose model
|
|
36
|
-
* @param {any[]} pipeline - Aggregation pipeline stages (before pagination)
|
|
37
|
-
* @param {Object} [options={}] - Pagination options
|
|
38
|
-
* @param {number} [options.page=1] - Page number (1-indexed)
|
|
39
|
-
* @param {number} [options.limit=10] - Documents per page
|
|
40
|
-
* @param {ClientSession} [options.session] - MongoDB session
|
|
41
|
-
* @returns {Promise<{docs: any[], total: number, page: number, limit: number, pages: number, hasNext: boolean, hasPrev: boolean}>} Paginated results
|
|
42
|
-
*
|
|
43
|
-
* @example
|
|
44
|
-
* const result = await aggregatePaginate(UserModel, [
|
|
45
|
-
* { $match: { status: 'active' } },
|
|
46
|
-
* { $group: { _id: '$category', count: { $sum: 1 } } }
|
|
47
|
-
* ], { page: 1, limit: 20 });
|
|
48
|
-
*/
|
|
49
|
-
export async function aggregatePaginate(Model, pipeline, options = {}) {
|
|
50
|
-
const page = parseInt(String(options.page || 1), 10);
|
|
51
|
-
const limit = parseInt(String(options.limit || 10), 10);
|
|
52
|
-
const skip = (page - 1) * limit;
|
|
53
|
-
|
|
54
|
-
// 16MB MongoDB document size limit safety check
|
|
55
|
-
const SAFE_LIMIT = 1000;
|
|
56
|
-
if (limit > SAFE_LIMIT) {
|
|
57
|
-
console.warn(
|
|
58
|
-
`[mongokit] Large aggregation limit (${limit}). $facet results must be <16MB. ` +
|
|
59
|
-
`Consider using Repository.aggregatePaginate() for safer handling of large datasets.`
|
|
60
|
-
);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const facetPipeline = [
|
|
64
|
-
...pipeline,
|
|
65
|
-
{
|
|
66
|
-
$facet: {
|
|
67
|
-
docs: [
|
|
68
|
-
{ $skip: skip },
|
|
69
|
-
{ $limit: limit }
|
|
70
|
-
],
|
|
71
|
-
total: [
|
|
72
|
-
{ $count: 'count' }
|
|
73
|
-
]
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
];
|
|
77
|
-
|
|
78
|
-
const aggregation = Model.aggregate(facetPipeline);
|
|
79
|
-
if (options.session) {
|
|
80
|
-
aggregation.session(options.session);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const [result] = await aggregation.exec();
|
|
84
|
-
const docs = result.docs || [];
|
|
85
|
-
const total = result.total[0]?.count || 0;
|
|
86
|
-
const pages = Math.ceil(total / limit);
|
|
87
|
-
|
|
88
|
-
return {
|
|
89
|
-
docs,
|
|
90
|
-
total,
|
|
91
|
-
page,
|
|
92
|
-
limit,
|
|
93
|
-
pages,
|
|
94
|
-
hasNext: page < pages,
|
|
95
|
-
hasPrev: page > 1
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Group documents by field value
|
|
101
|
-
*
|
|
102
|
-
* @param {Model} Model - Mongoose model
|
|
103
|
-
* @param {string} field - Field name to group by
|
|
104
|
-
* @param {Object} [options={}] - Options
|
|
105
|
-
* @param {number} [options.limit] - Maximum groups to return
|
|
106
|
-
* @param {ClientSession} [options.session] - MongoDB session
|
|
107
|
-
* @returns {Promise<Array<{_id: any, count: number}>>} Grouped results
|
|
108
|
-
*/
|
|
109
|
-
export async function groupBy(Model, field, options = {}) {
|
|
110
|
-
const pipeline = [
|
|
111
|
-
{ $group: { _id: `$${field}`, count: { $sum: 1 } } },
|
|
112
|
-
{ $sort: { count: -1 } },
|
|
113
|
-
];
|
|
114
|
-
|
|
115
|
-
if (options.limit) {
|
|
116
|
-
pipeline.push(/** @type {any} */({ $limit: options.limit }));
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
return aggregate(Model, pipeline, options);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Count by field values
|
|
124
|
-
*/
|
|
125
|
-
export async function countBy(Model, field, query = {}, options = {}) {
|
|
126
|
-
const pipeline = [];
|
|
127
|
-
|
|
128
|
-
if (Object.keys(query).length > 0) {
|
|
129
|
-
pipeline.push({ $match: query });
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
pipeline.push(
|
|
133
|
-
{ $group: { _id: `$${field}`, count: { $sum: 1 } } },
|
|
134
|
-
{ $sort: { count: -1 } }
|
|
135
|
-
);
|
|
136
|
-
|
|
137
|
-
return aggregate(Model, pipeline, options);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Lookup (join) with another collection
|
|
142
|
-
*/
|
|
143
|
-
export async function lookup(Model, {
|
|
144
|
-
from,
|
|
145
|
-
localField,
|
|
146
|
-
foreignField,
|
|
147
|
-
as,
|
|
148
|
-
pipeline = [],
|
|
149
|
-
query = {},
|
|
150
|
-
options = {}
|
|
151
|
-
}) {
|
|
152
|
-
const aggPipeline = [];
|
|
153
|
-
|
|
154
|
-
if (Object.keys(query).length > 0) {
|
|
155
|
-
aggPipeline.push({ $match: query });
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
aggPipeline.push({
|
|
159
|
-
$lookup: {
|
|
160
|
-
from,
|
|
161
|
-
localField,
|
|
162
|
-
foreignField,
|
|
163
|
-
as,
|
|
164
|
-
...(pipeline.length > 0 ? { pipeline } : {}),
|
|
165
|
-
},
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
return aggregate(Model, aggPipeline, options);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Unwind array field
|
|
173
|
-
*/
|
|
174
|
-
export async function unwind(Model, field, options = {}) {
|
|
175
|
-
const pipeline = [
|
|
176
|
-
{
|
|
177
|
-
$unwind: {
|
|
178
|
-
path: `$${field}`,
|
|
179
|
-
preserveNullAndEmptyArrays: options.preserveEmpty !== false,
|
|
180
|
-
},
|
|
181
|
-
},
|
|
182
|
-
];
|
|
183
|
-
|
|
184
|
-
return aggregate(Model, pipeline, options);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Facet search (multiple aggregations in one query)
|
|
189
|
-
*/
|
|
190
|
-
export async function facet(Model, facets, options = {}) {
|
|
191
|
-
const pipeline = [{ $facet: facets }];
|
|
192
|
-
|
|
193
|
-
return aggregate(Model, pipeline, options);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Get distinct values
|
|
198
|
-
*/
|
|
199
|
-
export async function distinct(Model, field, query = {}, options = {}) {
|
|
200
|
-
return Model.distinct(field, query).session(options.session);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Calculate sum
|
|
205
|
-
*/
|
|
206
|
-
export async function sum(Model, field, query = {}, options = {}) {
|
|
207
|
-
const pipeline = [];
|
|
208
|
-
|
|
209
|
-
if (Object.keys(query).length > 0) {
|
|
210
|
-
pipeline.push({ $match: query });
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
pipeline.push({
|
|
214
|
-
$group: {
|
|
215
|
-
_id: null,
|
|
216
|
-
total: { $sum: `$${field}` },
|
|
217
|
-
},
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
const result = await aggregate(Model, pipeline, options);
|
|
221
|
-
return result[0]?.total || 0;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* Calculate average
|
|
226
|
-
*/
|
|
227
|
-
export async function average(Model, field, query = {}, options = {}) {
|
|
228
|
-
const pipeline = [];
|
|
229
|
-
|
|
230
|
-
if (Object.keys(query).length > 0) {
|
|
231
|
-
pipeline.push({ $match: query });
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
pipeline.push({
|
|
235
|
-
$group: {
|
|
236
|
-
_id: null,
|
|
237
|
-
average: { $avg: `$${field}` },
|
|
238
|
-
},
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
const result = await aggregate(Model, pipeline, options);
|
|
242
|
-
return result[0]?.average || 0;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* Min/Max
|
|
247
|
-
*/
|
|
248
|
-
export async function minMax(Model, field, query = {}, options = {}) {
|
|
249
|
-
const pipeline = [];
|
|
250
|
-
|
|
251
|
-
if (Object.keys(query).length > 0) {
|
|
252
|
-
pipeline.push({ $match: query });
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
pipeline.push({
|
|
256
|
-
$group: {
|
|
257
|
-
_id: null,
|
|
258
|
-
min: { $min: `$${field}` },
|
|
259
|
-
max: { $max: `$${field}` },
|
|
260
|
-
},
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
const result = await aggregate(Model, pipeline, options);
|
|
264
|
-
return result[0] || { min: null, max: null };
|
|
265
|
-
}
|
|
266
|
-
|
package/src/actions/create.js
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Create Actions
|
|
3
|
-
* Pure functions for document creation
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Create single document
|
|
8
|
-
*/
|
|
9
|
-
export async function create(Model, data, options = {}) {
|
|
10
|
-
const document = new Model(data);
|
|
11
|
-
await document.save({ session: options.session });
|
|
12
|
-
return document;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Create multiple documents
|
|
17
|
-
*/
|
|
18
|
-
export async function createMany(Model, dataArray, options = {}) {
|
|
19
|
-
return Model.insertMany(dataArray, {
|
|
20
|
-
session: options.session,
|
|
21
|
-
ordered: options.ordered !== false,
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Create with defaults (useful for initialization)
|
|
27
|
-
*/
|
|
28
|
-
export async function createDefault(Model, overrides = {}, options = {}) {
|
|
29
|
-
const defaults = {};
|
|
30
|
-
|
|
31
|
-
// Extract defaults from schema
|
|
32
|
-
Model.schema.eachPath((path, schemaType) => {
|
|
33
|
-
if (schemaType.options.default !== undefined && path !== '_id') {
|
|
34
|
-
defaults[path] = typeof schemaType.options.default === 'function'
|
|
35
|
-
? schemaType.options.default()
|
|
36
|
-
: schemaType.options.default;
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
return create(Model, { ...defaults, ...overrides }, options);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Upsert (create or update)
|
|
45
|
-
*/
|
|
46
|
-
export async function upsert(Model, query, data, options = {}) {
|
|
47
|
-
return Model.findOneAndUpdate(
|
|
48
|
-
query,
|
|
49
|
-
{ $setOnInsert: data },
|
|
50
|
-
{
|
|
51
|
-
upsert: true,
|
|
52
|
-
new: true,
|
|
53
|
-
runValidators: true,
|
|
54
|
-
session: options.session,
|
|
55
|
-
...(options.updatePipeline !== undefined ? { updatePipeline: options.updatePipeline } : {}),
|
|
56
|
-
}
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
|
package/src/actions/delete.js
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Delete Actions
|
|
3
|
-
* Pure functions for document deletion
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { createError } from '../utils/error.js';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Delete by ID
|
|
10
|
-
*/
|
|
11
|
-
export async function deleteById(Model, id, options = {}) {
|
|
12
|
-
const document = await Model.findByIdAndDelete(id).session(options.session);
|
|
13
|
-
|
|
14
|
-
if (!document) {
|
|
15
|
-
throw createError(404, 'Document not found');
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
return { success: true, message: 'Deleted successfully' };
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Delete many documents
|
|
23
|
-
*/
|
|
24
|
-
export async function deleteMany(Model, query, options = {}) {
|
|
25
|
-
const result = await Model.deleteMany(query).session(options.session);
|
|
26
|
-
|
|
27
|
-
return {
|
|
28
|
-
success: true,
|
|
29
|
-
count: result.deletedCount,
|
|
30
|
-
message: 'Deleted successfully',
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Delete by query
|
|
36
|
-
*/
|
|
37
|
-
export async function deleteByQuery(Model, query, options = {}) {
|
|
38
|
-
const document = await Model.findOneAndDelete(query).session(options.session);
|
|
39
|
-
|
|
40
|
-
if (!document && options.throwOnNotFound !== false) {
|
|
41
|
-
throw createError(404, 'Document not found');
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return { success: true, message: 'Deleted successfully' };
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Soft delete (set deleted flag)
|
|
49
|
-
*/
|
|
50
|
-
export async function softDelete(Model, id, options = {}) {
|
|
51
|
-
const document = await Model.findByIdAndUpdate(
|
|
52
|
-
id,
|
|
53
|
-
{
|
|
54
|
-
deleted: true,
|
|
55
|
-
deletedAt: new Date(),
|
|
56
|
-
deletedBy: options.userId,
|
|
57
|
-
},
|
|
58
|
-
{ new: true, session: options.session }
|
|
59
|
-
);
|
|
60
|
-
|
|
61
|
-
if (!document) {
|
|
62
|
-
throw createError(404, 'Document not found');
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return { success: true, message: 'Soft deleted successfully' };
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Restore soft deleted document
|
|
70
|
-
*/
|
|
71
|
-
export async function restore(Model, id, options = {}) {
|
|
72
|
-
const document = await Model.findByIdAndUpdate(
|
|
73
|
-
id,
|
|
74
|
-
{
|
|
75
|
-
deleted: false,
|
|
76
|
-
deletedAt: null,
|
|
77
|
-
deletedBy: null,
|
|
78
|
-
},
|
|
79
|
-
{ new: true, session: options.session }
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
if (!document) {
|
|
83
|
-
throw createError(404, 'Document not found');
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return { success: true, message: 'Restored successfully' };
|
|
87
|
-
}
|
|
88
|
-
|
package/src/actions/index.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Repository Actions
|
|
3
|
-
* Modular, composable data access operations
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export * as create from './create.js';
|
|
7
|
-
export * as read from './read.js';
|
|
8
|
-
export * as update from './update.js';
|
|
9
|
-
export * as deleteActions from './delete.js';
|
|
10
|
-
export * as aggregate from './aggregate.js';
|
|
11
|
-
|
package/src/actions/read.js
DELETED
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Read Actions
|
|
3
|
-
* Pure functions for document retrieval
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { createError } from '../utils/error.js';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* @typedef {import('mongoose').Model} Model
|
|
10
|
-
* @typedef {import('mongoose').PopulateOptions} PopulateOptions
|
|
11
|
-
* @typedef {import('mongoose').ClientSession} ClientSession
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Get document by ID
|
|
16
|
-
*
|
|
17
|
-
* @param {Model} Model - Mongoose model
|
|
18
|
-
* @param {string} id - Document ID
|
|
19
|
-
* @param {Object} [options={}] - Query options
|
|
20
|
-
* @param {string|string[]} [options.select] - Fields to select
|
|
21
|
-
* @param {string|string[]|PopulateOptions|PopulateOptions[]} [options.populate] - Fields to populate
|
|
22
|
-
* @param {boolean} [options.lean] - Return plain JavaScript object
|
|
23
|
-
* @param {ClientSession} [options.session] - MongoDB session
|
|
24
|
-
* @param {boolean} [options.throwOnNotFound=true] - Throw error if not found
|
|
25
|
-
* @returns {Promise<any>} Document or null
|
|
26
|
-
* @throws {Error} If document not found and throwOnNotFound is true
|
|
27
|
-
*/
|
|
28
|
-
export async function getById(Model, id, options = {}) {
|
|
29
|
-
const query = Model.findById(id);
|
|
30
|
-
|
|
31
|
-
if (options.select) query.select(options.select);
|
|
32
|
-
if (options.populate) query.populate(parsePopulate(options.populate));
|
|
33
|
-
if (options.lean) query.lean();
|
|
34
|
-
if (options.session) query.session(options.session);
|
|
35
|
-
|
|
36
|
-
const document = await query.exec();
|
|
37
|
-
if (!document && options.throwOnNotFound !== false) {
|
|
38
|
-
throw createError(404, 'Document not found');
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return document;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Get document by query
|
|
46
|
-
*
|
|
47
|
-
* @param {Model} Model - Mongoose model
|
|
48
|
-
* @param {Record<string, any>} query - MongoDB query
|
|
49
|
-
* @param {Object} [options={}] - Query options
|
|
50
|
-
* @param {string|string[]} [options.select] - Fields to select
|
|
51
|
-
* @param {string|string[]|PopulateOptions|PopulateOptions[]} [options.populate] - Fields to populate
|
|
52
|
-
* @param {boolean} [options.lean] - Return plain JavaScript object
|
|
53
|
-
* @param {ClientSession} [options.session] - MongoDB session
|
|
54
|
-
* @param {boolean} [options.throwOnNotFound=true] - Throw error if not found
|
|
55
|
-
* @returns {Promise<any>} Document or null
|
|
56
|
-
* @throws {Error} If document not found and throwOnNotFound is true
|
|
57
|
-
*/
|
|
58
|
-
export async function getByQuery(Model, query, options = {}) {
|
|
59
|
-
const mongoQuery = Model.findOne(query);
|
|
60
|
-
|
|
61
|
-
if (options.select) mongoQuery.select(options.select);
|
|
62
|
-
if (options.populate) mongoQuery.populate(parsePopulate(options.populate));
|
|
63
|
-
if (options.lean) mongoQuery.lean();
|
|
64
|
-
if (options.session) mongoQuery.session(options.session);
|
|
65
|
-
|
|
66
|
-
const document = await mongoQuery.exec();
|
|
67
|
-
if (!document && options.throwOnNotFound !== false) {
|
|
68
|
-
throw createError(404, 'Document not found');
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return document;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Get document by query without throwing (returns null if not found)
|
|
76
|
-
*
|
|
77
|
-
* @param {Model} Model - Mongoose model
|
|
78
|
-
* @param {Record<string, any>} query - MongoDB query
|
|
79
|
-
* @param {Object} [options={}] - Query options
|
|
80
|
-
* @param {string|string[]} [options.select] - Fields to select
|
|
81
|
-
* @param {string|string[]|PopulateOptions|PopulateOptions[]} [options.populate] - Fields to populate
|
|
82
|
-
* @param {boolean} [options.lean] - Return plain JavaScript object
|
|
83
|
-
* @param {ClientSession} [options.session] - MongoDB session
|
|
84
|
-
* @returns {Promise<any|null>} Document or null
|
|
85
|
-
*/
|
|
86
|
-
export async function tryGetByQuery(Model, query, options = {}) {
|
|
87
|
-
return getByQuery(Model, query, { ...options, throwOnNotFound: false });
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Get all documents (basic query without pagination)
|
|
92
|
-
* For pagination, use Repository.paginate() or Repository.stream()
|
|
93
|
-
*
|
|
94
|
-
* @param {Model} Model - Mongoose model
|
|
95
|
-
* @param {Record<string, any>} [query={}] - MongoDB query
|
|
96
|
-
* @param {Object} [options={}] - Query options
|
|
97
|
-
* @param {string|string[]} [options.select] - Fields to select
|
|
98
|
-
* @param {string|string[]|PopulateOptions|PopulateOptions[]} [options.populate] - Fields to populate
|
|
99
|
-
* @param {Record<string, 1|-1>} [options.sort] - Sort specification
|
|
100
|
-
* @param {number} [options.limit] - Maximum documents to return
|
|
101
|
-
* @param {number} [options.skip] - Documents to skip
|
|
102
|
-
* @param {boolean} [options.lean=true] - Return plain JavaScript objects
|
|
103
|
-
* @param {ClientSession} [options.session] - MongoDB session
|
|
104
|
-
* @returns {Promise<any[]>} Array of documents
|
|
105
|
-
*/
|
|
106
|
-
export async function getAll(Model, query = {}, options = {}) {
|
|
107
|
-
let mongoQuery = Model.find(query);
|
|
108
|
-
|
|
109
|
-
if (options.select) mongoQuery = mongoQuery.select(options.select);
|
|
110
|
-
if (options.populate) mongoQuery = mongoQuery.populate(parsePopulate(options.populate));
|
|
111
|
-
if (options.sort) mongoQuery = mongoQuery.sort(options.sort);
|
|
112
|
-
if (options.limit) mongoQuery = mongoQuery.limit(options.limit);
|
|
113
|
-
if (options.skip) mongoQuery = mongoQuery.skip(options.skip);
|
|
114
|
-
|
|
115
|
-
mongoQuery = mongoQuery.lean(options.lean !== false);
|
|
116
|
-
if (options.session) mongoQuery = mongoQuery.session(options.session);
|
|
117
|
-
|
|
118
|
-
return mongoQuery.exec();
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Get or create document (upsert)
|
|
123
|
-
*
|
|
124
|
-
* @param {Model} Model - Mongoose model
|
|
125
|
-
* @param {Record<string, any>} query - Query to find document
|
|
126
|
-
* @param {Record<string, any>} createData - Data to insert if not found
|
|
127
|
-
* @param {Object} [options={}] - Query options
|
|
128
|
-
* @param {ClientSession} [options.session] - MongoDB session
|
|
129
|
-
* @param {boolean} [options.updatePipeline] - Use update pipeline
|
|
130
|
-
* @returns {Promise<any>} Created or found document
|
|
131
|
-
*/
|
|
132
|
-
export async function getOrCreate(Model, query, createData, options = {}) {
|
|
133
|
-
return Model.findOneAndUpdate(
|
|
134
|
-
query,
|
|
135
|
-
{ $setOnInsert: createData },
|
|
136
|
-
{
|
|
137
|
-
upsert: true,
|
|
138
|
-
new: true,
|
|
139
|
-
runValidators: true,
|
|
140
|
-
session: options.session,
|
|
141
|
-
...(options.updatePipeline !== undefined ? { updatePipeline: options.updatePipeline } : {}),
|
|
142
|
-
}
|
|
143
|
-
);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Count documents matching query
|
|
148
|
-
*
|
|
149
|
-
* @param {Model} Model - Mongoose model
|
|
150
|
-
* @param {Record<string, any>} [query={}] - MongoDB query
|
|
151
|
-
* @param {Object} [options={}] - Query options
|
|
152
|
-
* @param {ClientSession} [options.session] - MongoDB session
|
|
153
|
-
* @returns {Promise<number>} Document count
|
|
154
|
-
*/
|
|
155
|
-
export async function count(Model, query = {}, options = {}) {
|
|
156
|
-
return Model.countDocuments(query).session(options.session);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Check if document exists
|
|
161
|
-
*
|
|
162
|
-
* @param {Model} Model - Mongoose model
|
|
163
|
-
* @param {Record<string, any>} query - MongoDB query
|
|
164
|
-
* @param {Object} [options={}] - Query options
|
|
165
|
-
* @param {ClientSession} [options.session] - MongoDB session
|
|
166
|
-
* @returns {Promise<{_id: any} | null>} Document ID if exists, null otherwise
|
|
167
|
-
*/
|
|
168
|
-
export async function exists(Model, query, options = {}) {
|
|
169
|
-
return Model.exists(query).session(options.session);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Parses populate parameter into Mongoose-compatible format
|
|
174
|
-
*
|
|
175
|
-
* @param {string|string[]|PopulateOptions|PopulateOptions[]} populate - Populate specification
|
|
176
|
-
* @returns {(string|PopulateOptions)[]} Normalized populate array
|
|
177
|
-
*/
|
|
178
|
-
function parsePopulate(populate) {
|
|
179
|
-
if (!populate) return [];
|
|
180
|
-
if (typeof populate === 'string') {
|
|
181
|
-
return populate.split(',').map(/** @param {string} p */ (p) => p.trim());
|
|
182
|
-
}
|
|
183
|
-
if (Array.isArray(populate)) {
|
|
184
|
-
return populate.map(/** @param {string|PopulateOptions} p */ (p) => typeof p === 'string' ? p.trim() : p);
|
|
185
|
-
}
|
|
186
|
-
return [populate];
|
|
187
|
-
}
|
|
188
|
-
|