@famgia/omnify-laravel 0.0.6 → 0.0.8
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/{chunk-BA63DET3.js → chunk-2XKSPWNJ.js} +319 -13
- package/dist/chunk-2XKSPWNJ.js.map +1 -0
- package/dist/index.cjs +321 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -1
- package/dist/index.d.ts +21 -1
- package/dist/index.js +7 -1
- package/dist/plugin.cjs +49 -12
- package/dist/plugin.cjs.map +1 -1
- package/dist/plugin.js +1 -1
- package/package.json +4 -3
- package/dist/chunk-BA63DET3.js.map +0 -1
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,
|
|
@@ -225,7 +228,6 @@ function generateForeignKey(propertyName, property, allSchemas) {
|
|
|
225
228
|
onUpdate: assocProp.onUpdate ?? "cascade"
|
|
226
229
|
};
|
|
227
230
|
const index = {
|
|
228
|
-
name: `idx_${columnName}`,
|
|
229
231
|
columns: [columnName],
|
|
230
232
|
unique: false
|
|
231
233
|
};
|
|
@@ -427,12 +429,10 @@ function generatePivotTableBlueprint(pivot) {
|
|
|
427
429
|
unique: true
|
|
428
430
|
});
|
|
429
431
|
indexes.push({
|
|
430
|
-
name: `idx_${pivot.sourceColumn}`,
|
|
431
432
|
columns: [pivot.sourceColumn],
|
|
432
433
|
unique: false
|
|
433
434
|
});
|
|
434
435
|
indexes.push({
|
|
435
|
-
name: `idx_${pivot.targetColumn}`,
|
|
436
436
|
columns: [pivot.targetColumn],
|
|
437
437
|
unique: false
|
|
438
438
|
});
|
|
@@ -583,14 +583,57 @@ return new class extends Migration
|
|
|
583
583
|
type: "drop"
|
|
584
584
|
};
|
|
585
585
|
}
|
|
586
|
+
function extractDependencies(schema) {
|
|
587
|
+
const deps = [];
|
|
588
|
+
if (!schema.properties) {
|
|
589
|
+
return deps;
|
|
590
|
+
}
|
|
591
|
+
for (const property of Object.values(schema.properties)) {
|
|
592
|
+
if (property.type !== "Association") {
|
|
593
|
+
continue;
|
|
594
|
+
}
|
|
595
|
+
const assocProp = property;
|
|
596
|
+
if ((assocProp.relation === "ManyToOne" || assocProp.relation === "OneToOne") && !assocProp.mappedBy && assocProp.target) {
|
|
597
|
+
deps.push(assocProp.target);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
return deps;
|
|
601
|
+
}
|
|
602
|
+
function topologicalSort(schemas) {
|
|
603
|
+
const schemaList = Object.values(schemas).filter((s) => s.kind !== "enum");
|
|
604
|
+
const sorted = [];
|
|
605
|
+
const visited = /* @__PURE__ */ new Set();
|
|
606
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
607
|
+
function visit(schema) {
|
|
608
|
+
if (visited.has(schema.name)) {
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
if (visiting.has(schema.name)) {
|
|
612
|
+
return;
|
|
613
|
+
}
|
|
614
|
+
visiting.add(schema.name);
|
|
615
|
+
const deps = extractDependencies(schema);
|
|
616
|
+
for (const depName of deps) {
|
|
617
|
+
const depSchema = schemas[depName];
|
|
618
|
+
if (depSchema && depSchema.kind !== "enum") {
|
|
619
|
+
visit(depSchema);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
visiting.delete(schema.name);
|
|
623
|
+
visited.add(schema.name);
|
|
624
|
+
sorted.push(schema);
|
|
625
|
+
}
|
|
626
|
+
for (const schema of schemaList) {
|
|
627
|
+
visit(schema);
|
|
628
|
+
}
|
|
629
|
+
return sorted;
|
|
630
|
+
}
|
|
586
631
|
function generateMigrations(schemas, options = {}) {
|
|
587
632
|
const migrations = [];
|
|
588
633
|
const pivotTablesGenerated = /* @__PURE__ */ new Set();
|
|
589
634
|
let timestampOffset = 0;
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
continue;
|
|
593
|
-
}
|
|
635
|
+
const sortedSchemas = topologicalSort(schemas);
|
|
636
|
+
for (const schema of sortedSchemas) {
|
|
594
637
|
const timestamp = options.timestamp ?? generateTimestamp();
|
|
595
638
|
const offsetTimestamp = incrementTimestamp(timestamp, timestampOffset);
|
|
596
639
|
timestampOffset++;
|
|
@@ -601,10 +644,7 @@ function generateMigrations(schemas, options = {}) {
|
|
|
601
644
|
});
|
|
602
645
|
migrations.push(migration);
|
|
603
646
|
}
|
|
604
|
-
for (const schema of
|
|
605
|
-
if (schema.kind === "enum") {
|
|
606
|
-
continue;
|
|
607
|
-
}
|
|
647
|
+
for (const schema of sortedSchemas) {
|
|
608
648
|
const pivotTables = extractManyToManyRelations(schema, schemas);
|
|
609
649
|
for (const pivot of pivotTables) {
|
|
610
650
|
if (pivotTablesGenerated.has(pivot.tableName)) {
|
|
@@ -663,6 +703,272 @@ function getMigrationPath(migration, outputDir = "database/migrations") {
|
|
|
663
703
|
return `${outputDir}/${migration.fileName}`;
|
|
664
704
|
}
|
|
665
705
|
|
|
706
|
+
// src/migration/alter-generator.ts
|
|
707
|
+
var TYPE_METHOD_MAP2 = {
|
|
708
|
+
String: "string",
|
|
709
|
+
Int: "integer",
|
|
710
|
+
BigInt: "bigInteger",
|
|
711
|
+
Float: "double",
|
|
712
|
+
Boolean: "boolean",
|
|
713
|
+
Text: "text",
|
|
714
|
+
LongText: "longText",
|
|
715
|
+
Date: "date",
|
|
716
|
+
Time: "time",
|
|
717
|
+
Timestamp: "timestamp",
|
|
718
|
+
Json: "json",
|
|
719
|
+
Email: "string",
|
|
720
|
+
Password: "string",
|
|
721
|
+
File: "string",
|
|
722
|
+
MultiFile: "json",
|
|
723
|
+
Enum: "enum",
|
|
724
|
+
Select: "string",
|
|
725
|
+
Lookup: "unsignedBigInteger"
|
|
726
|
+
};
|
|
727
|
+
function generateTimestamp2() {
|
|
728
|
+
const now = /* @__PURE__ */ new Date();
|
|
729
|
+
const year = now.getFullYear();
|
|
730
|
+
const month = String(now.getMonth() + 1).padStart(2, "0");
|
|
731
|
+
const day = String(now.getDate()).padStart(2, "0");
|
|
732
|
+
const hours = String(now.getHours()).padStart(2, "0");
|
|
733
|
+
const minutes = String(now.getMinutes()).padStart(2, "0");
|
|
734
|
+
const seconds = String(now.getSeconds()).padStart(2, "0");
|
|
735
|
+
return `${year}_${month}_${day}_${hours}${minutes}${seconds}`;
|
|
736
|
+
}
|
|
737
|
+
function formatAddColumn(columnName, prop) {
|
|
738
|
+
const snakeColumn = toColumnName(columnName);
|
|
739
|
+
const method = TYPE_METHOD_MAP2[prop.type] ?? "string";
|
|
740
|
+
let code = `$table->${method}('${snakeColumn}')`;
|
|
741
|
+
if (prop.nullable) code += "->nullable()";
|
|
742
|
+
if (prop.unique) code += "->unique()";
|
|
743
|
+
if (prop.default !== void 0) {
|
|
744
|
+
const defaultValue = typeof prop.default === "string" ? `'${prop.default}'` : JSON.stringify(prop.default);
|
|
745
|
+
code += `->default(${defaultValue})`;
|
|
746
|
+
}
|
|
747
|
+
return code + ";";
|
|
748
|
+
}
|
|
749
|
+
function formatDropColumn(columnName) {
|
|
750
|
+
const snakeColumn = toColumnName(columnName);
|
|
751
|
+
return `$table->dropColumn('${snakeColumn}');`;
|
|
752
|
+
}
|
|
753
|
+
function formatRenameColumn(oldName, newName) {
|
|
754
|
+
const oldSnake = toColumnName(oldName);
|
|
755
|
+
const newSnake = toColumnName(newName);
|
|
756
|
+
return `$table->renameColumn('${oldSnake}', '${newSnake}');`;
|
|
757
|
+
}
|
|
758
|
+
function formatModifyColumn(columnName, _prevProp, currProp) {
|
|
759
|
+
const snakeColumn = toColumnName(columnName);
|
|
760
|
+
const method = TYPE_METHOD_MAP2[currProp.type] ?? "string";
|
|
761
|
+
let code = `$table->${method}('${snakeColumn}')`;
|
|
762
|
+
if (currProp.nullable) code += "->nullable()";
|
|
763
|
+
if (currProp.unique) code += "->unique()";
|
|
764
|
+
if (currProp.default !== void 0) {
|
|
765
|
+
const defaultValue = typeof currProp.default === "string" ? `'${currProp.default}'` : JSON.stringify(currProp.default);
|
|
766
|
+
code += `->default(${defaultValue})`;
|
|
767
|
+
}
|
|
768
|
+
return code + "->change();";
|
|
769
|
+
}
|
|
770
|
+
function formatAddIndex(columns, unique) {
|
|
771
|
+
const snakeColumns = columns.map(toColumnName);
|
|
772
|
+
const method = unique ? "unique" : "index";
|
|
773
|
+
const colsArg = snakeColumns.length === 1 ? `'${snakeColumns[0]}'` : `[${snakeColumns.map((c) => `'${c}'`).join(", ")}]`;
|
|
774
|
+
return `$table->${method}(${colsArg});`;
|
|
775
|
+
}
|
|
776
|
+
function formatDropIndex(tableName, columns, unique) {
|
|
777
|
+
const snakeColumns = columns.map(toColumnName);
|
|
778
|
+
const method = unique ? "dropUnique" : "dropIndex";
|
|
779
|
+
const suffix = unique ? "unique" : "index";
|
|
780
|
+
const indexName = `${tableName}_${snakeColumns.join("_")}_${suffix}`;
|
|
781
|
+
return `$table->${method}('${indexName}');`;
|
|
782
|
+
}
|
|
783
|
+
function generateAlterMigrationContent(tableName, change, options = {}) {
|
|
784
|
+
const upLines = [];
|
|
785
|
+
const downLines = [];
|
|
786
|
+
if (change.columnChanges) {
|
|
787
|
+
for (const col of change.columnChanges) {
|
|
788
|
+
if (col.changeType === "added" && col.currentDef) {
|
|
789
|
+
upLines.push(` ${formatAddColumn(col.column, col.currentDef)}`);
|
|
790
|
+
downLines.push(` ${formatDropColumn(col.column)}`);
|
|
791
|
+
} else if (col.changeType === "removed" && col.previousDef) {
|
|
792
|
+
upLines.push(` ${formatDropColumn(col.column)}`);
|
|
793
|
+
downLines.push(` ${formatAddColumn(col.column, col.previousDef)}`);
|
|
794
|
+
} else if (col.changeType === "modified" && col.previousDef && col.currentDef) {
|
|
795
|
+
upLines.push(` ${formatModifyColumn(col.column, col.previousDef, col.currentDef)}`);
|
|
796
|
+
downLines.push(` ${formatModifyColumn(col.column, col.currentDef, col.previousDef)}`);
|
|
797
|
+
} else if (col.changeType === "renamed" && col.previousColumn) {
|
|
798
|
+
upLines.push(` ${formatRenameColumn(col.previousColumn, col.column)}`);
|
|
799
|
+
downLines.push(` ${formatRenameColumn(col.column, col.previousColumn)}`);
|
|
800
|
+
if (col.modifications && col.modifications.length > 0 && col.previousDef && col.currentDef) {
|
|
801
|
+
upLines.push(` ${formatModifyColumn(col.column, col.previousDef, col.currentDef)}`);
|
|
802
|
+
downLines.push(` ${formatModifyColumn(col.column, col.currentDef, col.previousDef)}`);
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
if (change.indexChanges) {
|
|
808
|
+
for (const idx of change.indexChanges) {
|
|
809
|
+
if (idx.changeType === "added") {
|
|
810
|
+
upLines.push(` ${formatAddIndex(idx.index.columns, idx.index.unique)}`);
|
|
811
|
+
downLines.push(` ${formatDropIndex(tableName, idx.index.columns, idx.index.unique)}`);
|
|
812
|
+
} else {
|
|
813
|
+
upLines.push(` ${formatDropIndex(tableName, idx.index.columns, idx.index.unique)}`);
|
|
814
|
+
downLines.push(` ${formatAddIndex(idx.index.columns, idx.index.unique)}`);
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
if (change.optionChanges) {
|
|
819
|
+
if (change.optionChanges.timestamps) {
|
|
820
|
+
const { from, to } = change.optionChanges.timestamps;
|
|
821
|
+
if (to && !from) {
|
|
822
|
+
upLines.push(` $table->timestamps();`);
|
|
823
|
+
downLines.push(` $table->dropTimestamps();`);
|
|
824
|
+
} else if (from && !to) {
|
|
825
|
+
upLines.push(` $table->dropTimestamps();`);
|
|
826
|
+
downLines.push(` $table->timestamps();`);
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
if (change.optionChanges.softDelete) {
|
|
830
|
+
const { from, to } = change.optionChanges.softDelete;
|
|
831
|
+
if (to && !from) {
|
|
832
|
+
upLines.push(` $table->softDeletes();`);
|
|
833
|
+
downLines.push(` $table->dropSoftDeletes();`);
|
|
834
|
+
} else if (from && !to) {
|
|
835
|
+
upLines.push(` $table->dropSoftDeletes();`);
|
|
836
|
+
downLines.push(` $table->softDeletes();`);
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
const connection = options.connection ? `
|
|
841
|
+
protected $connection = '${options.connection}';
|
|
842
|
+
` : "";
|
|
843
|
+
return `<?php
|
|
844
|
+
|
|
845
|
+
use Illuminate\\Database\\Migrations\\Migration;
|
|
846
|
+
use Illuminate\\Database\\Schema\\Blueprint;
|
|
847
|
+
use Illuminate\\Support\\Facades\\Schema;
|
|
848
|
+
|
|
849
|
+
return new class extends Migration
|
|
850
|
+
{${connection}
|
|
851
|
+
/**
|
|
852
|
+
* Run the migrations.
|
|
853
|
+
*/
|
|
854
|
+
public function up(): void
|
|
855
|
+
{
|
|
856
|
+
Schema::table('${tableName}', function (Blueprint $table) {
|
|
857
|
+
${upLines.join("\n")}
|
|
858
|
+
});
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
/**
|
|
862
|
+
* Reverse the migrations.
|
|
863
|
+
*/
|
|
864
|
+
public function down(): void
|
|
865
|
+
{
|
|
866
|
+
Schema::table('${tableName}', function (Blueprint $table) {
|
|
867
|
+
${downLines.join("\n")}
|
|
868
|
+
});
|
|
869
|
+
}
|
|
870
|
+
};
|
|
871
|
+
`;
|
|
872
|
+
}
|
|
873
|
+
function generateAlterMigration(change, options = {}) {
|
|
874
|
+
if (change.changeType !== "modified") {
|
|
875
|
+
return null;
|
|
876
|
+
}
|
|
877
|
+
const hasChanges = change.columnChanges && change.columnChanges.length > 0 || change.indexChanges && change.indexChanges.length > 0 || change.optionChanges && (change.optionChanges.timestamps || change.optionChanges.softDelete);
|
|
878
|
+
if (!hasChanges) {
|
|
879
|
+
return null;
|
|
880
|
+
}
|
|
881
|
+
const tableName = toTableName(change.schemaName);
|
|
882
|
+
const timestamp = options.timestamp ?? generateTimestamp2();
|
|
883
|
+
const fileName = `${timestamp}_update_${tableName}_table.php`;
|
|
884
|
+
const content = generateAlterMigrationContent(tableName, change, options);
|
|
885
|
+
return {
|
|
886
|
+
fileName,
|
|
887
|
+
className: `Update${change.schemaName}Table`,
|
|
888
|
+
content,
|
|
889
|
+
tables: [tableName],
|
|
890
|
+
type: "alter"
|
|
891
|
+
};
|
|
892
|
+
}
|
|
893
|
+
function generateDropTableMigration(schemaName, options = {}) {
|
|
894
|
+
const tableName = toTableName(schemaName);
|
|
895
|
+
const timestamp = options.timestamp ?? generateTimestamp2();
|
|
896
|
+
const fileName = `${timestamp}_drop_${tableName}_table.php`;
|
|
897
|
+
const connection = options.connection ? `
|
|
898
|
+
protected $connection = '${options.connection}';
|
|
899
|
+
` : "";
|
|
900
|
+
const content = `<?php
|
|
901
|
+
|
|
902
|
+
use Illuminate\\Database\\Migrations\\Migration;
|
|
903
|
+
use Illuminate\\Database\\Schema\\Blueprint;
|
|
904
|
+
use Illuminate\\Support\\Facades\\Schema;
|
|
905
|
+
|
|
906
|
+
return new class extends Migration
|
|
907
|
+
{${connection}
|
|
908
|
+
/**
|
|
909
|
+
* Run the migrations.
|
|
910
|
+
*/
|
|
911
|
+
public function up(): void
|
|
912
|
+
{
|
|
913
|
+
Schema::dropIfExists('${tableName}');
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
/**
|
|
917
|
+
* Reverse the migrations.
|
|
918
|
+
*/
|
|
919
|
+
public function down(): void
|
|
920
|
+
{
|
|
921
|
+
// Cannot recreate table without full schema
|
|
922
|
+
// Consider restoring from backup if needed
|
|
923
|
+
}
|
|
924
|
+
};
|
|
925
|
+
`;
|
|
926
|
+
return {
|
|
927
|
+
fileName,
|
|
928
|
+
className: `Drop${schemaName}Table`,
|
|
929
|
+
content,
|
|
930
|
+
tables: [tableName],
|
|
931
|
+
type: "drop"
|
|
932
|
+
};
|
|
933
|
+
}
|
|
934
|
+
function generateMigrationsFromChanges(changes, options = {}) {
|
|
935
|
+
const migrations = [];
|
|
936
|
+
let timestampOffset = 0;
|
|
937
|
+
const getNextTimestamp = () => {
|
|
938
|
+
const ts = options.timestamp ?? generateTimestamp2();
|
|
939
|
+
const offset = timestampOffset++;
|
|
940
|
+
if (offset === 0) return ts;
|
|
941
|
+
const parts = ts.split("_");
|
|
942
|
+
if (parts.length >= 4) {
|
|
943
|
+
const timePart = parts[3] ?? "000000";
|
|
944
|
+
const secs = parseInt(timePart.substring(4, 6), 10) + offset;
|
|
945
|
+
const newSecs = String(secs % 60).padStart(2, "0");
|
|
946
|
+
parts[3] = timePart.substring(0, 4) + newSecs;
|
|
947
|
+
return parts.join("_");
|
|
948
|
+
}
|
|
949
|
+
return ts;
|
|
950
|
+
};
|
|
951
|
+
for (const change of changes) {
|
|
952
|
+
if (change.changeType === "modified") {
|
|
953
|
+
const migration = generateAlterMigration(change, {
|
|
954
|
+
...options,
|
|
955
|
+
timestamp: getNextTimestamp()
|
|
956
|
+
});
|
|
957
|
+
if (migration) {
|
|
958
|
+
migrations.push(migration);
|
|
959
|
+
}
|
|
960
|
+
} else if (change.changeType === "removed") {
|
|
961
|
+
migrations.push(
|
|
962
|
+
generateDropTableMigration(change.schemaName, {
|
|
963
|
+
...options,
|
|
964
|
+
timestamp: getNextTimestamp()
|
|
965
|
+
})
|
|
966
|
+
);
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
return migrations;
|
|
970
|
+
}
|
|
971
|
+
|
|
666
972
|
// src/typescript/interface-generator.ts
|
|
667
973
|
var TYPE_MAP = {
|
|
668
974
|
String: "string",
|
|
@@ -1076,7 +1382,7 @@ function laravelPlugin(options) {
|
|
|
1076
1382
|
const resolved = resolveOptions(options);
|
|
1077
1383
|
return {
|
|
1078
1384
|
name: "@famgia/omnify-laravel",
|
|
1079
|
-
version: "0.0.
|
|
1385
|
+
version: "0.0.7",
|
|
1080
1386
|
generators: [
|
|
1081
1387
|
// Laravel Migrations Generator
|
|
1082
1388
|
...resolved.generateMigrations ? [
|
|
@@ -1137,12 +1443,15 @@ function laravelPlugin(options) {
|
|
|
1137
1443
|
formatMigrationFile,
|
|
1138
1444
|
formatProperty,
|
|
1139
1445
|
formatTypeAlias,
|
|
1446
|
+
generateAlterMigration,
|
|
1140
1447
|
generateDropMigrationForTable,
|
|
1448
|
+
generateDropTableMigration,
|
|
1141
1449
|
generateEnums,
|
|
1142
1450
|
generateForeignKey,
|
|
1143
1451
|
generateInterfaces,
|
|
1144
1452
|
generateMigrationFromSchema,
|
|
1145
1453
|
generateMigrations,
|
|
1454
|
+
generateMigrationsFromChanges,
|
|
1146
1455
|
generatePrimaryKeyColumn,
|
|
1147
1456
|
generateSoftDeleteColumn,
|
|
1148
1457
|
generateTimestampColumns,
|