jerkjs 2.1.7 → 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 +30 -0
  2. package/README.md +201 -4
  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/mvc/GenericAdapter.js +136 -0
  7. package/lib/mvc/MariaDBAdapter.js +315 -0
  8. package/lib/mvc/MemoryAdapter.js +269 -0
  9. package/lib/mvc/ModelControllerExample.js +285 -0
  10. package/lib/mvc/controllerBase.js +60 -0
  11. package/lib/mvc/modelBase.js +383 -0
  12. package/lib/mvc/modelManager.js +284 -0
  13. package/lib/mvc/userModel.js +265 -0
  14. package/lib/mvc/viewEngine.js +32 -1
  15. package/lib/utils/mimeType.js +62 -0
  16. package/package.json +5 -3
  17. package/BUG_REPORTE_COMPRESION.txt +0 -72
  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
@@ -0,0 +1,383 @@
1
+ /**
2
+ * Clase base para modelos en el framework JERK
3
+ * Implementación del componente MVC modelBase.js
4
+ * Permite la comunicación bidireccional con controladores y la interacción con componentes del framework
5
+ */
6
+
7
+ // Importar hooks dinámicamente para evitar dependencias circulares
8
+ let _hooks = null;
9
+ const getHooks = () => {
10
+ if (!_hooks) {
11
+ _hooks = require('../../index.js').hooks;
12
+ }
13
+ return _hooks;
14
+ };
15
+
16
+ class ModelBase {
17
+ /**
18
+ * Constructor del modelo base
19
+ * @param {Object} options - Opciones de configuración del modelo
20
+ * @param {string} options.tableName - Nombre de la tabla en la base de datos
21
+ * @param {Object} options.adapter - Adaptador de base de datos a utilizar
22
+ * @param {Object} options.logger - Instancia de logger para auditoría
23
+ */
24
+ constructor(options = {}) {
25
+ this.tableName = options.tableName || this.constructor.name.toLowerCase();
26
+ this.adapter = options.adapter || null;
27
+ this.logger = options.logger || console;
28
+
29
+ // Almacenar referencias a controladores asociados
30
+ this.controllers = new Set();
31
+
32
+ // Inicializar hooks para el modelo
33
+ this.initializeHooks();
34
+ }
35
+
36
+ /**
37
+ * Inicializa los hooks específicos para el modelo
38
+ */
39
+ initializeHooks() {
40
+ // Disparar hook cuando se crea una instancia del modelo
41
+ const hooks = getHooks();
42
+ if (hooks) {
43
+ hooks.doAction('model_created', this.constructor.name, this);
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Establece el adaptador de base de datos para el modelo
49
+ * @param {Object} adapter - Adaptador de base de datos
50
+ */
51
+ setAdapter(adapter) {
52
+ this.adapter = adapter;
53
+ }
54
+
55
+ /**
56
+ * Registra un controlador que puede interactuar con este modelo
57
+ * @param {Object} controller - Instancia del controlador
58
+ */
59
+ registerController(controller) {
60
+ this.controllers.add(controller);
61
+
62
+ // Disparar hook cuando se registra un controlador
63
+ const hooks = getHooks();
64
+ if (hooks) {
65
+ hooks.doAction('controller_registered_with_model', controller.constructor.name, this.constructor.name);
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Elimina un controlador registrado
71
+ * @param {Object} controller - Instancia del controlador
72
+ */
73
+ unregisterController(controller) {
74
+ this.controllers.delete(controller);
75
+
76
+ // Disparar hook cuando se elimina un controlador
77
+ const hooks = getHooks();
78
+ if (hooks) {
79
+ hooks.doAction('controller_unregistered_from_model', controller.constructor.name, this.constructor.name);
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Obtiene todos los controladores registrados
85
+ * @returns {Set} - Conjunto de controladores registrados
86
+ */
87
+ getControllers() {
88
+ return this.controllers;
89
+ }
90
+
91
+ /**
92
+ * Método para crear un nuevo registro
93
+ * @param {Object} data - Datos del nuevo registro
94
+ * @returns {Promise<Object>} - Promesa con el resultado de la operación
95
+ */
96
+ async create(data) {
97
+ if (!this.adapter) {
98
+ throw new Error(`No se ha configurado un adaptador para el modelo ${this.constructor.name}`);
99
+ }
100
+
101
+ // Disparar hook antes de crear
102
+ const hooks = getHooks();
103
+ if (hooks) {
104
+ data = hooks.applyFilters('model_before_create', data, this.constructor.name);
105
+ }
106
+
107
+ try {
108
+ const result = await this.adapter.create(this.tableName, data);
109
+
110
+ // Disparar hook después de crear
111
+ if (hooks) {
112
+ hooks.doAction('model_after_create', result, this.constructor.name);
113
+ }
114
+
115
+ return result;
116
+ } catch (error) {
117
+ this.logger.error(`Error creando registro en ${this.tableName}:`, error.message);
118
+
119
+ // Disparar hook en caso de error
120
+ if (hooks) {
121
+ hooks.doAction('model_create_error', error, this.constructor.name);
122
+ }
123
+
124
+ throw error;
125
+ }
126
+ }
127
+
128
+ /**
129
+ * Método para obtener registros
130
+ * @param {Object} conditions - Condiciones de búsqueda
131
+ * @param {Object} options - Opciones adicionales (orden, límites, etc.)
132
+ * @returns {Promise<Array>} - Promesa con los resultados
133
+ */
134
+ async find(conditions = {}, options = {}) {
135
+ if (!this.adapter) {
136
+ throw new Error(`No se ha configurado un adaptador para el modelo ${this.constructor.name}`);
137
+ }
138
+
139
+ // Disparar hook antes de buscar
140
+ const hooks = getHooks();
141
+ if (hooks) {
142
+ conditions = hooks.applyFilters('model_before_find', conditions, this.constructor.name);
143
+ }
144
+
145
+ try {
146
+ const results = await this.adapter.find(this.tableName, conditions, options);
147
+
148
+ // Disparar hook después de buscar
149
+ if (hooks) {
150
+ hooks.doAction('model_after_find', results, this.constructor.name);
151
+ }
152
+
153
+ return results;
154
+ } catch (error) {
155
+ this.logger.error(`Error buscando registros en ${this.tableName}:`, error.message);
156
+
157
+ // Disparar hook en caso de error
158
+ if (hooks) {
159
+ hooks.doAction('model_find_error', error, this.constructor.name);
160
+ }
161
+
162
+ throw error;
163
+ }
164
+ }
165
+
166
+ /**
167
+ * Método para obtener un solo registro
168
+ * @param {Object} conditions - Condiciones de búsqueda
169
+ * @param {Object} options - Opciones adicionales
170
+ * @returns {Promise<Object|null>} - Promesa con el resultado o null
171
+ */
172
+ async findOne(conditions = {}, options = {}) {
173
+ if (!this.adapter) {
174
+ throw new Error(`No se ha configurado un adaptador para el modelo ${this.constructor.name}`);
175
+ }
176
+
177
+ // Disparar hook antes de buscar uno
178
+ const hooks = getHooks();
179
+ if (hooks) {
180
+ conditions = hooks.applyFilters('model_before_find_one', conditions, this.constructor.name);
181
+ }
182
+
183
+ try {
184
+ const result = await this.adapter.findOne(this.tableName, conditions, options);
185
+
186
+ // Disparar hook después de buscar uno
187
+ if (hooks) {
188
+ hooks.doAction('model_after_find_one', result, this.constructor.name);
189
+ }
190
+
191
+ return result;
192
+ } catch (error) {
193
+ this.logger.error(`Error buscando un registro en ${this.tableName}:`, error.message);
194
+
195
+ // Disparar hook en caso de error
196
+ if (hooks) {
197
+ hooks.doAction('model_find_one_error', error, this.constructor.name);
198
+ }
199
+
200
+ throw error;
201
+ }
202
+ }
203
+
204
+ /**
205
+ * Método para actualizar registros
206
+ * @param {Object} conditions - Condiciones para seleccionar registros a actualizar
207
+ * @param {Object} data - Datos a actualizar
208
+ * @returns {Promise<number>} - Número de registros afectados
209
+ */
210
+ async update(conditions, data) {
211
+ if (!this.adapter) {
212
+ throw new Error(`No se ha configurado un adaptador para el modelo ${this.constructor.name}`);
213
+ }
214
+
215
+ // Disparar hook antes de actualizar
216
+ const hooks = getHooks();
217
+ if (hooks) {
218
+ const hookResult = hooks.applyFilters('model_before_update', { conditions, data }, this.constructor.name);
219
+ conditions = hookResult.conditions;
220
+ data = hookResult.data;
221
+ }
222
+
223
+ try {
224
+ const result = await this.adapter.update(this.tableName, conditions, data);
225
+
226
+ // Disparar hook después de actualizar
227
+ if (hooks) {
228
+ hooks.doAction('model_after_update', result, data, this.constructor.name);
229
+ }
230
+
231
+ return result;
232
+ } catch (error) {
233
+ this.logger.error(`Error actualizando registros en ${this.tableName}:`, error.message);
234
+
235
+ // Disparar hook en caso de error
236
+ if (hooks) {
237
+ hooks.doAction('model_update_error', error, this.constructor.name);
238
+ }
239
+
240
+ throw error;
241
+ }
242
+ }
243
+
244
+ /**
245
+ * Método para eliminar registros
246
+ * @param {Object} conditions - Condiciones para seleccionar registros a eliminar
247
+ * @returns {Promise<number>} - Número de registros eliminados
248
+ */
249
+ async delete(conditions) {
250
+ if (!this.adapter) {
251
+ throw new Error(`No se ha configurado un adaptador para el modelo ${this.constructor.name}`);
252
+ }
253
+
254
+ // Disparar hook antes de eliminar
255
+ const hooks = getHooks();
256
+ if (hooks) {
257
+ conditions = hooks.applyFilters('model_before_delete', conditions, this.constructor.name);
258
+ }
259
+
260
+ try {
261
+ const result = await this.adapter.delete(this.tableName, conditions);
262
+
263
+ // Disparar hook después de eliminar
264
+ if (hooks) {
265
+ hooks.doAction('model_after_delete', result, this.constructor.name);
266
+ }
267
+
268
+ return result;
269
+ } catch (error) {
270
+ this.logger.error(`Error eliminando registros en ${this.tableName}:`, error.message);
271
+
272
+ // Disparar hook en caso de error
273
+ if (hooks) {
274
+ hooks.doAction('model_delete_error', error, this.constructor.name);
275
+ }
276
+
277
+ throw error;
278
+ }
279
+ }
280
+
281
+ /**
282
+ * Método para contar registros
283
+ * @param {Object} conditions - Condiciones de conteo
284
+ * @returns {Promise<number>} - Número de registros
285
+ */
286
+ async count(conditions = {}) {
287
+ if (!this.adapter) {
288
+ throw new Error(`No se ha configurado un adaptador para el modelo ${this.constructor.name}`);
289
+ }
290
+
291
+ const hooks = getHooks();
292
+ try {
293
+ const result = await this.adapter.count(this.tableName, conditions);
294
+
295
+ // Disparar hook después de contar
296
+ if (hooks) {
297
+ hooks.doAction('model_count_result', result, this.constructor.name);
298
+ }
299
+
300
+ return result;
301
+ } catch (error) {
302
+ this.logger.error(`Error contando registros en ${this.tableName}:`, error.message);
303
+
304
+ // Disparar hook en caso de error
305
+ if (hooks) {
306
+ hooks.doAction('model_count_error', error, this.constructor.name);
307
+ }
308
+
309
+ throw error;
310
+ }
311
+ }
312
+
313
+ /**
314
+ * Método para ejecutar consultas personalizadas
315
+ * @param {string} query - Consulta personalizada
316
+ * @param {Array} params - Parámetros de la consulta
317
+ * @returns {Promise<any>} - Resultado de la consulta
318
+ */
319
+ async query(query, params = []) {
320
+ if (!this.adapter) {
321
+ throw new Error(`No se ha configurado un adaptador para el modelo ${this.constructor.name}`);
322
+ }
323
+
324
+ const hooks = getHooks();
325
+ try {
326
+ const result = await this.adapter.query(query, params);
327
+
328
+ // Disparar hook después de la consulta
329
+ if (hooks) {
330
+ hooks.doAction('model_custom_query_result', result, query, this.constructor.name);
331
+ }
332
+
333
+ return result;
334
+ } catch (error) {
335
+ this.logger.error(`Error ejecutando consulta personalizada en ${this.tableName}:`, error.message);
336
+
337
+ // Disparar hook en caso de error
338
+ if (hooks) {
339
+ hooks.doAction('model_custom_query_error', error, query, this.constructor.name);
340
+ }
341
+
342
+ throw error;
343
+ }
344
+ }
345
+
346
+ /**
347
+ * Método para validar datos antes de operaciones CRUD
348
+ * @param {string} operation - Operación a realizar (create, update, etc.)
349
+ * @param {Object} data - Datos a validar
350
+ * @returns {boolean} - Verdadero si los datos son válidos
351
+ */
352
+ validate(operation, data) {
353
+ // Disparar hook para validación
354
+ const hooks = getHooks();
355
+ if (hooks) {
356
+ const validationResult = hooks.applyFilters(
357
+ 'model_validate',
358
+ { isValid: true, errors: [] },
359
+ operation,
360
+ data,
361
+ this.constructor.name
362
+ );
363
+
364
+ return validationResult;
365
+ }
366
+
367
+ return { isValid: true, errors: [] };
368
+ }
369
+
370
+ /**
371
+ * Método para serializar el modelo a JSON
372
+ * @returns {Object} - Representación JSON del modelo
373
+ */
374
+ toJSON() {
375
+ return {
376
+ tableName: this.tableName,
377
+ hasAdapter: !!this.adapter,
378
+ registeredControllersCount: this.controllers.size
379
+ };
380
+ }
381
+ }
382
+
383
+ module.exports = ModelBase;
@@ -0,0 +1,284 @@
1
+ /**
2
+ * Gestor de modelos para el framework JERK
3
+ * Implementación del componente MVC modelManager.js
4
+ * Administra instancias de modelos y su interacción con componentes del framework
5
+ */
6
+
7
+ const ModelBase = require('./modelBase');
8
+
9
+ // Importar hooks dinámicamente para evitar dependencias circulares
10
+ let _hooks = null;
11
+ const getHooks = () => {
12
+ if (!_hooks) {
13
+ _hooks = require('../../index.js').hooks;
14
+ }
15
+ return _hooks;
16
+ };
17
+
18
+ class ModelManager {
19
+ /**
20
+ * Constructor del gestor de modelos
21
+ * @param {Object} options - Opciones de configuración
22
+ */
23
+ constructor(options = {}) {
24
+ this.models = new Map(); // Almacena instancias de modelos
25
+ this.adapters = new Map(); // Almacena adaptadores disponibles
26
+ this.logger = options.logger || console;
27
+
28
+ // Inicializar hooks para el gestor de modelos
29
+ this.initializeHooks();
30
+ }
31
+
32
+ /**
33
+ * Inicializa los hooks específicos para el gestor de modelos
34
+ */
35
+ initializeHooks() {
36
+ // Disparar hook cuando se crea una instancia del gestor de modelos
37
+ const hooks = getHooks();
38
+ if (hooks) {
39
+ hooks.doAction('model_manager_created', this);
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Registra un adaptador de base de datos
45
+ * @param {string} name - Nombre del adaptador
46
+ * @param {Object} adapter - Instancia del adaptador
47
+ */
48
+ registerAdapter(name, adapter) {
49
+ this.adapters.set(name, adapter);
50
+
51
+ // Disparar hook cuando se registra un adaptador
52
+ const hooks = getHooks();
53
+ if (hooks) {
54
+ hooks.doAction('adapter_registered', name, adapter);
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Obtiene un adaptador registrado
60
+ * @param {string} name - Nombre del adaptador
61
+ * @returns {Object|null} - Instancia del adaptador o null
62
+ */
63
+ getAdapter(name) {
64
+ return this.adapters.get(name) || null;
65
+ }
66
+
67
+ /**
68
+ * Registra un modelo en el gestor
69
+ * @param {string} name - Nombre del modelo
70
+ * @param {ModelBase} model - Instancia del modelo
71
+ */
72
+ registerModel(name, model) {
73
+ if (!(model instanceof ModelBase)) {
74
+ throw new Error('El modelo debe ser una instancia de ModelBase');
75
+ }
76
+
77
+ this.models.set(name, model);
78
+
79
+ // Disparar hook cuando se registra un modelo
80
+ const hooks = getHooks();
81
+ if (hooks) {
82
+ hooks.doAction('model_registered', name, model);
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Obtiene un modelo registrado
88
+ * @param {string} name - Nombre del modelo
89
+ * @returns {ModelBase|null} - Instancia del modelo o null
90
+ */
91
+ getModel(name) {
92
+ return this.models.get(name) || null;
93
+ }
94
+
95
+ /**
96
+ * Crea una instancia de modelo con un adaptador específico
97
+ * @param {string} modelName - Nombre del modelo
98
+ * @param {Object} options - Opciones para la creación del modelo
99
+ * @param {string} options.adapterName - Nombre del adaptador a usar
100
+ * @param {Object} options.modelOptions - Opciones específicas del modelo
101
+ * @returns {ModelBase} - Instancia del modelo creado
102
+ */
103
+ createModel(modelName, options = {}) {
104
+ const { adapterName, modelOptions = {} } = options;
105
+
106
+ // Obtener el adaptador si se especificó
107
+ let adapter = null;
108
+ if (adapterName) {
109
+ adapter = this.getAdapter(adapterName);
110
+ if (!adapter) {
111
+ throw new Error(`Adaptador '${adapterName}' no encontrado para el modelo '${modelName}'`);
112
+ }
113
+ }
114
+
115
+ // Crear una clase modelo dinámicamente si no existe
116
+ if (!this.models.has(modelName)) {
117
+ // Creamos una clase modelo específica para este nombre
118
+ class DynamicModel extends ModelBase {
119
+ constructor(opts) {
120
+ super(opts);
121
+ this.modelName = modelName;
122
+ }
123
+ }
124
+
125
+ // Instanciar el modelo con el adaptador
126
+ const modelInstance = new DynamicModel({
127
+ ...modelOptions,
128
+ adapter: adapter,
129
+ logger: this.logger
130
+ });
131
+
132
+ // Registrar el modelo
133
+ this.registerModel(modelName, modelInstance);
134
+
135
+ return modelInstance;
136
+ } else {
137
+ // Si ya existe, actualizar el adaptador si se proporcionó
138
+ const existingModel = this.getModel(modelName);
139
+ if (adapter) {
140
+ existingModel.setAdapter(adapter);
141
+ }
142
+
143
+ return existingModel;
144
+ }
145
+ }
146
+
147
+ /**
148
+ * Asocia un modelo con un controlador para permitir comunicación bidireccional
149
+ * @param {string} modelName - Nombre del modelo
150
+ * @param {Object} controller - Instancia del controlador
151
+ */
152
+ associateModelWithController(modelName, controller) {
153
+ const model = this.getModel(modelName);
154
+ if (!model) {
155
+ throw new Error(`Modelo '${modelName}' no encontrado`);
156
+ }
157
+
158
+ // Registrar el controlador en el modelo
159
+ model.registerController(controller);
160
+
161
+ // Disparar hook cuando se asocia un modelo con un controlador
162
+ const hooks = getHooks();
163
+ if (hooks) {
164
+ hooks.doAction('model_controller_associated', modelName, controller.constructor.name);
165
+ }
166
+ }
167
+
168
+ /**
169
+ * Obtiene todos los modelos registrados
170
+ * @returns {Map} - Mapa de modelos registrados
171
+ */
172
+ getModels() {
173
+ return this.models;
174
+ }
175
+
176
+ /**
177
+ * Obtiene todos los adaptadores registrados
178
+ * @returns {Map} - Mapa de adaptadores registrados
179
+ */
180
+ getAdapters() {
181
+ return this.adapters;
182
+ }
183
+
184
+ /**
185
+ * Inicializa todos los modelos con un adaptador por defecto
186
+ * @param {string} adapterName - Nombre del adaptador por defecto
187
+ */
188
+ async initializeAllModels(adapterName) {
189
+ const adapter = this.getAdapter(adapterName);
190
+ if (!adapter) {
191
+ throw new Error(`Adaptador '${adapterName}' no encontrado`);
192
+ }
193
+
194
+ // Configurar el adaptador para todos los modelos que no lo tengan
195
+ for (const [modelName, model] of this.models) {
196
+ if (!model.adapter) {
197
+ model.setAdapter(adapter);
198
+
199
+ // Disparar hook cuando se inicializa un modelo con un adaptador
200
+ const hooks = getHooks();
201
+ if (hooks) {
202
+ hooks.doAction('model_initialized_with_adapter', modelName, adapterName);
203
+ }
204
+ }
205
+ }
206
+ }
207
+
208
+ /**
209
+ * Método para migrar todas las tablas de los modelos
210
+ * @param {string} adapterName - Nombre del adaptador a usar para la migración
211
+ */
212
+ async migrateAll(adapterName) {
213
+ const adapter = this.getAdapter(adapterName);
214
+ if (!adapter) {
215
+ throw new Error(`Adaptador '${adapterName}' no encontrado`);
216
+ }
217
+
218
+ // Verificar si el adaptador tiene método de migración
219
+ if (typeof adapter.migrate !== 'function') {
220
+ throw new Error(`El adaptador '${adapterName}' no soporta migraciones`);
221
+ }
222
+
223
+ // Realizar migración para cada modelo
224
+ for (const [modelName, model] of this.models) {
225
+ try {
226
+ await adapter.migrate(model.tableName);
227
+
228
+ // Disparar hook cuando se migra una tabla
229
+ const hooks = getHooks();
230
+ if (hooks) {
231
+ hooks.doAction('model_table_migrated', modelName, model.tableName);
232
+ }
233
+ } catch (error) {
234
+ this.logger.error(`Error migrando tabla para el modelo '${modelName}':`, error.message);
235
+
236
+ // Disparar hook en caso de error de migración
237
+ const hooks = getHooks();
238
+ if (hooks) {
239
+ hooks.doAction('model_migration_error', modelName, error);
240
+ }
241
+
242
+ throw error;
243
+ }
244
+ }
245
+ }
246
+
247
+ /**
248
+ * Método para limpiar (eliminar) todos los modelos del gestor
249
+ */
250
+ clear() {
251
+ this.models.clear();
252
+
253
+ // Disparar hook cuando se limpia el gestor de modelos
254
+ const hooks = getHooks();
255
+ if (hooks) {
256
+ hooks.doAction('model_manager_cleared', this);
257
+ }
258
+ }
259
+
260
+ /**
261
+ * Serializa el estado del gestor de modelos a JSON
262
+ * @returns {Object} - Representación JSON del gestor de modelos
263
+ */
264
+ toJSON() {
265
+ const modelsInfo = {};
266
+ for (const [name, model] of this.models) {
267
+ modelsInfo[name] = model.toJSON();
268
+ }
269
+
270
+ const adaptersInfo = {};
271
+ for (const [name, adapter] of this.adapters) {
272
+ adaptersInfo[name] = { registered: true };
273
+ }
274
+
275
+ return {
276
+ registeredModels: Object.keys(modelsInfo),
277
+ registeredAdapters: Object.keys(adaptersInfo),
278
+ modelsInfo,
279
+ adaptersInfo
280
+ };
281
+ }
282
+ }
283
+
284
+ module.exports = ModelManager;