This commit is contained in:
2026-07-14 22:50:46 +04:00
parent 27143319e3
commit bd19e0682b
3116 changed files with 467189 additions and 0 deletions

View File

@@ -0,0 +1,77 @@
defmodule Mix.Tasks.Ecto.Create do
use Mix.Task
import Mix.Ecto
@shortdoc "Creates the repository storage"
@switches [
quiet: :boolean,
repo: [:string, :keep],
no_compile: :boolean,
no_deps_check: :boolean
]
@aliases [
r: :repo,
q: :quiet
]
@moduledoc """
Create the storage for the given repository.
The repositories to create are the ones specified under the
`:ecto_repos` option in the current app configuration. However,
if the `-r` option is given, it replaces the `:ecto_repos` config.
Since Ecto tasks can only be executed once, if you need to create
multiple repositories, set `:ecto_repos` accordingly or pass the `-r`
flag multiple times.
## Examples
$ mix ecto.create
$ mix ecto.create -r Custom.Repo
## Command line options
* `-r`, `--repo` - the repo to create
* `--quiet` - do not log output
* `--no-compile` - do not compile before creating
* `--no-deps-check` - do not compile before creating
"""
@impl true
def run(args) do
repos = parse_repo(args)
{opts, _} = OptionParser.parse!(args, strict: @switches, aliases: @aliases)
Enum.each(repos, fn repo ->
ensure_repo(repo, args)
ensure_implements(
repo.__adapter__(),
Ecto.Adapter.Storage,
"create storage for #{inspect(repo)}"
)
case repo.__adapter__().storage_up(repo.config()) do
:ok ->
unless opts[:quiet] do
Mix.shell().info("The database for #{inspect(repo)} has been created")
end
{:error, :already_up} ->
unless opts[:quiet] do
Mix.shell().info("The database for #{inspect(repo)} has already been created")
end
{:error, term} when is_binary(term) ->
Mix.raise("The database for #{inspect(repo)} couldn't be created: #{term}")
{:error, term} ->
Mix.raise("The database for #{inspect(repo)} couldn't be created: #{inspect(term)}")
end
end)
end
end

View File

@@ -0,0 +1,106 @@
defmodule Mix.Tasks.Ecto.Drop do
use Mix.Task
import Mix.Ecto
@shortdoc "Drops the repository storage"
@default_opts [force: false, force_drop: false]
@aliases [
f: :force,
q: :quiet,
r: :repo
]
@switches [
force: :boolean,
force_drop: :boolean,
quiet: :boolean,
repo: [:keep, :string],
no_compile: :boolean,
no_deps_check: :boolean
]
@moduledoc """
Drop the storage for the given repository.
The repositories to drop are the ones specified under the
`:ecto_repos` option in the current app configuration. However,
if the `-r` option is given, it replaces the `:ecto_repos` config.
Since Ecto tasks can only be executed once, if you need to drop
multiple repositories, set `:ecto_repos` accordingly or pass the `-r`
flag multiple times.
## Examples
$ mix ecto.drop
$ mix ecto.drop -r Custom.Repo
## Command line options
* `-r`, `--repo` - the repo to drop
* `-q`, `--quiet` - run the command quietly
* `-f`, `--force` - do not ask for confirmation when dropping the database.
Configuration is asked only when `:start_permanent` is set to true
(typically in production)
* `--force-drop` - force the database to be dropped even
if it has connections to it (requires PostgreSQL 13+)
* `--no-compile` - do not compile before dropping
* `--no-deps-check` - do not compile before dropping
"""
@impl true
def run(args) do
repos = parse_repo(args)
{opts, _} = OptionParser.parse!(args, strict: @switches, aliases: @aliases)
opts = Keyword.merge(@default_opts, opts)
Enum.each(repos, fn repo ->
ensure_repo(repo, args)
ensure_implements(
repo.__adapter__(),
Ecto.Adapter.Storage,
"drop storage for #{inspect(repo)}"
)
if skip_safety_warnings?() or
opts[:force] or
Mix.shell().yes?(
"Are you sure you want to drop the database for repo #{inspect(repo)}?"
) do
drop_database(repo, opts)
end
end)
end
defp skip_safety_warnings? do
Mix.Project.config()[:start_permanent] != true
end
defp drop_database(repo, opts) do
config =
opts
|> Keyword.take([:force_drop])
|> Keyword.merge(repo.config())
case repo.__adapter__().storage_down(config) do
:ok ->
unless opts[:quiet] do
Mix.shell().info("The database for #{inspect(repo)} has been dropped")
end
{:error, :already_down} ->
unless opts[:quiet] do
Mix.shell().info("The database for #{inspect(repo)} has already been dropped")
end
{:error, term} when is_binary(term) ->
Mix.raise("The database for #{inspect(repo)} couldn't be dropped: #{term}")
{:error, term} ->
Mix.raise("The database for #{inspect(repo)} couldn't be dropped: #{inspect(term)}")
end
end
end

View File

@@ -0,0 +1,30 @@
defmodule Mix.Tasks.Ecto do
use Mix.Task
@shortdoc "Prints Ecto help information"
@moduledoc """
Prints Ecto tasks and their information.
$ mix ecto
"""
@impl true
def run(args) do
{_opts, args} = OptionParser.parse!(args, strict: [])
case args do
[] -> general()
_ -> Mix.raise "Invalid arguments, expected: mix ecto"
end
end
defp general() do
Application.ensure_all_started(:ecto)
Mix.shell().info "Ecto v#{Application.spec(:ecto, :vsn)}"
Mix.shell().info "A toolkit for data mapping and language integrated query for Elixir."
Mix.shell().info "\nAvailable tasks:\n"
Mix.Tasks.Help.run(["--search", "ecto."])
end
end

View File

@@ -0,0 +1,110 @@
defmodule Mix.Tasks.Ecto.Gen.Repo do
use Mix.Task
import Mix.Ecto
import Mix.Generator
@shortdoc "Generates a new repository"
@switches [
repo: [:string, :keep],
]
@aliases [
r: :repo,
]
@moduledoc """
Generates a new repository.
The repository will be placed in the `lib` directory.
## Examples
$ mix ecto.gen.repo -r Custom.Repo
This generator will automatically open the config/config.exs
after generation if you have `ECTO_EDITOR` set in your environment
variable.
## Command line options
* `-r`, `--repo` - the repo to generate
"""
@impl true
def run(args) do
no_umbrella!("ecto.gen.repo")
{opts, _} = OptionParser.parse!(args, strict: @switches, aliases: @aliases)
repo =
case Keyword.get_values(opts, :repo) do
[] -> Mix.raise "ecto.gen.repo expects the repository to be given as -r MyApp.Repo"
[repo] -> Module.concat([repo])
[_ | _] -> Mix.raise "ecto.gen.repo expects a single repository to be given"
end
config = Mix.Project.config()
underscored = Macro.underscore(inspect(repo))
base = Path.basename(underscored)
file = Path.join("lib", underscored) <> ".ex"
app = config[:app] || :YOUR_APP_NAME
opts = [mod: repo, app: app, base: base]
create_directory Path.dirname(file)
create_file file, repo_template(opts)
config_path = config[:config_path] || "config/config.exs"
case File.read(config_path) do
{:ok, contents} ->
check = String.contains?(contents, "import Config")
config_first_line = get_first_config_line(check) <> "\n"
new_contents = config_first_line <> "\n" <> config_template(opts)
Mix.shell().info [:green, "* updating ", :reset, config_path]
File.write! config_path, String.replace(contents, config_first_line, new_contents)
{:error, _} ->
create_file config_path, "import Config\n\n" <> config_template(opts)
end
open?(config_path, 3)
Mix.shell().info """
Don't forget to add your new repo to your supervision tree
(typically in lib/#{app}/application.ex):
def start(_type, _args) do
children = [
#{inspect repo},
]
And to add it to the list of Ecto repositories in your
configuration files (so Ecto tasks work as expected):
config #{inspect app},
ecto_repos: [#{inspect repo}]
"""
end
defp get_first_config_line(true), do: "import Config"
defp get_first_config_line(false), do: "use Mix.Config"
embed_template :repo, """
defmodule <%= inspect @mod %> do
use Ecto.Repo,
otp_app: <%= inspect @app %>,
adapter: Ecto.Adapters.Postgres
end
"""
embed_template :config, """
config <%= inspect @app %>, <%= inspect @mod %>,
database: "<%= @app %>_<%= @base %>",
username: "user",
password: "pass",
hostname: "localhost"
"""
end