jerkjs 2.1.7 → 2.3.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 (51) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/README.md +204 -4
  3. package/README_EN.md +1 -1
  4. package/README_PT.md +1 -1
  5. package/docs/ARQUITECTURA_ROUTES.md +84 -38
  6. package/{JERK_FRAMEWORK_DOCUMENTATION.md → docs/JERK_FRAMEWORK_DOCUMENTATION.md} +28 -2
  7. package/docs/JERK_MODELOS_HOWTO.md +566 -0
  8. package/index.js +41 -5
  9. package/jerk-qbuilder/CHANGELOG.md +71 -0
  10. package/jerk-qbuilder/HOWTO.md +325 -0
  11. package/jerk-qbuilder/README.md +52 -0
  12. package/lib/core/server.js +328 -27
  13. package/lib/loader/routeLoader.js +148 -117
  14. package/lib/mvc/GenericAdapter.js +136 -0
  15. package/lib/mvc/MariaDBAdapter.js +315 -0
  16. package/lib/mvc/MemoryAdapter.js +269 -0
  17. package/lib/mvc/ModelControllerExample.js +285 -0
  18. package/lib/mvc/controllerBase.js +77 -0
  19. package/lib/mvc/modelBase.js +383 -0
  20. package/lib/mvc/modelManager.js +284 -0
  21. package/lib/mvc/userModel.js +265 -0
  22. package/lib/mvc/viewEngine.js +32 -1
  23. package/lib/query/MariaDBAdapter.js +78 -0
  24. package/lib/query/consoleAdapter.js +184 -0
  25. package/lib/query/queryBuilder.js +953 -0
  26. package/lib/query/queryBuilderHooks.js +455 -0
  27. package/lib/query/queryBuilderMiddleware.js +332 -0
  28. package/lib/utils/mimeType.js +62 -0
  29. package/package.json +5 -3
  30. package/utils/find_file_path.sh +36 -0
  31. package/BUG_REPORTE_COMPRESION.txt +0 -72
  32. package/standard/CompressionTestController.js +0 -56
  33. package/standard/HealthController.js +0 -16
  34. package/standard/HomeController.js +0 -12
  35. package/standard/ProductController.js +0 -18
  36. package/standard/README.md +0 -47
  37. package/standard/UserController.js +0 -23
  38. package/standard/package.json +0 -22
  39. package/standard/routes.json +0 -65
  40. package/standard/server.js +0 -140
  41. package/standardA/controllers/AuthController.js +0 -82
  42. package/standardA/controllers/HomeController.js +0 -19
  43. package/standardA/controllers/UserController.js +0 -41
  44. package/standardA/server.js +0 -311
  45. package/standardA/views/auth/dashboard.html +0 -51
  46. package/standardA/views/auth/login.html +0 -47
  47. package/standardA/views/index.html +0 -32
  48. package/standardA/views/users/detail.html +0 -28
  49. package/standardA/views/users/list.html +0 -36
  50. /package/{JERK_FRAMEWORK_DIAGRAM.txt → docs/JERK_FRAMEWORK_DIAGRAM.txt} +0 -0
  51. /package/{JERK_FRAMEWORK_DIAGRAM_MERMAID.mmd → docs/JERK_FRAMEWORK_DIAGRAM_MERMAID.mmd} +0 -0
@@ -0,0 +1,285 @@
1
+ /**
2
+ * Controlador de ejemplo que demuestra la interacción con modelos en el framework JERK
3
+ * Implementación del componente MVC ModelControllerExample.js
4
+ * Muestra cómo los controladores pueden interactuar con modelos
5
+ */
6
+
7
+ const ControllerBase = require('./controllerBase');
8
+
9
+ // Importar componentes dinámicamente para evitar dependencias circulares
10
+ let _ModelManager, _UserModel, _MemoryAdapter;
11
+
12
+ const loadComponents = () => {
13
+ if (!_ModelManager || !_UserModel || !_MemoryAdapter) {
14
+ const components = require('../../index.js');
15
+ _ModelManager = components.ModelManager;
16
+ _UserModel = components.UserModel;
17
+ _MemoryAdapter = components.MemoryAdapter;
18
+ }
19
+ return { _ModelManager, _UserModel, _MemoryAdapter };
20
+ };
21
+
22
+ class ModelControllerExample extends ControllerBase {
23
+ constructor() {
24
+ super();
25
+
26
+ // Cargar componentes dinámicamente
27
+ const { _ModelManager, _MemoryAdapter } = loadComponents();
28
+
29
+ // Crear instancia del gestor de modelos
30
+ this.modelManager = new _ModelManager();
31
+
32
+ // Crear e registrar un adaptador de memoria
33
+ const memoryAdapter = new _MemoryAdapter();
34
+ this.modelManager.registerAdapter('memory', memoryAdapter);
35
+
36
+ // Crear e registrar el modelo de usuario
37
+ this.userModel = this.modelManager.createModel('User', {
38
+ adapterName: 'memory',
39
+ modelOptions: { tableName: 'users' }
40
+ });
41
+
42
+ // Asociar el modelo con este controlador para comunicación bidireccional
43
+ this.modelManager.associateModelWithController('User', this);
44
+ }
45
+
46
+ /**
47
+ * Método para obtener todos los usuarios
48
+ * @param {Object} req - Objeto de solicitud
49
+ * @param {Object} res - Objeto de respuesta
50
+ */
51
+ async getAllUsers(req, res) {
52
+ try {
53
+ const users = await this.userModel.find({});
54
+
55
+ res.writeHead(200, { 'Content-Type': 'application/json' });
56
+ res.end(JSON.stringify({
57
+ success: true,
58
+ data: users,
59
+ count: users.length
60
+ }));
61
+ } catch (error) {
62
+ console.error('Error obteniendo usuarios:', error);
63
+ res.writeHead(500, { 'Content-Type': 'application/json' });
64
+ res.end(JSON.stringify({
65
+ success: false,
66
+ error: error.message
67
+ }));
68
+ }
69
+ }
70
+
71
+ /**
72
+ * Método para obtener un usuario por ID
73
+ * @param {Object} req - Objeto de solicitud
74
+ * @param {Object} res - Objeto de respuesta
75
+ */
76
+ async getUserById(req, res) {
77
+ try {
78
+ const userId = req.params.id;
79
+
80
+ if (!userId) {
81
+ res.writeHead(400, { 'Content-Type': 'application/json' });
82
+ res.end(JSON.stringify({
83
+ success: false,
84
+ error: 'ID de usuario es requerido'
85
+ }));
86
+ return;
87
+ }
88
+
89
+ const user = await this.userModel.findOne({ id: parseInt(userId) });
90
+
91
+ if (!user) {
92
+ res.writeHead(404, { 'Content-Type': 'application/json' });
93
+ res.end(JSON.stringify({
94
+ success: false,
95
+ error: 'Usuario no encontrado'
96
+ }));
97
+ return;
98
+ }
99
+
100
+ res.writeHead(200, { 'Content-Type': 'application/json' });
101
+ res.end(JSON.stringify({
102
+ success: true,
103
+ data: user
104
+ }));
105
+ } catch (error) {
106
+ console.error('Error obteniendo usuario por ID:', error);
107
+ res.writeHead(500, { 'Content-Type': 'application/json' });
108
+ res.end(JSON.stringify({
109
+ success: false,
110
+ error: error.message
111
+ }));
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Método para crear un nuevo usuario
117
+ * @param {Object} req - Objeto de solicitud
118
+ * @param {Object} res - Objeto de respuesta
119
+ */
120
+ async createUser(req, res) {
121
+ try {
122
+ const userData = req.body;
123
+
124
+ // Validar que se proporcionen los datos necesarios
125
+ if (!userData.username || !userData.email || !userData.password) {
126
+ res.writeHead(400, { 'Content-Type': 'application/json' });
127
+ res.end(JSON.stringify({
128
+ success: false,
129
+ error: 'Username, email y password son requeridos'
130
+ }));
131
+ return;
132
+ }
133
+
134
+ // Crear el usuario usando el modelo
135
+ const newUser = await this.userModel.createUser(userData);
136
+
137
+ res.writeHead(201, { 'Content-Type': 'application/json' });
138
+ res.end(JSON.stringify({
139
+ success: true,
140
+ data: newUser
141
+ }));
142
+ } catch (error) {
143
+ console.error('Error creando usuario:', error);
144
+ res.writeHead(500, { 'Content-Type': 'application/json' });
145
+ res.end(JSON.stringify({
146
+ success: false,
147
+ error: error.message
148
+ }));
149
+ }
150
+ }
151
+
152
+ /**
153
+ * Método para actualizar un usuario
154
+ * @param {Object} req - Objeto de solicitud
155
+ * @param {Object} res - Objeto de respuesta
156
+ */
157
+ async updateUser(req, res) {
158
+ try {
159
+ const userId = req.params.id;
160
+ const userData = req.body;
161
+
162
+ if (!userId) {
163
+ res.writeHead(400, { 'Content-Type': 'application/json' });
164
+ res.end(JSON.stringify({
165
+ success: false,
166
+ error: 'ID de usuario es requerido'
167
+ }));
168
+ return;
169
+ }
170
+
171
+ // Actualizar el usuario usando el modelo
172
+ const affectedRows = await this.userModel.updateUser({ id: parseInt(userId) }, userData);
173
+
174
+ if (affectedRows === 0) {
175
+ res.writeHead(404, { 'Content-Type': 'application/json' });
176
+ res.end(JSON.stringify({
177
+ success: false,
178
+ error: 'Usuario no encontrado'
179
+ }));
180
+ return;
181
+ }
182
+
183
+ res.writeHead(200, { 'Content-Type': 'application/json' });
184
+ res.end(JSON.stringify({
185
+ success: true,
186
+ message: 'Usuario actualizado exitosamente',
187
+ affectedRows
188
+ }));
189
+ } catch (error) {
190
+ console.error('Error actualizando usuario:', error);
191
+ res.writeHead(500, { 'Content-Type': 'application/json' });
192
+ res.end(JSON.stringify({
193
+ success: false,
194
+ error: error.message
195
+ }));
196
+ }
197
+ }
198
+
199
+ /**
200
+ * Método para eliminar un usuario
201
+ * @param {Object} req - Objeto de solicitud
202
+ * @param {Object} res - Objeto de respuesta
203
+ */
204
+ async deleteUser(req, res) {
205
+ try {
206
+ const userId = req.params.id;
207
+
208
+ if (!userId) {
209
+ res.writeHead(400, { 'Content-Type': 'application/json' });
210
+ res.end(JSON.stringify({
211
+ success: false,
212
+ error: 'ID de usuario es requerido'
213
+ }));
214
+ return;
215
+ }
216
+
217
+ // Eliminar el usuario usando el modelo
218
+ const deletedRows = await this.userModel.delete({ id: parseInt(userId) });
219
+
220
+ if (deletedRows === 0) {
221
+ res.writeHead(404, { 'Content-Type': 'application/json' });
222
+ res.end(JSON.stringify({
223
+ success: false,
224
+ error: 'Usuario no encontrado'
225
+ }));
226
+ return;
227
+ }
228
+
229
+ res.writeHead(200, { 'Content-Type': 'application/json' });
230
+ res.end(JSON.stringify({
231
+ success: true,
232
+ message: 'Usuario eliminado exitosamente',
233
+ deletedRows
234
+ }));
235
+ } catch (error) {
236
+ console.error('Error eliminando usuario:', error);
237
+ res.writeHead(500, { 'Content-Type': 'application/json' });
238
+ res.end(JSON.stringify({
239
+ success: false,
240
+ error: error.message
241
+ }));
242
+ }
243
+ }
244
+
245
+ /**
246
+ * Método para obtener usuarios con paginación
247
+ * @param {Object} req - Objeto de solicitud
248
+ * @param {Object} res - Objeto de respuesta
249
+ */
250
+ async getUsersPaginated(req, res) {
251
+ try {
252
+ // Obtener parámetros de paginación de la consulta
253
+ const page = parseInt(req.query.page) || 1;
254
+ const limit = parseInt(req.query.limit) || 10;
255
+
256
+ // Validar parámetros
257
+ if (page < 1 || limit < 1 || limit > 100) {
258
+ res.writeHead(400, { 'Content-Type': 'application/json' });
259
+ res.end(JSON.stringify({
260
+ success: false,
261
+ error: 'Parámetros de paginación inválidos'
262
+ }));
263
+ return;
264
+ }
265
+
266
+ // Obtener usuarios con paginación usando el modelo
267
+ const result = await this.userModel.getUsersPaginated({ page, limit });
268
+
269
+ res.writeHead(200, { 'Content-Type': 'application/json' });
270
+ res.end(JSON.stringify({
271
+ success: true,
272
+ ...result
273
+ }));
274
+ } catch (error) {
275
+ console.error('Error obteniendo usuarios paginados:', error);
276
+ res.writeHead(500, { 'Content-Type': 'application/json' });
277
+ res.end(JSON.stringify({
278
+ success: false,
279
+ error: error.message
280
+ }));
281
+ }
282
+ }
283
+ }
284
+
285
+ module.exports = ModelControllerExample;
@@ -202,6 +202,83 @@ class ControllerBase {
202
202
  clearViewData() {
203
203
  this.viewData = {};
204
204
  }
205
+
206
+ /**
207
+ * Carga un modelo para su uso en el controlador
208
+ * @param {string} modelName - Nombre del modelo a cargar
209
+ * @param {Object} options - Opciones para la creación del modelo
210
+ * @returns {ModelBase} - Instancia del modelo cargado
211
+ */
212
+ loadModel(modelName, options = {}) {
213
+ try {
214
+ // Construir la ruta del modelo
215
+ // Buscar en diferentes ubicaciones posibles
216
+ let ModelClass;
217
+
218
+ // Array de rutas posibles para buscar el modelo
219
+ // Usamos rutas absolutas basadas en el directorio actual de trabajo
220
+ const possiblePaths = [
221
+ `./models/${modelName}`, // En el subdirectorio models del directorio actual
222
+ `./models/${modelName}.js`, // Con extensión explícita
223
+ `../models/${modelName}`, // En el directorio models del directorio padre
224
+ `../models/${modelName}.js`, // Con extensión explícita
225
+ `../../models/${modelName}`, // En el directorio models del directorio abuelo
226
+ `../../models/${modelName}.js`, // Con extensión explícita
227
+ `../../../models/${modelName}`, // En el directorio models del directorio bisabuelo
228
+ `../../../models/${modelName}.js`, // Con extensión explícita
229
+ `./${modelName}`, // En el directorio actual sin subdirectorio
230
+ `./${modelName}.js` // En el directorio actual con extensión
231
+ ];
232
+
233
+ let lastError = null;
234
+
235
+ for (const path of possiblePaths) {
236
+ try {
237
+ // Usar require con la ruta absoluta desde el directorio actual
238
+ ModelClass = require(path);
239
+ // Si la importación fue exitosa, salir del bucle
240
+ break;
241
+ } catch (error) {
242
+ // Guardar el último error para propósitos de depuración
243
+ lastError = error;
244
+ continue;
245
+ }
246
+ }
247
+
248
+ // Si no se encontró el modelo en ninguna ubicación
249
+ if (!ModelClass) {
250
+ throw new Error(`Modelo '${modelName}' no encontrado en ubicaciones estándar. Ultimo error: ${lastError?.message || 'desconocido'}`);
251
+ }
252
+
253
+ // Crear instancia del modelo con las opciones proporcionadas
254
+ const modelInstance = new ModelClass(options);
255
+
256
+ // Guardar referencia del modelo en el controlador
257
+ if (!this.models) {
258
+ this.models = {};
259
+ }
260
+
261
+ this.models[modelName] = modelInstance;
262
+
263
+ return modelInstance;
264
+ } catch (error) {
265
+ console.error(`Error cargando modelo '${modelName}':`, error.message);
266
+ throw error;
267
+ }
268
+ }
269
+
270
+ /**
271
+ * Obtiene un modelo previamente cargado
272
+ * @param {string} modelName - Nombre del modelo a obtener
273
+ * @returns {ModelBase|null} - Instancia del modelo o null si no está cargado
274
+ */
275
+ getModel(modelName) {
276
+ if (!this.models) {
277
+ this.models = {};
278
+ }
279
+
280
+ return this.models[modelName] || null;
281
+ }
205
282
  }
206
283
 
207
284
  module.exports = ControllerBase;