Skip to content

Commit

Permalink
Add support for generating services (#4)
Browse files Browse the repository at this point in the history
* (feat): add support for Create services

* (refactor): put common functions for generators in their own module

* (feat): add update & delete services. Bump version. Update docs.
  • Loading branch information
hamptokr committed Mar 25, 2022
1 parent 9b14392 commit 915816a
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 37 deletions.
2 changes: 1 addition & 1 deletion guides/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ overrideable.

- `Mix.Tasks.Phx.Gen.Solid.Value` - used to generate a value
- `Mix.Tasks.Phx.Gen.Solid.Handler` - TODO
- `Mix.Tasks.Phx.Gen.Solid.Service` - TODO
- `Mix.Tasks.Phx.Gen.Solid.Service` - used to generate C~~R~~UD services
- `Mix.Tasks.Phx.Gen.Solid.Finder` - TODO

## SOLID Principles
Expand Down
73 changes: 73 additions & 0 deletions lib/mix/tasks/phx.gen.solid.service.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
defmodule Mix.Tasks.Phx.Gen.Solid.Service do
@shortdoc "Generates C~~R~~UD services for a resource"

@moduledoc """
Generates C~~R~~UD Services for a resource.
mix phx.gen.solid.value Accounts User users
The first argument is the context module followed by the schema module and its
plural name.
This creates the following services:
- `MyApp.Accounts.Service.CreateUser`
- `MyApp.Accounts.Service.UpdateUser`
- `MyApp.Accounts.Service.DeleteUser`
For more information about the generated Services, see the [Overview](overview.html).
"""

use Mix.Task

alias Mix.Phoenix.Context
alias Mix.Tasks.Phx.Gen
alias PhxGenSolid.Generator

@switches []

@impl true
def run(args) do
if Mix.Project.umbrella?() do
Mix.raise("mix phx.gen.solid can only be run inside an application directory")
end

{opts, parsed} = OptionParser.parse!(args, strict: @switches)

# Don't pass along the opts
{context, schema} = Gen.Context.build(parsed, __MODULE__)

binding = [
context: context,
opts: opts,
schema: schema,
web_app_name: Generator.web_app_name(context),
service_create_module: build_cud_module_name(context, schema, "Create"),
service_update_module: build_cud_module_name(context, schema, "Update"),
service_delete_module: build_cud_module_name(context, schema, "Delete")
]

paths = Generator.paths()
Generator.prompt_for_conflicts(context, &files_to_be_generated/1)
Generator.copy_new_files(context, binding, paths, &files_to_be_generated/1)
end

defp files_to_be_generated(%Context{schema: schema} = context) do
[
{:eex, "service_create.ex",
Path.join([context.dir, "services", "create_#{schema.singular}.ex"])},
{:eex, "service_update.ex",
Path.join([context.dir, "services", "update_#{schema.singular}.ex"])},
{:eex, "service_delete.ex",
Path.join([context.dir, "services", "delete_#{schema.singular}.ex"])}
]
end

defp build_cud_module_name(context, schema, action) do
Module.concat([
context.base_module,
"#{inspect(context.alias)}",
"Service",
"#{action}#{inspect(schema.alias)}"
])
end
end
40 changes: 5 additions & 35 deletions lib/mix/tasks/phx.gen.solid.value.ex
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ defmodule Mix.Tasks.Phx.Gen.Solid.Value do

alias Mix.Phoenix.Context
alias Mix.Tasks.Phx.Gen
alias PhxGenSolid.Generator

@switches [helpers: :boolean, value_context: :string]

Expand All @@ -47,7 +48,7 @@ defmodule Mix.Tasks.Phx.Gen.Solid.Value do
context: context,
opts: opts,
schema: schema,
web_app_name: web_app_name(context),
web_app_name: Generator.web_app_name(context),
value_context: build_value_context(context, opts),
value_fields: build_value_fields(schema.attrs),
value_module:
Expand All @@ -59,12 +60,9 @@ defmodule Mix.Tasks.Phx.Gen.Solid.Value do
])
]

paths = generator_paths()

prompt_for_conflicts(context, opts)

context
|> copy_new_files(binding, paths)
paths = Generator.paths()
Generator.prompt_for_conflicts(context, &files_to_be_generated/2, opts)
Generator.copy_new_files(context, binding, paths, &files_to_be_generated/2, opts)
end

defp build_value_context(context, opts) do
Expand All @@ -82,26 +80,6 @@ defmodule Mix.Tasks.Phx.Gen.Solid.Value do
end
end

defp web_app_name(%Context{} = context) do
context.web_module
|> inspect()
|> Phoenix.Naming.underscore()
end

# The paths to look for template files for generators.
#
# Defaults to checking the current app's `priv` directory and falls back to
# phx_gen_solid's `priv` directory.
defp generator_paths do
[".", :phx_gen_solid, :phoenix]
end

defp prompt_for_conflicts(context, opts) do
context
|> files_to_be_generated(opts)
|> Mix.Phoenix.prompt_for_conflicts()
end

defp files_to_be_generated(%Context{schema: schema} = context, opts) do
should_gen_helpers = Keyword.get(opts, :helpers, false)

Expand All @@ -125,14 +103,6 @@ defmodule Mix.Tasks.Phx.Gen.Solid.Value do
defp maybe_gen_helpers(base_files, helpers, true), do: Enum.concat(base_files, helpers)
defp maybe_gen_helpers(base_files, _helpers, false), do: base_files

defp copy_new_files(%Context{} = context, binding, paths) do
opts = Keyword.get(binding, :opts)
files = files_to_be_generated(context, opts)
Mix.Phoenix.copy_from(paths, "priv/templates/phx.gen.solid", binding, files)

context
end

defp build_value_fields(attrs) do
Keyword.keys(attrs)
end
Expand Down
43 changes: 43 additions & 0 deletions lib/phx_gen_solid/generator.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
defmodule PhxGenSolid.Generator do
alias Mix.Phoenix.Context

# The paths to look for template files for generators.
#
# Defaults to checking the current app's `priv` directory and falls back to
# phx_gen_solid's `priv` directory.
def paths do
[".", :phx_gen_solid, :phoenix]
end

def web_app_name(%Context{} = context) do
context.web_module
|> inspect()
|> Phoenix.Naming.underscore()
end

def copy_new_files(%Context{} = context, binding, paths, files_fn) do
files = files_fn.(context)
Mix.Phoenix.copy_from(paths, "priv/templates/phx.gen.solid", binding, files)

context
end

def copy_new_files(%Context{} = context, binding, paths, files_fn, opts) do
files = files_fn.(context, opts)
Mix.Phoenix.copy_from(paths, "priv/templates/phx.gen.solid", binding, files)

context
end

def prompt_for_conflicts(context, files_fn) do
context
|> files_fn.()
|> Mix.Phoenix.prompt_for_conflicts()
end

def prompt_for_conflicts(context, files_fn, opts) do
context
|> files_fn.(opts)
|> Mix.Phoenix.prompt_for_conflicts()
end
end
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule PhxGenSolid.MixProject do
use Mix.Project

@version "0.1.0"
@version "0.2.0"

def project do
[
Expand Down
15 changes: 15 additions & 0 deletions priv/templates/phx.gen.solid/service_create.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
defmodule <%= inspect service_create_module %> do
@moduledoc """
Creates a <%= schema.singular %>.
"""

alias <%= inspect context.module %>

def call(params) do
params
|> <%= inspect context.alias %>.create_<%= schema.singular %>(params)
|> handle_result()
end

defp handle_result(result), do: result
end
15 changes: 15 additions & 0 deletions priv/templates/phx.gen.solid/service_delete.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
defmodule <%= inspect service_delete_module %> do
@moduledoc """
Deletes a <%= schema.singular %>.
"""

alias <%= inspect context.module %>

def call(params) do
params
|> <%= inspect context.alias %>.delete_<%= schema.singular %>(params)
|> handle_result()
end

defp handle_result(result), do: result
end
15 changes: 15 additions & 0 deletions priv/templates/phx.gen.solid/service_update.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
defmodule <%= inspect service_update_module %> do
@moduledoc """
Updates a <%= schema.singular %>.
"""

alias <%= inspect context.module %>

def call(params) do
params
|> <%= inspect context.alias %>.update_<%= schema.singular %>(params)
|> handle_result()
end

defp handle_result(result), do: result
end

0 comments on commit 915816a

Please sign in to comment.