Repository: elixir-ecto/ecto (elixir)

Issue:
unique index name inference inconsistency
### Environment

* Elixir version (elixir -v): 1.5.2
* Database and version (PostgreSQL 9.4, MongoDB 3.2, etc.): Postgres 10.1
* Ecto version (mix deps): 2.2.6
* Database adapter and version (mix deps): postgres 0.13.3
* Operating system: OSX and Debian

### Current behavior

I am having an issue with underscores where the index name generated in a migration is not matching the index name inferred in a changeset constraint.

When naming tables, i use single underscores to delimit a context and schema, and a _double underscore_ to delimit a join.  This is how Django does it.

For example, if I have a logical join table between a "person" in my system and a user id in a third-party (like twitter):

```ex
defmodule Website.Twitter.UserPerson do
  use Ecto.Schema
  
  alias Website.Accounts

  schema "twitter_users__accounts_people" do
    field :twitter_id, :string
    belongs_to :person, Accounts.Person
  end
end
```

I'll add a unique index using **[`Ecto.Migration.unique_index`](https://hexdocs.pm/ecto/Ecto.Migration.html#unique_index/3)** so that twitter id is only added once.


```ex
def change do
  create table(:twitter_users__accounts_people) do
    add :twitter_id, :string
    add :person_id, references(:accounts_people)
  end

  create unique_index(:twitter_users__accounts_people, [:twitter_id])
end
```

Ecto will generate an index _with the double underscore trimmed to a single underscore_.

```
Indexes:
    "twitter_users_accounts_people_twitter_id_index" UNIQUE, btree (twitter_id)
```

This is inconsistent with how **[`Ecto.Changeset.unique_constraint`](https://hexdocs.pm/ecto/Ecto.Changeset.html#unique_constraint/3)** works!

If I have an insert operation, e.g.:

```ex
change(%Twitter.UserPerson{}, twitter_username: "already joined!")
|> put_assoc(:person, person)
|> unique_constraint(:twitter_username)
|> Repo.insert()
```

I get an error:

```
** (Ecto.ConstraintError) constraint error when attempting to insert struct:

         * unique: twitter_users_accounts_people_twitter_id_index

     If you would like to convert this constraint into an error, please
     call unique_constraint/3 in your changeset and define the proper
     constraint name. The changeset defined the following constraints:

         * unique: twitter_users__accounts_people_twitter_id_index
```

the constraint is using the actual table name with the _double underscore_.

### Expected behavior

`Ecto.Changeset.unique_constraint` and `Ecto.Migration.unique_index` should be consistent in how they infer the name of an index.

### Workaround

I know that I can explicitly add a `name` option to unique_constraint to override the inferred name.  This issue is about the inconsistency only.


Pull request:
Keep double underscores on index names
# Summary
Index names are composed of index.table name, index.columns names and
the "index" suffix. If index.table or index.columns names cointained two
underscores, they were replaced by a single underscore. This caused
issues when applying unique index constraints on changesets.

## Additional info
Fixes #2311

Patch:
diff --git a/lib/ecto/migration.ex b/lib/ecto/migration.ex
index 878d615e..55824959 100644
--- a/lib/ecto/migration.ex
+++ b/lib/ecto/migration.ex
@@ -583,9 +583,10 @@ defmodule Ecto.Migration do
   defp default_index_name(index) do
     [index.table, index.columns, "index"]
     |> List.flatten
+    |> Enum.map(&to_string(&1))
+    |> Enum.map(&String.replace(&1, ~r"[^\w_]", "_"))
+    |> Enum.map(&String.replace_trailing(&1, "_", ""))
     |> Enum.join("_")
-    |> String.replace(~r"[^\w_]", "_")
-    |> String.replace("__", "_")
     |> String.to_atom
   end
 


Test patch:
diff --git a/test/ecto/migration_test.exs b/test/ecto/migration_test.exs
index c017fb0a..67a8257e 100644
--- a/test/ecto/migration_test.exs
+++ b/test/ecto/migration_test.exs
@@ -58,6 +58,8 @@ defmodule Ecto.MigrationTest do
            %Index{table: "posts", unique: true, name: :foo, columns: [:title]}
     assert unique_index(:posts, :title, name: :foo) ==
            %Index{table: "posts", unique: true, name: :foo, columns: [:title]}
+    assert unique_index(:table_one__table_two, :title) ==
+           %Index{table: "table_one__table_two", unique: true, name: :table_one__table_two_title_index, columns: [:title]}
   end
 
   test "creates a reference" do