Repository: elixir-ecto/ecto_sql
Pull request #593 (2024-01-25 15:51:02)

Fix `nil` prefix with `references`
Closes https://github.com/elixir-ecto/ecto_sql/issues/590

There are 2 things I wasn't sure about:

1. Is there a way to mark a struct field as deprecated? Or should I just leave a comment?
2. I am still populating `:prefix` because I assumed removals only happen during new major versions


Patch:
diff --git a/Earthfile b/Earthfile
index 1470cae..480ce47 100644
--- a/Earthfile
+++ b/Earthfile
@@ -1,4 +1,4 @@
-VERSION 0.5
+VERSION 0.6
 
 all:
     ARG ELIXIR_BASE=1.15.6-erlang-25.3.2.6-alpine-3.17.4
diff --git a/lib/ecto/adapters/myxql/connection.ex b/lib/ecto/adapters/myxql/connection.ex
index aee1e9c..39f3196 100644
--- a/lib/ecto/adapters/myxql/connection.ex
+++ b/lib/ecto/adapters/myxql/connection.ex
@@ -1314,7 +1314,7 @@ if Code.ensure_loaded?(MyXQL) do
         quote_names(current_columns),
         ?),
         " REFERENCES ",
-        quote_table(ref.prefix || table.prefix, ref.table),
+        quote_table(Keyword.get(ref.options, :prefix, table.prefix), ref.table),
         ?(,
         quote_names(reference_columns),
         ?),
diff --git a/lib/ecto/adapters/postgres/connection.ex b/lib/ecto/adapters/postgres/connection.ex
index 030e768..0b74241 100644
--- a/lib/ecto/adapters/postgres/connection.ex
+++ b/lib/ecto/adapters/postgres/connection.ex
@@ -1706,7 +1706,7 @@ if Code.ensure_loaded?(Postgrex) do
         "FOREIGN KEY (",
         quote_names(current_columns),
         ") REFERENCES ",
-        quote_name(ref.prefix || table.prefix, ref.table),
+        quote_name(Keyword.get(ref.options, :prefix, table.prefix), ref.table),
         ?(,
         quote_names(reference_columns),
         ?),
diff --git a/lib/ecto/adapters/tds/connection.ex b/lib/ecto/adapters/tds/connection.ex
index 021d464..4c2ca9c 100644
--- a/lib/ecto/adapters/tds/connection.ex
+++ b/lib/ecto/adapters/tds/connection.ex
@@ -1571,7 +1571,7 @@ if Code.ensure_loaded?(Tds) do
         reference_name(ref, table, name),
         " FOREIGN KEY (#{quote_names(current_columns)})",
         " REFERENCES ",
-        quote_table(ref.prefix || table.prefix, ref.table),
+        quote_table(Keyword.get(ref.options, :prefix, table.prefix), ref.table),
         "(#{quote_names(reference_columns)})",
         reference_on_delete(ref.on_delete),
         reference_on_update(ref.on_update)
diff --git a/lib/ecto/migration.ex b/lib/ecto/migration.ex
index c20050f..9cf8429 100644
--- a/lib/ecto/migration.ex
+++ b/lib/ecto/migration.ex
@@ -443,8 +443,14 @@ defmodule Ecto.Migration do
               on_update: :nothing,
               validate: true,
               with: [],
-              match: nil
+              match: nil,
+              options: []
 
+    @typedoc """
+    The reference struct.
+
+    The `:prefix` field is deprecated and should instead be stored in the `:options` field.
+    """
     @type t :: %__MODULE__{
             table: String.t(),
             prefix: atom | nil,
@@ -454,7 +460,8 @@ defmodule Ecto.Migration do
             on_update: atom,
             validate: boolean,
             with: list,
-            match: atom | nil
+            match: atom | nil,
+            options: [{:prefix, atom | nil}]
           }
   end
 
@@ -1416,7 +1423,13 @@ defmodule Ecto.Migration do
   end
 
   def references(table, opts) when is_binary(table) and is_list(opts) do
-    opts = Keyword.merge(foreign_key_repo_opts(), opts)
+    reference_options = Keyword.take(opts, [:prefix])
+
+    opts =
+      foreign_key_repo_opts()
+      |> Keyword.merge(opts)
+      |> Keyword.put(:options, reference_options)
+
     reference = struct!(%Reference{table: table}, opts)
     check_on_delete!(reference.on_delete)
     check_on_update!(reference.on_update)


Test patch:
diff --git a/test/ecto/adapters/myxql_test.exs b/test/ecto/adapters/myxql_test.exs
index c5039ec..99ed331 100644
--- a/test/ecto/adapters/myxql_test.exs
+++ b/test/ecto/adapters/myxql_test.exs
@@ -1661,8 +1661,8 @@ defmodule Ecto.Adapters.MyXQLTest do
          {:add, :category_3, %Reference{table: :categories, on_delete: :delete_all},
           [null: false]},
          {:add, :category_4, %Reference{table: :categories, on_delete: :nilify_all}, []},
-         {:add, :category_5, %Reference{table: :categories, prefix: :foo, on_delete: :nilify_all},
-          []},
+         {:add, :category_5,
+          %Reference{table: :categories, options: [prefix: :foo], on_delete: :nilify_all}, []},
          {:add, :category_6,
           %Reference{table: :categories, with: [here: :there], on_delete: :nilify_all}, []}
        ]}
diff --git a/test/ecto/adapters/postgres_test.exs b/test/ecto/adapters/postgres_test.exs
index 14d2ea9..f9981f9 100644
--- a/test/ecto/adapters/postgres_test.exs
+++ b/test/ecto/adapters/postgres_test.exs
@@ -2102,8 +2102,8 @@ defmodule Ecto.Adapters.PostgresTest do
           [null: false]},
          {:add, :category_9, %Reference{table: :categories, on_delete: :restrict}, []},
          {:add, :category_10, %Reference{table: :categories, on_update: :restrict}, []},
-         {:add, :category_11, %Reference{table: :categories, prefix: "foo", on_update: :restrict},
-          []},
+         {:add, :category_11,
+          %Reference{table: :categories, options: [prefix: "foo"], on_update: :restrict}, []},
          {:add, :category_12, %Reference{table: :categories, with: [here: :there]}, []},
          {:add, :category_13,
           %Reference{
diff --git a/test/ecto/adapters/tds_test.exs b/test/ecto/adapters/tds_test.exs
index 415731a..18adfef 100644
--- a/test/ecto/adapters/tds_test.exs
+++ b/test/ecto/adapters/tds_test.exs
@@ -1457,8 +1457,8 @@ defmodule Ecto.Adapters.TdsTest do
          {:add, :category_3, %Reference{table: :categories, on_delete: :delete_all},
           [null: false]},
          {:add, :category_4, %Reference{table: :categories, on_delete: :nilify_all}, []},
-         {:add, :category_5, %Reference{table: :categories, prefix: :foo, on_delete: :nilify_all},
-          []},
+         {:add, :category_5,
+          %Reference{table: :categories, options: [prefix: :foo], on_delete: :nilify_all}, []},
          {:add, :category_6,
           %Reference{table: :categories, with: [here: :there], on_delete: :nilify_all}, []}
        ]}
diff --git a/test/ecto/migration_test.exs b/test/ecto/migration_test.exs
index 2baf8f0..ab51f58 100644
--- a/test/ecto/migration_test.exs
+++ b/test/ecto/migration_test.exs
@@ -130,7 +130,13 @@ defmodule Ecto.MigrationTest do
              %Reference{table: "posts", column: :other, type: :uuid, prefix: nil}
 
     assert references(:posts, type: :uuid, column: :other, prefix: :blog) ==
-             %Reference{table: "posts", column: :other, type: :uuid, prefix: :blog}
+             %Reference{
+               table: "posts",
+               column: :other,
+               type: :uuid,
+               prefix: :blog,
+               options: [prefix: :blog]
+             }
   end
 
   @tag repo_config: [migration_foreign_key: [type: :uuid, column: :other, prefix: :blog]]