jerkjs 2.1.6 → 2.2.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.
Files changed (54) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +202 -5
  3. package/index.js +29 -4
  4. package/lib/core/server.js +328 -27
  5. package/lib/loader/routeLoader.js +148 -117
  6. package/lib/middleware/compressor.js +87 -18
  7. package/lib/mvc/GenericAdapter.js +136 -0
  8. package/lib/mvc/MariaDBAdapter.js +315 -0
  9. package/lib/mvc/MemoryAdapter.js +269 -0
  10. package/lib/mvc/ModelControllerExample.js +285 -0
  11. package/lib/mvc/controllerBase.js +60 -0
  12. package/lib/mvc/modelBase.js +383 -0
  13. package/lib/mvc/modelManager.js +284 -0
  14. package/lib/mvc/userModel.js +265 -0
  15. package/lib/mvc/viewEngine.js +32 -1
  16. package/lib/utils/mimeType.js +62 -0
  17. package/package.json +5 -3
  18. package/JERK_FRAMEWORK_DIAGRAM.txt +0 -492
  19. package/JERK_FRAMEWORK_DIAGRAM_MERMAID.mmd +0 -124
  20. package/JERK_FRAMEWORK_DOCUMENTATION.md +0 -527
  21. package/LICENSE +0 -201
  22. package/README_EN.md +0 -230
  23. package/README_PT.md +0 -230
  24. package/docs/ARQUITECTURA_ROUTES.md +0 -140
  25. package/docs/EXTENSION_MANUAL.md +0 -955
  26. package/docs/FIREWALL_MANUAL.md +0 -416
  27. package/docs/HOOK-2.0.md +0 -512
  28. package/docs/HOOKS_REFERENCE_IMPROVED.md +0 -596
  29. package/docs/MANUAL_API_SDK.md +0 -536
  30. package/docs/MARIADB_TOKENS_IMPLEMENTATION.md +0 -110
  31. package/docs/MIDDLEWARE_MANUAL.md +0 -518
  32. package/docs/OAUTH2_GOOGLE_MANUAL.md +0 -405
  33. package/docs/ROUTING_WITHOUT_JSON_GUIDE.md +0 -454
  34. package/docs/frontend-and-sessions.md +0 -353
  35. package/docs/guia_inicio_rapido_jerkjs.md +0 -113
  36. package/examples/examples.arj +0 -0
  37. package/standard/CompressionTestController.js +0 -56
  38. package/standard/HealthController.js +0 -16
  39. package/standard/HomeController.js +0 -12
  40. package/standard/ProductController.js +0 -18
  41. package/standard/README.md +0 -47
  42. package/standard/UserController.js +0 -23
  43. package/standard/package.json +0 -22
  44. package/standard/routes.json +0 -65
  45. package/standard/server.js +0 -140
  46. package/standardA/controllers/AuthController.js +0 -82
  47. package/standardA/controllers/HomeController.js +0 -19
  48. package/standardA/controllers/UserController.js +0 -41
  49. package/standardA/server.js +0 -311
  50. package/standardA/views/auth/dashboard.html +0 -51
  51. package/standardA/views/auth/login.html +0 -47
  52. package/standardA/views/index.html +0 -32
  53. package/standardA/views/users/detail.html +0 -28
  54. package/standardA/views/users/list.html +0 -36
@@ -83,12 +83,29 @@ class RouteLoader {
83
83
  throw new Error(`La ruta en la posición ${i} no tiene propiedad 'method'`);
84
84
  }
85
85
 
86
- if (!route.controller) {
87
- throw new Error(`La ruta en la posición ${i} no tiene propiedad 'controller'`);
88
- }
86
+ // Verificar si es una ruta estática
87
+ if (route.static) {
88
+ if (typeof route.static !== 'object' || route.static === null) {
89
+ throw new Error(`La ruta en la posición ${i} tiene una propiedad 'static' inválida`);
90
+ }
91
+
92
+ if (!route.static.dir) {
93
+ throw new Error(`La ruta en la posición ${i} tiene una configuración 'static' sin directorio 'dir'`);
94
+ }
95
+
96
+ // El método debe ser GET para rutas estáticas
97
+ if (route.method.toUpperCase() !== 'GET') {
98
+ throw new Error(`Las rutas estáticas deben usar el método GET, no ${route.method}`);
99
+ }
100
+ } else {
101
+ // Validación normal para rutas dinámicas
102
+ if (!route.controller) {
103
+ throw new Error(`La ruta en la posición ${i} no tiene propiedad 'controller'`);
104
+ }
89
105
 
90
- if (!route.handler) {
91
- throw new Error(`La ruta en la posición ${i} no tiene propiedad 'handler'`);
106
+ if (!route.handler) {
107
+ throw new Error(`La ruta en la posición ${i} no tiene propiedad 'handler'`);
108
+ }
92
109
  }
93
110
 
94
111
  // Validar que el content-type sea un string si está presente
@@ -104,134 +121,148 @@ class RouteLoader {
104
121
  * @param {Object} route - Objeto de ruta a cargar
105
122
  */
106
123
  async loadSingleRoute(server, route) {
107
- // Obtener el controlador
108
- const controllerPath = path.resolve(process.cwd(), route.controller);
109
- let controllerModule;
110
-
111
- try {
112
- controllerModule = require(controllerPath);
113
- } catch (error) {
114
- throw new Error(`No se pudo cargar el controlador: ${route.controller}. Error: ${error.message}`);
115
- }
124
+ // Verificar si es una ruta estática
125
+ if (route.static) {
126
+ // Para rutas estáticas, simplemente llamar a addRoute con la configuración estática
127
+ server.addRoute({
128
+ method: route.method,
129
+ path: route.path,
130
+ static: route.static,
131
+ contentType: route.contentType,
132
+ auth: route.auth,
133
+ authOptions: route.authOptions
134
+ });
135
+ } else {
136
+ // Lógica existente para rutas dinámicas
137
+ // Obtener el controlador
138
+ const controllerPath = path.resolve(process.cwd(), route.controller);
139
+ let controllerModule;
140
+
141
+ try {
142
+ controllerModule = require(controllerPath);
143
+ } catch (error) {
144
+ throw new Error(`No se pudo cargar el controlador: ${route.controller}. Error: ${error.message}`);
145
+ }
116
146
 
117
- // Obtener el handler del controlador
118
- const handler = controllerModule[route.handler];
119
- if (typeof handler !== 'function') {
120
- throw new Error(`El handler '${route.handler}' no es una función en el controlador: ${route.controller}`);
121
- }
147
+ // Obtener el handler del controlador
148
+ const handler = controllerModule[route.handler];
149
+ if (typeof handler !== 'function') {
150
+ throw new Error(`El handler '${route.handler}' no es una función en el controlador: ${route.controller}`);
151
+ }
122
152
 
123
- // Crear un handler que establezca el content-type si está especificado
124
- let finalHandler = handler;
153
+ // Crear un handler que establezca el content-type si está especificado
154
+ let finalHandler = handler;
125
155
 
126
- if (route.contentType) {
127
- finalHandler = async (req, res) => {
128
- // Establecer el content-type antes de ejecutar el handler original
129
- res.setHeader('Content-Type', route.contentType);
156
+ if (route.contentType) {
157
+ finalHandler = async (req, res) => {
158
+ // Establecer el content-type antes de ejecutar el handler original
159
+ res.setHeader('Content-Type', route.contentType);
130
160
 
131
- // Si el handler es asíncrono, esperarlo
132
- if (handler.constructor.name === 'AsyncFunction') {
133
- await handler(req, res);
134
- } else {
135
- handler(req, res);
136
- }
137
- };
138
- }
161
+ // Si el handler es asíncrono, esperarlo
162
+ if (handler.constructor.name === 'AsyncFunction') {
163
+ await handler(req, res);
164
+ } else {
165
+ handler(req, res);
166
+ }
167
+ };
168
+ }
139
169
 
140
- // Aplicar autenticación si está especificada
141
- if (route.auth && route.auth !== 'none') {
142
- // Verificar si es autenticación de sesión
143
- if (route.auth === 'session') {
144
- // Verificar si el servidor tiene sessionManager
145
- if (server.sessionManager) {
146
- // Importar el middleware de autenticación de sesión
147
- const { sessionAuth } = require('../middleware/session');
148
- const authMiddleware = sessionAuth(server.sessionManager, route.authOptions || {});
149
-
150
- // Crear un nuevo handler que ejecute la autenticación primero
151
- const authenticatedHandler = async (req, res) => {
152
- try {
153
- // Ejecutar el middleware de autenticación y esperar a que se resuelva
154
- await new Promise((resolve, reject) => {
155
- const next = () => resolve();
156
- const result = authMiddleware(req, res, next);
157
-
158
- // Si authMiddleware devuelve una promesa, esperarla
159
- if (result && typeof result.then === 'function') {
160
- result.then(resolve).catch(reject);
170
+ // Aplicar autenticación si está especificada
171
+ if (route.auth && route.auth !== 'none') {
172
+ // Verificar si es autenticación de sesión
173
+ if (route.auth === 'session') {
174
+ // Verificar si el servidor tiene sessionManager
175
+ if (server.sessionManager) {
176
+ // Importar el middleware de autenticación de sesión
177
+ const { sessionAuth } = require('../middleware/session');
178
+ const authMiddleware = sessionAuth(server.sessionManager, route.authOptions || {});
179
+
180
+ // Crear un nuevo handler que ejecute la autenticación primero
181
+ const authenticatedHandler = async (req, res) => {
182
+ try {
183
+ // Ejecutar el middleware de autenticación y esperar a que se resuelva
184
+ await new Promise((resolve, reject) => {
185
+ const next = () => resolve();
186
+ const result = authMiddleware(req, res, next);
187
+
188
+ // Si authMiddleware devuelve una promesa, esperarla
189
+ if (result && typeof result.then === 'function') {
190
+ result.then(resolve).catch(reject);
191
+ }
192
+ });
193
+
194
+ // Si la autenticación fue exitosa (no se envió respuesta aún), ejecutar el handler original
195
+ if (!res.headersSent) {
196
+ // Si el handler es asíncrono, esperarlo también
197
+ if (finalHandler.constructor.name === 'AsyncFunction') {
198
+ await finalHandler(req, res);
199
+ } else {
200
+ finalHandler(req, res);
201
+ }
161
202
  }
162
- });
163
-
164
- // Si la autenticación fue exitosa (no se envió respuesta aún), ejecutar el handler original
165
- if (!res.headersSent) {
166
- // Si el handler es asíncrono, esperarlo también
167
- if (finalHandler.constructor.name === 'AsyncFunction') {
168
- await finalHandler(req, res);
169
- } else {
170
- finalHandler(req, res);
203
+ } catch (error) {
204
+ console.error('Error en el manejo de autenticación de sesión:', error);
205
+ if (!res.headersSent) {
206
+ res.writeHead(500, { 'Content-Type': 'application/json' });
207
+ res.end(JSON.stringify({ error: 'Error interno del servidor' }));
171
208
  }
172
209
  }
173
- } catch (error) {
174
- console.error('Error en el manejo de autenticación de sesión:', error);
175
- if (!res.headersSent) {
176
- res.writeHead(500, { 'Content-Type': 'application/json' });
177
- res.end(JSON.stringify({ error: 'Error interno del servidor' }));
178
- }
179
- }
180
- };
210
+ };
181
211
 
182
- // Agregar la ruta con el handler autenticado
183
- server.addRoute(route.method, route.path, authenticatedHandler);
212
+ // Agregar la ruta con el handler autenticado
213
+ server.addRoute(route.method, route.path, authenticatedHandler);
214
+ } else {
215
+ // Si no hay sessionManager en el servidor, agregar la ruta normalmente
216
+ server.addRoute(route.method, route.path, finalHandler);
217
+ }
184
218
  } else {
185
- // Si no hay sessionManager en el servidor, agregar la ruta normalmente
186
- server.addRoute(route.method, route.path, finalHandler);
187
- }
188
- } else {
189
- // Usar el authenticator del servidor si está disponible para otros tipos de autenticación
190
- if (server.authenticator) {
191
- const authMiddleware = server.authenticator.authenticate(route.auth, route.authOptions || {});
192
-
193
- // Crear un nuevo handler que ejecute la autenticación primero
194
- const authenticatedHandler = async (req, res) => {
195
- try {
196
- // Ejecutar el middleware de autenticación y esperar a que se resuelva
197
- await new Promise((resolve, reject) => {
198
- const next = () => resolve();
199
- const result = authMiddleware(req, res, next);
200
-
201
- // Si authMiddleware devuelve una promesa, esperarla
202
- if (result && typeof result.then === 'function') {
203
- result.then(resolve).catch(reject);
219
+ // Usar el authenticator del servidor si está disponible para otros tipos de autenticación
220
+ if (server.authenticator) {
221
+ const authMiddleware = server.authenticator.authenticate(route.auth, route.authOptions || {});
222
+
223
+ // Crear un nuevo handler que ejecute la autenticación primero
224
+ const authenticatedHandler = async (req, res) => {
225
+ try {
226
+ // Ejecutar el middleware de autenticación y esperar a que se resuelva
227
+ await new Promise((resolve, reject) => {
228
+ const next = () => resolve();
229
+ const result = authMiddleware(req, res, next);
230
+
231
+ // Si authMiddleware devuelve una promesa, esperarla
232
+ if (result && typeof result.then === 'function') {
233
+ result.then(resolve).catch(reject);
234
+ }
235
+ });
236
+
237
+ // Si la autenticación fue exitosa (no se envió respuesta aún), ejecutar el handler original
238
+ if (!res.headersSent) {
239
+ // Si el handler es asíncrono, esperarlo también
240
+ if (finalHandler.constructor.name === 'AsyncFunction') {
241
+ await finalHandler(req, res);
242
+ } else {
243
+ finalHandler(req, res);
244
+ }
204
245
  }
205
- });
206
-
207
- // Si la autenticación fue exitosa (no se envió respuesta aún), ejecutar el handler original
208
- if (!res.headersSent) {
209
- // Si el handler es asíncrono, esperarlo también
210
- if (finalHandler.constructor.name === 'AsyncFunction') {
211
- await finalHandler(req, res);
212
- } else {
213
- finalHandler(req, res);
246
+ } catch (error) {
247
+ console.error('Error en el manejo de autenticación:', error);
248
+ if (!res.headersSent) {
249
+ res.writeHead(500, { 'Content-Type': 'application/json' });
250
+ res.end(JSON.stringify({ error: 'Error interno del servidor' }));
214
251
  }
215
252
  }
216
- } catch (error) {
217
- console.error('Error en el manejo de autenticación:', error);
218
- if (!res.headersSent) {
219
- res.writeHead(500, { 'Content-Type': 'application/json' });
220
- res.end(JSON.stringify({ error: 'Error interno del servidor' }));
221
- }
222
- }
223
- };
253
+ };
224
254
 
225
- // Agregar la ruta con el handler autenticado
226
- server.addRoute(route.method, route.path, authenticatedHandler);
227
- } else {
228
- // Si no hay authenticator en el servidor, agregar la ruta normalmente
229
- server.addRoute(route.method, route.path, finalHandler);
255
+ // Agregar la ruta con el handler autenticado
256
+ server.addRoute(route.method, route.path, authenticatedHandler);
257
+ } else {
258
+ // Si no hay authenticator en el servidor, agregar la ruta normalmente
259
+ server.addRoute(route.method, route.path, finalHandler);
260
+ }
230
261
  }
262
+ } else {
263
+ // Si no hay autenticación requerida, agregar la ruta normalmente
264
+ server.addRoute(route.method, route.path, finalHandler);
231
265
  }
232
- } else {
233
- // Si no hay autenticación requerida, agregar la ruta normalmente
234
- server.addRoute(route.method, route.path, finalHandler);
235
266
  }
236
267
  }
237
268
 
@@ -64,6 +64,39 @@ class Compressor {
64
64
  // Array para almacenar los chunks de la respuesta
65
65
  const responseChunks = [];
66
66
 
67
+ // Variables para almacenar información del encabezado
68
+ let statusCode = 200;
69
+ let responseHeaders = {};
70
+
71
+ // Sobrescribir res.writeHead para capturar los encabezados
72
+ res.writeHead = (code, headers) => {
73
+ statusCode = code;
74
+ if (typeof headers === 'object' && headers !== null) {
75
+ responseHeaders = { ...headers };
76
+ } else if (typeof headers === 'string') {
77
+ // Si headers es una string, intentar parsearla
78
+ try {
79
+ // Esto es un caso especial, normalmente headers debería ser un objeto
80
+ responseHeaders = { 'Content-Type': headers };
81
+ } catch (e) {
82
+ responseHeaders = {};
83
+ }
84
+ }
85
+
86
+ // Permitir a los hooks modificar los encabezados antes de escribirlos
87
+ if (this.hooks && this.hooks.applyFilters) {
88
+ responseHeaders = this.hooks.applyFilters('compressor_response_headers', responseHeaders, req, res);
89
+ }
90
+
91
+ // NO LLAMAR A ORIGINAL WRITEHEAD AÚN - ESPERAR A VER SI NECESITAMOS COMPRIMIR
92
+ // Marcar que writeHead ha sido llamado pero diferir el envío real
93
+ res.__hasCalledWriteHead = true;
94
+ res.__pendingStatusCode = code;
95
+ res.__pendingHeaders = { ...headers };
96
+
97
+ return res;
98
+ };
99
+
67
100
  // Sobrescribir res.write para capturar los chunks
68
101
  res.write = (chunk, encoding) => {
69
102
  // Permitir a los hooks interceptar los chunks antes de almacenarlos
@@ -101,7 +134,7 @@ class Compressor {
101
134
  const shouldCompress = this.hooks.applyFilters('compressor_should_compress', false, responseBody, req, res, this.threshold);
102
135
  if (shouldCompress) {
103
136
  // Si un hook determina que debería comprimirse, proseguir con la compresión
104
- this._performCompression(req, res, originalEnd, originalWriteHead, responseBody, compressionMethod);
137
+ this._performCompression(req, res, originalEnd, originalWriteHead, responseBody, compressionMethod, statusCode, responseHeaders);
105
138
  return;
106
139
  }
107
140
  }
@@ -113,8 +146,16 @@ class Compressor {
113
146
 
114
147
  // Solo establecer encabezados si no se han enviado aún
115
148
  if (!res.headersSent) {
116
- res.removeHeader('Content-Encoding'); // Asegurar que no haya encabezado de codificación
117
- originalWriteHead.call(res);
149
+ // Restaurar encabezados originales y asegurar que no haya encabezado de codificación
150
+ const headersToSend = { ...responseHeaders };
151
+ delete headersToSend['content-encoding']; // Asegurar que no haya encabezado de codificación
152
+
153
+ // Si writeHead fue llamado previamente, usar los encabezados pendientes
154
+ if (res.__hasCalledWriteHead && res.__pendingHeaders) {
155
+ originalWriteHead.call(res, res.__pendingStatusCode || statusCode, headersToSend);
156
+ } else {
157
+ originalWriteHead.call(res, statusCode, headersToSend);
158
+ }
118
159
  }
119
160
  originalEnd.call(res, responseBody, encoding);
120
161
  return;
@@ -169,17 +210,24 @@ class Compressor {
169
210
 
170
211
  // Solo establecer encabezados si no se han enviado aún
171
212
  if (!res.headersSent) {
172
- // Establecer encabezados apropiados
173
- res.setHeader('Content-Encoding', compressionMethod);
174
- res.removeHeader('Content-Length'); // Eliminar Content-Length original
213
+ // Combinar encabezados originales con el encabezado de compresión
214
+ const headersToSend = { ...responseHeaders };
215
+ headersToSend['Content-Encoding'] = compressionMethod;
216
+ delete headersToSend['content-length']; // Eliminar Content-Length original
175
217
 
176
218
  // Permitir a los hooks modificar los encabezados
177
219
  if (this.hooks && this.hooks.doAction) {
178
220
  this.hooks.doAction('compressor_before_headers_sent', req, res, compressionMethod);
179
221
  }
180
222
 
181
- // Llamar al writeHead original
182
- originalWriteHead.call(res);
223
+ // Si writeHead fue llamado previamente, usar los encabezados pendientes
224
+ if (res.__hasCalledWriteHead && res.__pendingHeaders) {
225
+ // Combinar los encabezados pendientes con el encabezado de compresión
226
+ const combinedHeaders = { ...res.__pendingHeaders, ...headersToSend };
227
+ originalWriteHead.call(res, res.__pendingStatusCode || statusCode, combinedHeaders);
228
+ } else {
229
+ originalWriteHead.call(res, statusCode, headersToSend);
230
+ }
183
231
  }
184
232
 
185
233
  // Permitir a los hooks modificar el comportamiento antes de enviar la respuesta
@@ -204,8 +252,15 @@ class Compressor {
204
252
 
205
253
  // Si ocurre un error, enviar sin comprimir
206
254
  if (!res.headersSent) {
207
- res.removeHeader('Content-Encoding');
208
- originalWriteHead.call(res);
255
+ const headersToSend = { ...responseHeaders };
256
+ delete headersToSend['content-encoding'];
257
+
258
+ // Si writeHead fue llamado previamente, usar los encabezados pendientes
259
+ if (res.__hasCalledWriteHead && res.__pendingHeaders) {
260
+ originalWriteHead.call(res, res.__pendingStatusCode || statusCode, { ...res.__pendingHeaders, ...headersToSend });
261
+ } else {
262
+ originalWriteHead.call(res, statusCode, headersToSend);
263
+ }
209
264
  }
210
265
  originalEnd.call(res, responseBody, encoding);
211
266
  });
@@ -390,7 +445,7 @@ class Compressor {
390
445
  * Método auxiliar para realizar la compresión
391
446
  * @private
392
447
  */
393
- _performCompression(req, res, originalEnd, originalWriteHead, responseBody, compressionMethod) {
448
+ _performCompression(req, res, originalEnd, originalWriteHead, responseBody, compressionMethod, statusCode = 200, responseHeaders = {}) {
394
449
  const zlib = require('zlib');
395
450
 
396
451
  // Permitir a los hooks modificar el comportamiento cuando se va a comprimir
@@ -442,17 +497,24 @@ class Compressor {
442
497
 
443
498
  // Solo establecer encabezados si no se han enviado aún
444
499
  if (!res.headersSent) {
445
- // Establecer encabezados apropiados
446
- res.setHeader('Content-Encoding', compressionMethod);
447
- res.removeHeader('Content-Length'); // Eliminar Content-Length original
500
+ // Combinar encabezados originales con el encabezado de compresión
501
+ const headersToSend = { ...responseHeaders };
502
+ headersToSend['Content-Encoding'] = compressionMethod;
503
+ delete headersToSend['content-length']; // Eliminar Content-Length original
448
504
 
449
505
  // Permitir a los hooks modificar los encabezados
450
506
  if (this.hooks && this.hooks.doAction) {
451
507
  this.hooks.doAction('compressor_before_headers_sent', req, res, compressionMethod);
452
508
  }
453
509
 
454
- // Llamar al writeHead original
455
- originalWriteHead.call(res);
510
+ // Si writeHead fue llamado previamente, usar los encabezados pendientes
511
+ if (res.__hasCalledWriteHead && res.__pendingHeaders) {
512
+ // Combinar los encabezados pendientes con el encabezado de compresión
513
+ const combinedHeaders = { ...res.__pendingHeaders, ...headersToSend };
514
+ originalWriteHead.call(res, res.__pendingStatusCode || statusCode, combinedHeaders);
515
+ } else {
516
+ originalWriteHead.call(res, statusCode, headersToSend);
517
+ }
456
518
  }
457
519
 
458
520
  // Permitir a los hooks modificar el comportamiento antes de enviar la respuesta
@@ -477,8 +539,15 @@ class Compressor {
477
539
 
478
540
  // Si ocurre un error, enviar sin comprimir
479
541
  if (!res.headersSent) {
480
- res.removeHeader('Content-Encoding');
481
- originalWriteHead.call(res);
542
+ const headersToSend = { ...responseHeaders };
543
+ delete headersToSend['content-encoding'];
544
+
545
+ // Si writeHead fue llamado previamente, usar los encabezados pendientes
546
+ if (res.__hasCalledWriteHead && res.__pendingHeaders) {
547
+ originalWriteHead.call(res, res.__pendingStatusCode || statusCode, { ...res.__pendingHeaders, ...headersToSend });
548
+ } else {
549
+ originalWriteHead.call(res, statusCode, headersToSend);
550
+ }
482
551
  }
483
552
  originalEnd.call(res, responseBody);
484
553
  });
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Adaptador genérico para modelos en el framework JERK
3
+ * Implementación del componente MVC GenericAdapter.js
4
+ * Proporciona una interfaz común para diferentes tipos de almacenamiento
5
+ */
6
+
7
+ class GenericAdapter {
8
+ /**
9
+ * Constructor del adaptador genérico
10
+ * @param {Object} options - Opciones de configuración
11
+ */
12
+ constructor(options = {}) {
13
+ this.options = options;
14
+ this.type = options.type || 'generic';
15
+ this.logger = options.logger || console;
16
+ }
17
+
18
+ /**
19
+ * Método para crear un registro
20
+ * @param {string} tableName - Nombre de la tabla
21
+ * @param {Object} data - Datos a crear
22
+ * @returns {Promise<Object>} - Promesa con el resultado
23
+ */
24
+ async create(tableName, data) {
25
+ throw new Error('Método create no implementado en el adaptador genérico');
26
+ }
27
+
28
+ /**
29
+ * Método para encontrar registros
30
+ * @param {string} tableName - Nombre de la tabla
31
+ * @param {Object} conditions - Condiciones de búsqueda
32
+ * @param {Object} options - Opciones adicionales
33
+ * @returns {Promise<Array>} - Promesa con los resultados
34
+ */
35
+ async find(tableName, conditions, options) {
36
+ throw new Error('Método find no implementado en el adaptador genérico');
37
+ }
38
+
39
+ /**
40
+ * Método para encontrar un solo registro
41
+ * @param {string} tableName - Nombre de la tabla
42
+ * @param {Object} conditions - Condiciones de búsqueda
43
+ * @param {Object} options - Opciones adicionales
44
+ * @returns {Promise<Object|null>} - Promesa con el resultado o null
45
+ */
46
+ async findOne(tableName, conditions, options) {
47
+ throw new Error('Método findOne no implementado en el adaptador genérico');
48
+ }
49
+
50
+ /**
51
+ * Método para actualizar registros
52
+ * @param {string} tableName - Nombre de la tabla
53
+ * @param {Object} conditions - Condiciones para seleccionar registros
54
+ * @param {Object} data - Datos a actualizar
55
+ * @returns {Promise<number>} - Promesa con el número de registros afectados
56
+ */
57
+ async update(tableName, conditions, data) {
58
+ throw new Error('Método update no implementado en el adaptador genérico');
59
+ }
60
+
61
+ /**
62
+ * Método para eliminar registros
63
+ * @param {string} tableName - Nombre de la tabla
64
+ * @param {Object} conditions - Condiciones para seleccionar registros
65
+ * @returns {Promise<number>} - Promesa con el número de registros eliminados
66
+ */
67
+ async delete(tableName, conditions) {
68
+ throw new Error('Método delete no implementado en el adaptador genérico');
69
+ }
70
+
71
+ /**
72
+ * Método para contar registros
73
+ * @param {string} tableName - Nombre de la tabla
74
+ * @param {Object} conditions - Condiciones de conteo
75
+ * @returns {Promise<number>} - Promesa con el número de registros
76
+ */
77
+ async count(tableName, conditions) {
78
+ throw new Error('Método count no implementado en el adaptador genérico');
79
+ }
80
+
81
+ /**
82
+ * Método para ejecutar consultas personalizadas
83
+ * @param {string} query - Consulta personalizada
84
+ * @param {Array} params - Parámetros de la consulta
85
+ * @returns {Promise<any>} - Promesa con el resultado
86
+ */
87
+ async query(query, params = []) {
88
+ throw new Error('Método query no implementado en el adaptador genérico');
89
+ }
90
+
91
+ /**
92
+ * Método para inicializar el adaptador
93
+ * @returns {Promise<void>}
94
+ */
95
+ async initialize() {
96
+ // Implementación por defecto
97
+ }
98
+
99
+ /**
100
+ * Método para cerrar la conexión
101
+ * @returns {Promise<void>}
102
+ */
103
+ async close() {
104
+ // Implementación por defecto
105
+ }
106
+
107
+ /**
108
+ * Método para verificar si el adaptador está conectado
109
+ * @returns {boolean} - Verdadero si está conectado
110
+ */
111
+ isConnected() {
112
+ return true; // Por defecto, asumimos que está conectado
113
+ }
114
+
115
+ /**
116
+ * Método para migrar una tabla
117
+ * @param {string} tableName - Nombre de la tabla a migrar
118
+ * @returns {Promise<void>}
119
+ */
120
+ async migrate(tableName) {
121
+ throw new Error('Método migrate no implementado en el adaptador genérico');
122
+ }
123
+
124
+ /**
125
+ * Serializa el adaptador a JSON
126
+ * @returns {Object} - Representación JSON del adaptador
127
+ */
128
+ toJSON() {
129
+ return {
130
+ type: this.type,
131
+ initialized: true
132
+ };
133
+ }
134
+ }
135
+
136
+ module.exports = GenericAdapter;