@dbcube/schema-builder 1.0.8 → 1.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -51,7 +51,7 @@ var FileUtils = class {
51
51
  const fullPath = path.join(currentDir, entry.name);
52
52
  if (entry.isDirectory()) {
53
53
  recurse(fullPath);
54
- } else if (entry.isFile() && (entry.name.endsWith(suffix) || entry.name.includes(suffix))) {
54
+ } else if (entry.isFile() && entry.name.endsWith(suffix)) {
55
55
  cubeFiles.push(fullPath);
56
56
  }
57
57
  }
@@ -64,32 +64,187 @@ var FileUtils = class {
64
64
  });
65
65
  return cubeFiles;
66
66
  }
67
+ /**
68
+ * Extrae nombres de tablas reales de archivos .cube
69
+ * @param {string} filePath - String ruta del archivo .cube
70
+ * @returns {object} - Objeto que contiene el estado y el mensaje con el nombre de la tabla
71
+ */
72
+ static extracTableNameFromCube(filePath) {
73
+ try {
74
+ const content = fs.readFileSync(filePath, "utf8");
75
+ const metaMatch = content.match(/@meta\s*\(\s*\{\s*name\s*:\s*["']([^"']+)["']\s*;\s*[^}]*\}\s*\)/s);
76
+ if (metaMatch) {
77
+ return {
78
+ status: 200,
79
+ message: metaMatch[1]
80
+ };
81
+ }
82
+ throw new Error(`Error to execute this file ${filePath} because no exist a name of table.`);
83
+ } catch (error) {
84
+ if (error instanceof Error) {
85
+ return {
86
+ status: 500,
87
+ message: error.message
88
+ };
89
+ }
90
+ return {
91
+ status: 500,
92
+ message: String(error)
93
+ };
94
+ }
95
+ }
67
96
  };
68
97
  var FileUtils_default = FileUtils;
69
98
 
99
+ // src/lib/UIUtils.ts
100
+ import chalk from "chalk";
101
+ var UIUtils = class {
102
+ /**
103
+ * Shows animated progress for processing items
104
+ */
105
+ static async showItemProgress(itemName, current, total, maxDots = 40) {
106
+ const startTime = Date.now();
107
+ const displayName = itemName.length > 25 ? itemName.substring(0, 22) + "..." : itemName.padEnd(25);
108
+ const progress = `[${current}/${total}]`.padStart(8);
109
+ return new Promise((resolve2) => {
110
+ process.stdout.write(`${chalk.blue("\u251C\u2500")} ${chalk.gray(progress)} ${chalk.cyan(displayName)} `);
111
+ let dotCount = 0;
112
+ const interval = setInterval(() => {
113
+ if (dotCount < maxDots) {
114
+ process.stdout.write(chalk.gray("."));
115
+ dotCount++;
116
+ } else {
117
+ clearInterval(interval);
118
+ resolve2();
119
+ }
120
+ }, 15);
121
+ });
122
+ }
123
+ /**
124
+ * Shows success for a processed item
125
+ */
126
+ static showItemSuccess(itemName) {
127
+ process.stdout.write(` ${chalk.green("\u2713")} ${chalk.gray("OK")}
128
+ `);
129
+ }
130
+ /**
131
+ * Shows error for an item
132
+ */
133
+ static showItemError(itemName, error) {
134
+ process.stdout.write(` ${chalk.red("\u2717")} ${chalk.red("ERROR")}
135
+ `);
136
+ console.log(`${chalk.red("\u2502 ")} ${chalk.gray("\u2514\u2500")} ${chalk.red(error)}`);
137
+ }
138
+ /**
139
+ * Shows operation header
140
+ */
141
+ static showOperationHeader(operationName, databaseName, icon = "\u{1F5D1}\uFE0F") {
142
+ console.log(`
143
+ ${chalk.cyan(icon)} ${chalk.bold.green(operationName.toUpperCase())}`);
144
+ console.log(chalk.gray("\u2500".repeat(60)));
145
+ console.log(`${chalk.blue("\u250C\u2500")} ${chalk.bold(`Database: ${databaseName}`)}`);
146
+ }
147
+ /**
148
+ * Shows comprehensive operation summary
149
+ */
150
+ static showOperationSummary(summary) {
151
+ const { startTime, totalProcessed, successCount, errorCount, processedItems, operationName, databaseName } = summary;
152
+ const totalTime = ((Date.now() - startTime) / 1e3).toFixed(1);
153
+ console.log(`
154
+ ${chalk.cyan("\u{1F4CA}")} ${chalk.bold.green(`RESUMEN DE ${operationName.toUpperCase()}`)}`);
155
+ console.log(chalk.gray("\u2500".repeat(60)));
156
+ if (successCount > 0) {
157
+ console.log(`${chalk.green("\u250C\u2500")} ${chalk.bold("Successful processing:")}`);
158
+ console.log(`${chalk.green("\u251C\u2500")} ${chalk.cyan(`Items processed: ${successCount}`)}`);
159
+ console.log(`${chalk.green("\u251C\u2500")} ${chalk.gray(`Database: ${databaseName}`)}`);
160
+ if (processedItems.length > 0) {
161
+ console.log(`${chalk.green("\u251C\u2500")} ${chalk.yellow("Items updated:")}`);
162
+ processedItems.forEach((item, index) => {
163
+ const isLast = index === processedItems.length - 1;
164
+ const connector = isLast ? "\u2514\u2500" : "\u251C\u2500";
165
+ console.log(`${chalk.green("\u2502 ")} ${chalk.gray(connector)} ${chalk.cyan(item)}`);
166
+ });
167
+ }
168
+ }
169
+ if (errorCount > 0) {
170
+ console.log(`${chalk.red("\u251C\u2500")} ${chalk.bold.red(`Errors: ${errorCount}`)}`);
171
+ }
172
+ console.log(`${chalk.blue("\u251C\u2500")} ${chalk.gray(`Total time: ${totalTime}s`)}`);
173
+ console.log(`${chalk.blue("\u2514\u2500")} ${chalk.bold(totalProcessed > 0 ? chalk.green("\u2705 Completed") : chalk.yellow("\u26A0\uFE0F No changes"))}`);
174
+ if (totalProcessed > 0) {
175
+ console.log(`
176
+ ${chalk.green("\u{1F389}")} ${chalk.bold(`${operationName} executed successfully!`)}`);
177
+ } else {
178
+ console.log(`
179
+ ${chalk.yellow("\u26A0\uFE0F ")} ${chalk.bold("No items were processed.")}`);
180
+ }
181
+ console.log("");
182
+ }
183
+ };
184
+
70
185
  // src/lib/Schema.ts
71
186
  var Schema = class {
72
187
  name;
73
188
  engine;
74
189
  constructor(name) {
75
190
  this.name = name;
76
- const engine = new Engine(name);
77
- this.engine = engine;
191
+ this.engine = new Engine(name);
78
192
  }
79
193
  async createDatabase() {
194
+ const startTime = Date.now();
80
195
  const rootPath = path2.resolve(process.cwd());
81
- const response = await this.engine.run("schema_engine", [
82
- "--action",
83
- "create_database",
84
- "--path",
85
- rootPath
86
- ]);
87
- if (response.status != 200) {
88
- returnFormattedError(response.status, response.message);
196
+ UIUtils.showOperationHeader("CREATING DATABASE", this.name, "\u{1F5C4}\uFE0F");
197
+ await UIUtils.showItemProgress("Database", 1, 1);
198
+ try {
199
+ const response = await this.engine.run("schema_engine", [
200
+ "--action",
201
+ "create_database",
202
+ "--path",
203
+ rootPath
204
+ ]);
205
+ if (response.status != 200) {
206
+ UIUtils.showItemError("Database", `Error creating: ${response.message}`);
207
+ const summary2 = {
208
+ startTime,
209
+ totalProcessed: 0,
210
+ successCount: 0,
211
+ errorCount: 1,
212
+ processedItems: [],
213
+ operationName: "create database",
214
+ databaseName: this.name
215
+ };
216
+ UIUtils.showOperationSummary(summary2);
217
+ returnFormattedError(response.status, response.message);
218
+ }
219
+ UIUtils.showItemSuccess("Database");
220
+ const summary = {
221
+ startTime,
222
+ totalProcessed: 1,
223
+ successCount: 1,
224
+ errorCount: 0,
225
+ processedItems: [this.name],
226
+ operationName: "create database",
227
+ databaseName: this.name
228
+ };
229
+ UIUtils.showOperationSummary(summary);
230
+ return response.data;
231
+ } catch (error) {
232
+ UIUtils.showItemError("Database", error.message);
233
+ const summary = {
234
+ startTime,
235
+ totalProcessed: 0,
236
+ successCount: 0,
237
+ errorCount: 1,
238
+ processedItems: [],
239
+ operationName: "create database",
240
+ databaseName: this.name
241
+ };
242
+ UIUtils.showOperationSummary(summary);
243
+ throw error;
89
244
  }
90
- return response.data;
91
245
  }
92
246
  async refreshTables() {
247
+ const startTime = Date.now();
93
248
  const cubesDir = path2.join(process.cwd(), "dbcube", "cubes");
94
249
  if (!fs2.existsSync(cubesDir)) {
95
250
  throw new Error("\u274C The cubes folder does not exist");
@@ -97,11 +252,21 @@ var Schema = class {
97
252
  const cubeFiles = FileUtils_default.getCubeFilesRecursively("dbcube", "table.cube");
98
253
  if (cubeFiles.length === 0) {
99
254
  throw new Error("\u274C There are no cubes to execute");
100
- } else {
101
- for (const file of cubeFiles) {
102
- const filePath = path2.isAbsolute(file) ? file : path2.join(cubesDir, file);
103
- const stats = fs2.statSync(filePath);
104
- if (stats.isFile()) {
255
+ }
256
+ UIUtils.showOperationHeader("EXECUTING REFRESH TABLES", this.name, "\u{1F504}");
257
+ let totalTablesProcessed = 0;
258
+ let successCount = 0;
259
+ let errorCount = 0;
260
+ const processedTables = [];
261
+ for (let index = 0; index < cubeFiles.length; index++) {
262
+ const file = cubeFiles[index];
263
+ const filePath = path2.isAbsolute(file) ? file : path2.join(cubesDir, file);
264
+ const stats = fs2.statSync(filePath);
265
+ if (stats.isFile()) {
266
+ const getTableName = FileUtils_default.extracTableNameFromCube(filePath);
267
+ const tableName = getTableName.status === 200 ? getTableName.message : path2.basename(file, ".table.cube");
268
+ await UIUtils.showItemProgress(tableName, index + 1, cubeFiles.length);
269
+ try {
105
270
  const dml = await this.engine.run("schema_engine", [
106
271
  "--action",
107
272
  "parse_table",
@@ -111,7 +276,9 @@ var Schema = class {
111
276
  filePath
112
277
  ]);
113
278
  if (dml.status != 200) {
114
- returnFormattedError(dml.status, dml.message);
279
+ UIUtils.showItemError(tableName, `Error parsing: ${dml.message}`);
280
+ errorCount++;
281
+ continue;
115
282
  }
116
283
  const parseJson = JSON.stringify(dml.data.actions).replace(/[\r\n\t]/g, "").replace(/\\[rnt]/g, "").replace(/\s{2,}/g, " ");
117
284
  const queries = await this.engine.run("schema_engine", [
@@ -123,7 +290,9 @@ var Schema = class {
123
290
  parseJson
124
291
  ]);
125
292
  if (queries.status != 200) {
126
- returnFormattedError(queries.status, queries.message);
293
+ UIUtils.showItemError(tableName, `Error generating queries: ${queries.message}`);
294
+ errorCount++;
295
+ continue;
127
296
  }
128
297
  delete queries.data.database_type;
129
298
  const parseJsonQueries = JSON.stringify(queries.data);
@@ -136,17 +305,36 @@ var Schema = class {
136
305
  parseJsonQueries
137
306
  ]);
138
307
  if (response.status != 200) {
139
- returnFormattedError(response.status, response.message);
308
+ UIUtils.showItemError(tableName, `Error executing: ${response.message}`);
309
+ errorCount++;
310
+ continue;
140
311
  }
141
312
  const createQuery = queries.data.regular_queries.filter((q) => q.includes("CREATE"))[0];
142
313
  await TableProcessor.saveQuery(dml.data.table, dml.data.database, createQuery);
143
- return response.data;
314
+ UIUtils.showItemSuccess(tableName);
315
+ successCount++;
316
+ processedTables.push(tableName);
317
+ totalTablesProcessed++;
318
+ } catch (error) {
319
+ UIUtils.showItemError(tableName, error.message);
320
+ errorCount++;
144
321
  }
145
322
  }
146
323
  }
147
- return null;
324
+ const summary = {
325
+ startTime,
326
+ totalProcessed: totalTablesProcessed,
327
+ successCount,
328
+ errorCount,
329
+ processedItems: processedTables,
330
+ operationName: "refresh tables",
331
+ databaseName: this.name
332
+ };
333
+ UIUtils.showOperationSummary(summary);
334
+ return totalTablesProcessed > 0 ? { processed: totalTablesProcessed, success: successCount, errors: errorCount } : null;
148
335
  }
149
336
  async freshTables() {
337
+ const startTime = Date.now();
150
338
  const cubesDir = path2.join(process.cwd(), "dbcube", "cubes");
151
339
  if (!fs2.existsSync(cubesDir)) {
152
340
  throw new Error("\u274C The cubes folder does not exist");
@@ -154,11 +342,21 @@ var Schema = class {
154
342
  const cubeFiles = FileUtils_default.getCubeFilesRecursively("dbcube", "table.cube");
155
343
  if (cubeFiles.length === 0) {
156
344
  throw new Error("\u274C There are no cubes to execute");
157
- } else {
158
- for (const file of cubeFiles) {
159
- const filePath = path2.isAbsolute(file) ? file : path2.join(cubesDir, file);
160
- const stats = fs2.statSync(filePath);
161
- if (stats.isFile()) {
345
+ }
346
+ UIUtils.showOperationHeader("EXECUTING FRESH TABLES", this.name);
347
+ let totalTablesProcessed = 0;
348
+ let successCount = 0;
349
+ let errorCount = 0;
350
+ const processedTables = [];
351
+ for (let index = 0; index < cubeFiles.length; index++) {
352
+ const file = cubeFiles[index];
353
+ const filePath = path2.isAbsolute(file) ? file : path2.join(cubesDir, file);
354
+ const stats = fs2.statSync(filePath);
355
+ if (stats.isFile()) {
356
+ const getTableName = FileUtils_default.extracTableNameFromCube(filePath);
357
+ const tableName = getTableName.status === 200 ? getTableName.message : path2.basename(file, ".table.cube");
358
+ await UIUtils.showItemProgress(tableName, index + 1, cubeFiles.length);
359
+ try {
162
360
  const dml = await this.engine.run("schema_engine", [
163
361
  "--action",
164
362
  "parse_table",
@@ -168,7 +366,9 @@ var Schema = class {
168
366
  "fresh"
169
367
  ]);
170
368
  if (dml.status != 200) {
171
- returnFormattedError(dml.status, dml.message);
369
+ UIUtils.showItemError(tableName, `Error parsing: ${dml.message}`);
370
+ errorCount++;
371
+ continue;
172
372
  }
173
373
  const parseJson = JSON.stringify(dml.data.actions).replace(/[\r\n\t]/g, "").replace(/\\[rnt]/g, "").replace(/\s{2,}/g, " ");
174
374
  const queries = await this.engine.run("schema_engine", [
@@ -178,7 +378,9 @@ var Schema = class {
178
378
  parseJson
179
379
  ]);
180
380
  if (queries.status != 200) {
181
- returnFormattedError(queries.status, queries.message);
381
+ UIUtils.showItemError(tableName, `Error generating queries: ${queries.message}`);
382
+ errorCount++;
383
+ continue;
182
384
  }
183
385
  delete queries.data._type;
184
386
  const createQuery = queries.data.regular_queries.filter((q) => q.includes("CREATE"))[0];
@@ -196,16 +398,35 @@ var Schema = class {
196
398
  parseJsonQueries
197
399
  ]);
198
400
  if (response.status != 200) {
199
- returnFormattedError(response.status, response.message);
401
+ UIUtils.showItemError(tableName, `Error executing: ${response.message}`);
402
+ errorCount++;
403
+ continue;
200
404
  }
201
405
  await TableProcessor.saveQuery(dml.data.table, dml.data.database, createQuery);
202
- return response.data;
406
+ UIUtils.showItemSuccess(tableName);
407
+ successCount++;
408
+ processedTables.push(tableName);
409
+ totalTablesProcessed++;
410
+ } catch (error) {
411
+ UIUtils.showItemError(tableName, error.message);
412
+ errorCount++;
203
413
  }
204
414
  }
205
415
  }
206
- return null;
416
+ const summary = {
417
+ startTime,
418
+ totalProcessed: totalTablesProcessed,
419
+ successCount,
420
+ errorCount,
421
+ processedItems: processedTables,
422
+ operationName: "fresh tables",
423
+ databaseName: this.name
424
+ };
425
+ UIUtils.showOperationSummary(summary);
426
+ return totalTablesProcessed > 0 ? { processed: totalTablesProcessed, success: successCount, errors: errorCount } : null;
207
427
  }
208
428
  async executeSeeders() {
429
+ const startTime = Date.now();
209
430
  const cubesDir = path2.join(process.cwd(), "dbcube", "cubes");
210
431
  if (!fs2.existsSync(cubesDir)) {
211
432
  throw new Error("\u274C The cubes folder does not exist");
@@ -213,11 +434,21 @@ var Schema = class {
213
434
  const cubeFiles = FileUtils_default.getCubeFilesRecursively("dbcube", "seeder.cube");
214
435
  if (cubeFiles.length === 0) {
215
436
  throw new Error("\u274C There are no cubes to execute");
216
- } else {
217
- for (const file of cubeFiles) {
218
- const filePath = path2.isAbsolute(file) ? file : path2.join(cubesDir, file);
219
- const stats = fs2.statSync(filePath);
220
- if (stats.isFile()) {
437
+ }
438
+ UIUtils.showOperationHeader("EXECUTING SEEDERS", this.name, "\u{1F331}");
439
+ let totalSeedersProcessed = 0;
440
+ let successCount = 0;
441
+ let errorCount = 0;
442
+ const processedSeeders = [];
443
+ for (let index = 0; index < cubeFiles.length; index++) {
444
+ const file = cubeFiles[index];
445
+ const filePath = path2.isAbsolute(file) ? file : path2.join(cubesDir, file);
446
+ const stats = fs2.statSync(filePath);
447
+ if (stats.isFile()) {
448
+ const getSeederName = FileUtils_default.extracTableNameFromCube(filePath);
449
+ const seederName = getSeederName.status === 200 ? getSeederName.message : path2.basename(file, ".seeder.cube");
450
+ await UIUtils.showItemProgress(seederName, index + 1, cubeFiles.length);
451
+ try {
221
452
  const response = await this.engine.run("schema_engine", [
222
453
  "--action",
223
454
  "seeder",
@@ -225,15 +456,34 @@ var Schema = class {
225
456
  filePath
226
457
  ]);
227
458
  if (response.status != 200) {
228
- returnFormattedError(response.status, response.message);
459
+ UIUtils.showItemError(seederName, `Error executing: ${response.message}`);
460
+ errorCount++;
461
+ continue;
229
462
  }
230
- return response.data;
463
+ UIUtils.showItemSuccess(seederName);
464
+ successCount++;
465
+ processedSeeders.push(seederName);
466
+ totalSeedersProcessed++;
467
+ } catch (error) {
468
+ UIUtils.showItemError(seederName, error.message);
469
+ errorCount++;
231
470
  }
232
471
  }
233
472
  }
234
- return null;
473
+ const summary = {
474
+ startTime,
475
+ totalProcessed: totalSeedersProcessed,
476
+ successCount,
477
+ errorCount,
478
+ processedItems: processedSeeders,
479
+ operationName: "seeders",
480
+ databaseName: this.name
481
+ };
482
+ UIUtils.showOperationSummary(summary);
483
+ return totalSeedersProcessed > 0 ? { processed: totalSeedersProcessed, success: successCount, errors: errorCount } : null;
235
484
  }
236
485
  async executeTriggers() {
486
+ const startTime = Date.now();
237
487
  const cubesDir = path2.join(process.cwd(), "dbcube", "cubes");
238
488
  const triggersDirExit = path2.join(process.cwd(), "dbcube", "triggers");
239
489
  if (!fs2.existsSync(cubesDir)) {
@@ -242,11 +492,21 @@ var Schema = class {
242
492
  const cubeFiles = FileUtils_default.getCubeFilesRecursively("dbcube", "trigger.cube");
243
493
  if (cubeFiles.length === 0) {
244
494
  throw new Error("\u274C There are no cubes to execute");
245
- } else {
246
- for (const file of cubeFiles) {
247
- const filePath = path2.isAbsolute(file) ? file : path2.join(cubesDir, file);
248
- const stats = fs2.statSync(filePath);
249
- if (stats.isFile()) {
495
+ }
496
+ UIUtils.showOperationHeader("EXECUTING TRIGGERS", this.name, "\u26A1");
497
+ let totalTriggersProcessed = 0;
498
+ let successCount = 0;
499
+ let errorCount = 0;
500
+ const processedTriggers = [];
501
+ for (let index = 0; index < cubeFiles.length; index++) {
502
+ const file = cubeFiles[index];
503
+ const filePath = path2.isAbsolute(file) ? file : path2.join(cubesDir, file);
504
+ const stats = fs2.statSync(filePath);
505
+ if (stats.isFile()) {
506
+ const getTriggerName = FileUtils_default.extracTableNameFromCube(filePath);
507
+ const triggerName = getTriggerName.status === 200 ? getTriggerName.message : path2.basename(file, ".trigger.cube");
508
+ await UIUtils.showItemProgress(triggerName, index + 1, cubeFiles.length);
509
+ try {
250
510
  const response = await this.engine.run("schema_engine", [
251
511
  "--action",
252
512
  "trigger",
@@ -256,13 +516,31 @@ var Schema = class {
256
516
  filePath
257
517
  ]);
258
518
  if (response.status != 200) {
259
- returnFormattedError(response.status, response.message);
519
+ UIUtils.showItemError(triggerName, `Error executing: ${response.message}`);
520
+ errorCount++;
521
+ continue;
260
522
  }
261
- return response.data;
523
+ UIUtils.showItemSuccess(triggerName);
524
+ successCount++;
525
+ processedTriggers.push(triggerName);
526
+ totalTriggersProcessed++;
527
+ } catch (error) {
528
+ UIUtils.showItemError(triggerName, error.message);
529
+ errorCount++;
262
530
  }
263
531
  }
264
532
  }
265
- return null;
533
+ const summary = {
534
+ startTime,
535
+ totalProcessed: totalTriggersProcessed,
536
+ successCount,
537
+ errorCount,
538
+ processedItems: processedTriggers,
539
+ operationName: "triggers",
540
+ databaseName: this.name
541
+ };
542
+ UIUtils.showOperationSummary(summary);
543
+ return totalTriggersProcessed > 0 ? { processed: totalTriggersProcessed, success: successCount, errors: errorCount } : null;
266
544
  }
267
545
  };
268
546
  function returnFormattedError(status, message) {