@coherent.js/database 1.0.0-beta.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.
- package/LICENSE +21 -0
- package/README.md +74 -0
- package/dist/database/adapters/memory.d.ts +48 -0
- package/dist/database/adapters/memory.d.ts.map +1 -0
- package/dist/database/adapters/memory.js +250 -0
- package/dist/database/adapters/memory.js.map +1 -0
- package/dist/database/adapters/mongodb.d.ts +15 -0
- package/dist/database/adapters/mongodb.d.ts.map +1 -0
- package/dist/database/adapters/mongodb.js +216 -0
- package/dist/database/adapters/mongodb.js.map +1 -0
- package/dist/database/adapters/mysql.d.ts +12 -0
- package/dist/database/adapters/mysql.d.ts.map +1 -0
- package/dist/database/adapters/mysql.js +171 -0
- package/dist/database/adapters/mysql.js.map +1 -0
- package/dist/database/adapters/postgresql.d.ts +12 -0
- package/dist/database/adapters/postgresql.d.ts.map +1 -0
- package/dist/database/adapters/postgresql.js +177 -0
- package/dist/database/adapters/postgresql.js.map +1 -0
- package/dist/database/adapters/sqlite.d.ts +15 -0
- package/dist/database/adapters/sqlite.d.ts.map +1 -0
- package/dist/database/adapters/sqlite.js +241 -0
- package/dist/database/adapters/sqlite.js.map +1 -0
- package/dist/database/connection-manager.d.ts +148 -0
- package/dist/database/connection-manager.d.ts.map +1 -0
- package/dist/database/connection-manager.js +377 -0
- package/dist/database/connection-manager.js.map +1 -0
- package/dist/database/index.d.ts +38 -0
- package/dist/database/index.d.ts.map +1 -0
- package/dist/database/index.js +63 -0
- package/dist/database/index.js.map +1 -0
- package/dist/database/middleware.d.ts +122 -0
- package/dist/database/middleware.d.ts.map +1 -0
- package/dist/database/middleware.js +403 -0
- package/dist/database/middleware.js.map +1 -0
- package/dist/database/migration.d.ts +168 -0
- package/dist/database/migration.d.ts.map +1 -0
- package/dist/database/migration.js +946 -0
- package/dist/database/migration.js.map +1 -0
- package/dist/database/model.d.ts +81 -0
- package/dist/database/model.d.ts.map +1 -0
- package/dist/database/model.js +686 -0
- package/dist/database/model.js.map +1 -0
- package/dist/database/query-builder.d.ts +136 -0
- package/dist/database/query-builder.d.ts.map +1 -0
- package/dist/database/query-builder.js +248 -0
- package/dist/database/query-builder.js.map +1 -0
- package/dist/database/utils.d.ts +196 -0
- package/dist/database/utils.d.ts.map +1 -0
- package/dist/database/utils.js +372 -0
- package/dist/database/utils.js.map +1 -0
- package/dist/index.cjs +2286 -0
- package/dist/index.cjs.map +7 -0
- package/dist/index.js +2240 -0
- package/dist/index.js.map +7 -0
- package/package.json +52 -0
- package/types/index.d.ts +732 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database Middleware for Coherent.js Router Integration
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Provides middleware for seamless database integration with the router,
|
|
5
|
+
* including connection management, transaction handling, and query helpers.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Database middleware for router integration
|
|
9
|
+
*
|
|
10
|
+
* @param {DatabaseManager} db - Database manager instance
|
|
11
|
+
* @param {Object} [options={}] - Middleware options
|
|
12
|
+
* @returns {Function} Middleware function
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* import { withDatabase } from '@coherent/database';
|
|
16
|
+
*
|
|
17
|
+
* const router = new SimpleRouter();
|
|
18
|
+
* router.use(withDatabase(db));
|
|
19
|
+
*
|
|
20
|
+
* router.get('/users', async (req, res) => {
|
|
21
|
+
* const users = await req.db.query('SELECT * FROM users');
|
|
22
|
+
* res.json(users.rows);
|
|
23
|
+
* });
|
|
24
|
+
*/
|
|
25
|
+
export function withDatabase(db: DatabaseManager, options?: Object): Function;
|
|
26
|
+
/**
|
|
27
|
+
* Transaction middleware for automatic transaction management
|
|
28
|
+
*
|
|
29
|
+
* @param {DatabaseManager} db - Database manager instance
|
|
30
|
+
* @param {Object} [options={}] - Transaction options
|
|
31
|
+
* @returns {Function} Middleware function
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* router.post('/transfer', withTransaction(db), async (req, res) => {
|
|
35
|
+
* // All database operations in this handler will be wrapped in a transaction
|
|
36
|
+
* await req.tx.query('UPDATE accounts SET balance = balance - ? WHERE id = ?', [amount, fromId]);
|
|
37
|
+
* await req.tx.query('UPDATE accounts SET balance = balance + ? WHERE id = ?', [amount, toId]);
|
|
38
|
+
* // Transaction is automatically committed on success or rolled back on error
|
|
39
|
+
* });
|
|
40
|
+
*/
|
|
41
|
+
export function withTransaction(db: DatabaseManager, options?: Object): Function;
|
|
42
|
+
/**
|
|
43
|
+
* Model binding middleware
|
|
44
|
+
*
|
|
45
|
+
* @param {Function} ModelClass - Model class to bind
|
|
46
|
+
* @param {string} [paramName='id'] - Route parameter name
|
|
47
|
+
* @param {string} [requestKey] - Request key to attach model (defaults to model name)
|
|
48
|
+
* @returns {Function} Middleware function
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* router.get('/users/:id', withModel(User), async (req, res) => {
|
|
52
|
+
* // req.user contains the loaded User model
|
|
53
|
+
* res.json(req.user.toJSON());
|
|
54
|
+
* });
|
|
55
|
+
*
|
|
56
|
+
* router.get('/posts/:postId', withModel(Post, 'postId', 'post'), async (req, res) => {
|
|
57
|
+
* // req.post contains the loaded Post model
|
|
58
|
+
* res.json(req.post.toJSON());
|
|
59
|
+
* });
|
|
60
|
+
*/
|
|
61
|
+
export function withModel(ModelClass: Function, paramName?: string, requestKey?: string): Function;
|
|
62
|
+
/**
|
|
63
|
+
* Pagination middleware
|
|
64
|
+
*
|
|
65
|
+
* @param {Object} [options={}] - Pagination options
|
|
66
|
+
* @returns {Function} Middleware function
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* router.get('/users', withPagination(), async (req, res) => {
|
|
70
|
+
* const users = await User.query()
|
|
71
|
+
* .limit(req.pagination.limit)
|
|
72
|
+
* .offset(req.pagination.offset)
|
|
73
|
+
* .execute();
|
|
74
|
+
*
|
|
75
|
+
* res.json({
|
|
76
|
+
* data: users.rows,
|
|
77
|
+
* pagination: req.pagination
|
|
78
|
+
* });
|
|
79
|
+
* });
|
|
80
|
+
*/
|
|
81
|
+
export function withPagination(options?: Object): Function;
|
|
82
|
+
/**
|
|
83
|
+
* Query validation middleware
|
|
84
|
+
*
|
|
85
|
+
* @param {Object} schema - Validation schema
|
|
86
|
+
* @param {Object} [options={}] - Validation options
|
|
87
|
+
* @returns {Function} Middleware function
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* router.get('/users', withQueryValidation({
|
|
91
|
+
* status: { type: 'string', enum: ['active', 'inactive'] },
|
|
92
|
+
* age: { type: 'number', min: 0, max: 120 }
|
|
93
|
+
* }), async (req, res) => {
|
|
94
|
+
* // req.query is validated and sanitized
|
|
95
|
+
* });
|
|
96
|
+
*/
|
|
97
|
+
export function withQueryValidation(schema: Object, options?: Object): Function;
|
|
98
|
+
/**
|
|
99
|
+
* Database health check middleware
|
|
100
|
+
*
|
|
101
|
+
* @param {DatabaseManager} db - Database manager instance
|
|
102
|
+
* @param {Object} [options={}] - Health check options
|
|
103
|
+
* @returns {Function} Middleware function
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* router.get('/health', withHealthCheck(db), (req, res) => {
|
|
107
|
+
* res.json({ status: 'healthy', database: req.dbHealth });
|
|
108
|
+
* });
|
|
109
|
+
*/
|
|
110
|
+
export function withHealthCheck(db: DatabaseManager, options?: Object): Function;
|
|
111
|
+
/**
|
|
112
|
+
* Connection pooling middleware for request-scoped connections
|
|
113
|
+
*
|
|
114
|
+
* @param {DatabaseManager} db - Database manager instance
|
|
115
|
+
* @param {Object} [options={}] - Pool options
|
|
116
|
+
* @returns {Function} Middleware function
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* router.use(withConnectionPool(db, { acquireTimeout: 10000 }));
|
|
120
|
+
*/
|
|
121
|
+
export function withConnectionPool(db: DatabaseManager, options?: Object): Function;
|
|
122
|
+
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../../../src/database/middleware.js"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;;;;;;;;;;;GAiBG;AACH,iCAfW,eAAe,YACf,MAAM,YAsEhB;AAED;;;;;;;;;;;;;;GAcG;AACH,oCAZW,eAAe,YACf,MAAM,YAuChB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,4DAfW,MAAM,eACN,MAAM,YAyDhB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,yCAhBW,MAAM,YA6ChB;AAED;;;;;;;;;;;;;;GAcG;AACH,4CAZW,MAAM,YACN,MAAM,YA8FhB;AAED;;;;;;;;;;;GAWG;AACH,oCATW,eAAe,YACf,MAAM,YAmDhB;AAED;;;;;;;;;GASG;AACH,uCAPW,eAAe,YACf,MAAM,YAgDhB"}
|
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database Middleware for Coherent.js Router Integration
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Provides middleware for seamless database integration with the router,
|
|
5
|
+
* including connection management, transaction handling, and query helpers.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Database middleware for router integration
|
|
9
|
+
*
|
|
10
|
+
* @param {DatabaseManager} db - Database manager instance
|
|
11
|
+
* @param {Object} [options={}] - Middleware options
|
|
12
|
+
* @returns {Function} Middleware function
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* import { withDatabase } from '@coherent/database';
|
|
16
|
+
*
|
|
17
|
+
* const router = new SimpleRouter();
|
|
18
|
+
* router.use(withDatabase(db));
|
|
19
|
+
*
|
|
20
|
+
* router.get('/users', async (req, res) => {
|
|
21
|
+
* const users = await req.db.query('SELECT * FROM users');
|
|
22
|
+
* res.json(users.rows);
|
|
23
|
+
* });
|
|
24
|
+
*/
|
|
25
|
+
export function withDatabase(db, options = {}) {
|
|
26
|
+
const _config = {
|
|
27
|
+
autoConnect: true,
|
|
28
|
+
attachModels: true,
|
|
29
|
+
transactionKey: 'tx',
|
|
30
|
+
...options
|
|
31
|
+
};
|
|
32
|
+
return async (req, res, next) => {
|
|
33
|
+
try {
|
|
34
|
+
// Ensure database is connected
|
|
35
|
+
if (config.autoConnect && !db.isConnected) {
|
|
36
|
+
await db.connect();
|
|
37
|
+
}
|
|
38
|
+
// Attach database to request
|
|
39
|
+
req.db = db;
|
|
40
|
+
// Attach query helper (preserve original req.query)
|
|
41
|
+
req.dbQuery = async (sql, params, queryOptions) => {
|
|
42
|
+
return await db.query(sql, params, queryOptions);
|
|
43
|
+
};
|
|
44
|
+
// Attach transaction helper
|
|
45
|
+
req.transaction = async (callback) => {
|
|
46
|
+
const tx = await db.transaction();
|
|
47
|
+
try {
|
|
48
|
+
const result = await callback(tx);
|
|
49
|
+
await tx.commit();
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
await tx.rollback();
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
// Attach models if configured
|
|
58
|
+
if (config.attachModels && db.models) {
|
|
59
|
+
req.models = db.models;
|
|
60
|
+
}
|
|
61
|
+
await next();
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
// Log database errors
|
|
65
|
+
console.error('Database middleware error:', error);
|
|
66
|
+
// Pass error to error handler
|
|
67
|
+
if (typeof next === 'function') {
|
|
68
|
+
next(error);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Transaction middleware for automatic transaction management
|
|
78
|
+
*
|
|
79
|
+
* @param {DatabaseManager} db - Database manager instance
|
|
80
|
+
* @param {Object} [options={}] - Transaction options
|
|
81
|
+
* @returns {Function} Middleware function
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* router.post('/transfer', withTransaction(db), async (req, res) => {
|
|
85
|
+
* // All database operations in this handler will be wrapped in a transaction
|
|
86
|
+
* await req.tx.query('UPDATE accounts SET balance = balance - ? WHERE id = ?', [amount, fromId]);
|
|
87
|
+
* await req.tx.query('UPDATE accounts SET balance = balance + ? WHERE id = ?', [amount, toId]);
|
|
88
|
+
* // Transaction is automatically committed on success or rolled back on error
|
|
89
|
+
* });
|
|
90
|
+
*/
|
|
91
|
+
export function withTransaction(db, options = {}) {
|
|
92
|
+
const _config = {
|
|
93
|
+
isolationLevel: null,
|
|
94
|
+
readOnly: false,
|
|
95
|
+
...options
|
|
96
|
+
};
|
|
97
|
+
return async (req, res, next) => {
|
|
98
|
+
const tx = await db.transaction(config);
|
|
99
|
+
req.tx = tx;
|
|
100
|
+
try {
|
|
101
|
+
await next();
|
|
102
|
+
// Commit transaction if not already committed
|
|
103
|
+
if (!tx.isCommitted && !tx.isRolledBack) {
|
|
104
|
+
await tx.commit();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
// Rollback transaction if not already rolled back
|
|
109
|
+
if (!tx.isRolledBack && !tx.isCommitted) {
|
|
110
|
+
await tx.rollback();
|
|
111
|
+
}
|
|
112
|
+
throw error;
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Model binding middleware
|
|
118
|
+
*
|
|
119
|
+
* @param {Function} ModelClass - Model class to bind
|
|
120
|
+
* @param {string} [paramName='id'] - Route parameter name
|
|
121
|
+
* @param {string} [requestKey] - Request key to attach model (defaults to model name)
|
|
122
|
+
* @returns {Function} Middleware function
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* router.get('/users/:id', withModel(User), async (req, res) => {
|
|
126
|
+
* // req.user contains the loaded User model
|
|
127
|
+
* res.json(req.user.toJSON());
|
|
128
|
+
* });
|
|
129
|
+
*
|
|
130
|
+
* router.get('/posts/:postId', withModel(Post, 'postId', 'post'), async (req, res) => {
|
|
131
|
+
* // req.post contains the loaded Post model
|
|
132
|
+
* res.json(req.post.toJSON());
|
|
133
|
+
* });
|
|
134
|
+
*/
|
|
135
|
+
export function withModel(ModelClass, paramName = 'id', requestKey = null) {
|
|
136
|
+
// Handle different model types - class vs object
|
|
137
|
+
let modelName = requestKey;
|
|
138
|
+
if (!modelName) {
|
|
139
|
+
if (ModelClass && ModelClass.name) {
|
|
140
|
+
modelName = ModelClass.name.toLowerCase();
|
|
141
|
+
}
|
|
142
|
+
else if (ModelClass && ModelClass.tableName) {
|
|
143
|
+
modelName = ModelClass.tableName.slice(0, -1); // Remove 's' from table name
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
modelName = 'model'; // fallback
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
const key = modelName;
|
|
150
|
+
return async (req, res, next) => {
|
|
151
|
+
try {
|
|
152
|
+
const paramValue = req.params[paramName];
|
|
153
|
+
if (!paramValue) {
|
|
154
|
+
const _error = new Error(`Parameter '${paramName}' is required`);
|
|
155
|
+
error.status = 400;
|
|
156
|
+
throw error;
|
|
157
|
+
}
|
|
158
|
+
const model = await ModelClass.find(paramValue);
|
|
159
|
+
if (!model) {
|
|
160
|
+
const _error = new Error(`${ModelClass.name} not found`);
|
|
161
|
+
error.status = 404;
|
|
162
|
+
throw error;
|
|
163
|
+
}
|
|
164
|
+
req[key] = model;
|
|
165
|
+
await next();
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
if (typeof next === 'function') {
|
|
169
|
+
next(error);
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
throw error;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Pagination middleware
|
|
179
|
+
*
|
|
180
|
+
* @param {Object} [options={}] - Pagination options
|
|
181
|
+
* @returns {Function} Middleware function
|
|
182
|
+
*
|
|
183
|
+
* @example
|
|
184
|
+
* router.get('/users', withPagination(), async (req, res) => {
|
|
185
|
+
* const users = await User.query()
|
|
186
|
+
* .limit(req.pagination.limit)
|
|
187
|
+
* .offset(req.pagination.offset)
|
|
188
|
+
* .execute();
|
|
189
|
+
*
|
|
190
|
+
* res.json({
|
|
191
|
+
* data: users.rows,
|
|
192
|
+
* pagination: req.pagination
|
|
193
|
+
* });
|
|
194
|
+
* });
|
|
195
|
+
*/
|
|
196
|
+
export function withPagination(options = {}) {
|
|
197
|
+
const _config = {
|
|
198
|
+
defaultLimit: 20,
|
|
199
|
+
maxLimit: 100,
|
|
200
|
+
pageParam: 'page',
|
|
201
|
+
limitParam: 'limit',
|
|
202
|
+
...options
|
|
203
|
+
};
|
|
204
|
+
return async (req, res, next) => {
|
|
205
|
+
const page = Math.max(1, parseInt(req.query[config.pageParam]) || 1);
|
|
206
|
+
const limit = Math.min(config.maxLimit, Math.max(1, parseInt(req.query[config.limitParam]) || config.defaultLimit));
|
|
207
|
+
const offset = (page - 1) * limit;
|
|
208
|
+
req.pagination = {
|
|
209
|
+
page,
|
|
210
|
+
limit,
|
|
211
|
+
offset,
|
|
212
|
+
hasNext: null, // To be set by the handler
|
|
213
|
+
hasPrev: page > 1,
|
|
214
|
+
totalPages: null, // To be set by the handler
|
|
215
|
+
totalCount: null // To be set by the handler
|
|
216
|
+
};
|
|
217
|
+
await next();
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Query validation middleware
|
|
222
|
+
*
|
|
223
|
+
* @param {Object} schema - Validation schema
|
|
224
|
+
* @param {Object} [options={}] - Validation options
|
|
225
|
+
* @returns {Function} Middleware function
|
|
226
|
+
*
|
|
227
|
+
* @example
|
|
228
|
+
* router.get('/users', withQueryValidation({
|
|
229
|
+
* status: { type: 'string', enum: ['active', 'inactive'] },
|
|
230
|
+
* age: { type: 'number', min: 0, max: 120 }
|
|
231
|
+
* }), async (req, res) => {
|
|
232
|
+
* // req.query is validated and sanitized
|
|
233
|
+
* });
|
|
234
|
+
*/
|
|
235
|
+
export function withQueryValidation(schema, options = {}) {
|
|
236
|
+
const _config = {
|
|
237
|
+
stripUnknown: true,
|
|
238
|
+
coerceTypes: true,
|
|
239
|
+
...options
|
|
240
|
+
};
|
|
241
|
+
return async (req, res, next) => {
|
|
242
|
+
try {
|
|
243
|
+
const validatedQuery = {};
|
|
244
|
+
for (const [key, rules] of Object.entries(schema)) {
|
|
245
|
+
const value = req.query[key];
|
|
246
|
+
// Skip if not provided and not required
|
|
247
|
+
if (value === undefined || value === null || value === '') {
|
|
248
|
+
if (rules.required) {
|
|
249
|
+
const _error = new Error(`Query parameter '${key}' is required`);
|
|
250
|
+
error.status = 400;
|
|
251
|
+
throw error;
|
|
252
|
+
}
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
// Type coercion
|
|
256
|
+
let coercedValue = value;
|
|
257
|
+
if (config.coerceTypes) {
|
|
258
|
+
switch (rules.type) {
|
|
259
|
+
case 'number':
|
|
260
|
+
coercedValue = Number(value);
|
|
261
|
+
if (isNaN(coercedValue)) {
|
|
262
|
+
const _error = new Error(`Query parameter '${key}' must be a number`);
|
|
263
|
+
error.status = 400;
|
|
264
|
+
throw error;
|
|
265
|
+
}
|
|
266
|
+
break;
|
|
267
|
+
case 'boolean':
|
|
268
|
+
coercedValue = value === 'true' || value === '1';
|
|
269
|
+
break;
|
|
270
|
+
case 'array':
|
|
271
|
+
coercedValue = Array.isArray(value) ? value : [value];
|
|
272
|
+
break;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
// Validation
|
|
276
|
+
if (rules.enum && !rules.enum.includes(coercedValue)) {
|
|
277
|
+
const _error = new Error(`Query parameter '${key}' must be one of: ${rules.enum.join(', ')}`);
|
|
278
|
+
error.status = 400;
|
|
279
|
+
throw error;
|
|
280
|
+
}
|
|
281
|
+
if (rules.min !== undefined && coercedValue < rules.min) {
|
|
282
|
+
const _error = new Error(`Query parameter '${key}' must be at least ${rules.min}`);
|
|
283
|
+
error.status = 400;
|
|
284
|
+
throw error;
|
|
285
|
+
}
|
|
286
|
+
if (rules.max !== undefined && coercedValue > rules.max) {
|
|
287
|
+
const _error = new Error(`Query parameter '${key}' must be at most ${rules.max}`);
|
|
288
|
+
error.status = 400;
|
|
289
|
+
throw error;
|
|
290
|
+
}
|
|
291
|
+
validatedQuery[key] = coercedValue;
|
|
292
|
+
}
|
|
293
|
+
// Replace query with validated version
|
|
294
|
+
if (!config.stripUnknown) {
|
|
295
|
+
Object.assign(validatedQuery, req.query);
|
|
296
|
+
}
|
|
297
|
+
req.query = validatedQuery;
|
|
298
|
+
await next();
|
|
299
|
+
}
|
|
300
|
+
catch (error) {
|
|
301
|
+
if (typeof next === 'function') {
|
|
302
|
+
next(error);
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
throw error;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Database health check middleware
|
|
312
|
+
*
|
|
313
|
+
* @param {DatabaseManager} db - Database manager instance
|
|
314
|
+
* @param {Object} [options={}] - Health check options
|
|
315
|
+
* @returns {Function} Middleware function
|
|
316
|
+
*
|
|
317
|
+
* @example
|
|
318
|
+
* router.get('/health', withHealthCheck(db), (req, res) => {
|
|
319
|
+
* res.json({ status: 'healthy', database: req.dbHealth });
|
|
320
|
+
* });
|
|
321
|
+
*/
|
|
322
|
+
export function withHealthCheck(db, options = {}) {
|
|
323
|
+
const _config = {
|
|
324
|
+
timeout: 5000,
|
|
325
|
+
includeStats: true,
|
|
326
|
+
...options
|
|
327
|
+
};
|
|
328
|
+
return async (req, res, next) => {
|
|
329
|
+
try {
|
|
330
|
+
const startTime = Date.now();
|
|
331
|
+
// Test database connection
|
|
332
|
+
await Promise.race([
|
|
333
|
+
db.query('SELECT 1'),
|
|
334
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('Health check timeout')), config.timeout))
|
|
335
|
+
]);
|
|
336
|
+
const responseTime = Date.now() - startTime;
|
|
337
|
+
req.dbHealth = {
|
|
338
|
+
status: 'healthy',
|
|
339
|
+
responseTime,
|
|
340
|
+
connected: db.isConnected
|
|
341
|
+
};
|
|
342
|
+
if (config.includeStats) {
|
|
343
|
+
req.dbHealth.stats = db.getStats();
|
|
344
|
+
}
|
|
345
|
+
await next();
|
|
346
|
+
}
|
|
347
|
+
catch (error) {
|
|
348
|
+
req.dbHealth = {
|
|
349
|
+
status: 'unhealthy',
|
|
350
|
+
error: error.message,
|
|
351
|
+
connected: db.isConnected
|
|
352
|
+
};
|
|
353
|
+
await next();
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Connection pooling middleware for request-scoped connections
|
|
359
|
+
*
|
|
360
|
+
* @param {DatabaseManager} db - Database manager instance
|
|
361
|
+
* @param {Object} [options={}] - Pool options
|
|
362
|
+
* @returns {Function} Middleware function
|
|
363
|
+
*
|
|
364
|
+
* @example
|
|
365
|
+
* router.use(withConnectionPool(db, { acquireTimeout: 10000 }));
|
|
366
|
+
*/
|
|
367
|
+
export function withConnectionPool(db, options = {}) {
|
|
368
|
+
const _config = {
|
|
369
|
+
acquireTimeout: 30000,
|
|
370
|
+
releaseOnResponse: true,
|
|
371
|
+
...options
|
|
372
|
+
};
|
|
373
|
+
return async (req, res, next) => {
|
|
374
|
+
let connection = null;
|
|
375
|
+
try {
|
|
376
|
+
// Acquire connection from pool
|
|
377
|
+
connection = await db.pool.acquire(config.acquireTimeout);
|
|
378
|
+
// Attach connection to request
|
|
379
|
+
req.dbConnection = connection;
|
|
380
|
+
// Attach query helper to use this connection
|
|
381
|
+
req.dbQuery = async (sql, params, queryOptions) => {
|
|
382
|
+
return await db.adapter.query(connection, sql, params, queryOptions);
|
|
383
|
+
};
|
|
384
|
+
// Release connection when response finishes
|
|
385
|
+
if (config.releaseOnResponse) {
|
|
386
|
+
res.on('finish', () => {
|
|
387
|
+
if (connection) {
|
|
388
|
+
db.pool.release(connection);
|
|
389
|
+
}
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
await next();
|
|
393
|
+
}
|
|
394
|
+
catch (error) {
|
|
395
|
+
// Release connection on error
|
|
396
|
+
if (connection) {
|
|
397
|
+
db.pool.release(connection);
|
|
398
|
+
}
|
|
399
|
+
throw error;
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
//# sourceMappingURL=middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../../../src/database/middleware.js"],"names":[],"mappings":"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"}
|