jerkjs 2.5.4 → 2.5.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/BENCHMARK_RESULTS.md +60 -0
  2. package/CHANGELOG.md +43 -0
  3. package/ESTADISTICAS_RENDIMIENTO.md +106 -0
  4. package/README.md +142 -423
  5. package/README_LEGACY.md +513 -0
  6. package/debug_hook.js +11 -0
  7. package/doc-2.5/ADMIN_EXTENSION_COMMANDS_MANUAL.md +261 -0
  8. package/doc-2.5/ADMIN_EXTENSION_HOOK_EXAMPLE.md +28 -0
  9. package/doc-2.5/ADMIN_EXTENSION_INTEGRATION_MANUAL.md +232 -0
  10. package/doc-2.5/CACHE_SYSTEM_MAP.md +206 -0
  11. package/doc-2.5/SESSION_SECURITY_FLAGS.md +174 -0
  12. package/doc-2.5/an/303/241lisis-completo-jerk-framework.md +213 -0
  13. package/docs/CACHE_SYSTEM_MAP.md +206 -0
  14. package/docs/SERVER_OPTIMIZATION_NOTES.md +87 -0
  15. package/index.js +7 -1
  16. package/jerk2.5.webp +0 -0
  17. package/lib/admin/AdminExtension.js +436 -0
  18. package/lib/admin/ModuleLoader.js +77 -0
  19. package/lib/admin/config.js +21 -0
  20. package/lib/admin/modules/CacheModule.js +145 -0
  21. package/lib/admin/modules/STATS_MODULE_README.md +98 -0
  22. package/lib/admin/modules/StatsModule.js +140 -0
  23. package/lib/admin/modules/SystemModule.js +140 -0
  24. package/lib/admin/modules/TimeModule.js +95 -0
  25. package/lib/cache/CacheHooks.js +141 -0
  26. package/lib/core/server.js +199 -46
  27. package/lib/middleware/session.js +11 -3
  28. package/lib/mvc/viewEngine.js +26 -1
  29. package/lib/router/RouteMatcher.js +242 -54
  30. package/lib/utils/globalStats.js +16 -0
  31. package/package.json +2 -2
  32. package/@qaLoadModel/controllers/ProductController.js +0 -143
  33. package/@qaLoadModel/controllers/UserController.js +0 -143
  34. package/@qaLoadModel/models/ProductModel.js +0 -41
  35. package/@qaLoadModel/models/UserModel.js +0 -41
  36. package/@qaLoadModel/package.json +0 -22
  37. package/@qaLoadModel/qa_report.md +0 -71
  38. package/@qaLoadModel/results.md +0 -97
  39. package/@qaLoadModel/routes.json +0 -58
  40. package/@qaLoadModel/server.js +0 -43
  41. package/@qaLoadModel/simple-test.js +0 -96
  42. package/@qaLoadModel/test-models.js +0 -144
  43. package/@qaLoadModel/test_endpoints.sh +0 -35
  44. package/@qaLoadModel/test_final.js +0 -89
  45. package/@qaLoadModel/views/products/index.html +0 -45
  46. package/@qaLoadModel/views/products/show.html +0 -27
  47. package/@qaLoadModel/views/users/index.html +0 -44
  48. package/@qaLoadModel/views/users/show.html +0 -26
  49. package/qa/INFORME_QA_JERKJS_ROUTING.md +0 -108
  50. package/qa/informe_qa_fix_enrutamiento.md +0 -93
  51. package/qa-app/controllers/homeController.js +0 -9
  52. package/qa-app/controllers/userController.js +0 -76
  53. package/qa-app/hooks-config.js +0 -65
  54. package/qa-app/models/UserModel.js +0 -36
  55. package/qa-app/package-lock.json +0 -1683
  56. package/qa-app/package.json +0 -25
  57. package/qa-app/public/css/style.css +0 -15
  58. package/qa-app/public/images/logo.png +0 -3
  59. package/qa-app/public/index.html +0 -15
  60. package/qa-app/public/js/main.js +0 -7
  61. package/qa-app/routes/api-routes.json +0 -23
  62. package/qa-app/routes/page-routes.json +0 -16
  63. package/qa-app/routes/static-routes.json +0 -20
  64. package/qa-app/server.js +0 -68
  65. package/qa-app/views/footer.html +0 -3
  66. package/qa-app/views/index.html +0 -20
  67. package/qa-app/views/users.html +0 -20
  68. package/utils/find_file_path.sh +0 -36
  69. /package/{doc2.5.3 → doc-2.5}/manual-mvc-completo.md +0 -0
@@ -1,31 +1,79 @@
1
1
  /**
2
- * Componente especializado para la lógica de enrutado
2
+ * Componente especializado para la lógica de enrutado optimizado
3
3
  * Implementación del componente router/RouteMatcher.js
4
- * JERK Framework v2.1 - Separación de responsabilidades para enrutamiento
4
+ * JERK Framework v2.5.7 - Optimización de rendimiento con índices y pre-filtrado
5
5
  */
6
6
 
7
7
  class RouteMatcher {
8
8
  /**
9
- * Constructor del matcher de rutas
9
+ * Constructor del matcher de rutas optimizado
10
10
  */
11
11
  constructor() {
12
12
  // Cache de expresiones regulares para rutas parametrizadas
13
13
  this.routeRegexCache = new Map();
14
+
15
+ // Índices para optimización
16
+ this.exactRoutes = new Map(); // Rutas exactas indexadas por método y path
17
+ this.routeBuckets = {}; // Rutas organizadas por método, número de segmentos y primer segmento
18
+ this.indexesValid = false;
19
+
20
+ // Referencia al sistema de hooks (se establecerá externamente)
21
+ this.hooks = null;
22
+ }
23
+
24
+ /**
25
+ * Actualiza los índices basados en el conjunto actual de rutas
26
+ * @param {Array} routes - Array de rutas registradas
27
+ */
28
+ updateIndexes(routes) {
29
+ // Limpiar índices existentes
30
+ this.exactRoutes.clear();
31
+ this.routeBuckets = {};
32
+
33
+ // Reconstruir índices
34
+ for (const route of routes) {
35
+ // Indexar rutas exactas
36
+ const methodPathKey = `${route.method}:${route.path}`;
37
+ this.exactRoutes.set(methodPathKey, route);
38
+
39
+ // Organizar rutas en buckets por método, número de segmentos y primer segmento
40
+ const segments = route.path.split('/').filter(s => s !== '');
41
+ const segmentCount = segments.length;
42
+ const firstSegment = segments.length > 0 ? segments[0] : '';
43
+
44
+ // Inicializar estructura de buckets si no existe
45
+ if (!this.routeBuckets[route.method]) {
46
+ this.routeBuckets[route.method] = {};
47
+ }
48
+ if (!this.routeBuckets[route.method][segmentCount]) {
49
+ this.routeBuckets[route.method][segmentCount] = {};
50
+ }
51
+ if (!this.routeBuckets[route.method][segmentCount][firstSegment]) {
52
+ this.routeBuckets[route.method][segmentCount][firstSegment] = [];
53
+ }
54
+
55
+ // Agregar ruta al bucket correspondiente
56
+ this.routeBuckets[route.method][segmentCount][firstSegment].push(route);
57
+ }
58
+
59
+ this.indexesValid = true;
14
60
  }
15
61
 
16
62
  /**
17
- * Método para encontrar una ruta coincidente
63
+ * Método para encontrar una ruta coincidente con optimizaciones
18
64
  * @param {Array} routes - Array de rutas registradas
19
65
  * @param {string} method - Método HTTP
20
66
  * @param {string} pathname - Ruta a buscar
21
67
  * @returns {Object|null} - Objeto de ruta encontrado o null
22
68
  */
23
69
  findRoute(routes, method, pathname) {
24
- // Buscar ruta exacta primero
25
- const exactMatch = routes.find(route =>
26
- route.method === method && route.path === pathname
27
- );
70
+ // Actualizar índices si es necesario
71
+ if (!this.indexesValid || routes.length !== this.getStoredRoutesCount()) {
72
+ this.updateIndexes(routes);
73
+ }
28
74
 
75
+ // Búsqueda por ruta exacta (más rápida)
76
+ const exactMatch = this.findExactMatch(method, pathname);
29
77
  if (exactMatch) {
30
78
  return {
31
79
  route: exactMatch,
@@ -33,45 +81,143 @@ class RouteMatcher {
33
81
  };
34
82
  }
35
83
 
36
- // Buscar rutas estáticas que coincidan exactamente antes que rutas parametrizadas
37
- // Esto permite que rutas estáticas como /css/style.css tengan prioridad sobre rutas parametrizadas
38
- for (const route of routes) {
39
- if (route.method !== method) continue;
40
-
41
- // Verificar si es una ruta estática que coincide exactamente
84
+ // Pre-filtrar rutas candidatas usando índices
85
+ const pathnameSegments = pathname.split('/').filter(s => s !== '');
86
+ const segmentCount = pathnameSegments.length;
87
+ const firstSegment = pathnameSegments.length > 0 ? pathnameSegments[0] : '';
88
+
89
+ // Obtener rutas candidatas basadas en número de segmentos y primer segmento
90
+ const candidateRoutes = this.getCandidateRoutes(method, segmentCount, firstSegment, pathname);
91
+
92
+ // Buscar rutas estáticas que coincidan exactamente
93
+ const staticExactMatch = this.findStaticExactMatch(candidateRoutes, pathname);
94
+ if (staticExactMatch) {
95
+ return {
96
+ route: staticExactMatch,
97
+ params: {}
98
+ };
99
+ }
100
+
101
+ // Buscar rutas parametrizadas entre los candidatos
102
+ const parametrizedMatch = this.findParametrizedMatch(candidateRoutes, pathname);
103
+ if (parametrizedMatch) {
104
+ return parametrizedMatch;
105
+ }
106
+
107
+ // Buscar rutas estáticas (prefijos) entre los candidatos
108
+ const staticPrefixMatch = this.findStaticPrefixMatch(candidateRoutes, pathname);
109
+ if (staticPrefixMatch) {
110
+ return staticPrefixMatch;
111
+ }
112
+
113
+ return null;
114
+ }
115
+
116
+ /**
117
+ * Busca rutas exactas usando el índice
118
+ * @param {string} method - Método HTTP
119
+ * @param {string} pathname - Ruta a buscar
120
+ * @returns {Object|null} - Ruta exacta encontrada o null
121
+ */
122
+ findExactMatch(method, pathname) {
123
+ const methodPathKey = `${method}:${pathname}`;
124
+ return this.exactRoutes.get(methodPathKey) || null;
125
+ }
126
+
127
+ /**
128
+ * Obtiene rutas candidatas basadas en número de segmentos y primer segmento
129
+ * @param {string} method - Método HTTP
130
+ * @param {number} segmentCount - Número de segmentos de la ruta buscada
131
+ * @param {string} firstSegment - Primer segmento de la ruta buscada
132
+ * @param {string} pathname - Ruta completa buscada
133
+ * @returns {Array} - Array de rutas candidatas
134
+ */
135
+ getCandidateRoutes(method, segmentCount, firstSegment, pathname) {
136
+ const candidates = [];
137
+
138
+ // Si existe un bucket para este método, número de segmentos y primer segmento
139
+ if (this.routeBuckets[method] &&
140
+ this.routeBuckets[method][segmentCount] &&
141
+ this.routeBuckets[method][segmentCount][firstSegment]) {
142
+ candidates.push(...this.routeBuckets[method][segmentCount][firstSegment]);
143
+ }
144
+
145
+ // También agregar rutas de otros primeros segmentos para este método y número de segmentos
146
+ // (por si hay rutas parametrizadas que también podrían coincidir)
147
+ if (this.routeBuckets[method] && this.routeBuckets[method][segmentCount]) {
148
+ for (const segment in this.routeBuckets[method][segmentCount]) {
149
+ if (segment !== firstSegment) {
150
+ candidates.push(...this.routeBuckets[method][segmentCount][segment]);
151
+ }
152
+ }
153
+ }
154
+
155
+ // Agregar rutas estáticas que podrían coincidir por prefijo
156
+ if (this.routeBuckets[method]) {
157
+ for (const count in this.routeBuckets[method]) {
158
+ for (const segment in this.routeBuckets[method][count]) {
159
+ const routes = this.routeBuckets[method][count][segment];
160
+ for (const route of routes) {
161
+ if (route.isStatic && pathname.startsWith(route.path)) {
162
+ candidates.push(route);
163
+ }
164
+ }
165
+ }
166
+ }
167
+ }
168
+
169
+ return candidates;
170
+ }
171
+
172
+ /**
173
+ * Busca rutas estáticas con coincidencia exacta entre candidatos
174
+ * @param {Array} candidateRoutes - Rutas candidatas
175
+ * @param {string} pathname - Ruta a buscar
176
+ * @returns {Object|null} - Ruta estática exacta encontrada o null
177
+ */
178
+ findStaticExactMatch(candidateRoutes, pathname) {
179
+ for (const route of candidateRoutes) {
42
180
  if (route.isStatic && route.path === pathname) {
43
- return {
44
- route: route,
45
- params: {}
46
- };
181
+ return route;
47
182
  }
48
183
  }
184
+ return null;
185
+ }
49
186
 
50
- // Buscar rutas parametrizadas
51
- // Pero antes de devolver una ruta parametrizada, verificar si hay una ruta estática más específica
52
- const parametrizedMatches = [];
53
- for (const route of routes) {
54
- if (route.method !== method) continue;
55
-
56
- // Convertir ruta parametrizada a expresión regular
57
- const routeRegex = this.pathToRegex(route.path);
58
- const match = pathname.match(routeRegex);
59
-
60
- if (match) {
61
- const params = this.extractParams(route.path, pathname);
62
- parametrizedMatches.push({
63
- route: route,
64
- params: params
65
- });
187
+ /**
188
+ * Busca rutas parametrizadas entre candidatos
189
+ * @param {Array} candidateRoutes - Rutas candidatas
190
+ * @param {string} pathname - Ruta a buscar
191
+ * @returns {Object|null} - Ruta parametrizada encontrada o null
192
+ */
193
+ findParametrizedMatch(candidateRoutes, pathname) {
194
+ for (const route of candidateRoutes) {
195
+ if (this.isParametrizedRoute(route.path)) {
196
+ // Convertir ruta parametrizada a expresión regular
197
+ const routeRegex = this.pathToRegex(route.path);
198
+ const match = pathname.match(routeRegex);
199
+
200
+ if (match) {
201
+ const params = this.extractParams(route.path, pathname);
202
+ return {
203
+ route: route,
204
+ params: params
205
+ };
206
+ }
66
207
  }
67
208
  }
209
+ return null;
210
+ }
68
211
 
69
- // Buscar rutas estáticas (prefijos)
212
+ /**
213
+ * Busca rutas estáticas por prefijo entre candidatos
214
+ * @param {Array} candidateRoutes - Rutas candidatas
215
+ * @param {string} pathname - Ruta a buscar
216
+ * @returns {Object|null} - Ruta estática por prefijo encontrada o null
217
+ */
218
+ findStaticPrefixMatch(candidateRoutes, pathname) {
70
219
  const staticMatches = [];
71
- for (const route of routes) {
72
- if (route.method !== method) continue;
73
-
74
- // Para rutas estáticas, verificar si la ruta solicitada comienza con el prefijo de la ruta estática
220
+ for (const route of candidateRoutes) {
75
221
  if (route.isStatic && pathname.startsWith(route.path)) {
76
222
  // Verificar que sea exactamente el prefijo o que haya una barra después del prefijo
77
223
  const remainingPath = pathname.substring(route.path.length);
@@ -85,27 +231,40 @@ class RouteMatcher {
85
231
  }
86
232
  }
87
233
 
88
- // Prioridad: si hay rutas estáticas que coinciden, y la solicitud parece ser para un archivo
89
- // (tiene extensión), dar prioridad a la ruta estática más específica
90
- const hasFileExtension = /\.[^.]+$/.test(pathname);
91
-
92
- if (hasFileExtension && staticMatches.length > 0) {
234
+ if (staticMatches.length > 0) {
93
235
  // Ordenar por especificidad (longitud del prefijo, descendente) y tomar la más específica
94
236
  staticMatches.sort((a, b) => b.specificity - a.specificity);
95
- // Para solicitudes de archivos, dar prioridad a rutas estáticas más específicas
96
- return staticMatches[0]; // Devolver la coincidencia estática más específica
97
- } else if (parametrizedMatches.length > 0) {
98
- // Para solicitudes sin extensión o rutas API, dar prioridad a rutas parametrizadas
99
- return parametrizedMatches[0]; // Devolver la primera coincidencia parametrizada
100
- } else if (staticMatches.length > 0) {
101
- // Si no hay coincidencias parametrizadas, usar la estática más específica
102
- staticMatches.sort((a, b) => b.specificity - a.specificity);
103
237
  return staticMatches[0];
104
238
  }
105
239
 
106
240
  return null;
107
241
  }
108
242
 
243
+ /**
244
+ * Determina si una ruta es parametrizada
245
+ * @param {string} path - Ruta a verificar
246
+ * @returns {boolean} - True si la ruta contiene parámetros
247
+ */
248
+ isParametrizedRoute(path) {
249
+ return path.includes(':');
250
+ }
251
+
252
+ /**
253
+ * Obtiene el conteo total de rutas almacenadas en índices
254
+ * @returns {number} - Número total de rutas indexadas
255
+ */
256
+ getStoredRoutesCount() {
257
+ let count = 0;
258
+ for (const method in this.routeBuckets) {
259
+ for (const segmentCount in this.routeBuckets[method]) {
260
+ for (const firstSegment in this.routeBuckets[method][segmentCount]) {
261
+ count += this.routeBuckets[method][segmentCount][firstSegment].length;
262
+ }
263
+ }
264
+ }
265
+ return count;
266
+ }
267
+
109
268
  /**
110
269
  * Convierte una ruta con parámetros a expresión regular
111
270
  * @param {string} path - Ruta con posibles parámetros
@@ -131,8 +290,20 @@ class RouteMatcher {
131
290
  const regexPath = escapedPath.replace(/:([a-zA-Z0-9_]+)/g, '([^/]+?)');
132
291
  const regex = new RegExp(`^${regexPath}$`);
133
292
 
134
- // Almacenar en caché
135
- this.routeRegexCache.set(path, regex);
293
+ // Verificar con hook si se debe cachear esta expresión regular
294
+ const shouldCache = this.hooks ?
295
+ this.hooks.applyFilters('should_cache_route_regex', true, path, regex) : true;
296
+
297
+ if (shouldCache) {
298
+ // Almacenar en caché
299
+ this.routeRegexCache.set(path, regex);
300
+
301
+ // Disparar hook después de cachear
302
+ if (this.hooks) {
303
+ this.hooks.doAction('route_regex_cached', path, regex);
304
+ }
305
+ }
306
+
136
307
  return regex;
137
308
  }
138
309
 
@@ -169,6 +340,23 @@ class RouteMatcher {
169
340
 
170
341
  return params;
171
342
  }
343
+
344
+ /**
345
+ * Limpia el caché de expresiones regulares
346
+ */
347
+ clearCache() {
348
+ // Disparar hook antes de limpiar el caché
349
+ if (this.hooks) {
350
+ this.hooks.doAction('before_route_regex_cache_clear', this);
351
+ }
352
+
353
+ this.routeRegexCache.clear();
354
+
355
+ // Disparar hook después de limpiar el caché
356
+ if (this.hooks) {
357
+ this.hooks.doAction('route_regex_cache_cleared');
358
+ }
359
+ }
172
360
  }
173
361
 
174
362
  module.exports = RouteMatcher;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Almacenamiento global de estadísticas para el framework JERK
3
+ */
4
+
5
+ // Crear un objeto global para almacenar estadísticas
6
+ const globalStats = {
7
+ requestsProcessed: 0,
8
+ responsesSent: 0,
9
+ requestBytes: 0,
10
+ responseBytes: 0,
11
+ routeAccesses: new Map(), // Contador de accesos por ruta
12
+ endpointHits: new Map(), // Contador de hits por endpoint
13
+ lastRequests: [] // Últimas solicitudes para análisis
14
+ };
15
+
16
+ module.exports = { globalStats };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "jerkjs",
3
- "version": "2.5.4",
4
- "description": "JERK Framework v2.5.4 - A comprehensive framework for building secure and scalable APIs with frontend support, sessions, template engine, integration with qbuilderjs, complete MVC architecture with models, enhanced route loading from directory, improved model loading system, and fixed routing issues with static and parametrized routes",
3
+ "version": "2.5.8",
4
+ "description": "JERK Framework v2.5.8 - A comprehensive framework for building secure and scalable APIs with frontend support, sessions, template engine, integration with qbuilderjs, complete MVC architecture with models, enhanced route loading from directory, improved model loading system, administration extension, and fixed routing issues with static and parametrized routes",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
7
  "test": "echo \"Error: no test specified\" && exit 1",
@@ -1,143 +0,0 @@
1
- // controllers/ProductController.js
2
- const { ControllerBase } = require('../../index.js');
3
-
4
- class ProductController extends ControllerBase {
5
- constructor() {
6
- super();
7
- }
8
-
9
- // Método para mostrar la lista de productos
10
- async index(req, res) {
11
- try {
12
- // Obtener el adaptador desde el modelManager en la solicitud
13
- const adapter = req.modelManager?.getAdapter('memory') || null;
14
-
15
- // Cargar el modelo de productos con el adaptador
16
- const productModel = await this.loadModel('ProductModel', {
17
- adapter: adapter
18
- });
19
-
20
- // Obtener todos los productos
21
- const products = await productModel.getAllProducts();
22
-
23
- // Renderizar la vista con los datos
24
- res.render('products/index', {
25
- title: 'Lista de Productos',
26
- products: products,
27
- message: 'Productos disponibles en el sistema'
28
- });
29
- } catch (error) {
30
- console.error('Error en ProductController.index:', error);
31
- res.writeHead(500, { 'Content-Type': 'application/json' });
32
- res.end(JSON.stringify({ error: 'Error interno del servidor' }));
33
- }
34
- }
35
-
36
- // Método para mostrar un producto específico
37
- async show(req, res) {
38
- try {
39
- // Obtener el adaptador desde el modelManager en la solicitud
40
- const adapter = req.modelManager?.getAdapter('memory') || null;
41
-
42
- // Cargar el modelo de productos con el adaptador
43
- const productModel = await this.loadModel('ProductModel', {
44
- adapter: adapter
45
- });
46
-
47
- // Obtener el ID de los parámetros
48
- const id = req.params.id;
49
-
50
- // Obtener el producto específico
51
- const product = await productModel.getProductById(id);
52
-
53
- if (!product) {
54
- res.writeHead(404, { 'Content-Type': 'application/json' });
55
- res.end(JSON.stringify({ error: 'Producto no encontrado' }));
56
- return;
57
- }
58
-
59
- // Renderizar la vista con los datos
60
- res.render('products/show', {
61
- title: `Producto #${id}`,
62
- product: product
63
- });
64
- } catch (error) {
65
- console.error('Error en ProductController.show:', error);
66
- res.writeHead(500, { 'Content-Type': 'application/json' });
67
- res.end(JSON.stringify({ error: 'Error interno del servidor' }));
68
- }
69
- }
70
-
71
- // Método para crear un nuevo producto
72
- async create(req, res) {
73
- try {
74
- // Obtener el adaptador desde el modelManager en la solicitud
75
- const adapter = req.modelManager?.getAdapter('memory') || null;
76
-
77
- // Cargar el modelo de productos con el adaptador
78
- const productModel = await this.loadModel('ProductModel', {
79
- adapter: adapter
80
- });
81
-
82
- // Obtener los datos del cuerpo de la solicitud
83
- const productData = req.body;
84
-
85
- // Crear el nuevo producto
86
- const productId = await productModel.createProduct(productData);
87
-
88
- // Responder con éxito
89
- res.writeHead(201, { 'Content-Type': 'application/json' });
90
- res.end(JSON.stringify({
91
- success: true,
92
- id: productId,
93
- message: 'Producto creado exitosamente'
94
- }));
95
- } catch (error) {
96
- console.error('Error en ProductController.create:', error);
97
- res.writeHead(500, { 'Content-Type': 'application/json' });
98
- res.end(JSON.stringify({ error: 'Error interno del servidor' }));
99
- }
100
- }
101
-
102
- // Método para buscar productos por categoría
103
- async searchByCategory(req, res) {
104
- try {
105
- // Obtener el adaptador desde el modelManager en la solicitud
106
- const adapter = req.modelManager?.getAdapter('memory') || null;
107
-
108
- // Cargar el modelo de productos con el adaptador
109
- const productModel = await this.loadModel('ProductModel', {
110
- adapter: adapter
111
- });
112
-
113
- // Obtener la categoría de los parámetros de consulta
114
- const category = req.query.category || '';
115
-
116
- // Buscar productos por categoría
117
- const products = await productModel.getProductsByCategory(category);
118
-
119
- // Responder con los resultados
120
- res.writeHead(200, { 'Content-Type': 'application/json' });
121
- res.end(JSON.stringify({
122
- success: true,
123
- results: products,
124
- count: products.length
125
- }));
126
- } catch (error) {
127
- console.error('Error en ProductController.searchByCategory:', error);
128
- res.writeHead(500, { 'Content-Type': 'application/json' });
129
- res.end(JSON.stringify({ error: 'Error interno del servidor' }));
130
- }
131
- }
132
- }
133
-
134
- // Crear instancia del controlador
135
- const productController = new ProductController();
136
-
137
- // Preservar el contexto 'this' para cada método
138
- productController.index = productController.index.bind(productController);
139
- productController.show = productController.show.bind(productController);
140
- productController.create = productController.create.bind(productController);
141
- productController.searchByCategory = productController.searchByCategory.bind(productController);
142
-
143
- module.exports = productController;
@@ -1,143 +0,0 @@
1
- // controllers/UserController.js
2
- const { ControllerBase } = require('../../index.js');
3
-
4
- class UserController extends ControllerBase {
5
- constructor() {
6
- super();
7
- }
8
-
9
- // Método para mostrar la lista de usuarios
10
- async index(req, res) {
11
- try {
12
- // Obtener el adaptador desde el modelManager en la solicitud
13
- const adapter = req.modelManager?.getAdapter('memory') || null;
14
-
15
- // Cargar el modelo de usuarios con el adaptador
16
- const userModel = await this.loadModel('UserModel', {
17
- adapter: adapter
18
- });
19
-
20
- // Obtener todos los usuarios
21
- const users = await userModel.getAllUsers();
22
-
23
- // Renderizar la vista con los datos
24
- res.render('users/index', {
25
- title: 'Lista de Usuarios',
26
- users: users,
27
- message: 'Usuarios registrados en el sistema'
28
- });
29
- } catch (error) {
30
- console.error('Error en UserController.index:', error);
31
- res.writeHead(500, { 'Content-Type': 'application/json' });
32
- res.end(JSON.stringify({ error: 'Error interno del servidor' }));
33
- }
34
- }
35
-
36
- // Método para mostrar un usuario específico
37
- async show(req, res) {
38
- try {
39
- // Obtener el adaptador desde el modelManager en la solicitud
40
- const adapter = req.modelManager?.getAdapter('memory') || null;
41
-
42
- // Cargar el modelo de usuarios con el adaptador
43
- const userModel = await this.loadModel('UserModel', {
44
- adapter: adapter
45
- });
46
-
47
- // Obtener el ID de los parámetros
48
- const id = req.params.id;
49
-
50
- // Obtener el usuario específico
51
- const user = await userModel.getUserById(id);
52
-
53
- if (!user) {
54
- res.writeHead(404, { 'Content-Type': 'application/json' });
55
- res.end(JSON.stringify({ error: 'Usuario no encontrado' }));
56
- return;
57
- }
58
-
59
- // Renderizar la vista con los datos
60
- res.render('users/show', {
61
- title: `Usuario #${id}`,
62
- user: user
63
- });
64
- } catch (error) {
65
- console.error('Error en UserController.show:', error);
66
- res.writeHead(500, { 'Content-Type': 'application/json' });
67
- res.end(JSON.stringify({ error: 'Error interno del servidor' }));
68
- }
69
- }
70
-
71
- // Método para crear un nuevo usuario
72
- async create(req, res) {
73
- try {
74
- // Obtener el adaptador desde el modelManager en la solicitud
75
- const adapter = req.modelManager?.getAdapter('memory') || null;
76
-
77
- // Cargar el modelo de usuarios con el adaptador
78
- const userModel = await this.loadModel('UserModel', {
79
- adapter: adapter
80
- });
81
-
82
- // Obtener los datos del cuerpo de la solicitud
83
- const userData = req.body;
84
-
85
- // Crear el nuevo usuario
86
- const userId = await userModel.createUser(userData);
87
-
88
- // Responder con éxito
89
- res.writeHead(201, { 'Content-Type': 'application/json' });
90
- res.end(JSON.stringify({
91
- success: true,
92
- id: userId,
93
- message: 'Usuario creado exitosamente'
94
- }));
95
- } catch (error) {
96
- console.error('Error en UserController.create:', error);
97
- res.writeHead(500, { 'Content-Type': 'application/json' });
98
- res.end(JSON.stringify({ error: 'Error interno del servidor' }));
99
- }
100
- }
101
-
102
- // Método para buscar usuarios por nombre
103
- async search(req, res) {
104
- try {
105
- // Obtener el adaptador desde el modelManager en la solicitud
106
- const adapter = req.modelManager?.getAdapter('memory') || null;
107
-
108
- // Cargar el modelo de usuarios con el adaptador
109
- const userModel = await this.loadModel('UserModel', {
110
- adapter: adapter
111
- });
112
-
113
- // Obtener el término de búsqueda de los parámetros de consulta
114
- const name = req.query.name || '';
115
-
116
- // Buscar usuarios por nombre
117
- const users = await userModel.getUsersByName(name);
118
-
119
- // Responder con los resultados
120
- res.writeHead(200, { 'Content-Type': 'application/json' });
121
- res.end(JSON.stringify({
122
- success: true,
123
- results: users,
124
- count: users.length
125
- }));
126
- } catch (error) {
127
- console.error('Error en UserController.search:', error);
128
- res.writeHead(500, { 'Content-Type': 'application/json' });
129
- res.end(JSON.stringify({ error: 'Error interno del servidor' }));
130
- }
131
- }
132
- }
133
-
134
- // Crear instancia del controlador
135
- const userController = new UserController();
136
-
137
- // Preservar el contexto 'this' para cada método
138
- userController.index = userController.index.bind(userController);
139
- userController.show = userController.show.bind(userController);
140
- userController.create = userController.create.bind(userController);
141
- userController.search = userController.search.bind(userController);
142
-
143
- module.exports = userController;