@dbcube/schema-builder 1.0.16 → 1.0.18

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
@@ -6,9 +6,9 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
6
6
  });
7
7
 
8
8
  // src/lib/Schema.ts
9
- import fs3 from "fs";
9
+ import fs5 from "fs";
10
10
  import { Engine, TableProcessor, Config as ConfigClass } from "@dbcube/core";
11
- import path2 from "path";
11
+ import path4 from "path";
12
12
 
13
13
  // src/lib/FileUtils.ts
14
14
  import * as fs from "fs";
@@ -255,6 +255,550 @@ ${chalk.red("\u{1F6AB}")} ${chalk.bold.red("ERRORS FOUND")}`);
255
255
  }
256
256
  };
257
257
 
258
+ // src/lib/CubeValidator.ts
259
+ import fs3 from "fs";
260
+ import path2 from "path";
261
+ var CubeValidator = class {
262
+ validTypes = ["varchar", "int", "string", "text", "boolean", "date", "datetime", "timestamp", "decimal", "float", "double", "enum", "json"];
263
+ validOptions = ["not null", "primary", "autoincrement", "unique", "zerofill", "index", "required", "unsigned"];
264
+ validProperties = ["type", "length", "options", "value", "defaultValue", "foreign", "enumValues", "description"];
265
+ knownAnnotations = ["database", "table", "meta", "columns", "fields", "dataset", "beforeAdd", "afterAdd", "beforeUpdate", "afterUpdate", "beforeDelete", "afterDelete", "compute", "column"];
266
+ /**
267
+ * Validates a cube file comprehensively
268
+ */
269
+ validateCubeFile(filePath) {
270
+ const errors = [];
271
+ try {
272
+ const content = fs3.readFileSync(filePath, "utf8");
273
+ const lines = content.split("\n");
274
+ const fileName = path2.basename(filePath, path2.extname(filePath));
275
+ for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
276
+ const line = lines[lineIndex];
277
+ if (line.trim() === "" || line.trim().startsWith("//")) {
278
+ continue;
279
+ }
280
+ this.validateAnnotations(line, lineIndex + 1, filePath, fileName, errors);
281
+ this.validateDataTypes(line, lineIndex + 1, filePath, fileName, errors, content);
282
+ this.validateColumnOptions(line, lineIndex + 1, filePath, fileName, errors, lines);
283
+ this.validateColumnProperties(line, lineIndex + 1, filePath, fileName, errors, content);
284
+ this.validateRequiredColumnProperties(lines, lineIndex + 1, filePath, fileName, errors);
285
+ this.validateGeneralSyntax(line, lineIndex + 1, filePath, fileName, errors);
286
+ }
287
+ this.validateOverallStructure(content, filePath, fileName, errors);
288
+ } catch (error) {
289
+ errors.push({
290
+ itemName: path2.basename(filePath, path2.extname(filePath)),
291
+ error: `Failed to read cube file: ${error.message}`,
292
+ filePath,
293
+ lineNumber: 1
294
+ });
295
+ }
296
+ return {
297
+ isValid: errors.length === 0,
298
+ errors
299
+ };
300
+ }
301
+ validateAnnotations(line, lineNumber, filePath, fileName, errors) {
302
+ const annotationRegex = /@(\w+)/g;
303
+ let match;
304
+ while ((match = annotationRegex.exec(line)) !== null) {
305
+ const annotation = match[1];
306
+ if (!this.knownAnnotations.includes(annotation)) {
307
+ errors.push({
308
+ itemName: fileName,
309
+ error: `Unknown annotation '@${annotation}'. Valid annotations: ${this.knownAnnotations.join(", ")}`,
310
+ filePath,
311
+ lineNumber
312
+ });
313
+ }
314
+ }
315
+ }
316
+ validateDataTypes(line, lineNumber, filePath, fileName, errors, content) {
317
+ const typeRegex = /type:\s*["'](\w+)["']/g;
318
+ let match;
319
+ while ((match = typeRegex.exec(line)) !== null) {
320
+ const type = match[1];
321
+ if (!this.validTypes.includes(type)) {
322
+ errors.push({
323
+ itemName: fileName,
324
+ error: `Invalid data type '${type}'. Valid types: ${this.validTypes.join(", ")}`,
325
+ filePath,
326
+ lineNumber
327
+ });
328
+ }
329
+ }
330
+ if (line.includes('type: "varchar"')) {
331
+ const lines = content.split("\n");
332
+ const hasLengthNearby = lines.slice(Math.max(0, lineNumber - 1), Math.min(lineNumber + 4, lines.length)).some((nextLine) => nextLine.includes("length:"));
333
+ if (!hasLengthNearby) {
334
+ errors.push({
335
+ itemName: fileName,
336
+ error: "VARCHAR type requires a length specification",
337
+ filePath,
338
+ lineNumber
339
+ });
340
+ }
341
+ }
342
+ }
343
+ validateColumnOptions(line, lineNumber, filePath, fileName, errors, lines) {
344
+ const optionsMatch = line.match(/^\s*options\s*:\s*\[(.*)\]\s*;?\s*$/);
345
+ if (!optionsMatch) return;
346
+ const optionsContent = optionsMatch[1].trim();
347
+ const invalidSyntaxMatch = optionsContent.match(/[^",\s]+(?![^"]*")/);
348
+ if (invalidSyntaxMatch) {
349
+ errors.push({
350
+ itemName: fileName,
351
+ error: `Invalid syntax '${invalidSyntaxMatch[0]}' in options array. All values must be quoted strings`,
352
+ filePath,
353
+ lineNumber
354
+ });
355
+ return;
356
+ }
357
+ const optionMatches = optionsContent.match(/"([^"]*)"/g);
358
+ if (optionMatches) {
359
+ const columnType = this.getColumnTypeForOptions(lines, lineNumber - 1);
360
+ optionMatches.forEach((optionMatch) => {
361
+ const option = optionMatch.replace(/"/g, "");
362
+ if (option.trim() === "") {
363
+ errors.push({
364
+ itemName: fileName,
365
+ error: "Empty option found in options array. All options must have a value",
366
+ filePath,
367
+ lineNumber
368
+ });
369
+ } else if (!this.validOptions.includes(option)) {
370
+ errors.push({
371
+ itemName: fileName,
372
+ error: `Invalid option '${option}'. Valid options: ${this.validOptions.join(", ")}`,
373
+ filePath,
374
+ lineNumber
375
+ });
376
+ } else if (columnType !== "unknown" && !this.isOptionCompatibleWithType(option, columnType)) {
377
+ errors.push({
378
+ itemName: fileName,
379
+ error: `Option '${option}' is not compatible with type '${columnType}'`,
380
+ filePath,
381
+ lineNumber
382
+ });
383
+ }
384
+ });
385
+ }
386
+ }
387
+ validateColumnProperties(line, lineNumber, filePath, fileName, errors, content) {
388
+ const propertyKeyRegex = /^\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*:/;
389
+ const propMatch = propertyKeyRegex.exec(line);
390
+ if (!propMatch) return;
391
+ const propertyName = propMatch[1];
392
+ if (/^\s*[a-zA-Z_][a-zA-Z0-9_]*\s*:\s*\{/.test(line)) {
393
+ return;
394
+ }
395
+ if (this.isInsideForeignKeyObject(content, lineNumber - 1)) {
396
+ const validForeignKeyProperties = ["table", "column"];
397
+ if (!validForeignKeyProperties.includes(propertyName)) {
398
+ errors.push({
399
+ itemName: fileName,
400
+ error: `Invalid foreign key property '${propertyName}'. Valid foreign key properties: ${validForeignKeyProperties.join(", ")}`,
401
+ filePath,
402
+ lineNumber
403
+ });
404
+ }
405
+ return;
406
+ }
407
+ if (this.isInsideColumnsBlock(content, lineNumber - 1)) {
408
+ if (!this.validProperties.includes(propertyName)) {
409
+ errors.push({
410
+ itemName: fileName,
411
+ error: `Invalid property '${propertyName}'. Valid properties: ${this.validProperties.join(", ")}`,
412
+ filePath,
413
+ lineNumber
414
+ });
415
+ }
416
+ }
417
+ if (/^\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*$/.test(line)) {
418
+ errors.push({
419
+ itemName: fileName,
420
+ error: `Property '${propertyName}' is missing a value`,
421
+ filePath,
422
+ lineNumber
423
+ });
424
+ }
425
+ }
426
+ validateRequiredColumnProperties(lines, lineNumber, filePath, fileName, errors) {
427
+ const line = lines[lineNumber - 1];
428
+ if (!/^\s*\}\s*;?\s*$/.test(line)) {
429
+ return;
430
+ }
431
+ let columnStartLine = -1;
432
+ let columnName = "";
433
+ for (let i = lineNumber - 2; i >= 0; i--) {
434
+ const currentLine = lines[i];
435
+ const columnDefMatch = currentLine.match(/^\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*\{/);
436
+ if (columnDefMatch) {
437
+ let openBraces = 0;
438
+ let closeBraces = 0;
439
+ for (let j = i; j < lineNumber; j++) {
440
+ openBraces += (lines[j].match(/\{/g) || []).length;
441
+ closeBraces += (lines[j].match(/\}/g) || []).length;
442
+ }
443
+ if (openBraces === closeBraces) {
444
+ columnStartLine = i;
445
+ columnName = columnDefMatch[1];
446
+ break;
447
+ }
448
+ }
449
+ }
450
+ if (columnStartLine === -1 || !columnName) return;
451
+ let hasType = false;
452
+ for (let i = columnStartLine + 1; i < lineNumber - 1; i++) {
453
+ if (lines[i].match(/^\s*type\s*:/)) {
454
+ hasType = true;
455
+ break;
456
+ }
457
+ }
458
+ if (!hasType && columnName !== "foreign" && columnName !== "defaultValue") {
459
+ errors.push({
460
+ itemName: fileName,
461
+ error: `Column '${columnName}' is missing required 'type' property`,
462
+ filePath,
463
+ lineNumber: columnStartLine + 1
464
+ });
465
+ }
466
+ }
467
+ validateGeneralSyntax(line, lineNumber, filePath, fileName, errors) {
468
+ const quotes = line.match(/["']/g);
469
+ if (quotes && quotes.length % 2 !== 0) {
470
+ errors.push({
471
+ itemName: fileName,
472
+ error: "Mismatched quotes detected",
473
+ filePath,
474
+ lineNumber
475
+ });
476
+ }
477
+ if (line.includes("@database") || line.includes("@table")) {
478
+ const stringAnnotationRegex = /@(database|table)\s*\(\s*"([^"]*)"\s*\)/;
479
+ if (!stringAnnotationRegex.test(line)) {
480
+ errors.push({
481
+ itemName: fileName,
482
+ error: 'Invalid annotation syntax. Expected format: @annotation("value")',
483
+ filePath,
484
+ lineNumber
485
+ });
486
+ }
487
+ }
488
+ if (line.includes("@meta")) {
489
+ const metaObjectRegex = /@meta\s*\(\s*\{/;
490
+ if (!metaObjectRegex.test(line)) {
491
+ errors.push({
492
+ itemName: fileName,
493
+ error: "Invalid @meta syntax. Expected format: @meta({ ... })",
494
+ filePath,
495
+ lineNumber
496
+ });
497
+ }
498
+ }
499
+ }
500
+ validateOverallStructure(content, filePath, fileName, errors) {
501
+ const lines = content.split("\n");
502
+ const hasDatabase = lines.some((line) => line.includes("@database"));
503
+ if (!hasDatabase) {
504
+ errors.push({
505
+ itemName: fileName,
506
+ error: "Missing required @database annotation",
507
+ filePath,
508
+ lineNumber: 1
509
+ });
510
+ }
511
+ if (filePath.includes(".table.cube")) {
512
+ const hasColumns = lines.some((line) => line.includes("@columns"));
513
+ if (!hasColumns) {
514
+ errors.push({
515
+ itemName: fileName,
516
+ error: "Table cube files require @columns annotation",
517
+ filePath,
518
+ lineNumber: 1
519
+ });
520
+ }
521
+ }
522
+ }
523
+ getColumnTypeForOptions(lines, optionsLineIndex) {
524
+ for (let i = optionsLineIndex - 1; i >= 0; i--) {
525
+ const line = lines[i];
526
+ const typeMatch = line.match(/^\s*type\s*:\s*"([^"]+)"/);
527
+ if (typeMatch) {
528
+ return typeMatch[1];
529
+ }
530
+ if (/^\s*[a-zA-Z_][a-zA-Z0-9_]*\s*:\s*\{/.test(line)) {
531
+ break;
532
+ }
533
+ }
534
+ return "unknown";
535
+ }
536
+ isOptionCompatibleWithType(option, type) {
537
+ const compatibilityRules = {
538
+ "zerofill": ["int", "decimal", "float", "double"],
539
+ "unsigned": ["int", "decimal", "float", "double"],
540
+ "autoincrement": ["int"],
541
+ "primary": ["int", "varchar", "string"],
542
+ "not null": ["int", "varchar", "string", "text", "boolean", "date", "datetime", "timestamp", "decimal", "float", "double"],
543
+ "unique": ["int", "varchar", "string", "text"],
544
+ "index": ["int", "varchar", "string", "text", "date", "datetime", "timestamp"],
545
+ "required": ["int", "varchar", "string", "text", "boolean", "date", "datetime", "timestamp", "decimal", "float", "double"]
546
+ };
547
+ const compatibleTypes = compatibilityRules[option];
548
+ if (!compatibleTypes) {
549
+ return true;
550
+ }
551
+ return compatibleTypes.includes(type);
552
+ }
553
+ isInsideColumnsBlock(content, lineIndex) {
554
+ const lines = content.split("\n");
555
+ let columnsStartLine = -1;
556
+ let columnsEndLine = -1;
557
+ for (let i = 0; i < lines.length; i++) {
558
+ if (lines[i].includes("@columns")) {
559
+ columnsStartLine = i;
560
+ let braceCount = 0;
561
+ for (let j = i; j < lines.length; j++) {
562
+ const currentLine = lines[j];
563
+ braceCount += (currentLine.match(/\{/g) || []).length;
564
+ braceCount -= (currentLine.match(/\}/g) || []).length;
565
+ if (braceCount === 0 && j > i) {
566
+ columnsEndLine = j;
567
+ break;
568
+ }
569
+ }
570
+ break;
571
+ }
572
+ }
573
+ return columnsStartLine !== -1 && columnsEndLine !== -1 && lineIndex > columnsStartLine && lineIndex < columnsEndLine;
574
+ }
575
+ isInsideForeignKeyObject(content, lineIndex) {
576
+ const lines = content.split("\n");
577
+ for (let i = lineIndex; i >= 0; i--) {
578
+ const line = lines[i];
579
+ if (/foreign\s*:\s*\{/.test(line)) {
580
+ let braceCount = 0;
581
+ for (let j = i; j <= lineIndex; j++) {
582
+ const currentLine = lines[j];
583
+ const openBraces = (currentLine.match(/\{/g) || []).length;
584
+ const closeBraces = (currentLine.match(/\}/g) || []).length;
585
+ braceCount += openBraces - closeBraces;
586
+ if (braceCount === 0 && j > i) {
587
+ return false;
588
+ }
589
+ }
590
+ return braceCount > 0;
591
+ }
592
+ if (line.trim() === "}" || line.includes("};")) {
593
+ break;
594
+ }
595
+ }
596
+ return false;
597
+ }
598
+ };
599
+
600
+ // src/lib/DependencyResolver.ts
601
+ import fs4 from "fs";
602
+ import path3 from "path";
603
+ var DependencyResolver = class {
604
+ /**
605
+ * Resolves table dependencies and creates execution order
606
+ */
607
+ static resolveDependencies(cubeFiles, cubeType = "table") {
608
+ const tableDependencies = this.extractDependencies(cubeFiles, cubeType);
609
+ const orderedTables = this.topologicalSort(tableDependencies);
610
+ const executionOrder = {
611
+ tables: cubeType === "table" ? orderedTables : [],
612
+ seeders: cubeType === "seeder" ? orderedTables : [],
613
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
614
+ };
615
+ this.saveExecutionOrder(executionOrder);
616
+ return executionOrder;
617
+ }
618
+ /**
619
+ * Extracts dependencies from cube files
620
+ */
621
+ static extractDependencies(cubeFiles, cubeType) {
622
+ const dependencies = [];
623
+ for (const file of cubeFiles) {
624
+ let filePath;
625
+ if (path3.isAbsolute(file)) {
626
+ filePath = file;
627
+ } else if (fs4.existsSync(file)) {
628
+ filePath = path3.resolve(file);
629
+ } else {
630
+ filePath = path3.join(process.cwd(), "dbcube", "cubes", file);
631
+ }
632
+ try {
633
+ const tableNameResult = FileUtils_default.extracTableNameFromCube(filePath);
634
+ const tableName = tableNameResult.status === 200 ? tableNameResult.message : path3.basename(file, `.${cubeType}.cube`);
635
+ const deps = this.extractForeignKeyReferences(filePath);
636
+ dependencies.push({
637
+ tableName,
638
+ filePath,
639
+ dependencies: deps
640
+ });
641
+ } catch (error) {
642
+ console.error(`Error processing ${filePath}:`, error);
643
+ }
644
+ }
645
+ return dependencies;
646
+ }
647
+ /**
648
+ * Extracts foreign key references from a cube file
649
+ */
650
+ static extractForeignKeyReferences(filePath) {
651
+ const dependencies = [];
652
+ try {
653
+ const content = fs4.readFileSync(filePath, "utf8");
654
+ const lines = content.split("\n");
655
+ let insideForeignKey = false;
656
+ let braceCount = 0;
657
+ for (const line of lines) {
658
+ if (/foreign\s*:\s*\{/.test(line)) {
659
+ insideForeignKey = true;
660
+ braceCount = 1;
661
+ const sameLineMatch = line.match(/table\s*:\s*["']([^"']+)["']/);
662
+ if (sameLineMatch) {
663
+ dependencies.push(sameLineMatch[1]);
664
+ insideForeignKey = false;
665
+ braceCount = 0;
666
+ }
667
+ continue;
668
+ }
669
+ if (insideForeignKey) {
670
+ braceCount += (line.match(/\{/g) || []).length;
671
+ braceCount -= (line.match(/\}/g) || []).length;
672
+ const tableMatch = line.match(/table\s*:\s*["']([^"']+)["']/);
673
+ if (tableMatch) {
674
+ dependencies.push(tableMatch[1]);
675
+ }
676
+ if (braceCount === 0) {
677
+ insideForeignKey = false;
678
+ }
679
+ }
680
+ }
681
+ } catch (error) {
682
+ console.error(`Error reading file ${filePath}:`, error);
683
+ }
684
+ return dependencies;
685
+ }
686
+ /**
687
+ * Performs topological sort to determine execution order
688
+ */
689
+ static topologicalSort(dependencies) {
690
+ const graph = /* @__PURE__ */ new Map();
691
+ const inDegree = /* @__PURE__ */ new Map();
692
+ const tableMap = /* @__PURE__ */ new Map();
693
+ for (const dep of dependencies) {
694
+ graph.set(dep.tableName, dep.dependencies);
695
+ inDegree.set(dep.tableName, 0);
696
+ tableMap.set(dep.tableName, dep);
697
+ }
698
+ for (const dep of dependencies) {
699
+ for (const dependency of dep.dependencies) {
700
+ if (inDegree.has(dependency)) {
701
+ inDegree.set(dep.tableName, (inDegree.get(dep.tableName) || 0) + 1);
702
+ }
703
+ }
704
+ }
705
+ const queue = [];
706
+ const result = [];
707
+ for (const [table, degree] of inDegree) {
708
+ if (degree === 0) {
709
+ queue.push(table);
710
+ }
711
+ }
712
+ while (queue.length > 0) {
713
+ const current = queue.shift();
714
+ result.push(current);
715
+ const currentDeps = graph.get(current) || [];
716
+ for (const neighbor of currentDeps) {
717
+ if (inDegree.has(neighbor)) {
718
+ const newDegree = (inDegree.get(neighbor) || 0) - 1;
719
+ inDegree.set(neighbor, newDegree);
720
+ if (newDegree === 0) {
721
+ queue.push(neighbor);
722
+ }
723
+ }
724
+ }
725
+ }
726
+ if (result.length !== dependencies.length) {
727
+ console.warn("\u26A0\uFE0F Circular dependencies detected in tables. Some tables may not execute in optimal order.");
728
+ for (const dep of dependencies) {
729
+ if (!result.includes(dep.tableName)) {
730
+ result.push(dep.tableName);
731
+ }
732
+ }
733
+ }
734
+ return result;
735
+ }
736
+ /**
737
+ * Saves the execution order to .dbcube/orderexecute.json
738
+ */
739
+ static saveExecutionOrder(order) {
740
+ try {
741
+ const projectRoot = process.cwd();
742
+ const dbcubeDir = path3.join(projectRoot, ".dbcube");
743
+ const orderFile = path3.join(dbcubeDir, "orderexecute.json");
744
+ if (!fs4.existsSync(dbcubeDir)) {
745
+ fs4.mkdirSync(dbcubeDir, { recursive: true });
746
+ }
747
+ fs4.writeFileSync(orderFile, JSON.stringify(order, null, 2), "utf8");
748
+ console.log(`\u{1F4C4} Execution order saved to: ${path3.relative(projectRoot, orderFile)}`);
749
+ } catch (error) {
750
+ console.error("\u274C Failed to save execution order:", error);
751
+ }
752
+ }
753
+ /**
754
+ * Loads the execution order from .dbcube/orderexecute.json
755
+ */
756
+ static loadExecutionOrder() {
757
+ try {
758
+ const projectRoot = process.cwd();
759
+ const orderFile = path3.join(projectRoot, ".dbcube", "orderexecute.json");
760
+ if (!fs4.existsSync(orderFile)) {
761
+ return null;
762
+ }
763
+ const content = fs4.readFileSync(orderFile, "utf8");
764
+ return JSON.parse(content);
765
+ } catch (error) {
766
+ console.error("\u274C Failed to load execution order:", error);
767
+ return null;
768
+ }
769
+ }
770
+ /**
771
+ * Orders cube files based on saved execution order
772
+ */
773
+ static orderCubeFiles(cubeFiles, cubeType) {
774
+ const executionOrder = this.loadExecutionOrder();
775
+ if (!executionOrder) {
776
+ console.log("\u{1F4C4} No execution order found, processing files in current order");
777
+ return cubeFiles;
778
+ }
779
+ const orderList = cubeType === "table" ? executionOrder.tables : executionOrder.seeders;
780
+ const orderedFiles = [];
781
+ const fileMap = /* @__PURE__ */ new Map();
782
+ for (const file of cubeFiles) {
783
+ const filePath = path3.isAbsolute(file) ? file : path3.join(process.cwd(), "dbcube", "cubes", file);
784
+ const tableNameResult = FileUtils_default.extracTableNameFromCube(filePath);
785
+ const tableName = tableNameResult.status === 200 ? tableNameResult.message : path3.basename(file, `.${cubeType}.cube`);
786
+ fileMap.set(tableName, file);
787
+ }
788
+ for (const tableName of orderList) {
789
+ if (fileMap.has(tableName)) {
790
+ orderedFiles.push(fileMap.get(tableName));
791
+ fileMap.delete(tableName);
792
+ }
793
+ }
794
+ for (const [, file] of fileMap) {
795
+ orderedFiles.push(file);
796
+ }
797
+ console.log(`\u{1F4CB} Using dependency order: ${orderList.join(" \u2192 ")}`);
798
+ return orderedFiles;
799
+ }
800
+ };
801
+
258
802
  // src/lib/Schema.ts
259
803
  var Schema = class {
260
804
  name;
@@ -264,18 +808,27 @@ var Schema = class {
264
808
  this.engine = new Engine(name);
265
809
  }
266
810
  /**
267
- * Validates that the database specified in cube file exists in configuration
811
+ * Validates cube file comprehensively including syntax, database configuration, and structure
268
812
  * @param filePath - Path to the cube file
269
- * @returns true if valid, throws error if invalid
813
+ * @returns validation result with any errors found
270
814
  */
271
815
  validateDatabaseConfiguration(filePath) {
272
816
  try {
817
+ const cubeValidator = new CubeValidator();
818
+ const cubeValidation = cubeValidator.validateCubeFile(filePath);
819
+ if (!cubeValidation.isValid && cubeValidation.errors.length > 0) {
820
+ return {
821
+ isValid: false,
822
+ error: cubeValidation.errors[0]
823
+ // Return the first error found
824
+ };
825
+ }
273
826
  const dbResult = FileUtils_default.extractDatabaseNameFromCube(filePath);
274
827
  if (dbResult.status !== 200) {
275
828
  return {
276
829
  isValid: false,
277
830
  error: {
278
- itemName: path2.basename(filePath, path2.extname(filePath)),
831
+ itemName: path4.basename(filePath, path4.extname(filePath)),
279
832
  error: `Error reading database directive: ${dbResult.message}`,
280
833
  filePath,
281
834
  lineNumber: this.findDatabaseLineNumber(filePath)
@@ -284,7 +837,7 @@ var Schema = class {
284
837
  }
285
838
  const cubeDbName = dbResult.message;
286
839
  const configInstance = new ConfigClass();
287
- const configFilePath = path2.resolve(process.cwd(), "dbcube.config.js");
840
+ const configFilePath = path4.resolve(process.cwd(), "dbcube.config.js");
288
841
  const configFn = __require(configFilePath);
289
842
  if (typeof configFn === "function") {
290
843
  configFn(configInstance);
@@ -311,7 +864,7 @@ var Schema = class {
311
864
  return {
312
865
  isValid: false,
313
866
  error: {
314
- itemName: path2.basename(filePath, path2.extname(filePath)),
867
+ itemName: path4.basename(filePath, path4.extname(filePath)),
315
868
  error: `Database configuration '${cubeDbName}' not found in dbcube.config.js. Available: ${availableText}`,
316
869
  filePath,
317
870
  lineNumber: this.findDatabaseLineNumber(filePath)
@@ -323,7 +876,7 @@ var Schema = class {
323
876
  return {
324
877
  isValid: false,
325
878
  error: {
326
- itemName: path2.basename(filePath, path2.extname(filePath)),
879
+ itemName: path4.basename(filePath, path4.extname(filePath)),
327
880
  error: `Database configuration validation failed: ${error.message}`,
328
881
  filePath,
329
882
  lineNumber: this.findDatabaseLineNumber(filePath)
@@ -336,7 +889,7 @@ var Schema = class {
336
889
  */
337
890
  findDatabaseLineNumber(filePath) {
338
891
  try {
339
- const content = fs3.readFileSync(filePath, "utf8");
892
+ const content = fs5.readFileSync(filePath, "utf8");
340
893
  const lines = content.split("\n");
341
894
  for (let i = 0; i < lines.length; i++) {
342
895
  if (lines[i].includes("@database")) {
@@ -350,7 +903,7 @@ var Schema = class {
350
903
  }
351
904
  async createDatabase() {
352
905
  const startTime = Date.now();
353
- const rootPath = path2.resolve(process.cwd());
906
+ const rootPath = path4.resolve(process.cwd());
354
907
  UIUtils.showOperationHeader(" CREATING DATABASE", this.name, "\u{1F5C4}\uFE0F");
355
908
  await UIUtils.showItemProgress("Preparando e instalando base de datos", 1, 1);
356
909
  try {
@@ -394,28 +947,31 @@ var Schema = class {
394
947
  }
395
948
  async refreshTables() {
396
949
  const startTime = Date.now();
397
- const cubesDir = path2.join(process.cwd(), "dbcube", "cubes");
398
- if (!fs3.existsSync(cubesDir)) {
950
+ const cubesDir = path4.join(process.cwd(), "dbcube", "cubes");
951
+ if (!fs5.existsSync(cubesDir)) {
399
952
  throw new Error("\u274C The cubes folder does not exist");
400
953
  }
401
954
  const cubeFiles = FileUtils_default.getCubeFilesRecursively("dbcube", "table.cube");
402
955
  if (cubeFiles.length === 0) {
403
956
  throw new Error("\u274C There are no cubes to execute");
404
957
  }
958
+ console.log("\u{1F504} Resolving table dependencies...");
959
+ DependencyResolver.resolveDependencies(cubeFiles, "table");
960
+ const orderedCubeFiles = DependencyResolver.orderCubeFiles(cubeFiles, "table");
405
961
  UIUtils.showOperationHeader("EXECUTING REFRESH TABLES", this.name, "\u{1F504}");
406
962
  let totalTablesProcessed = 0;
407
963
  let successCount = 0;
408
964
  let errorCount = 0;
409
965
  const processedTables = [];
410
966
  const errors = [];
411
- for (let index = 0; index < cubeFiles.length; index++) {
412
- const file = cubeFiles[index];
413
- const filePath = path2.isAbsolute(file) ? file : path2.join(cubesDir, file);
414
- const stats = fs3.statSync(filePath);
967
+ for (let index = 0; index < orderedCubeFiles.length; index++) {
968
+ const file = orderedCubeFiles[index];
969
+ const filePath = path4.isAbsolute(file) ? file : path4.join(cubesDir, file);
970
+ const stats = fs5.statSync(filePath);
415
971
  if (stats.isFile()) {
416
972
  const getTableName = FileUtils_default.extracTableNameFromCube(filePath);
417
- const tableName = getTableName.status === 200 ? getTableName.message : path2.basename(file, ".table.cube");
418
- await UIUtils.showItemProgress(tableName, index + 1, cubeFiles.length);
973
+ const tableName = getTableName.status === 200 ? getTableName.message : path4.basename(file, ".table.cube");
974
+ await UIUtils.showItemProgress(tableName, index + 1, orderedCubeFiles.length);
419
975
  try {
420
976
  const validation = this.validateDatabaseConfiguration(filePath);
421
977
  if (!validation.isValid && validation.error) {
@@ -496,28 +1052,31 @@ var Schema = class {
496
1052
  }
497
1053
  async freshTables() {
498
1054
  const startTime = Date.now();
499
- const cubesDir = path2.join(process.cwd(), "dbcube", "cubes");
500
- if (!fs3.existsSync(cubesDir)) {
1055
+ const cubesDir = path4.join(process.cwd(), "dbcube", "cubes");
1056
+ if (!fs5.existsSync(cubesDir)) {
501
1057
  throw new Error("\u274C The cubes folder does not exist");
502
1058
  }
503
1059
  const cubeFiles = FileUtils_default.getCubeFilesRecursively("dbcube", "table.cube");
504
1060
  if (cubeFiles.length === 0) {
505
1061
  throw new Error("\u274C There are no cubes to execute");
506
1062
  }
1063
+ console.log("\u{1F504} Resolving table dependencies...");
1064
+ DependencyResolver.resolveDependencies(cubeFiles, "table");
1065
+ const orderedCubeFiles = DependencyResolver.orderCubeFiles(cubeFiles, "table");
507
1066
  UIUtils.showOperationHeader("EXECUTING FRESH TABLES", this.name);
508
1067
  let totalTablesProcessed = 0;
509
1068
  let successCount = 0;
510
1069
  let errorCount = 0;
511
1070
  const processedTables = [];
512
1071
  const errors = [];
513
- for (let index = 0; index < cubeFiles.length; index++) {
514
- const file = cubeFiles[index];
515
- const filePath = path2.isAbsolute(file) ? file : path2.join(cubesDir, file);
516
- const stats = fs3.statSync(filePath);
1072
+ for (let index = 0; index < orderedCubeFiles.length; index++) {
1073
+ const file = orderedCubeFiles[index];
1074
+ const filePath = path4.isAbsolute(file) ? file : path4.join(cubesDir, file);
1075
+ const stats = fs5.statSync(filePath);
517
1076
  if (stats.isFile()) {
518
1077
  const getTableName = FileUtils_default.extracTableNameFromCube(filePath);
519
- const tableName = getTableName.status === 200 ? getTableName.message : path2.basename(file, ".table.cube");
520
- await UIUtils.showItemProgress(tableName, index + 1, cubeFiles.length);
1078
+ const tableName = getTableName.status === 200 ? getTableName.message : path4.basename(file, ".table.cube");
1079
+ await UIUtils.showItemProgress(tableName, index + 1, orderedCubeFiles.length);
521
1080
  try {
522
1081
  const validation = this.validateDatabaseConfiguration(filePath);
523
1082
  if (!validation.isValid && validation.error) {
@@ -596,28 +1155,29 @@ var Schema = class {
596
1155
  }
597
1156
  async executeSeeders() {
598
1157
  const startTime = Date.now();
599
- const cubesDir = path2.join(process.cwd(), "dbcube", "cubes");
600
- if (!fs3.existsSync(cubesDir)) {
1158
+ const cubesDir = path4.join(process.cwd(), "dbcube", "cubes");
1159
+ if (!fs5.existsSync(cubesDir)) {
601
1160
  throw new Error("\u274C The cubes folder does not exist");
602
1161
  }
603
1162
  const cubeFiles = FileUtils_default.getCubeFilesRecursively("dbcube", "seeder.cube");
604
1163
  if (cubeFiles.length === 0) {
605
1164
  throw new Error("\u274C There are no cubes to execute");
606
1165
  }
1166
+ const orderedCubeFiles = DependencyResolver.orderCubeFiles(cubeFiles, "seeder");
607
1167
  UIUtils.showOperationHeader("EXECUTING SEEDERS", this.name, "\u{1F331}");
608
1168
  let totalSeedersProcessed = 0;
609
1169
  let successCount = 0;
610
1170
  let errorCount = 0;
611
1171
  const processedSeeders = [];
612
1172
  const errors = [];
613
- for (let index = 0; index < cubeFiles.length; index++) {
614
- const file = cubeFiles[index];
615
- const filePath = path2.isAbsolute(file) ? file : path2.join(cubesDir, file);
616
- const stats = fs3.statSync(filePath);
1173
+ for (let index = 0; index < orderedCubeFiles.length; index++) {
1174
+ const file = orderedCubeFiles[index];
1175
+ const filePath = path4.isAbsolute(file) ? file : path4.join(cubesDir, file);
1176
+ const stats = fs5.statSync(filePath);
617
1177
  if (stats.isFile()) {
618
1178
  const getSeederName = FileUtils_default.extracTableNameFromCube(filePath);
619
- const seederName = getSeederName.status === 200 ? getSeederName.message : path2.basename(file, ".seeder.cube");
620
- await UIUtils.showItemProgress(seederName, index + 1, cubeFiles.length);
1179
+ const seederName = getSeederName.status === 200 ? getSeederName.message : path4.basename(file, ".seeder.cube");
1180
+ await UIUtils.showItemProgress(seederName, index + 1, orderedCubeFiles.length);
621
1181
  try {
622
1182
  const validation = this.validateDatabaseConfiguration(filePath);
623
1183
  if (!validation.isValid && validation.error) {
@@ -667,9 +1227,9 @@ var Schema = class {
667
1227
  }
668
1228
  async executeTriggers() {
669
1229
  const startTime = Date.now();
670
- const cubesDir = path2.join(process.cwd(), "dbcube", "cubes");
671
- const triggersDirExit = path2.join(process.cwd(), "dbcube", "triggers");
672
- if (!fs3.existsSync(cubesDir)) {
1230
+ const cubesDir = path4.join(process.cwd(), "dbcube", "cubes");
1231
+ const triggersDirExit = path4.join(process.cwd(), "dbcube", "triggers");
1232
+ if (!fs5.existsSync(cubesDir)) {
673
1233
  throw new Error("\u274C The cubes folder does not exist");
674
1234
  }
675
1235
  const cubeFiles = FileUtils_default.getCubeFilesRecursively("dbcube", "trigger.cube");
@@ -684,11 +1244,11 @@ var Schema = class {
684
1244
  const errors = [];
685
1245
  for (let index = 0; index < cubeFiles.length; index++) {
686
1246
  const file = cubeFiles[index];
687
- const filePath = path2.isAbsolute(file) ? file : path2.join(cubesDir, file);
688
- const stats = fs3.statSync(filePath);
1247
+ const filePath = path4.isAbsolute(file) ? file : path4.join(cubesDir, file);
1248
+ const stats = fs5.statSync(filePath);
689
1249
  if (stats.isFile()) {
690
1250
  const getTriggerName = FileUtils_default.extracTableNameFromCube(filePath);
691
- const triggerName = getTriggerName.status === 200 ? getTriggerName.message : path2.basename(file, ".trigger.cube");
1251
+ const triggerName = getTriggerName.status === 200 ? getTriggerName.message : path4.basename(file, ".trigger.cube");
692
1252
  await UIUtils.showItemProgress(triggerName, index + 1, cubeFiles.length);
693
1253
  try {
694
1254
  const validation = this.validateDatabaseConfiguration(filePath);
@@ -759,7 +1319,7 @@ ${chalk2.red("\u{1F6AB}")} ${chalk2.bold.red("ERRORS FOUND")}`);
759
1319
  const errorLocation = `${filePath}:${lineStr}:${columnStr}`;
760
1320
  console.log(`${chalk2.cyan("[code]")} ${chalk2.yellow(errorLocation)}`);
761
1321
  try {
762
- const codeLines = fs3.readFileSync(filePath, "utf-8").split("\n");
1322
+ const codeLines = fs5.readFileSync(filePath, "utf-8").split("\n");
763
1323
  const start = Math.max(0, lineNum - 3);
764
1324
  const end = Math.min(codeLines.length, lineNum + 2);
765
1325
  for (let i = start; i < end; i++) {
@@ -773,13 +1333,17 @@ ${chalk2.red("\u{1F6AB}")} ${chalk2.bold.red("ERRORS FOUND")}`);
773
1333
  }
774
1334
  }
775
1335
  }
1336
+ console.log("");
776
1337
  process.exit(1);
777
1338
  }
778
1339
 
779
1340
  // src/index.ts
780
1341
  var index_default = Schema;
781
1342
  export {
1343
+ CubeValidator,
1344
+ DependencyResolver,
782
1345
  Schema,
1346
+ UIUtils,
783
1347
  index_default as default
784
1348
  };
785
1349
  //# sourceMappingURL=index.js.map