Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add mix phx.new --database cockroach #5813

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions guides/ecto.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Most web applications today need some form of data validation and persistence. I
Phoenix uses Ecto to provide builtin support to the following databases:

* PostgreSQL (via [`postgrex`](https://github.com/elixir-ecto/postgrex))
* CockroachDB (via [`postgrex`](https://github.com/elixir-ecto/postgrex))
* MySQL (via [`myxql`](https://github.com/elixir-ecto/myxql))
* MSSQL (via [`tds`](https://github.com/livehelpnow/tds))
* ETS (via [`etso`](https://github.com/evadne/etso))
Expand Down
3 changes: 2 additions & 1 deletion installer/lib/mix/tasks/phx.new.ex
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ defmodule Mix.Tasks.Phx.New do
* `--database` - specify the database adapter for Ecto. One of:

* `postgres` - via https://github.com/elixir-ecto/postgrex
* `cockroach` - via https://github.com/elixir-ecto/postgrex
* `mysql` - via https://github.com/elixir-ecto/myxql
* `mssql` - via https://github.com/livehelpnow/tds
* `sqlite3` - via https://github.com/elixir-sqlite/ecto_sqlite3
Expand Down Expand Up @@ -53,7 +54,7 @@ defmodule Mix.Tasks.Phx.New do

* `--no-html` - do not generate HTML views

* `--no-live` - comment out LiveView socket setup in your Endpoint
* `--no-live` - comment out LiveView socket setup in your Endpoint
and assets/js/app.js. Automatically disabled if --no-html is given

* `--no-mailer` - do not generate Swoosh mailer files
Expand Down
70 changes: 69 additions & 1 deletion installer/lib/phx_new/generator.ex
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,74 @@ defmodule Phx.New.Generator do
{:ecto_sqlite3, Ecto.Adapters.SQLite3, fs_db_config(app, module)}
end

defp get_ecto_adapter("cockroach", app, module) do
{:postgrex, Ecto.Adapters.Postgres,
case_insensitive_field_type: :"STRING COLLATE \"en-US-u-ks-level2\"",
dev: [
username: "root",
password: nil,
hostname: "localhost",
port: 26257,
database: "#{app}_dev",
stacktrace: true,
migration_lock: false,
show_sensitive_data_on_connection_error: true,
pool_size: 10
],
test: [
username: "root",
password: nil,
hostname: "localhost",
port: 26257,
database: {:literal, ~s|"#{app}_test\#{System.get_env("MIX_TEST_PARTITION")}"|},
migration_lock: false,
pool: Ecto.Adapters.SQL.Sandbox,
pool_size: {:literal, ~s|System.schedulers_online() * 2|}
],
test_setup_all: "Ecto.Adapters.SQL.Sandbox.mode(#{inspect(module)}.Repo, :manual)",
test_setup: """
pid = Ecto.Adapters.SQL.Sandbox.start_owner!(#{inspect(module)}.Repo, shared: not tags[:async])
on_exit(fn -> Ecto.Adapters.SQL.Sandbox.stop_owner(pid) end)\
""",
prod_variables: ~S"""
database_url =
System.get_env("DATABASE_URL") ||
raise \"""
environment variable DATABASE_URL is missing.
For example: postgres://USER:PASS@HOST/DATABASE
\"""

database_cert = System.get_env("DATABASE_CERT") ||
raise \"""
environment variable DATABASE_CERT is missing.
You must set this to the certificate file contents of the CockroachDB cluster.
\"""

db_conf =
Regex.named_captures(
~r/^postgresql:\/\/(?<username>[^:]+):(?<password>[^@]+)@(?<hostname>[^:]+):(?<port>\d+)\/(?<database>[^\?]+)/,
database_url
)

""",
prod_config: ~S"""
username: db_conf["username"],
password: db_conf["password"],
hostname: db_conf["hostname"],
port: db_conf["port"],
database: db_conf["database"],
migration_lock: false,
pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"),
show_sensitive_data_on_connection_error: true,
ssl: true,
ssl_opts: [
server_name_indication: ~c"#{db_conf["hostname"]}",
chrismccord marked this conversation as resolved.
Show resolved Hide resolved
customize_hostname_check: [match_fun: :public_key.pkix_verify_hostname_match_fun(:https)],
cacerts: for({:Certificate, der, _} <- :public_key.pem_decode(database_cert), do: der)
]
"""}
end

defp get_ecto_adapter(db, _app, _mod) do
Mix.raise("Unknown database #{inspect(db)}")
end
Expand Down Expand Up @@ -394,7 +462,7 @@ defmodule Phx.New.Generator do

defp adapter_generators(adapter_config) do
adapter_config
|> Keyword.take([:binary_id, :migration, :sample_binary_id])
|> Keyword.take([:binary_id, :migration, :sample_binary_id, :case_insensitive_field_type])
|> Enum.filter(fn {_, value} -> not is_nil(value) end)
end

Expand Down
56 changes: 56 additions & 0 deletions installer/test/phx_new_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,62 @@ defmodule Mix.Tasks.Phx.NewTest do
end)
end

test "new with cockroach adapter" do
in_tmp("new with cockroach adapter", fn ->
project_path = Path.join(File.cwd!(), "custom_path")
Mix.Tasks.Phx.New.run([project_path, "--database", "cockroach"])

assert_file("custom_path/mix.exs", ":postgrex")

assert_file("custom_path/config/config.exs", fn file ->
assert file =~ "ecto_repos: [CustomPath.Repo]"
assert file =~ """
generators: [
timestamp_type: :utc_datetime,
case_insensitive_field_type: :"STRING COLLATE \\"en-US-u-ks-level2\\""
]
"""
end)

assert_file("custom_path/config/dev.exs", [
~r/username: "root"/,
~r/password: nil/,
~r/hostname: "localhost"/,
~r/port: 26257/,
~r/migration_lock: false/,
])

assert_file("custom_path/config/test.exs", [
~r/username: "root"/,
~r/password: nil/,
~r/hostname: "localhost"/,
~r/port: 26257/,
~r/migration_lock: false/,
])

assert_file("custom_path/config/runtime.exs", fn file ->
assert file =~ ~s|database_cert =|
assert file =~ ~s|db_conf =|
assert file =~ ~s|migration_lock: false|
assert file =~ ~s|username: db_conf["username"]|
assert file =~ ~s|password: db_conf["password"]|
assert file =~ ~s|hostname: db_conf["hostname"]|
assert file =~ ~s|database: db_conf["database"]|
assert file =~ ~s|ssl_opts:|
assert file =~ ~s| ssl: true|
refute file =~ ~s|url: database_url|
end)
assert_file("custom_path/lib/custom_path/repo.ex", "Ecto.Adapters.Postgres")

assert_file("custom_path/test/support/conn_case.ex", "DataCase.setup_sandbox(tags)")

assert_file(
"custom_path/test/support/data_case.ex",
"Ecto.Adapters.SQL.Sandbox.start_owner"
)
end)
end

test "new with mysql adapter" do
in_tmp("new with mysql adapter", fn ->
project_path = Path.join(File.cwd!(), "custom_path")
Expand Down
21 changes: 18 additions & 3 deletions lib/mix/tasks/phx.gen.auth/migration.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,34 @@ defmodule Mix.Tasks.Phx.Gen.Auth.Migration do
end

defp extensions(Ecto.Adapters.Postgres) do
["execute \"CREATE EXTENSION IF NOT EXISTS citext\", \"\""]
if case_insensitive_field_type() == :citext do
["execute \"CREATE EXTENSION IF NOT EXISTS citext\", \"\""]
else
[]
end
end

defp extensions(_), do: []

defp case_insensitive_field_type do
case Application.get_env(Mix.Phoenix.otp_app(), :generators, [])[:case_insensitive_field_type] do
type when type in [nil, :citext] -> :citext
custom_type -> custom_type
end
end
chrismccord marked this conversation as resolved.
Show resolved Hide resolved

defp column_definitions(ecto_adapter) do
for field <- ~w(email token)a,
into: %{},
do: {field, column_definition(field, ecto_adapter)}
end

defp column_definition(:email, Ecto.Adapters.Postgres), do: "add :email, :citext, null: false"
defp column_definition(:email, Ecto.Adapters.SQLite3), do: "add :email, :string, null: false, collate: :nocase"
defp column_definition(:email, Ecto.Adapters.Postgres),
do: "add :email, #{inspect(case_insensitive_field_type())}, null: false"

defp column_definition(:email, Ecto.Adapters.SQLite3),
do: "add :email, :string, null: false, collate: :nocase"

defp column_definition(:email, _), do: "add :email, :string, null: false, size: 160"

defp column_definition(:token, Ecto.Adapters.Postgres), do: "add :token, :binary, null: false"
Expand Down
2 changes: 1 addition & 1 deletion priv/templates/phx.gen.live/index.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
</:action>
<:action :let={{id, <%= schema.singular %>}}>
<.link
phx-click={JS.push("delete", value: %{id: <%= schema.singular %>.id}) |> hide("##{id}")}
phx-click={JS.push("delete", value: %{id: to_string(<%= schema.singular %>.id)}) |> hide("##{id}")}
data-confirm="Are you sure?"
>
Delete
Expand Down
Loading
Loading