@famgia/omnify-laravel 0.0.7 → 0.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.cjs CHANGED
@@ -30,12 +30,15 @@ __export(index_exports, {
30
30
  formatMigrationFile: () => formatMigrationFile,
31
31
  formatProperty: () => formatProperty,
32
32
  formatTypeAlias: () => formatTypeAlias,
33
+ generateAlterMigration: () => generateAlterMigration,
33
34
  generateDropMigrationForTable: () => generateDropMigrationForTable,
35
+ generateDropTableMigration: () => generateDropTableMigration,
34
36
  generateEnums: () => generateEnums,
35
37
  generateForeignKey: () => generateForeignKey,
36
38
  generateInterfaces: () => generateInterfaces,
37
39
  generateMigrationFromSchema: () => generateMigrationFromSchema,
38
40
  generateMigrations: () => generateMigrations,
41
+ generateMigrationsFromChanges: () => generateMigrationsFromChanges,
39
42
  generatePrimaryKeyColumn: () => generatePrimaryKeyColumn,
40
43
  generateSoftDeleteColumn: () => generateSoftDeleteColumn,
41
44
  generateTimestampColumns: () => generateTimestampColumns,
@@ -66,6 +69,7 @@ var TYPE_METHOD_MAP = {
66
69
  Int: "integer",
67
70
  BigInt: "bigInteger",
68
71
  Float: "double",
72
+ Decimal: "decimal",
69
73
  Boolean: "boolean",
70
74
  Text: "text",
71
75
  LongText: "longText",
@@ -112,6 +116,12 @@ function propertyToColumnMethod(propertyName, property) {
112
116
  if (method === "string" && propWithLength.length) {
113
117
  args.push(propWithLength.length);
114
118
  }
119
+ if (property.type === "Decimal") {
120
+ const decimalProp = property;
121
+ const precision = decimalProp.precision ?? 8;
122
+ const scale = decimalProp.scale ?? 2;
123
+ args.push(precision, scale);
124
+ }
115
125
  if (property.type === "Enum") {
116
126
  const enumProp = property;
117
127
  if (enumProp.enum && enumProp.enum.length > 0) {
@@ -225,7 +235,6 @@ function generateForeignKey(propertyName, property, allSchemas) {
225
235
  onUpdate: assocProp.onUpdate ?? "cascade"
226
236
  };
227
237
  const index = {
228
- name: `idx_${columnName}`,
229
238
  columns: [columnName],
230
239
  unique: false
231
240
  };
@@ -427,12 +436,10 @@ function generatePivotTableBlueprint(pivot) {
427
436
  unique: true
428
437
  });
429
438
  indexes.push({
430
- name: `idx_${pivot.sourceColumn}`,
431
439
  columns: [pivot.sourceColumn],
432
440
  unique: false
433
441
  });
434
442
  indexes.push({
435
- name: `idx_${pivot.targetColumn}`,
436
443
  columns: [pivot.targetColumn],
437
444
  unique: false
438
445
  });
@@ -583,14 +590,57 @@ return new class extends Migration
583
590
  type: "drop"
584
591
  };
585
592
  }
593
+ function extractDependencies(schema) {
594
+ const deps = [];
595
+ if (!schema.properties) {
596
+ return deps;
597
+ }
598
+ for (const property of Object.values(schema.properties)) {
599
+ if (property.type !== "Association") {
600
+ continue;
601
+ }
602
+ const assocProp = property;
603
+ if ((assocProp.relation === "ManyToOne" || assocProp.relation === "OneToOne") && !assocProp.mappedBy && assocProp.target) {
604
+ deps.push(assocProp.target);
605
+ }
606
+ }
607
+ return deps;
608
+ }
609
+ function topologicalSort(schemas) {
610
+ const schemaList = Object.values(schemas).filter((s) => s.kind !== "enum");
611
+ const sorted = [];
612
+ const visited = /* @__PURE__ */ new Set();
613
+ const visiting = /* @__PURE__ */ new Set();
614
+ function visit(schema) {
615
+ if (visited.has(schema.name)) {
616
+ return;
617
+ }
618
+ if (visiting.has(schema.name)) {
619
+ return;
620
+ }
621
+ visiting.add(schema.name);
622
+ const deps = extractDependencies(schema);
623
+ for (const depName of deps) {
624
+ const depSchema = schemas[depName];
625
+ if (depSchema && depSchema.kind !== "enum") {
626
+ visit(depSchema);
627
+ }
628
+ }
629
+ visiting.delete(schema.name);
630
+ visited.add(schema.name);
631
+ sorted.push(schema);
632
+ }
633
+ for (const schema of schemaList) {
634
+ visit(schema);
635
+ }
636
+ return sorted;
637
+ }
586
638
  function generateMigrations(schemas, options = {}) {
587
639
  const migrations = [];
588
640
  const pivotTablesGenerated = /* @__PURE__ */ new Set();
589
641
  let timestampOffset = 0;
590
- for (const schema of Object.values(schemas)) {
591
- if (schema.kind === "enum") {
592
- continue;
593
- }
642
+ const sortedSchemas = topologicalSort(schemas);
643
+ for (const schema of sortedSchemas) {
594
644
  const timestamp = options.timestamp ?? generateTimestamp();
595
645
  const offsetTimestamp = incrementTimestamp(timestamp, timestampOffset);
596
646
  timestampOffset++;
@@ -601,10 +651,7 @@ function generateMigrations(schemas, options = {}) {
601
651
  });
602
652
  migrations.push(migration);
603
653
  }
604
- for (const schema of Object.values(schemas)) {
605
- if (schema.kind === "enum") {
606
- continue;
607
- }
654
+ for (const schema of sortedSchemas) {
608
655
  const pivotTables = extractManyToManyRelations(schema, schemas);
609
656
  for (const pivot of pivotTables) {
610
657
  if (pivotTablesGenerated.has(pivot.tableName)) {
@@ -663,6 +710,287 @@ function getMigrationPath(migration, outputDir = "database/migrations") {
663
710
  return `${outputDir}/${migration.fileName}`;
664
711
  }
665
712
 
713
+ // src/migration/alter-generator.ts
714
+ var TYPE_METHOD_MAP2 = {
715
+ String: "string",
716
+ Int: "integer",
717
+ BigInt: "bigInteger",
718
+ Float: "double",
719
+ Decimal: "decimal",
720
+ Boolean: "boolean",
721
+ Text: "text",
722
+ LongText: "longText",
723
+ Date: "date",
724
+ Time: "time",
725
+ Timestamp: "timestamp",
726
+ Json: "json",
727
+ Email: "string",
728
+ Password: "string",
729
+ File: "string",
730
+ MultiFile: "json",
731
+ Enum: "enum",
732
+ Select: "string",
733
+ Lookup: "unsignedBigInteger"
734
+ };
735
+ function generateTimestamp2() {
736
+ const now = /* @__PURE__ */ new Date();
737
+ const year = now.getFullYear();
738
+ const month = String(now.getMonth() + 1).padStart(2, "0");
739
+ const day = String(now.getDate()).padStart(2, "0");
740
+ const hours = String(now.getHours()).padStart(2, "0");
741
+ const minutes = String(now.getMinutes()).padStart(2, "0");
742
+ const seconds = String(now.getSeconds()).padStart(2, "0");
743
+ return `${year}_${month}_${day}_${hours}${minutes}${seconds}`;
744
+ }
745
+ function formatAddColumn(columnName, prop) {
746
+ const snakeColumn = toColumnName(columnName);
747
+ const method = TYPE_METHOD_MAP2[prop.type] ?? "string";
748
+ let code;
749
+ if (prop.type === "Decimal") {
750
+ const precision = prop.precision ?? 8;
751
+ const scale = prop.scale ?? 2;
752
+ code = `$table->${method}('${snakeColumn}', ${precision}, ${scale})`;
753
+ } else {
754
+ code = `$table->${method}('${snakeColumn}')`;
755
+ }
756
+ if (prop.nullable) code += "->nullable()";
757
+ if (prop.unique) code += "->unique()";
758
+ if (prop.default !== void 0) {
759
+ const defaultValue = typeof prop.default === "string" ? `'${prop.default}'` : JSON.stringify(prop.default);
760
+ code += `->default(${defaultValue})`;
761
+ }
762
+ return code + ";";
763
+ }
764
+ function formatDropColumn(columnName) {
765
+ const snakeColumn = toColumnName(columnName);
766
+ return `$table->dropColumn('${snakeColumn}');`;
767
+ }
768
+ function formatRenameColumn(oldName, newName) {
769
+ const oldSnake = toColumnName(oldName);
770
+ const newSnake = toColumnName(newName);
771
+ return `$table->renameColumn('${oldSnake}', '${newSnake}');`;
772
+ }
773
+ function formatModifyColumn(columnName, _prevProp, currProp) {
774
+ const snakeColumn = toColumnName(columnName);
775
+ const method = TYPE_METHOD_MAP2[currProp.type] ?? "string";
776
+ let code;
777
+ if (currProp.type === "Decimal") {
778
+ const precision = currProp.precision ?? 8;
779
+ const scale = currProp.scale ?? 2;
780
+ code = `$table->${method}('${snakeColumn}', ${precision}, ${scale})`;
781
+ } else {
782
+ code = `$table->${method}('${snakeColumn}')`;
783
+ }
784
+ if (currProp.nullable) code += "->nullable()";
785
+ if (currProp.unique) code += "->unique()";
786
+ if (currProp.default !== void 0) {
787
+ const defaultValue = typeof currProp.default === "string" ? `'${currProp.default}'` : JSON.stringify(currProp.default);
788
+ code += `->default(${defaultValue})`;
789
+ }
790
+ return code + "->change();";
791
+ }
792
+ function formatAddIndex(columns, unique) {
793
+ const snakeColumns = columns.map(toColumnName);
794
+ const method = unique ? "unique" : "index";
795
+ const colsArg = snakeColumns.length === 1 ? `'${snakeColumns[0]}'` : `[${snakeColumns.map((c) => `'${c}'`).join(", ")}]`;
796
+ return `$table->${method}(${colsArg});`;
797
+ }
798
+ function formatDropIndex(tableName, columns, unique) {
799
+ const snakeColumns = columns.map(toColumnName);
800
+ const method = unique ? "dropUnique" : "dropIndex";
801
+ const suffix = unique ? "unique" : "index";
802
+ const indexName = `${tableName}_${snakeColumns.join("_")}_${suffix}`;
803
+ return `$table->${method}('${indexName}');`;
804
+ }
805
+ function generateAlterMigrationContent(tableName, change, options = {}) {
806
+ const upLines = [];
807
+ const downLines = [];
808
+ if (change.columnChanges) {
809
+ for (const col of change.columnChanges) {
810
+ if (col.changeType === "added" && col.currentDef) {
811
+ upLines.push(` ${formatAddColumn(col.column, col.currentDef)}`);
812
+ downLines.push(` ${formatDropColumn(col.column)}`);
813
+ } else if (col.changeType === "removed" && col.previousDef) {
814
+ upLines.push(` ${formatDropColumn(col.column)}`);
815
+ downLines.push(` ${formatAddColumn(col.column, col.previousDef)}`);
816
+ } else if (col.changeType === "modified" && col.previousDef && col.currentDef) {
817
+ upLines.push(` ${formatModifyColumn(col.column, col.previousDef, col.currentDef)}`);
818
+ downLines.push(` ${formatModifyColumn(col.column, col.currentDef, col.previousDef)}`);
819
+ } else if (col.changeType === "renamed" && col.previousColumn) {
820
+ upLines.push(` ${formatRenameColumn(col.previousColumn, col.column)}`);
821
+ downLines.push(` ${formatRenameColumn(col.column, col.previousColumn)}`);
822
+ if (col.modifications && col.modifications.length > 0 && col.previousDef && col.currentDef) {
823
+ upLines.push(` ${formatModifyColumn(col.column, col.previousDef, col.currentDef)}`);
824
+ downLines.push(` ${formatModifyColumn(col.column, col.currentDef, col.previousDef)}`);
825
+ }
826
+ }
827
+ }
828
+ }
829
+ if (change.indexChanges) {
830
+ for (const idx of change.indexChanges) {
831
+ if (idx.changeType === "added") {
832
+ upLines.push(` ${formatAddIndex(idx.index.columns, idx.index.unique)}`);
833
+ downLines.push(` ${formatDropIndex(tableName, idx.index.columns, idx.index.unique)}`);
834
+ } else {
835
+ upLines.push(` ${formatDropIndex(tableName, idx.index.columns, idx.index.unique)}`);
836
+ downLines.push(` ${formatAddIndex(idx.index.columns, idx.index.unique)}`);
837
+ }
838
+ }
839
+ }
840
+ if (change.optionChanges) {
841
+ if (change.optionChanges.timestamps) {
842
+ const { from, to } = change.optionChanges.timestamps;
843
+ if (to && !from) {
844
+ upLines.push(` $table->timestamps();`);
845
+ downLines.push(` $table->dropTimestamps();`);
846
+ } else if (from && !to) {
847
+ upLines.push(` $table->dropTimestamps();`);
848
+ downLines.push(` $table->timestamps();`);
849
+ }
850
+ }
851
+ if (change.optionChanges.softDelete) {
852
+ const { from, to } = change.optionChanges.softDelete;
853
+ if (to && !from) {
854
+ upLines.push(` $table->softDeletes();`);
855
+ downLines.push(` $table->dropSoftDeletes();`);
856
+ } else if (from && !to) {
857
+ upLines.push(` $table->dropSoftDeletes();`);
858
+ downLines.push(` $table->softDeletes();`);
859
+ }
860
+ }
861
+ }
862
+ const connection = options.connection ? `
863
+ protected $connection = '${options.connection}';
864
+ ` : "";
865
+ return `<?php
866
+
867
+ use Illuminate\\Database\\Migrations\\Migration;
868
+ use Illuminate\\Database\\Schema\\Blueprint;
869
+ use Illuminate\\Support\\Facades\\Schema;
870
+
871
+ return new class extends Migration
872
+ {${connection}
873
+ /**
874
+ * Run the migrations.
875
+ */
876
+ public function up(): void
877
+ {
878
+ Schema::table('${tableName}', function (Blueprint $table) {
879
+ ${upLines.join("\n")}
880
+ });
881
+ }
882
+
883
+ /**
884
+ * Reverse the migrations.
885
+ */
886
+ public function down(): void
887
+ {
888
+ Schema::table('${tableName}', function (Blueprint $table) {
889
+ ${downLines.join("\n")}
890
+ });
891
+ }
892
+ };
893
+ `;
894
+ }
895
+ function generateAlterMigration(change, options = {}) {
896
+ if (change.changeType !== "modified") {
897
+ return null;
898
+ }
899
+ const hasChanges = change.columnChanges && change.columnChanges.length > 0 || change.indexChanges && change.indexChanges.length > 0 || change.optionChanges && (change.optionChanges.timestamps || change.optionChanges.softDelete);
900
+ if (!hasChanges) {
901
+ return null;
902
+ }
903
+ const tableName = toTableName(change.schemaName);
904
+ const timestamp = options.timestamp ?? generateTimestamp2();
905
+ const fileName = `${timestamp}_update_${tableName}_table.php`;
906
+ const content = generateAlterMigrationContent(tableName, change, options);
907
+ return {
908
+ fileName,
909
+ className: `Update${change.schemaName}Table`,
910
+ content,
911
+ tables: [tableName],
912
+ type: "alter"
913
+ };
914
+ }
915
+ function generateDropTableMigration(schemaName, options = {}) {
916
+ const tableName = toTableName(schemaName);
917
+ const timestamp = options.timestamp ?? generateTimestamp2();
918
+ const fileName = `${timestamp}_drop_${tableName}_table.php`;
919
+ const connection = options.connection ? `
920
+ protected $connection = '${options.connection}';
921
+ ` : "";
922
+ const content = `<?php
923
+
924
+ use Illuminate\\Database\\Migrations\\Migration;
925
+ use Illuminate\\Database\\Schema\\Blueprint;
926
+ use Illuminate\\Support\\Facades\\Schema;
927
+
928
+ return new class extends Migration
929
+ {${connection}
930
+ /**
931
+ * Run the migrations.
932
+ */
933
+ public function up(): void
934
+ {
935
+ Schema::dropIfExists('${tableName}');
936
+ }
937
+
938
+ /**
939
+ * Reverse the migrations.
940
+ */
941
+ public function down(): void
942
+ {
943
+ // Cannot recreate table without full schema
944
+ // Consider restoring from backup if needed
945
+ }
946
+ };
947
+ `;
948
+ return {
949
+ fileName,
950
+ className: `Drop${schemaName}Table`,
951
+ content,
952
+ tables: [tableName],
953
+ type: "drop"
954
+ };
955
+ }
956
+ function generateMigrationsFromChanges(changes, options = {}) {
957
+ const migrations = [];
958
+ let timestampOffset = 0;
959
+ const getNextTimestamp = () => {
960
+ const ts = options.timestamp ?? generateTimestamp2();
961
+ const offset = timestampOffset++;
962
+ if (offset === 0) return ts;
963
+ const parts = ts.split("_");
964
+ if (parts.length >= 4) {
965
+ const timePart = parts[3] ?? "000000";
966
+ const secs = parseInt(timePart.substring(4, 6), 10) + offset;
967
+ const newSecs = String(secs % 60).padStart(2, "0");
968
+ parts[3] = timePart.substring(0, 4) + newSecs;
969
+ return parts.join("_");
970
+ }
971
+ return ts;
972
+ };
973
+ for (const change of changes) {
974
+ if (change.changeType === "modified") {
975
+ const migration = generateAlterMigration(change, {
976
+ ...options,
977
+ timestamp: getNextTimestamp()
978
+ });
979
+ if (migration) {
980
+ migrations.push(migration);
981
+ }
982
+ } else if (change.changeType === "removed") {
983
+ migrations.push(
984
+ generateDropTableMigration(change.schemaName, {
985
+ ...options,
986
+ timestamp: getNextTimestamp()
987
+ })
988
+ );
989
+ }
990
+ }
991
+ return migrations;
992
+ }
993
+
666
994
  // src/typescript/interface-generator.ts
667
995
  var TYPE_MAP = {
668
996
  String: "string",
@@ -1137,12 +1465,15 @@ function laravelPlugin(options) {
1137
1465
  formatMigrationFile,
1138
1466
  formatProperty,
1139
1467
  formatTypeAlias,
1468
+ generateAlterMigration,
1140
1469
  generateDropMigrationForTable,
1470
+ generateDropTableMigration,
1141
1471
  generateEnums,
1142
1472
  generateForeignKey,
1143
1473
  generateInterfaces,
1144
1474
  generateMigrationFromSchema,
1145
1475
  generateMigrations,
1476
+ generateMigrationsFromChanges,
1146
1477
  generatePrimaryKeyColumn,
1147
1478
  generateSoftDeleteColumn,
1148
1479
  generateTimestampColumns,