@famgia/omnify-laravel 0.0.17 → 0.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.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { PropertyDefinition, SchemaCollection, LoadedSchema } from '@famgia/omnify-types';
1
+ import { CustomTypeDefinition, PropertyDefinition, SchemaCollection, LoadedSchema } from '@famgia/omnify-types';
2
2
  import { SchemaChange } from '@famgia/omnify-atlas';
3
3
  export { LaravelPluginOptions, laravelPlugin } from './plugin.cjs';
4
4
 
@@ -7,6 +7,7 @@ export { LaravelPluginOptions, laravelPlugin } from './plugin.cjs';
7
7
  *
8
8
  * Types for Laravel migration generation.
9
9
  */
10
+
10
11
  /**
11
12
  * Laravel migration file structure.
12
13
  */
@@ -34,6 +35,8 @@ interface MigrationOptions {
34
35
  readonly generateDown?: boolean | undefined;
35
36
  /** Database connection name */
36
37
  readonly connection?: string | undefined;
38
+ /** Custom types from plugins (for compound type expansion) */
39
+ readonly customTypes?: ReadonlyMap<string, CustomTypeDefinition> | undefined;
37
40
  }
38
41
  /**
39
42
  * Schema Builder column method.
@@ -161,10 +164,17 @@ declare function generateForeignKey(propertyName: string, property: PropertyDefi
161
164
  foreignKey: ForeignKeyDefinition;
162
165
  index: IndexDefinition;
163
166
  } | null;
167
+ /**
168
+ * Options for schema to blueprint conversion.
169
+ */
170
+ interface SchemaToBlueprintOptions {
171
+ /** Custom types from plugins (for compound type expansion) */
172
+ customTypes?: ReadonlyMap<string, CustomTypeDefinition>;
173
+ }
164
174
  /**
165
175
  * Generates table blueprint from schema.
166
176
  */
167
- declare function schemaToBlueprint(schema: LoadedSchema, allSchemas: SchemaCollection): TableBlueprint;
177
+ declare function schemaToBlueprint(schema: LoadedSchema, allSchemas: SchemaCollection, options?: SchemaToBlueprintOptions): TableBlueprint;
168
178
  /**
169
179
  * Formats a column method to PHP code.
170
180
  */
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { PropertyDefinition, SchemaCollection, LoadedSchema } from '@famgia/omnify-types';
1
+ import { CustomTypeDefinition, PropertyDefinition, SchemaCollection, LoadedSchema } from '@famgia/omnify-types';
2
2
  import { SchemaChange } from '@famgia/omnify-atlas';
3
3
  export { LaravelPluginOptions, laravelPlugin } from './plugin.js';
4
4
 
@@ -7,6 +7,7 @@ export { LaravelPluginOptions, laravelPlugin } from './plugin.js';
7
7
  *
8
8
  * Types for Laravel migration generation.
9
9
  */
10
+
10
11
  /**
11
12
  * Laravel migration file structure.
12
13
  */
@@ -34,6 +35,8 @@ interface MigrationOptions {
34
35
  readonly generateDown?: boolean | undefined;
35
36
  /** Database connection name */
36
37
  readonly connection?: string | undefined;
38
+ /** Custom types from plugins (for compound type expansion) */
39
+ readonly customTypes?: ReadonlyMap<string, CustomTypeDefinition> | undefined;
37
40
  }
38
41
  /**
39
42
  * Schema Builder column method.
@@ -161,10 +164,17 @@ declare function generateForeignKey(propertyName: string, property: PropertyDefi
161
164
  foreignKey: ForeignKeyDefinition;
162
165
  index: IndexDefinition;
163
166
  } | null;
167
+ /**
168
+ * Options for schema to blueprint conversion.
169
+ */
170
+ interface SchemaToBlueprintOptions {
171
+ /** Custom types from plugins (for compound type expansion) */
172
+ customTypes?: ReadonlyMap<string, CustomTypeDefinition>;
173
+ }
164
174
  /**
165
175
  * Generates table blueprint from schema.
166
176
  */
167
- declare function schemaToBlueprint(schema: LoadedSchema, allSchemas: SchemaCollection): TableBlueprint;
177
+ declare function schemaToBlueprint(schema: LoadedSchema, allSchemas: SchemaCollection, options?: SchemaToBlueprintOptions): TableBlueprint;
168
178
  /**
169
179
  * Formats a column method to PHP code.
170
180
  */
package/dist/index.js CHANGED
@@ -19,7 +19,7 @@ import {
19
19
  schemaToBlueprint,
20
20
  toColumnName,
21
21
  toTableName
22
- } from "./chunk-52JAFQBQ.js";
22
+ } from "./chunk-H37M25AK.js";
23
23
  export {
24
24
  formatColumnMethod,
25
25
  formatForeignKey,
package/dist/plugin.cjs CHANGED
@@ -39,6 +39,7 @@ var TYPE_METHOD_MAP = {
39
39
  LongText: "longText",
40
40
  Date: "date",
41
41
  Time: "time",
42
+ DateTime: "dateTime",
42
43
  Timestamp: "timestamp",
43
44
  Json: "json",
44
45
  Email: "string",
@@ -111,6 +112,10 @@ function propertyToColumnMethod(propertyName, property) {
111
112
  if (baseProp.unsigned && (method === "integer" || method === "bigInteger")) {
112
113
  modifiers.push({ method: "unsigned" });
113
114
  }
115
+ const displayName = property.displayName;
116
+ if (displayName) {
117
+ modifiers.push({ method: "comment", args: [displayName] });
118
+ }
114
119
  return {
115
120
  name: columnName,
116
121
  method,
@@ -245,6 +250,9 @@ function generateForeignKey(propertyName, property, allSchemas) {
245
250
  if (assocProp.default !== void 0 && assocProp.default !== null) {
246
251
  modifiers.push({ method: "default", args: [assocProp.default] });
247
252
  }
253
+ if (assocProp.displayName) {
254
+ modifiers.push({ method: "comment", args: [assocProp.displayName] });
255
+ }
248
256
  const column = {
249
257
  name: columnName,
250
258
  method,
@@ -264,7 +272,65 @@ function generateForeignKey(propertyName, property, allSchemas) {
264
272
  };
265
273
  return { column, foreignKey, index };
266
274
  }
267
- function schemaToBlueprint(schema, allSchemas) {
275
+ function expandCompoundType(propName, property, customTypes) {
276
+ const typeDef = customTypes.get(property.type);
277
+ if (!typeDef || !typeDef.compound || !typeDef.expand) {
278
+ return null;
279
+ }
280
+ const expanded = [];
281
+ const baseProp = property;
282
+ for (const field of typeDef.expand) {
283
+ const suffixSnake = toColumnName(field.suffix);
284
+ const columnName = `${propName}_${suffixSnake}`;
285
+ const expandedProp = {
286
+ type: "String"
287
+ // Default type, will be overridden by sql definition
288
+ };
289
+ if (field.sql) {
290
+ const sqlType = field.sql.sqlType.toUpperCase();
291
+ if (sqlType === "VARCHAR" || sqlType === "CHAR" || sqlType === "STRING") {
292
+ expandedProp.type = "String";
293
+ if (field.sql.length) {
294
+ expandedProp.length = field.sql.length;
295
+ }
296
+ } else if (sqlType === "INT" || sqlType === "INTEGER") {
297
+ expandedProp.type = "Int";
298
+ } else if (sqlType === "BIGINT") {
299
+ expandedProp.type = "BigInt";
300
+ } else if (sqlType === "TEXT") {
301
+ expandedProp.type = "Text";
302
+ } else if (sqlType === "BOOLEAN" || sqlType === "BOOL") {
303
+ expandedProp.type = "Boolean";
304
+ } else if (sqlType === "DECIMAL") {
305
+ expandedProp.type = "Decimal";
306
+ if (field.sql.precision) expandedProp.precision = field.sql.precision;
307
+ if (field.sql.scale) expandedProp.scale = field.sql.scale;
308
+ } else if (sqlType === "DATE") {
309
+ expandedProp.type = "Date";
310
+ } else if (sqlType === "TIMESTAMP" || sqlType === "DATETIME") {
311
+ expandedProp.type = "Timestamp";
312
+ }
313
+ if (field.sql.nullable !== void 0) {
314
+ expandedProp.nullable = field.sql.nullable;
315
+ } else if (baseProp.nullable !== void 0) {
316
+ expandedProp.nullable = baseProp.nullable;
317
+ }
318
+ if (field.sql.default !== void 0) {
319
+ expandedProp.default = field.sql.default;
320
+ }
321
+ }
322
+ if (baseProp.displayName) {
323
+ expandedProp.displayName = `${baseProp.displayName} (${field.suffix})`;
324
+ }
325
+ expanded.push({
326
+ name: columnName,
327
+ property: expandedProp
328
+ });
329
+ }
330
+ return expanded;
331
+ }
332
+ function schemaToBlueprint(schema, allSchemas, options = {}) {
333
+ const { customTypes = /* @__PURE__ */ new Map() } = options;
268
334
  const tableName = toTableName(schema.name);
269
335
  const columns = [];
270
336
  const foreignKeys = [];
@@ -275,6 +341,16 @@ function schemaToBlueprint(schema, allSchemas) {
275
341
  }
276
342
  if (schema.properties) {
277
343
  for (const [propName, property] of Object.entries(schema.properties)) {
344
+ const expandedProps = expandCompoundType(propName, property, customTypes);
345
+ if (expandedProps) {
346
+ for (const { name: expandedName, property: expandedProp } of expandedProps) {
347
+ const columnMethod2 = propertyToColumnMethod(expandedName, expandedProp);
348
+ if (columnMethod2) {
349
+ columns.push(columnMethod2);
350
+ }
351
+ }
352
+ continue;
353
+ }
278
354
  const columnMethod = propertyToColumnMethod(propName, property);
279
355
  if (columnMethod) {
280
356
  columns.push(columnMethod);
@@ -681,7 +757,9 @@ function generateMigrations(schemas, options = {}) {
681
757
  const timestamp = options.timestamp ?? generateTimestamp();
682
758
  const offsetTimestamp = incrementTimestamp(timestamp, timestampOffset);
683
759
  timestampOffset++;
684
- const blueprint = schemaToBlueprint(schema, schemas);
760
+ const blueprint = schemaToBlueprint(schema, schemas, {
761
+ customTypes: options.customTypes
762
+ });
685
763
  const migration = generateCreateMigration(blueprint, {
686
764
  ...options,
687
765
  timestamp: offsetTimestamp
@@ -737,6 +815,288 @@ function getMigrationPath(migration, outputDir = "database/migrations") {
737
815
  return `${outputDir}/${migration.fileName}`;
738
816
  }
739
817
 
818
+ // src/migration/alter-generator.ts
819
+ var TYPE_METHOD_MAP2 = {
820
+ String: "string",
821
+ Int: "integer",
822
+ BigInt: "bigInteger",
823
+ Float: "double",
824
+ Decimal: "decimal",
825
+ Boolean: "boolean",
826
+ Text: "text",
827
+ LongText: "longText",
828
+ Date: "date",
829
+ Time: "time",
830
+ DateTime: "dateTime",
831
+ Timestamp: "timestamp",
832
+ Json: "json",
833
+ Email: "string",
834
+ Password: "string",
835
+ File: "string",
836
+ MultiFile: "json",
837
+ Enum: "enum",
838
+ Select: "string",
839
+ Lookup: "unsignedBigInteger"
840
+ };
841
+ function generateTimestamp2() {
842
+ const now = /* @__PURE__ */ new Date();
843
+ const year = now.getFullYear();
844
+ const month = String(now.getMonth() + 1).padStart(2, "0");
845
+ const day = String(now.getDate()).padStart(2, "0");
846
+ const hours = String(now.getHours()).padStart(2, "0");
847
+ const minutes = String(now.getMinutes()).padStart(2, "0");
848
+ const seconds = String(now.getSeconds()).padStart(2, "0");
849
+ return `${year}_${month}_${day}_${hours}${minutes}${seconds}`;
850
+ }
851
+ function formatAddColumn(columnName, prop) {
852
+ const snakeColumn = toColumnName(columnName);
853
+ const method = TYPE_METHOD_MAP2[prop.type] ?? "string";
854
+ let code;
855
+ if (prop.type === "Decimal") {
856
+ const precision = prop.precision ?? 8;
857
+ const scale = prop.scale ?? 2;
858
+ code = `$table->${method}('${snakeColumn}', ${precision}, ${scale})`;
859
+ } else {
860
+ code = `$table->${method}('${snakeColumn}')`;
861
+ }
862
+ if (prop.nullable) code += "->nullable()";
863
+ if (prop.unique) code += "->unique()";
864
+ if (prop.default !== void 0) {
865
+ const defaultValue = typeof prop.default === "string" ? `'${prop.default}'` : JSON.stringify(prop.default);
866
+ code += `->default(${defaultValue})`;
867
+ }
868
+ return code + ";";
869
+ }
870
+ function formatDropColumn(columnName) {
871
+ const snakeColumn = toColumnName(columnName);
872
+ return `$table->dropColumn('${snakeColumn}');`;
873
+ }
874
+ function formatRenameColumn(oldName, newName) {
875
+ const oldSnake = toColumnName(oldName);
876
+ const newSnake = toColumnName(newName);
877
+ return `$table->renameColumn('${oldSnake}', '${newSnake}');`;
878
+ }
879
+ function formatModifyColumn(columnName, _prevProp, currProp) {
880
+ const snakeColumn = toColumnName(columnName);
881
+ const method = TYPE_METHOD_MAP2[currProp.type] ?? "string";
882
+ let code;
883
+ if (currProp.type === "Decimal") {
884
+ const precision = currProp.precision ?? 8;
885
+ const scale = currProp.scale ?? 2;
886
+ code = `$table->${method}('${snakeColumn}', ${precision}, ${scale})`;
887
+ } else {
888
+ code = `$table->${method}('${snakeColumn}')`;
889
+ }
890
+ if (currProp.nullable) code += "->nullable()";
891
+ if (currProp.unique) code += "->unique()";
892
+ if (currProp.default !== void 0) {
893
+ const defaultValue = typeof currProp.default === "string" ? `'${currProp.default}'` : JSON.stringify(currProp.default);
894
+ code += `->default(${defaultValue})`;
895
+ }
896
+ return code + "->change();";
897
+ }
898
+ function formatAddIndex(columns, unique) {
899
+ const snakeColumns = columns.map(toColumnName);
900
+ const method = unique ? "unique" : "index";
901
+ const colsArg = snakeColumns.length === 1 ? `'${snakeColumns[0]}'` : `[${snakeColumns.map((c) => `'${c}'`).join(", ")}]`;
902
+ return `$table->${method}(${colsArg});`;
903
+ }
904
+ function formatDropIndex(tableName, columns, unique) {
905
+ const snakeColumns = columns.map(toColumnName);
906
+ const method = unique ? "dropUnique" : "dropIndex";
907
+ const suffix = unique ? "unique" : "index";
908
+ const indexName = `${tableName}_${snakeColumns.join("_")}_${suffix}`;
909
+ return `$table->${method}('${indexName}');`;
910
+ }
911
+ function generateAlterMigrationContent(tableName, change, options = {}) {
912
+ const upLines = [];
913
+ const downLines = [];
914
+ if (change.columnChanges) {
915
+ for (const col of change.columnChanges) {
916
+ if (col.changeType === "added" && col.currentDef) {
917
+ upLines.push(` ${formatAddColumn(col.column, col.currentDef)}`);
918
+ downLines.push(` ${formatDropColumn(col.column)}`);
919
+ } else if (col.changeType === "removed" && col.previousDef) {
920
+ upLines.push(` ${formatDropColumn(col.column)}`);
921
+ downLines.push(` ${formatAddColumn(col.column, col.previousDef)}`);
922
+ } else if (col.changeType === "modified" && col.previousDef && col.currentDef) {
923
+ upLines.push(` ${formatModifyColumn(col.column, col.previousDef, col.currentDef)}`);
924
+ downLines.push(` ${formatModifyColumn(col.column, col.currentDef, col.previousDef)}`);
925
+ } else if (col.changeType === "renamed" && col.previousColumn) {
926
+ upLines.push(` ${formatRenameColumn(col.previousColumn, col.column)}`);
927
+ downLines.push(` ${formatRenameColumn(col.column, col.previousColumn)}`);
928
+ if (col.modifications && col.modifications.length > 0 && col.previousDef && col.currentDef) {
929
+ upLines.push(` ${formatModifyColumn(col.column, col.previousDef, col.currentDef)}`);
930
+ downLines.push(` ${formatModifyColumn(col.column, col.currentDef, col.previousDef)}`);
931
+ }
932
+ }
933
+ }
934
+ }
935
+ if (change.indexChanges) {
936
+ for (const idx of change.indexChanges) {
937
+ if (idx.changeType === "added") {
938
+ upLines.push(` ${formatAddIndex(idx.index.columns, idx.index.unique)}`);
939
+ downLines.push(` ${formatDropIndex(tableName, idx.index.columns, idx.index.unique)}`);
940
+ } else {
941
+ upLines.push(` ${formatDropIndex(tableName, idx.index.columns, idx.index.unique)}`);
942
+ downLines.push(` ${formatAddIndex(idx.index.columns, idx.index.unique)}`);
943
+ }
944
+ }
945
+ }
946
+ if (change.optionChanges) {
947
+ if (change.optionChanges.timestamps) {
948
+ const { from, to } = change.optionChanges.timestamps;
949
+ if (to && !from) {
950
+ upLines.push(` $table->timestamps();`);
951
+ downLines.push(` $table->dropTimestamps();`);
952
+ } else if (from && !to) {
953
+ upLines.push(` $table->dropTimestamps();`);
954
+ downLines.push(` $table->timestamps();`);
955
+ }
956
+ }
957
+ if (change.optionChanges.softDelete) {
958
+ const { from, to } = change.optionChanges.softDelete;
959
+ if (to && !from) {
960
+ upLines.push(` $table->softDeletes();`);
961
+ downLines.push(` $table->dropSoftDeletes();`);
962
+ } else if (from && !to) {
963
+ upLines.push(` $table->dropSoftDeletes();`);
964
+ downLines.push(` $table->softDeletes();`);
965
+ }
966
+ }
967
+ }
968
+ const connection = options.connection ? `
969
+ protected $connection = '${options.connection}';
970
+ ` : "";
971
+ return `<?php
972
+
973
+ use Illuminate\\Database\\Migrations\\Migration;
974
+ use Illuminate\\Database\\Schema\\Blueprint;
975
+ use Illuminate\\Support\\Facades\\Schema;
976
+
977
+ return new class extends Migration
978
+ {${connection}
979
+ /**
980
+ * Run the migrations.
981
+ */
982
+ public function up(): void
983
+ {
984
+ Schema::table('${tableName}', function (Blueprint $table) {
985
+ ${upLines.join("\n")}
986
+ });
987
+ }
988
+
989
+ /**
990
+ * Reverse the migrations.
991
+ */
992
+ public function down(): void
993
+ {
994
+ Schema::table('${tableName}', function (Blueprint $table) {
995
+ ${downLines.join("\n")}
996
+ });
997
+ }
998
+ };
999
+ `;
1000
+ }
1001
+ function generateAlterMigration(change, options = {}) {
1002
+ if (change.changeType !== "modified") {
1003
+ return null;
1004
+ }
1005
+ const hasChanges = change.columnChanges && change.columnChanges.length > 0 || change.indexChanges && change.indexChanges.length > 0 || change.optionChanges && (change.optionChanges.timestamps || change.optionChanges.softDelete);
1006
+ if (!hasChanges) {
1007
+ return null;
1008
+ }
1009
+ const tableName = toTableName(change.schemaName);
1010
+ const timestamp = options.timestamp ?? generateTimestamp2();
1011
+ const fileName = `${timestamp}_update_${tableName}_table.php`;
1012
+ const content = generateAlterMigrationContent(tableName, change, options);
1013
+ return {
1014
+ fileName,
1015
+ className: `Update${change.schemaName}Table`,
1016
+ content,
1017
+ tables: [tableName],
1018
+ type: "alter"
1019
+ };
1020
+ }
1021
+ function generateDropTableMigration(schemaName, options = {}) {
1022
+ const tableName = toTableName(schemaName);
1023
+ const timestamp = options.timestamp ?? generateTimestamp2();
1024
+ const fileName = `${timestamp}_drop_${tableName}_table.php`;
1025
+ const connection = options.connection ? `
1026
+ protected $connection = '${options.connection}';
1027
+ ` : "";
1028
+ const content = `<?php
1029
+
1030
+ use Illuminate\\Database\\Migrations\\Migration;
1031
+ use Illuminate\\Database\\Schema\\Blueprint;
1032
+ use Illuminate\\Support\\Facades\\Schema;
1033
+
1034
+ return new class extends Migration
1035
+ {${connection}
1036
+ /**
1037
+ * Run the migrations.
1038
+ */
1039
+ public function up(): void
1040
+ {
1041
+ Schema::dropIfExists('${tableName}');
1042
+ }
1043
+
1044
+ /**
1045
+ * Reverse the migrations.
1046
+ */
1047
+ public function down(): void
1048
+ {
1049
+ // Cannot recreate table without full schema
1050
+ // Consider restoring from backup if needed
1051
+ }
1052
+ };
1053
+ `;
1054
+ return {
1055
+ fileName,
1056
+ className: `Drop${schemaName}Table`,
1057
+ content,
1058
+ tables: [tableName],
1059
+ type: "drop"
1060
+ };
1061
+ }
1062
+ function generateMigrationsFromChanges(changes, options = {}) {
1063
+ const migrations = [];
1064
+ let timestampOffset = 0;
1065
+ const getNextTimestamp = () => {
1066
+ const ts = options.timestamp ?? generateTimestamp2();
1067
+ const offset = timestampOffset++;
1068
+ if (offset === 0) return ts;
1069
+ const parts = ts.split("_");
1070
+ if (parts.length >= 4) {
1071
+ const timePart = parts[3] ?? "000000";
1072
+ const secs = parseInt(timePart.substring(4, 6), 10) + offset;
1073
+ const newSecs = String(secs % 60).padStart(2, "0");
1074
+ parts[3] = timePart.substring(0, 4) + newSecs;
1075
+ return parts.join("_");
1076
+ }
1077
+ return ts;
1078
+ };
1079
+ for (const change of changes) {
1080
+ if (change.changeType === "modified") {
1081
+ const migration = generateAlterMigration(change, {
1082
+ ...options,
1083
+ timestamp: getNextTimestamp()
1084
+ });
1085
+ if (migration) {
1086
+ migrations.push(migration);
1087
+ }
1088
+ } else if (change.changeType === "removed") {
1089
+ migrations.push(
1090
+ generateDropTableMigration(change.schemaName, {
1091
+ ...options,
1092
+ timestamp: getNextTimestamp()
1093
+ })
1094
+ );
1095
+ }
1096
+ }
1097
+ return migrations;
1098
+ }
1099
+
740
1100
  // src/utils.ts
741
1101
  function toSnakeCase(str) {
742
1102
  return str.replace(/([A-Z])/g, "_$1").replace(/^_/, "").toLowerCase();
@@ -1748,6 +2108,24 @@ function getFactoryPath(factory) {
1748
2108
  }
1749
2109
 
1750
2110
  // src/plugin.ts
2111
+ function getExistingMigrationTables(migrationsDir) {
2112
+ const existingTables = /* @__PURE__ */ new Set();
2113
+ if (!(0, import_node_fs.existsSync)(migrationsDir)) {
2114
+ return existingTables;
2115
+ }
2116
+ try {
2117
+ const files = (0, import_node_fs.readdirSync)(migrationsDir);
2118
+ const createMigrationPattern = /^\d{4}_\d{2}_\d{2}_\d{6}_create_(.+)_table\.php$/;
2119
+ for (const file of files) {
2120
+ const match = file.match(createMigrationPattern);
2121
+ if (match) {
2122
+ existingTables.add(match[1]);
2123
+ }
2124
+ }
2125
+ } catch {
2126
+ }
2127
+ return existingTables;
2128
+ }
1751
2129
  var LARAVEL_CONFIG_SCHEMA = {
1752
2130
  fields: [
1753
2131
  {
@@ -1831,18 +2209,81 @@ function laravelPlugin(options) {
1831
2209
  generate: async (ctx) => {
1832
2210
  const migrationOptions = {
1833
2211
  connection: resolved.connection,
1834
- timestamp: resolved.timestamp
2212
+ timestamp: resolved.timestamp,
2213
+ customTypes: ctx.customTypes
1835
2214
  };
1836
- const migrations = generateMigrations(ctx.schemas, migrationOptions);
1837
- return migrations.map((migration) => ({
1838
- path: getMigrationPath(migration, resolved.migrationsPath),
1839
- content: migration.content,
1840
- type: "migration",
1841
- metadata: {
1842
- tableName: migration.tables[0],
1843
- migrationType: migration.type
2215
+ const outputs = [];
2216
+ const migrationsDir = (0, import_node_path.join)(ctx.cwd, resolved.migrationsPath);
2217
+ const existingTables = getExistingMigrationTables(migrationsDir);
2218
+ if (ctx.changes !== void 0) {
2219
+ if (ctx.changes.length === 0) {
2220
+ return outputs;
1844
2221
  }
1845
- }));
2222
+ const addedSchemaNames = new Set(
2223
+ ctx.changes.filter((c) => c.changeType === "added").map((c) => c.schemaName)
2224
+ );
2225
+ if (addedSchemaNames.size > 0) {
2226
+ const addedSchemas = Object.fromEntries(
2227
+ Object.entries(ctx.schemas).filter(([name]) => addedSchemaNames.has(name))
2228
+ );
2229
+ const createMigrations = generateMigrations(addedSchemas, migrationOptions);
2230
+ for (const migration of createMigrations) {
2231
+ const tableName = migration.tables[0];
2232
+ if (existingTables.has(tableName)) {
2233
+ ctx.logger.debug(`Skipping CREATE for ${tableName} (already exists)`);
2234
+ continue;
2235
+ }
2236
+ outputs.push({
2237
+ path: getMigrationPath(migration, resolved.migrationsPath),
2238
+ content: migration.content,
2239
+ type: "migration",
2240
+ metadata: {
2241
+ tableName,
2242
+ migrationType: "create"
2243
+ }
2244
+ });
2245
+ }
2246
+ }
2247
+ const alterChanges = ctx.changes.filter(
2248
+ (c) => c.changeType === "modified" || c.changeType === "removed"
2249
+ );
2250
+ if (alterChanges.length > 0) {
2251
+ const alterMigrations = generateMigrationsFromChanges(
2252
+ alterChanges,
2253
+ migrationOptions
2254
+ );
2255
+ for (const migration of alterMigrations) {
2256
+ outputs.push({
2257
+ path: getMigrationPath(migration, resolved.migrationsPath),
2258
+ content: migration.content,
2259
+ type: "migration",
2260
+ metadata: {
2261
+ tableName: migration.tables[0],
2262
+ migrationType: migration.type
2263
+ }
2264
+ });
2265
+ }
2266
+ }
2267
+ } else {
2268
+ const migrations = generateMigrations(ctx.schemas, migrationOptions);
2269
+ for (const migration of migrations) {
2270
+ const tableName = migration.tables[0];
2271
+ if (migration.type === "create" && existingTables.has(tableName)) {
2272
+ ctx.logger.debug(`Skipping migration for ${tableName} (already exists)`);
2273
+ continue;
2274
+ }
2275
+ outputs.push({
2276
+ path: getMigrationPath(migration, resolved.migrationsPath),
2277
+ content: migration.content,
2278
+ type: "migration",
2279
+ metadata: {
2280
+ tableName,
2281
+ migrationType: migration.type
2282
+ }
2283
+ });
2284
+ }
2285
+ }
2286
+ return outputs;
1846
2287
  }
1847
2288
  };
1848
2289
  const modelGenerator = {