Current section

Files

Jump to
ecto_gen lib mix tasks generate.ex
Raw

lib/mix/tasks/generate.ex

defmodule Mix.Tasks.Eg.Gen do
use Mix.Task
@moduledoc """
This task starts the whole machinery to introspect specfied PostgreSQL database
and create function calls for found stored procedures.
"""
alias EctoGen.{Database, EEx.EExGenerator}
alias Mix.Shell.IO, as: MixIO
def run(_) do
MixIO.info("Running generate task")
Application.ensure_all_started(:postgrex)
config = EctoGen.Configuration.get_config()
{:ok, pg_pid} = Postgrex.start_link(config.database)
config
|> do_magic(pg_pid)
MixIO.info("Task finished")
end
defp do_magic(config, pg_pid) do
%{db_project: db_project_config} = config
MixIO.info("Getting routines from database")
{time, routines_with_params} =
:timer.tc(fn ->
Database.Helpers.get_routines_with_params_to_create(pg_pid, db_project_config)
# |> Enum.map(fn {routine, params} ->
# {
# routine
# |> Database.DbRoutine.to_routine_with_unique_name(),
# params
# }
# end)
end)
MixIO.info("Fetching routines took: #{inspect(time)}")
%{
output_module: output_module,
output_location: output_location,
include_sensitive_data: include_sensitive_data,
db_config: repo_module
} = config
sanitized_module_name = sanitize_module_name(output_module)
prepare_directory_structure(output_location)
create_context_module(
routines_with_params,
output_location,
sanitized_module_name,
repo_module
)
create_routine_parser_modules(
routines_with_params,
output_location,
sanitized_module_name,
include_sensitive_data
)
create_routines_results_modules(routines_with_params, output_location, sanitized_module_name)
:ok
end
defp create_context_module(routines_with_params, output_location, module_name, repo_module) do
MixIO.info("Generating context module")
context_module =
routines_with_params
|> EExGenerator.generate_context_module(
module_name: module_name,
repo_module: repo_module
)
MixIO.info("Creating db_context.ex")
File.write(Path.join(output_location, "db_context.ex"), context_module)
end
defp create_routine_parser_modules(
routines_with_params,
output_location,
module_name,
include_sensitive_data
) do
MixIO.info("Generating routines parser modules")
EExGenerator.generate_routines_parser_modules(
routines_with_params,
module_name,
include_sensitive_data
)
|> Enum.map(fn {routine, routine_parser_module_code} ->
routine_parser_filename =
routine
|> Database.DbRoutine.to_routine_with_unique_name()
|> Database.DbRoutine.get_routine_parser_name()
|> IO.iodata_to_binary()
|> Macro.underscore()
filename = Path.join([output_location, "parsers", [routine_parser_filename, ".ex"]])
MixIO.info(" * Creating: #{filename}")
File.write!(
filename,
routine_parser_module_code
)
end)
end
defp create_routines_results_modules(routines_with_params, output_location, module_name) do
MixIO.info("Generating routines result items modules")
EExGenerator.generate_routines_results_modules(routines_with_params, module_name)
|> Enum.map(fn {routine, routine_result_module_code} ->
routine_result_struct_filename =
routine
|> Database.DbRoutine.to_routine_with_unique_name()
|> Database.DbRoutine.get_routine_result_item_struct_name()
|> IO.iodata_to_binary()
|> Macro.underscore()
filename = Path.join([output_location, "models", [routine_result_struct_filename, ".ex"]])
MixIO.info(" * Creating: #{filename}")
File.write!(
filename,
routine_result_module_code
)
end)
end
defp sanitize_module_name(module_name) when is_atom(module_name) do
Atom.to_string(module_name)
end
defp sanitize_module_name(module_name) when is_binary(module_name), do: module_name
defp prepare_directory_structure(output_location) do
MixIO.info("Preparing directory structure")
if MixIO.yes?(
"Ensuring that output location: \"#{output_location}\" is clean by deleting it. \nProceed?"
) do
File.rm_rf(output_location)
[
output_location,
Path.join(output_location, "models"),
Path.join(output_location, "parsers")
]
|> ensure_locations()
else
Mix.raise("Operation aborted")
end
end
defp ensure_locations(output_locations) do
output_locations
|> Enum.map(fn x ->
case File.mkdir(x) do
:ok ->
{:ok, x}
{:error, :eexist} ->
{:exist, x}
{:error, reason} ->
Mix.raise(
"Could not create directory at output location: #{x}. reason: #{inspect(reason)}"
)
{:error, x}
end
end)
end
end