# EctoResource
Eliminate boilerplate involved in defining basic CRUD functions in a Phoenix context or Elixir module.
Turn this:
```elixir
defmodule MyApp.Accounts do
@moduledoc """
The Accounts context.
"""
import Ecto.Query, warn: false
alias MyApp.Repo
alias MyApp.Accounts.User
@doc """
Returns the list of users.
## Examples
iex> all_users()
[%User{}, ...]
"""
def all_users do
Repo.all(User)
end
@doc """
Gets a single user.
## Examples
iex> get_user(123)
{:ok, %User{}}
iex> get_user(456)
{:error, %Ecto.Changeset{}}
"""
def get_user(id), do: Repo.get(User, id)
@doc """
Gets a single user.
Raises `Ecto.NoResultsError` if the User does not exist.
## Examples
iex> get_user!(123)
%User{}
iex> get_user!(456)
** (Ecto.NoResultsError)
"""
def get_user!(id), do: Repo.get!(User, id)
@doc """
Creates a user.
## Examples
iex> create_user(%{field: value})
{:ok, %User{}}
iex> create_user(%{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def create_user(attrs \\ %{}) do
%User{}
|> User.changeset(attrs)
|> Repo.insert()
end
@doc """
Creates a user.
Raises `Postgrex.Error` if the insert fails.
## Examples
iex> create_user!(%{field: value})
{:ok, %User{}}
iex> create_user!(%{field: bad_value})
** (Postgrex.Error)
"""
def create_user!(attrs \\ %{}) do
%User{}
|> User.changeset(attrs)
|> Repo.insert!()
end
@doc """
Updates a user.
## Examples
iex> update_user(user, %{field: new_value})
{:ok, %User{}}
iex> update_user(user, %{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def update_user(%User{} = user, attrs) do
user
|> User.changeset(attrs)
|> Repo.update()
end
@doc """
Updates a user.
Raises `Postgrex.Error` if the update fails.
## Examples
iex> update_user!(user, %{field: new_value})
{:ok, %User{}}
iex> update_user!(user, %{field: bad_value})
** (Postgrex.Error)
"""
def update_user!(%User{} = user, attrs) do
user
|> User.changeset(attrs)
|> Repo.update!()
end
@doc """
Deletes a User.
## Examples
iex> delete_user(user)
{:ok, %User{}}
iex> delete_user(user)
{:error, %Ecto.Changeset{}}
"""
def delete_user(%User{} = user) do
Repo.delete(user)
end
@doc """
Deletes a User.
Raises `Postgrex.Error` if the delete fails.
## Examples
iex> delete_user!(user)
{:ok, %User{}}
iex> delete_user!(user)
** (Postgrex.Error)
"""
def delete_user!(%User{} = user) do
Repo.delete!(user)
end
@doc """
Returns an `%Ecto.Changeset{}` for tracking user changes.
## Examples
iex> change_user(user)
%Ecto.Changeset{source: %User{}}
"""
def change_user(%User{} = user) do
User.changeset(user, %{})
end
end
```
Into this:
```elixir
defmodule MyApp.Accounts do
use EctoResource
alias MyApp.Repo
alias MyApp.Accounts.User
using_repo(Repo) do
resource(User)
end
end
```
## Installation
If [available in Hex](https://hex.pm/docs/publish), the package can be installed
by adding `ecto_resource` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:ecto_resource, "~> 0.1.0"}
]
end
```
## Basic Usage
All examples are using a "context" module `Accounts` and a schema of `User`. This can be substituted for your Phoenix context, or any other module and schema.
```elixir
defmodule Accounts do
use EctoResource
using_repo(Repo) do
resource(User)
end
end
```
This will generate the functions:
```elixir
def create_user(attributes) do
EctoResource.create(Repo, User, attributes)
end
def create_user!(attributes) do
EctoResource.create!(Repo, User, attributes)
end
def all_users(options) do
EctoResource.all(Repo, User, options)
end
def get_user(id, options) do
EctoResource.get(Repo, User, id, options)
end
def get_user!(id, options) do
EctoResource.get!(Repo, User, id, options)
end
def change_user(struct_or_changeset) do
EctoResource.change(User, struct_or_changeset)
end
def update_user(%User{id: 1}, changeset) do
EctoResource.update(Repo, User, struct, changeset)
end
def update_user!(%User{id: 1}, changeset) do
EctoResource.update!(Repo, User, struct, changeset)
end
def delete_user(struct_or_changeset) do
EctoResource.delete(Repo, struct_or_changeset)
end
def delete_user!(struct_or_changeset) do
EctoResource.delete!(Repo, struct_or_changeset)
end
```
There are also introspection functions to understand what is generated by the macro
```elixir
Accounts.__resource__(:resources) == [
{Repo, User,
[
"all_users/1",
"change_user/1",
"create_user/1",
"create_user!/1",
"delete_user/1",
"delete_user!/1",
"get_user/2",
"get_user!/2",
"update_user/2",
"update_user!/2"
]}
]
```
## Advanced usage
More granular control is available through options
## :read
```elixir
defmodule Accounts do
use EctoResource
using_repo(Repo) do
resource(User, :read)
end
end
```
This will generate the functions:
```elixir
def all_users(options) do
EctoResource.all(Repo, User, options)
end
def get_user(id, options) do
EctoResource.get(Repo, User, id, options)
end
def get_user!(id, options) do
EctoResource.get!(Repo, User, id, options)
end
```
There are also introspection functions to understand what is generated by the macro
```elixir
Accounts.__resource__(:resources) == [
{Repo, User,
[
"all_users/1",
"get_user/2",
"get_user!/2"
]}
]
```
## :write
```elixir
defmodule Accounts do
use EctoResource
using_repo(Repo) do
resource(User, :write)
end
end
```
This will generate the functions:
```elixir
def create_user(attributes) do
EctoResource.create(Repo, User, attributes)
end
def create_user!(attributes) do
EctoResource.create!(Repo, User, attributes)
end
def change_user(struct_or_changeset) do
EctoResource.change(User, struct_or_changeset)
end
def update_user(%User{id: 1}, changeset) do
EctoResource.update(Repo, User, struct, changeset)
end
def update_user!(%User{id: 1}, changeset) do
EctoResource.update!(Repo, User, struct, changeset)
end
```
There are also introspection functions to understand what is generated by the macro
```elixir
Accounts.__resource__(:resources) == [
{Repo, User,
[
"change_user/1",
"create_user/1",
"create_user!/1",
"update_user/2",
"update_user!/2"
]}
]
```
## :delete
```elixir
defmodule Accounts do
use EctoResource
using_repo(Repo) do
resource(User, :delete)
end
end
```
This will generate the functions:
```elixir
def delete_user(struct_or_changeset) do
EctoResource.delete(Repo, struct_or_changeset)
end
def delete_user!(struct_or_changeset) do
EctoResource.delete!(Repo, struct_or_changeset)
end
```
There are also introspection functions to understand what is generated by the macro
```elixir
Accounts.__resource__(:resources) == [
{Repo, User,
[
"delete_user/1",
"delete_user!/1"
]}
]
```
## :only
```elixir
defmodule Accounts do
use EctoResource
using_repo(Repo) do
resource(User, only: [:change])
end
```
This will generate the functions:
```elixir
def change_user(struct_or_changeset) do
EctoResource.change(User, struct_or_changeset)
end
```
There are also introspection functions to understand what is generated by the macro
```elixir
Accounts.__resource__(:resources) == [
{Repo, User,
[
"change_user/1"
]}
]
```
## :except
```elixir
defmodule Accounts do
use EctoResource
using_repo(Repo) do
resource(User, except: [:change])
end
```
This will generate the functions:
```elixir
def create_user(attributes) do
EctoResource.create(Repo, User, attributes)
end
def create_user!(attributes) do
EctoResource.create!(Repo, User, attributes)
end
def all_users(options) do
EctoResource.all(Repo, User, options)
end
def get_user(id, options) do
EctoResource.get(Repo, User, id, options)
end
def get_user!(id, options) do
EctoResource.get!(Repo, User, id, options)
end
def update_user(%User{id: 1}, changeset) do
EctoResource.update(Repo, User, struct, changeset)
end
def update_user!(%User{id: 1}, changeset) do
EctoResource.update!(Repo, User, struct, changeset)
end
def delete_user(struct_or_changeset) do
EctoResource.delete(Repo, struct_or_changeset)
end
def delete_user!(struct_or_changeset) do
EctoResource.delete!(Repo, struct_or_changeset)
end
```
There are also introspection functions to understand what is generated by the macro
```elixir
Accounts.__resource__(:resources) == [
{Repo, User,
[
"all_users/1",
"create_user/1",
"create_user!/1",
"delete_user/1",
"delete_user!/1",
"get_user/2",
"get_user!/2",
"update_user/2",
"update_user!/2"
]}
]
```
Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
be found at [https://hexdocs.pm/ecto_resource](https://hexdocs.pm/ecto_resource).