@classytic/mongokit 1.0.1 → 2.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 +564 -157
- package/package.json +20 -12
- package/src/Repository.js +296 -225
- package/src/actions/aggregate.js +266 -191
- package/src/actions/create.js +59 -58
- package/src/actions/delete.js +88 -88
- package/src/actions/index.js +11 -11
- package/src/actions/read.js +188 -155
- package/src/actions/update.js +176 -172
- package/src/hooks/lifecycle.js +146 -146
- package/src/index.js +71 -60
- package/src/pagination/PaginationEngine.js +348 -0
- package/src/pagination/utils/cursor.js +119 -0
- package/src/pagination/utils/filter.js +42 -0
- package/src/pagination/utils/limits.js +82 -0
- package/src/pagination/utils/sort.js +101 -0
- package/src/plugins/aggregate-helpers.plugin.js +71 -71
- package/src/plugins/audit-log.plugin.js +60 -60
- package/src/plugins/batch-operations.plugin.js +66 -66
- package/src/plugins/field-filter.plugin.js +27 -27
- package/src/plugins/index.js +19 -19
- package/src/plugins/method-registry.plugin.js +140 -140
- package/src/plugins/mongo-operations.plugin.js +317 -313
- package/src/plugins/soft-delete.plugin.js +46 -46
- package/src/plugins/subdocument.plugin.js +66 -66
- package/src/plugins/timestamp.plugin.js +19 -19
- package/src/plugins/validation-chain.plugin.js +145 -145
- package/src/types.d.ts +87 -0
- package/src/utils/error.js +12 -0
- package/src/utils/field-selection.js +156 -156
- package/src/utils/index.js +12 -12
- package/types/Repository.d.ts +95 -0
- package/types/Repository.d.ts.map +1 -0
- package/types/actions/aggregate.d.ts +112 -0
- package/types/actions/aggregate.d.ts.map +1 -0
- package/types/actions/create.d.ts +21 -0
- package/types/actions/create.d.ts.map +1 -0
- package/types/actions/delete.d.ts +37 -0
- package/types/actions/delete.d.ts.map +1 -0
- package/types/actions/index.d.ts +6 -113
- package/types/actions/index.d.ts.map +1 -0
- package/types/actions/read.d.ts +135 -0
- package/types/actions/read.d.ts.map +1 -0
- package/types/actions/update.d.ts +58 -0
- package/types/actions/update.d.ts.map +1 -0
- package/types/hooks/lifecycle.d.ts +44 -0
- package/types/hooks/lifecycle.d.ts.map +1 -0
- package/types/index.d.ts +25 -96
- package/types/index.d.ts.map +1 -0
- package/types/pagination/PaginationEngine.d.ts +386 -0
- package/types/pagination/PaginationEngine.d.ts.map +1 -0
- package/types/pagination/utils/cursor.d.ts +40 -0
- package/types/pagination/utils/cursor.d.ts.map +1 -0
- package/types/pagination/utils/filter.d.ts +28 -0
- package/types/pagination/utils/filter.d.ts.map +1 -0
- package/types/pagination/utils/limits.d.ts +64 -0
- package/types/pagination/utils/limits.d.ts.map +1 -0
- package/types/pagination/utils/sort.d.ts +41 -0
- package/types/pagination/utils/sort.d.ts.map +1 -0
- package/types/plugins/aggregate-helpers.plugin.d.ts +6 -0
- package/types/plugins/aggregate-helpers.plugin.d.ts.map +1 -0
- package/types/plugins/audit-log.plugin.d.ts +6 -0
- package/types/plugins/audit-log.plugin.d.ts.map +1 -0
- package/types/plugins/batch-operations.plugin.d.ts +6 -0
- package/types/plugins/batch-operations.plugin.d.ts.map +1 -0
- package/types/plugins/field-filter.plugin.d.ts +6 -0
- package/types/plugins/field-filter.plugin.d.ts.map +1 -0
- package/types/plugins/index.d.ts +11 -88
- package/types/plugins/index.d.ts.map +1 -0
- package/types/plugins/method-registry.plugin.d.ts +3 -0
- package/types/plugins/method-registry.plugin.d.ts.map +1 -0
- package/types/plugins/mongo-operations.plugin.d.ts +4 -0
- package/types/plugins/mongo-operations.plugin.d.ts.map +1 -0
- package/types/plugins/soft-delete.plugin.d.ts +6 -0
- package/types/plugins/soft-delete.plugin.d.ts.map +1 -0
- package/types/plugins/subdocument.plugin.d.ts +6 -0
- package/types/plugins/subdocument.plugin.d.ts.map +1 -0
- package/types/plugins/timestamp.plugin.d.ts +6 -0
- package/types/plugins/timestamp.plugin.d.ts.map +1 -0
- package/types/plugins/validation-chain.plugin.d.ts +31 -0
- package/types/plugins/validation-chain.plugin.d.ts.map +1 -0
- package/types/utils/error.d.ts +11 -0
- package/types/utils/error.d.ts.map +1 -0
- package/types/utils/field-selection.d.ts +9 -0
- package/types/utils/field-selection.d.ts.map +1 -0
- package/types/utils/index.d.ts +2 -24
- package/types/utils/index.d.ts.map +1 -0
|
@@ -1,156 +1,156 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Field Selection Utilities
|
|
3
|
-
*
|
|
4
|
-
* Provides explicit, performant field filtering using Mongoose projections.
|
|
5
|
-
*
|
|
6
|
-
* Philosophy:
|
|
7
|
-
* - Explicit is better than implicit
|
|
8
|
-
* - Filter at DB level (10x faster than in-memory)
|
|
9
|
-
* - Progressive disclosure (show more fields as trust increases)
|
|
10
|
-
*
|
|
11
|
-
* Usage:
|
|
12
|
-
* ```javascript
|
|
13
|
-
* // For Mongoose queries (PREFERRED - 90% of cases)
|
|
14
|
-
* const projection = getMongooseProjection(request.user, fieldPresets.gymPlans);
|
|
15
|
-
* const plans = await GymPlan.find().select(projection).lean();
|
|
16
|
-
*
|
|
17
|
-
* // For complex data (10% of cases - aggregations, multiple sources)
|
|
18
|
-
* const filtered = filterResponseData(complexData, fieldPresets.gymPlans, request.user);
|
|
19
|
-
* ```
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Get allowed fields for a user based on their context
|
|
24
|
-
*
|
|
25
|
-
* @param {Object} user - User object from request.user (or null for public)
|
|
26
|
-
* @param {Object} preset - Field preset configuration
|
|
27
|
-
* @param {string[]} preset.public - Fields visible to everyone
|
|
28
|
-
* @param {string[]} preset.authenticated - Additional fields for authenticated users
|
|
29
|
-
* @param {string[]} preset.admin - Additional fields for admins
|
|
30
|
-
* @returns {string[]} Array of allowed field names
|
|
31
|
-
*/
|
|
32
|
-
export const getFieldsForUser = (user, preset) => {
|
|
33
|
-
if (!preset) {
|
|
34
|
-
throw new Error('Field preset is required');
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Start with public fields
|
|
38
|
-
let fields = [...(preset.public || [])];
|
|
39
|
-
|
|
40
|
-
// Add authenticated fields if user is logged in
|
|
41
|
-
if (user) {
|
|
42
|
-
fields.push(...(preset.authenticated || []));
|
|
43
|
-
|
|
44
|
-
// Add admin fields if user is admin/superadmin
|
|
45
|
-
const roles = Array.isArray(user.roles) ? user.roles : (user.roles ? [user.roles] : []);
|
|
46
|
-
if (roles.includes('admin') || roles.includes('superadmin')) {
|
|
47
|
-
fields.push(...(preset.admin || []));
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// Remove duplicates
|
|
52
|
-
return [...new Set(fields)];
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Get Mongoose projection string for query .select()
|
|
57
|
-
*
|
|
58
|
-
* @param {Object} user - User object from request.user
|
|
59
|
-
* @param {Object} preset - Field preset configuration
|
|
60
|
-
* @returns {string} Space-separated field names for Mongoose .select()
|
|
61
|
-
*
|
|
62
|
-
* @example
|
|
63
|
-
* const projection = getMongooseProjection(request.user, fieldPresets.gymPlans);
|
|
64
|
-
* const plans = await GymPlan.find({ organizationId }).select(projection).lean();
|
|
65
|
-
*/
|
|
66
|
-
export const getMongooseProjection = (user, preset) => {
|
|
67
|
-
const fields = getFieldsForUser(user, preset);
|
|
68
|
-
return fields.join(' ');
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Filter response data to include only allowed fields
|
|
73
|
-
*
|
|
74
|
-
* Use this for complex responses where Mongoose projections aren't applicable:
|
|
75
|
-
* - Aggregation pipeline results
|
|
76
|
-
* - Data from multiple sources
|
|
77
|
-
* - Custom computed fields
|
|
78
|
-
*
|
|
79
|
-
* For simple DB queries, prefer getMongooseProjection() (10x faster)
|
|
80
|
-
*
|
|
81
|
-
* @param {Object|Array} data - Data to filter
|
|
82
|
-
* @param {Object} preset - Field preset configuration
|
|
83
|
-
* @param {Object} user - User object from request.user
|
|
84
|
-
* @returns {Object|Array} Filtered data
|
|
85
|
-
*
|
|
86
|
-
* @example
|
|
87
|
-
* const stats = await calculateComplexStats();
|
|
88
|
-
* const filtered = filterResponseData(stats, fieldPresets.dashboard, request.user);
|
|
89
|
-
* return reply.send(filtered);
|
|
90
|
-
*/
|
|
91
|
-
export const filterResponseData = (data, preset, user = null) => {
|
|
92
|
-
const allowedFields = getFieldsForUser(user, preset);
|
|
93
|
-
|
|
94
|
-
// Handle arrays
|
|
95
|
-
if (Array.isArray(data)) {
|
|
96
|
-
return data.map(item => filterObject(item, allowedFields));
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Handle single object
|
|
100
|
-
return filterObject(data, allowedFields);
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Filter a single object to include only allowed fields
|
|
105
|
-
*
|
|
106
|
-
* @private
|
|
107
|
-
* @param {Object} obj - Object to filter
|
|
108
|
-
* @param {string[]} allowedFields - Array of allowed field names
|
|
109
|
-
* @returns {Object} Filtered object
|
|
110
|
-
*/
|
|
111
|
-
const filterObject = (obj, allowedFields) => {
|
|
112
|
-
if (!obj || typeof obj !== 'object' || Array.isArray(obj)) {
|
|
113
|
-
return obj;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const filtered = {};
|
|
117
|
-
|
|
118
|
-
for (const field of allowedFields) {
|
|
119
|
-
if (field in obj) {
|
|
120
|
-
filtered[field] = obj[field];
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
return filtered;
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Helper to create field presets (module-level)
|
|
129
|
-
*
|
|
130
|
-
* Each module should define its own field preset in its own directory.
|
|
131
|
-
* This keeps modules independent and self-contained.
|
|
132
|
-
*
|
|
133
|
-
* @param {Object} config - Field configuration
|
|
134
|
-
* @returns {Object} Field preset
|
|
135
|
-
*
|
|
136
|
-
* @example
|
|
137
|
-
* // In modules/gym-plan/gym-plan.fields.js
|
|
138
|
-
* import { createFieldPreset } from '#common/utils/field-selection.js';
|
|
139
|
-
*
|
|
140
|
-
* export const gymPlanFieldPreset = createFieldPreset({
|
|
141
|
-
* public: ['id', 'name', 'price'],
|
|
142
|
-
* authenticated: ['features', 'description'],
|
|
143
|
-
* admin: ['createdAt', 'updatedAt', 'internalNotes']
|
|
144
|
-
* });
|
|
145
|
-
*
|
|
146
|
-
* // Then in controller:
|
|
147
|
-
* import { gymPlanFieldPreset } from './gym-plan.fields.js';
|
|
148
|
-
* super(gymPlanRepository, { fieldPreset: gymPlanFieldPreset });
|
|
149
|
-
*/
|
|
150
|
-
export const createFieldPreset = (config) => {
|
|
151
|
-
return {
|
|
152
|
-
public: config.public || [],
|
|
153
|
-
authenticated: config.authenticated || [],
|
|
154
|
-
admin: config.admin || [],
|
|
155
|
-
};
|
|
156
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* Field Selection Utilities
|
|
3
|
+
*
|
|
4
|
+
* Provides explicit, performant field filtering using Mongoose projections.
|
|
5
|
+
*
|
|
6
|
+
* Philosophy:
|
|
7
|
+
* - Explicit is better than implicit
|
|
8
|
+
* - Filter at DB level (10x faster than in-memory)
|
|
9
|
+
* - Progressive disclosure (show more fields as trust increases)
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* ```javascript
|
|
13
|
+
* // For Mongoose queries (PREFERRED - 90% of cases)
|
|
14
|
+
* const projection = getMongooseProjection(request.user, fieldPresets.gymPlans);
|
|
15
|
+
* const plans = await GymPlan.find().select(projection).lean();
|
|
16
|
+
*
|
|
17
|
+
* // For complex data (10% of cases - aggregations, multiple sources)
|
|
18
|
+
* const filtered = filterResponseData(complexData, fieldPresets.gymPlans, request.user);
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Get allowed fields for a user based on their context
|
|
24
|
+
*
|
|
25
|
+
* @param {Object} user - User object from request.user (or null for public)
|
|
26
|
+
* @param {Object} preset - Field preset configuration
|
|
27
|
+
* @param {string[]} preset.public - Fields visible to everyone
|
|
28
|
+
* @param {string[]} preset.authenticated - Additional fields for authenticated users
|
|
29
|
+
* @param {string[]} preset.admin - Additional fields for admins
|
|
30
|
+
* @returns {string[]} Array of allowed field names
|
|
31
|
+
*/
|
|
32
|
+
export const getFieldsForUser = (user, preset) => {
|
|
33
|
+
if (!preset) {
|
|
34
|
+
throw new Error('Field preset is required');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Start with public fields
|
|
38
|
+
let fields = [...(preset.public || [])];
|
|
39
|
+
|
|
40
|
+
// Add authenticated fields if user is logged in
|
|
41
|
+
if (user) {
|
|
42
|
+
fields.push(...(preset.authenticated || []));
|
|
43
|
+
|
|
44
|
+
// Add admin fields if user is admin/superadmin
|
|
45
|
+
const roles = Array.isArray(user.roles) ? user.roles : (user.roles ? [user.roles] : []);
|
|
46
|
+
if (roles.includes('admin') || roles.includes('superadmin')) {
|
|
47
|
+
fields.push(...(preset.admin || []));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Remove duplicates
|
|
52
|
+
return [...new Set(fields)];
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Get Mongoose projection string for query .select()
|
|
57
|
+
*
|
|
58
|
+
* @param {Object} user - User object from request.user
|
|
59
|
+
* @param {Object} preset - Field preset configuration
|
|
60
|
+
* @returns {string} Space-separated field names for Mongoose .select()
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* const projection = getMongooseProjection(request.user, fieldPresets.gymPlans);
|
|
64
|
+
* const plans = await GymPlan.find({ organizationId }).select(projection).lean();
|
|
65
|
+
*/
|
|
66
|
+
export const getMongooseProjection = (user, preset) => {
|
|
67
|
+
const fields = getFieldsForUser(user, preset);
|
|
68
|
+
return fields.join(' ');
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Filter response data to include only allowed fields
|
|
73
|
+
*
|
|
74
|
+
* Use this for complex responses where Mongoose projections aren't applicable:
|
|
75
|
+
* - Aggregation pipeline results
|
|
76
|
+
* - Data from multiple sources
|
|
77
|
+
* - Custom computed fields
|
|
78
|
+
*
|
|
79
|
+
* For simple DB queries, prefer getMongooseProjection() (10x faster)
|
|
80
|
+
*
|
|
81
|
+
* @param {Object|Array} data - Data to filter
|
|
82
|
+
* @param {Object} preset - Field preset configuration
|
|
83
|
+
* @param {Object} user - User object from request.user
|
|
84
|
+
* @returns {Object|Array} Filtered data
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* const stats = await calculateComplexStats();
|
|
88
|
+
* const filtered = filterResponseData(stats, fieldPresets.dashboard, request.user);
|
|
89
|
+
* return reply.send(filtered);
|
|
90
|
+
*/
|
|
91
|
+
export const filterResponseData = (data, preset, user = null) => {
|
|
92
|
+
const allowedFields = getFieldsForUser(user, preset);
|
|
93
|
+
|
|
94
|
+
// Handle arrays
|
|
95
|
+
if (Array.isArray(data)) {
|
|
96
|
+
return data.map(item => filterObject(item, allowedFields));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Handle single object
|
|
100
|
+
return filterObject(data, allowedFields);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Filter a single object to include only allowed fields
|
|
105
|
+
*
|
|
106
|
+
* @private
|
|
107
|
+
* @param {Object} obj - Object to filter
|
|
108
|
+
* @param {string[]} allowedFields - Array of allowed field names
|
|
109
|
+
* @returns {Object} Filtered object
|
|
110
|
+
*/
|
|
111
|
+
const filterObject = (obj, allowedFields) => {
|
|
112
|
+
if (!obj || typeof obj !== 'object' || Array.isArray(obj)) {
|
|
113
|
+
return obj;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const filtered = {};
|
|
117
|
+
|
|
118
|
+
for (const field of allowedFields) {
|
|
119
|
+
if (field in obj) {
|
|
120
|
+
filtered[field] = obj[field];
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return filtered;
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Helper to create field presets (module-level)
|
|
129
|
+
*
|
|
130
|
+
* Each module should define its own field preset in its own directory.
|
|
131
|
+
* This keeps modules independent and self-contained.
|
|
132
|
+
*
|
|
133
|
+
* @param {Object} config - Field configuration
|
|
134
|
+
* @returns {Object} Field preset
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* // In modules/gym-plan/gym-plan.fields.js
|
|
138
|
+
* import { createFieldPreset } from '#common/utils/field-selection.js';
|
|
139
|
+
*
|
|
140
|
+
* export const gymPlanFieldPreset = createFieldPreset({
|
|
141
|
+
* public: ['id', 'name', 'price'],
|
|
142
|
+
* authenticated: ['features', 'description'],
|
|
143
|
+
* admin: ['createdAt', 'updatedAt', 'internalNotes']
|
|
144
|
+
* });
|
|
145
|
+
*
|
|
146
|
+
* // Then in controller:
|
|
147
|
+
* import { gymPlanFieldPreset } from './gym-plan.fields.js';
|
|
148
|
+
* super(gymPlanRepository, { fieldPreset: gymPlanFieldPreset });
|
|
149
|
+
*/
|
|
150
|
+
export const createFieldPreset = (config) => {
|
|
151
|
+
return {
|
|
152
|
+
public: config.public || [],
|
|
153
|
+
authenticated: config.authenticated || [],
|
|
154
|
+
admin: config.admin || [],
|
|
155
|
+
};
|
|
156
|
+
};
|
package/src/utils/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Utility Functions for MongoKit
|
|
3
|
-
* Reusable helpers for field selection, filtering, and more
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export {
|
|
7
|
-
getFieldsForUser,
|
|
8
|
-
getMongooseProjection,
|
|
9
|
-
filterResponseData,
|
|
10
|
-
createFieldPreset,
|
|
11
|
-
} from './field-selection.js';
|
|
12
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Utility Functions for MongoKit
|
|
3
|
+
* Reusable helpers for field selection, filtering, and more
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export {
|
|
7
|
+
getFieldsForUser,
|
|
8
|
+
getMongooseProjection,
|
|
9
|
+
filterResponseData,
|
|
10
|
+
createFieldPreset,
|
|
11
|
+
} from './field-selection.js';
|
|
12
|
+
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {import('./types.js').OffsetPaginationResult} OffsetPaginationResult
|
|
3
|
+
* @typedef {import('./types.js').KeysetPaginationResult} KeysetPaginationResult
|
|
4
|
+
* @typedef {import('./types.js').AggregatePaginationResult} AggregatePaginationResult
|
|
5
|
+
* @typedef {import('./types.js').ObjectId} ObjectId
|
|
6
|
+
*/
|
|
7
|
+
export class Repository {
|
|
8
|
+
constructor(Model: any, plugins?: any[], paginationConfig?: {});
|
|
9
|
+
Model: any;
|
|
10
|
+
model: any;
|
|
11
|
+
_hooks: Map<any, any>;
|
|
12
|
+
_pagination: PaginationEngine;
|
|
13
|
+
use(plugin: any): this;
|
|
14
|
+
on(event: any, listener: any): this;
|
|
15
|
+
emit(event: any, data: any): void;
|
|
16
|
+
create(data: any, options?: {}): Promise<any>;
|
|
17
|
+
createMany(dataArray: any, options?: {}): Promise<any>;
|
|
18
|
+
getById(id: any, options?: {}): Promise<any>;
|
|
19
|
+
getByQuery(query: any, options?: {}): Promise<any>;
|
|
20
|
+
/**
|
|
21
|
+
* Unified pagination - auto-detects offset vs keyset based on params
|
|
22
|
+
*
|
|
23
|
+
* Auto-detection logic:
|
|
24
|
+
* - If params has 'cursor' or 'after' → uses keyset pagination (stream)
|
|
25
|
+
* - If params has 'pagination' or 'page' → uses offset pagination (paginate)
|
|
26
|
+
* - Else → defaults to offset pagination with page=1
|
|
27
|
+
*
|
|
28
|
+
* @param {Object} params - Query and pagination parameters
|
|
29
|
+
* @param {Object} [params.filters] - MongoDB query filters
|
|
30
|
+
* @param {string|Object} [params.sort] - Sort specification
|
|
31
|
+
* @param {string} [params.cursor] - Cursor token for keyset pagination
|
|
32
|
+
* @param {string} [params.after] - Alias for cursor
|
|
33
|
+
* @param {number} [params.page] - Page number for offset pagination
|
|
34
|
+
* @param {Object} [params.pagination] - Pagination config { page, limit }
|
|
35
|
+
* @param {number} [params.limit] - Documents per page
|
|
36
|
+
* @param {string} [params.search] - Full-text search query
|
|
37
|
+
* @param {Object} [options] - Additional options (select, populate, lean, session)
|
|
38
|
+
* @returns {Promise<OffsetPaginationResult|KeysetPaginationResult>} Discriminated union based on method
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* // Offset pagination (page-based)
|
|
42
|
+
* await repo.getAll({ page: 1, limit: 50, filters: { status: 'active' } });
|
|
43
|
+
* await repo.getAll({ pagination: { page: 2, limit: 20 } });
|
|
44
|
+
*
|
|
45
|
+
* // Keyset pagination (cursor-based)
|
|
46
|
+
* await repo.getAll({ cursor: 'eyJ2Ij...', limit: 50 });
|
|
47
|
+
* await repo.getAll({ after: 'eyJ2Ij...', sort: { createdAt: -1 } });
|
|
48
|
+
*
|
|
49
|
+
* // Simple query (defaults to page 1)
|
|
50
|
+
* await repo.getAll({ filters: { status: 'active' } });
|
|
51
|
+
*/
|
|
52
|
+
getAll(params?: {
|
|
53
|
+
filters?: any;
|
|
54
|
+
sort?: string | any;
|
|
55
|
+
cursor?: string;
|
|
56
|
+
after?: string;
|
|
57
|
+
page?: number;
|
|
58
|
+
pagination?: any;
|
|
59
|
+
limit?: number;
|
|
60
|
+
search?: string;
|
|
61
|
+
}, options?: any): Promise<OffsetPaginationResult | KeysetPaginationResult>;
|
|
62
|
+
getOrCreate(query: any, createData: any, options?: {}): Promise<any>;
|
|
63
|
+
count(query?: {}, options?: {}): Promise<number>;
|
|
64
|
+
exists(query: any, options?: {}): Promise<{
|
|
65
|
+
_id: any;
|
|
66
|
+
}>;
|
|
67
|
+
update(id: any, data: any, options?: {}): Promise<any>;
|
|
68
|
+
delete(id: any, options?: {}): Promise<{
|
|
69
|
+
success: boolean;
|
|
70
|
+
message: string;
|
|
71
|
+
}>;
|
|
72
|
+
aggregate(pipeline: any, options?: {}): Promise<any[]>;
|
|
73
|
+
/**
|
|
74
|
+
* Aggregate pipeline with pagination
|
|
75
|
+
* Best for: Complex queries, grouping, joins
|
|
76
|
+
*
|
|
77
|
+
* @param {Object} options - Aggregate pagination options
|
|
78
|
+
* @returns {Promise<AggregatePaginationResult>}
|
|
79
|
+
*/
|
|
80
|
+
aggregatePaginate(options?: any): Promise<AggregatePaginationResult>;
|
|
81
|
+
distinct(field: any, query?: {}, options?: {}): Promise<any>;
|
|
82
|
+
withTransaction(callback: any): Promise<any>;
|
|
83
|
+
_executeQuery(buildQuery: any): Promise<any>;
|
|
84
|
+
_buildContext(operation: any, options: any): Promise<any>;
|
|
85
|
+
_parseSort(sort: any): any;
|
|
86
|
+
_parsePopulate(populate: any): any[];
|
|
87
|
+
_handleError(error: any): any;
|
|
88
|
+
}
|
|
89
|
+
export default Repository;
|
|
90
|
+
export type OffsetPaginationResult = import("./types.js").OffsetPaginationResult;
|
|
91
|
+
export type KeysetPaginationResult = import("./types.js").KeysetPaginationResult;
|
|
92
|
+
export type AggregatePaginationResult = import("./types.js").AggregatePaginationResult;
|
|
93
|
+
export type ObjectId = import("./types.js").ObjectId;
|
|
94
|
+
import { PaginationEngine } from './pagination/PaginationEngine.js';
|
|
95
|
+
//# sourceMappingURL=Repository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Repository.d.ts","sourceRoot":"","sources":["../src/Repository.js"],"names":[],"mappings":"AASA;;;;;GAKG;AAEH;IACE,gEAMC;IALC,WAAkB;IAClB,WAA4B;IAC5B,sBAAuB;IACvB,8BAAgE;IAIlE,uBAOC;IAED,oCAMC;IAED,kCAGC;IAED,8CAWC;IAED,uDAWC;IAED,6CAGC;IAED,mDAGC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+BG;IACH,gBAvBG;QAAwB,OAAO;QACA,IAAI,GAA3B,MAAM,MAAO;QACG,MAAM,GAAtB,MAAM;QACU,KAAK,GAArB,MAAM;QACU,IAAI,GAApB,MAAM;QACU,UAAU;QACV,KAAK,GAArB,MAAM;QACU,MAAM,GAAtB,MAAM;KACd,kBACU,OAAO,CAAC,sBAAsB,GAAC,sBAAsB,CAAC,CAgElE;IAED,qEAEC;IAED,iDAEC;IAED;;OAEC;IAED,uDAWC;IAED;;;OAWC;IAED,uDAEC;IAED;;;;;;OAMG;IACH,kCAFa,OAAO,CAAC,yBAAyB,CAAC,CAK9C;IAED,6DAEC;IAED,6CAaC;IAED,6CAYC;IAED,0DAUC;IAED,2BAOC;IAED,qCAKC;IAED,8BAUC;CACF;;qCA3RY,OAAO,YAAY,EAAE,sBAAsB;qCAC3C,OAAO,YAAY,EAAE,sBAAsB;wCAC3C,OAAO,YAAY,EAAE,yBAAyB;uBAC9C,OAAO,YAAY,EAAE,QAAQ;iCANT,kCAAkC"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aggregate Actions
|
|
3
|
+
* MongoDB aggregation pipeline operations
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* @typedef {import('mongoose').Model} Model
|
|
7
|
+
* @typedef {import('mongoose').ClientSession} ClientSession
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Execute aggregation pipeline
|
|
11
|
+
*
|
|
12
|
+
* @param {Model} Model - Mongoose model
|
|
13
|
+
* @param {any[]} pipeline - Aggregation pipeline stages
|
|
14
|
+
* @param {Object} [options={}] - Aggregation options
|
|
15
|
+
* @param {ClientSession} [options.session] - MongoDB session
|
|
16
|
+
* @returns {Promise<any[]>} Aggregation results
|
|
17
|
+
*/
|
|
18
|
+
export function aggregate(Model: Model, pipeline: any[], options?: {
|
|
19
|
+
session?: ClientSession;
|
|
20
|
+
}): Promise<any[]>;
|
|
21
|
+
/**
|
|
22
|
+
* Aggregate with pagination using native MongoDB $facet
|
|
23
|
+
* WARNING: $facet results must be <16MB. For larger results (limit >1000),
|
|
24
|
+
* consider using Repository.aggregatePaginate() or splitting into separate queries.
|
|
25
|
+
*
|
|
26
|
+
* @param {Model} Model - Mongoose model
|
|
27
|
+
* @param {any[]} pipeline - Aggregation pipeline stages (before pagination)
|
|
28
|
+
* @param {Object} [options={}] - Pagination options
|
|
29
|
+
* @param {number} [options.page=1] - Page number (1-indexed)
|
|
30
|
+
* @param {number} [options.limit=10] - Documents per page
|
|
31
|
+
* @param {ClientSession} [options.session] - MongoDB session
|
|
32
|
+
* @returns {Promise<{docs: any[], total: number, page: number, limit: number, pages: number, hasNext: boolean, hasPrev: boolean}>} Paginated results
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* const result = await aggregatePaginate(UserModel, [
|
|
36
|
+
* { $match: { status: 'active' } },
|
|
37
|
+
* { $group: { _id: '$category', count: { $sum: 1 } } }
|
|
38
|
+
* ], { page: 1, limit: 20 });
|
|
39
|
+
*/
|
|
40
|
+
export function aggregatePaginate(Model: Model, pipeline: any[], options?: {
|
|
41
|
+
page?: number;
|
|
42
|
+
limit?: number;
|
|
43
|
+
session?: ClientSession;
|
|
44
|
+
}): Promise<{
|
|
45
|
+
docs: any[];
|
|
46
|
+
total: number;
|
|
47
|
+
page: number;
|
|
48
|
+
limit: number;
|
|
49
|
+
pages: number;
|
|
50
|
+
hasNext: boolean;
|
|
51
|
+
hasPrev: boolean;
|
|
52
|
+
}>;
|
|
53
|
+
/**
|
|
54
|
+
* Group documents by field value
|
|
55
|
+
*
|
|
56
|
+
* @param {Model} Model - Mongoose model
|
|
57
|
+
* @param {string} field - Field name to group by
|
|
58
|
+
* @param {Object} [options={}] - Options
|
|
59
|
+
* @param {number} [options.limit] - Maximum groups to return
|
|
60
|
+
* @param {ClientSession} [options.session] - MongoDB session
|
|
61
|
+
* @returns {Promise<Array<{_id: any, count: number}>>} Grouped results
|
|
62
|
+
*/
|
|
63
|
+
export function groupBy(Model: Model, field: string, options?: {
|
|
64
|
+
limit?: number;
|
|
65
|
+
session?: ClientSession;
|
|
66
|
+
}): Promise<Array<{
|
|
67
|
+
_id: any;
|
|
68
|
+
count: number;
|
|
69
|
+
}>>;
|
|
70
|
+
/**
|
|
71
|
+
* Count by field values
|
|
72
|
+
*/
|
|
73
|
+
export function countBy(Model: any, field: any, query?: {}, options?: {}): Promise<any[]>;
|
|
74
|
+
/**
|
|
75
|
+
* Lookup (join) with another collection
|
|
76
|
+
*/
|
|
77
|
+
export function lookup(Model: any, { from, localField, foreignField, as, pipeline, query, options }: {
|
|
78
|
+
from: any;
|
|
79
|
+
localField: any;
|
|
80
|
+
foreignField: any;
|
|
81
|
+
as: any;
|
|
82
|
+
pipeline?: any[];
|
|
83
|
+
query?: {};
|
|
84
|
+
options?: {};
|
|
85
|
+
}): Promise<any[]>;
|
|
86
|
+
/**
|
|
87
|
+
* Unwind array field
|
|
88
|
+
*/
|
|
89
|
+
export function unwind(Model: any, field: any, options?: {}): Promise<any[]>;
|
|
90
|
+
/**
|
|
91
|
+
* Facet search (multiple aggregations in one query)
|
|
92
|
+
*/
|
|
93
|
+
export function facet(Model: any, facets: any, options?: {}): Promise<any[]>;
|
|
94
|
+
/**
|
|
95
|
+
* Get distinct values
|
|
96
|
+
*/
|
|
97
|
+
export function distinct(Model: any, field: any, query?: {}, options?: {}): Promise<any>;
|
|
98
|
+
/**
|
|
99
|
+
* Calculate sum
|
|
100
|
+
*/
|
|
101
|
+
export function sum(Model: any, field: any, query?: {}, options?: {}): Promise<any>;
|
|
102
|
+
/**
|
|
103
|
+
* Calculate average
|
|
104
|
+
*/
|
|
105
|
+
export function average(Model: any, field: any, query?: {}, options?: {}): Promise<any>;
|
|
106
|
+
/**
|
|
107
|
+
* Min/Max
|
|
108
|
+
*/
|
|
109
|
+
export function minMax(Model: any, field: any, query?: {}, options?: {}): Promise<any>;
|
|
110
|
+
export type Model = import("mongoose").Model<any, any, any, any, any, any, any>;
|
|
111
|
+
export type ClientSession = import("mongoose").ClientSession;
|
|
112
|
+
//# sourceMappingURL=aggregate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aggregate.d.ts","sourceRoot":"","sources":["../../src/actions/aggregate.js"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AAEH;;;;;;;;GAQG;AACH,iCANW,KAAK,YACL,GAAG,EAAE,YAEb;IAAgC,OAAO,GAA/B,aAAa;CACrB,GAAU,OAAO,CAAC,GAAG,EAAE,CAAC,CAU1B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,yCAdW,KAAK,YACL,GAAG,EAAE,YAEb;IAAyB,IAAI,GAArB,MAAM;IACW,KAAK,GAAtB,MAAM;IACkB,OAAO,GAA/B,aAAa;CACrB,GAAU,OAAO,CAAC;IAAC,IAAI,EAAE,GAAG,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAC,CAAC,CAwDjI;AAED;;;;;;;;;GASG;AACH,+BAPW,KAAK,SACL,MAAM,YAEd;IAAyB,KAAK,GAAtB,MAAM;IACkB,OAAO,GAA/B,aAAa;CACrB,GAAU,OAAO,CAAC,KAAK,CAAC;IAAC,GAAG,EAAE,GAAG,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAC,CAAC,CAAC,CAarD;AAED;;GAEG;AACH,0FAaC;AAED;;GAEG;AACH;;;;;;;;mBA0BC;AAED;;GAEG;AACH,6EAWC;AAED;;GAEG;AACH,6EAIC;AAED;;GAEG;AACH,yFAEC;AAED;;GAEG;AACH,oFAgBC;AAED;;GAEG;AACH,wFAgBC;AAED;;GAEG;AACH,uFAiBC;;4BAjQY,OAAO,UAAU,EAAE,aAAa"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create Actions
|
|
3
|
+
* Pure functions for document creation
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Create single document
|
|
7
|
+
*/
|
|
8
|
+
export function create(Model: any, data: any, options?: {}): Promise<any>;
|
|
9
|
+
/**
|
|
10
|
+
* Create multiple documents
|
|
11
|
+
*/
|
|
12
|
+
export function createMany(Model: any, dataArray: any, options?: {}): Promise<any>;
|
|
13
|
+
/**
|
|
14
|
+
* Create with defaults (useful for initialization)
|
|
15
|
+
*/
|
|
16
|
+
export function createDefault(Model: any, overrides?: {}, options?: {}): Promise<any>;
|
|
17
|
+
/**
|
|
18
|
+
* Upsert (create or update)
|
|
19
|
+
*/
|
|
20
|
+
export function upsert(Model: any, query: any, data: any, options?: {}): Promise<any>;
|
|
21
|
+
//# sourceMappingURL=create.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/actions/create.js"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,0EAIC;AAED;;GAEG;AACH,mFAKC;AAED;;GAEG;AACH,sFAaC;AAED;;GAEG;AACH,sFAYC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Delete by ID
|
|
3
|
+
*/
|
|
4
|
+
export function deleteById(Model: any, id: any, options?: {}): Promise<{
|
|
5
|
+
success: boolean;
|
|
6
|
+
message: string;
|
|
7
|
+
}>;
|
|
8
|
+
/**
|
|
9
|
+
* Delete many documents
|
|
10
|
+
*/
|
|
11
|
+
export function deleteMany(Model: any, query: any, options?: {}): Promise<{
|
|
12
|
+
success: boolean;
|
|
13
|
+
count: any;
|
|
14
|
+
message: string;
|
|
15
|
+
}>;
|
|
16
|
+
/**
|
|
17
|
+
* Delete by query
|
|
18
|
+
*/
|
|
19
|
+
export function deleteByQuery(Model: any, query: any, options?: {}): Promise<{
|
|
20
|
+
success: boolean;
|
|
21
|
+
message: string;
|
|
22
|
+
}>;
|
|
23
|
+
/**
|
|
24
|
+
* Soft delete (set deleted flag)
|
|
25
|
+
*/
|
|
26
|
+
export function softDelete(Model: any, id: any, options?: {}): Promise<{
|
|
27
|
+
success: boolean;
|
|
28
|
+
message: string;
|
|
29
|
+
}>;
|
|
30
|
+
/**
|
|
31
|
+
* Restore soft deleted document
|
|
32
|
+
*/
|
|
33
|
+
export function restore(Model: any, id: any, options?: {}): Promise<{
|
|
34
|
+
success: boolean;
|
|
35
|
+
message: string;
|
|
36
|
+
}>;
|
|
37
|
+
//# sourceMappingURL=delete.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delete.d.ts","sourceRoot":"","sources":["../../src/actions/delete.js"],"names":[],"mappings":"AAOA;;GAEG;AACH;;;GAQC;AAED;;GAEG;AACH;;;;GAQC;AAED;;GAEG;AACH;;;GAQC;AAED;;GAEG;AACH;;;GAgBC;AAED;;GAEG;AACH;;;GAgBC"}
|