@@ -74,12 +74,14 @@ defmodule AshPostgres.MigrationGenerator do
7474 extension_migration_files =
7575 create_extension_migrations ( repos , opts )
7676
77- tenant_migration_files =
77+ { tenant_migration_files , tenant_review_flags } =
7878 create_migrations ( tenant_snapshots , opts , true , snapshots , unmanaged_tenant_snapshots )
7979
80- migration_files =
80+ { migration_files , global_review_flags } =
8181 create_migrations ( snapshots , opts , false , [ ] , unmanaged_snapshots )
8282
83+ review_flags = merge_review_flag_maps ( tenant_review_flags , global_review_flags )
84+
8385 case extension_migration_files ++ tenant_migration_files ++ migration_files do
8486 [ ] ->
8587 if ! opts . check || opts . dry_run do
@@ -91,6 +93,10 @@ defmodule AshPostgres.MigrationGenerator do
9193 :ok
9294
9395 files ->
96+ if ! ( opts . check or opts . quiet or opts . no_shell? ) do
97+ emit_review_warnings ( review_flags )
98+ end
99+
94100 cond do
95101 opts . check ->
96102 raise Ash.Error.Framework.PendingCodegen ,
@@ -460,7 +466,7 @@ defmodule AshPostgres.MigrationGenerator do
460466 ) do
461467 snapshots
462468 |> Enum . group_by ( & & 1 . repo )
463- |> Enum . flat_map ( fn { repo , snapshots } ->
469+ |> Enum . reduce ( { [ ] , initial_review_flags ( ) } , fn { repo , snapshots } , { files_acc , flags_acc } ->
464470 deduped = deduplicate_snapshots ( snapshots , opts , non_tenant_snapshots )
465471
466472 managed_table_keys =
@@ -539,12 +545,13 @@ defmodule AshPostgres.MigrationGenerator do
539545 |> Enum . concat ( drop_operations )
540546 |> Enum . uniq ( )
541547
542- operations
543- |> case do
548+ case operations do
544549 [ ] ->
545- [ ]
550+ { files_acc , flags_acc }
546551
547552 operations ->
553+ repo_flags = classify_operations ( operations )
554+
548555 dev_migrations = get_dev_migrations ( opts , tenant? , repo )
549556
550557 if ! opts . dev and dev_migrations != [ ] do
@@ -582,16 +589,89 @@ defmodule AshPostgres.MigrationGenerator do
582589 operations_to_migrations ( public_operations , repo , opts , false )
583590 end
584591
585- migrations
586- |> Enum . concat ( create_new_snapshot ( snapshots , repo_name ( repo ) , opts , tenant? ) )
587- |> then ( fn files ->
588- remove_orphan_snapshots ( orphan_snapshots , opts )
589- files
590- end )
592+ files =
593+ migrations
594+ |> Enum . concat ( create_new_snapshot ( snapshots , repo_name ( repo ) , opts , tenant? ) )
595+ |> then ( fn files ->
596+ remove_orphan_snapshots ( orphan_snapshots , opts )
597+ files
598+ end )
599+
600+ { files_acc ++ files , merge_review_flag_maps ( flags_acc , repo_flags ) }
591601 end
592602 end )
593603 end
594604
605+ defp emit_review_warnings ( review_flags ) do
606+ shell = Mix . shell ( )
607+
608+ review_flags
609+ |> review_warning_messages ( )
610+ |> Enum . each ( & shell . info / 1 )
611+ end
612+
613+ defp review_warning_messages ( review_flags ) do
614+ [
615+ review_baseline_message ( ) ,
616+ review_commented_safeguards_message ( review_flags ) ,
617+ review_destructive_message ( review_flags )
618+ ]
619+ |> Enum . reject ( & is_nil / 1 )
620+ end
621+
622+ defp review_baseline_message do
623+ "Please always manually review the generated migrations for correctness."
624+ end
625+
626+ defp review_commented_safeguards_message ( % { commented_safeguards?: true } ) do
627+ "Warning: there are migration steps commented out and in need of manual review."
628+ end
629+
630+ defp review_commented_safeguards_message ( _ ) , do: nil
631+
632+ defp review_destructive_message ( % { destructive_uncommented?: true } ) do
633+ "Warning: this migration includes destructive operations (e.g. drops or column removals). Review carefully before migrating."
634+ end
635+
636+ defp review_destructive_message ( _ ) , do: nil
637+
638+ defp classify_operations ( operations ) do
639+ Enum . reduce ( operations , initial_review_flags ( ) , & merge_review_flags / 2 )
640+ end
641+
642+ defp initial_review_flags do
643+ % { commented_safeguards?: false , destructive_uncommented?: false }
644+ end
645+
646+ defp merge_review_flags ( op , acc ) do
647+ acc
648+ |> Map . update! ( :commented_safeguards? , & ( & 1 or commented_safeguard? ( op ) ) )
649+ |> Map . update! ( :destructive_uncommented? , & ( & 1 or destructive_uncommented? ( op ) ) )
650+ end
651+
652+ defp merge_review_flag_maps ( a , b ) do
653+ % {
654+ commented_safeguards?: a . commented_safeguards? or b . commented_safeguards? ,
655+ destructive_uncommented?: a . destructive_uncommented? or b . destructive_uncommented?
656+ }
657+ end
658+
659+ defp commented_safeguard? ( % { commented?: true } ) , do: true
660+ defp commented_safeguard? ( _ ) , do: false
661+
662+ defp destructive_uncommented? ( % Operation.DropTable { } ) , do: true
663+ defp destructive_uncommented? ( % Operation.RemoveAttribute { commented?: false } ) , do: true
664+ defp destructive_uncommented? ( % Operation.RemovePrimaryKey { } ) , do: true
665+ defp destructive_uncommented? ( % Operation.RemovePrimaryKeyDown { commented?: false } ) , do: true
666+ defp destructive_uncommented? ( % Operation.DropForeignKey { } ) , do: true
667+ defp destructive_uncommented? ( % Operation.RemoveCustomStatement { } ) , do: true
668+ defp destructive_uncommented? ( % Operation.RemoveCustomIndex { } ) , do: true
669+ defp destructive_uncommented? ( % Operation.RemoveReferenceIndex { } ) , do: true
670+ defp destructive_uncommented? ( % Operation.RemoveUniqueIndex { } ) , do: true
671+ defp destructive_uncommented? ( % Operation.RemoveCheckConstraint { } ) , do: true
672+ defp destructive_uncommented? ( % Operation.AddPrimaryKeyDown { remove_old?: true } ) , do: true
673+ defp destructive_uncommented? ( _ ) , do: false
674+
595675 defp operations_to_migrations ( [ ] , _repo , _opts , _tenant? ) , do: [ ]
596676
597677 defp operations_to_migrations ( operations , repo , opts , tenant? ) do
0 commit comments