Current section
Files
Jump to
Current section
Files
lib/database_api.ex
defmodule EctoForge.DatabaseApi do
alias EctoForge.Utls.ExecuteExtensionEvents
@moduledoc """
## Implements base functions for database
```elixir
use(
EctoForge.DatabaseApi,
[
repo: MyApp.Repo, # required param
extensions_get: [], # default list
extensions_events: [] # default list
]
)
```
functions find_all, works only with extension `EctoForge.Extension.Get.Preload`, `EctoForge.Extension.Get.Filter` or you can write yours own
This module creates an instance of the database all functions function. It can be used through the use of Parameter
- create(map) # takes changeset and does repo.insert()
- create(map, :function_for_changeset),
- create!(map, :function_for_changeset), # takes function_for_changeset from the module and does repo.insert!()
- create!(map, :function_for_changeset), # takes the changeset and does a repo.insert!()
- find_all(map or keyword) # returns result_list or nil
- find(map or keyword) # returns result or nil
- get(map or keyword) # returns {:ok, result_one} or {:error, result_one}
- get!(map or keyword) # returns result or return throw
- get_all(map or keyword) # returns {:ok, list} or {:error, list}
- get_all!(map or keyword) # result items or throw(no results)
- update_by_opts(get_params, update) # result {:ok, item} or {:error, result}
- update(item, opts_update) # result {:ok, item} or {:error, result}
- update!(item, update_opts) # return item or throw
- update(item) # return {:ok, item} or {:error, result}
- update_with_another_changeset!(%@module_model{} = item, opts, function_atom) # return item or throw
- update_with_another_changeset(%@module_model{} = item, opts, function_atom) # return {:ok, item} or {:error, result}
- delete(%@module_model{} or opts_for_get) # result {:ok, _} or {:error, _}
- delete!(%@module_model{} or opts_for_get) # result {:ok, _} or {:error, _}
"""
defmacro __using__(opts) do
quote location: :keep, bind_quoted: [opts: opts] do
@module_model opts[:module_model] || __MODULE__
@doc """
## Implements base functions for database
functions find_all, works only with extension `EctoForge.Extension.Get.Preload`, `EctoForge.Extension.Get.Filter` or you can write yours own
This module creates an instance of the database all functions function. It can be used through the use of Parameter
- create(map) # takes changeset and does repo.insert()
- create(map, :function_for_changeset),
- create!(map, :function_for_changeset), # takes function_for_changeset from the module and does repo.insert!()
- create!(map, :function_for_changeset), # takes the changeset and does a repo.insert!()
- find_all(map or keyword) # returns result_list or nil
- find(map or keyword) # returns result or nil
- get(map or keyword) # returns {:ok, result_one} or {:error, result_one}
- get!(map or keyword) # returns result or return throw
- get_all(map or keyword) # returns {:ok, list} or {:error, list}
- get_all!(map or keyword) # result items or throw(no results)
- update_by_opts(get_params, update) # result {:ok, item} or {:error, result}
- update(item, opts_update) # result {:ok, item} or {:error, result}
- update!(item, update_opts) # return item or throw
- update(item) # return {:ok, item} or {:error, result}
- update_with_another_changeset!(%@module_model{} = item, opts, function_atom) # return item or throw
- update_with_another_changeset(%@module_model{} = item, opts, function_atom) # return {:ok, item} or {:error, result}
- delete(%@module_model{} or opts_for_get) # result {:ok, _} or {:error, _}
- delete!(%@module_model{} or opts_for_get!) # result {:ok, _} or {:error, _}
"""
@repo opts[:repo]
@extensions_events opts[:extensions_events] || []
@ignore_fields opts[:ignore_fields] || []
@extensions_get opts[:extensions_get] || []
@not_found_message opts[:error_message] || :not_found
use EctoForge.Helpers.QueryBinderGet,
repo: @repo,
extensions_get: opts[:extensions_get],
module_model: @module_model
@doc """
## Creates and does structure insert by default pulls the changeset function from `#{@module_model}`.
Returns `{{:ok, item}` or `{:error, error_changeset}`.
## Example
```elixir
#{@module_model}.create(%{name: "artem"})
```
"""
def create(map) do
map = ExecuteExtensionEvents.exucute_before_created(map, @extensions_events)
@module_model.changeset(%@module_model{}, map)
|> @repo.insert()
|> ExecuteExtensionEvents.exucute_after_created(@extensions_events)
end
@doc """
## Creates and makes insert structures, together with the changeset function
Returns `{:ok, item}` or `{:error, error_changeset}`.
## Example
```elixir
#{@module_model}.create(%{name: "artem"}, :changeset_register)
```
"""
def create(map, function) do
map = ExecuteExtensionEvents.exucute_before_created(map, @extensions_events)
apply(@module_model, function, [map])
|> @repo.insert()
|> ExecuteExtensionEvents.exucute_after_created(@extensions_events)
end
@doc """
## Creates and does structure insert by default pulls the changeset function from `#{@module_model}`.
Returns `{:ok, item}` or `{:error, error_changeset}`.
## Example
```elixir
#{@module_model}.create(%{name: "artem"})
```
"""
def create!(map) do
map = ExecuteExtensionEvents.exucute_before_created!(map, @extensions_events)
@module_model.changeset(%@module_model{}, map)
|> @repo.insert!()
|> ExecuteExtensionEvents.exucute_after_created!(@extensions_events)
end
@doc """
## Creates and makes insert structures, together with the changeset function
Returns `{:ok, item}` or `{:error, error_changeset}`.
## Example
```elixir
#{@module_model}.create(%{name: "artem"}, :changeset_register)
```
"""
def create!(map, function) do
map = ExecuteExtensionEvents.exucute_before_created!(map, @extensions_events)
res =
apply(@module_model, function, [map])
|> @repo.insert!()
|> ExecuteExtensionEvents.exucute_after_created!(@extensions_events)
end
@doc """
# Returns all fields in the scheme
## Example
```elixir
iex> #{@module_model}.fields()
[:id, :name]
```
## You can filter out values that are not needed
```elixir
iex> #{@module_model}.fields([:id])
[:name]
```
"""
def fields(filtered \\ []) when is_list(filtered) do
schema = @module_model.__schema__(:fields)
if filtered != [] do
schema
|> Enum.filter(fn x ->
!(x in filtered)
end)
else
schema
end
end
@doc """
## Returns a structure by its id or by matching the value of the structure's fields
```elixir
#{@module_model}.find(id: id) # nil or item
```
"""
def find(opts) when is_list(opts) or is_map(opts) do
try do
query_bindings(opts, :one)
rescue
Ecto.Query.CastError -> nil
end
|> get_helper_after
end
@doc """
## Returns a structure by its id or by matching the value of the structure's fields
```elixir
#{@module_model}.find(1) # nil or item
```
"""
def find(item_id) do
try do
query_bindings([id: item_id], :all)
rescue
Ecto.Query.CastError -> nil
end
|> get_helper_after
end
@doc """
## Returns a structure by its id or by matching the value of the structure's fields
## Example
```elixir
iex -> #{@module_model}.get(
type_private: :public,
)
iex -> {:ok, #{@module_model}} # or {:error, #{@module_model}}
```
"""
def get(item_id_or_opts) do
case find(item_id_or_opts) do
%@module_model{} = item -> {:ok, item}
nil -> {:error, @not_found_message}
end
end
@doc """
## Returns a structure by its id or by matching the value of the structure's fields
## Example
```elixir
iex -> #{@module_model}.get!(
type_private: :public,
)
iex -> #{@module_model} # or throw()
```
"""
def get!(item_id_or_opts) do
case find(item_id_or_opts) do
%@module_model{} = item -> item
nil -> throw(%Ecto.NoResultsError{message: "#{inspect(%@module_model{})} not found"})
end
end
@doc """
## Gets or adds an entry if not found
## Example
```elixir
#{@module_model}.get_or_insert(%{user_id: ""}, %{login: "12", password: "1234"})
```
"""
def get_or_insert(attrs_get, attrs_create) do
case get(attrs_get) do
{:ok, user} -> {:ok, user}
{:error, _} -> create(attrs_create)
end
end
@doc """
## reurn true false if model exists
## Example
```elixir
#{@module_model}.exists(id: 1)
```
"""
def exists?(opts) when is_list(opts) or is_map(opts) do
get!(opts)
|> @repo.exists?()
end
@doc """
## Returns a list of all available structures or matching structure field values
## The most important thing to understand
In get_all you can pass map or keyword list everything will fall where
#{@module_model}.get_all(%{status: 1}))
will equate to `#{@module_model}|> where(%{status: 1)`
#{@module_model}.get_all(%{preload: [:user]})
will equate to `#{@module_model}|> preload( [:user])`
## Example
```elixir
##{@module_model}.get_all(
type_private: :public,
)
```
"""
def find_all(opts \\ nil) do
try do
query_bindings(opts, :all)
rescue
Ecto.Query.CastError -> []
end
|> get_helper_after
end
@doc """
## Returns a list of all available structures or matching structure field values
## example
```elixir
iex-> #{@module_model}.get_all(
type_private: :public,
)
iex-> {:ok, [#{@module_model}]} or {:error, #{@not_found_message}}
```
"""
def get_all(opts \\ nil) do
case find_all(opts) do
[] -> {:error, @not_found_message}
items -> {:ok, items}
end
end
@doc """
## Returns a list of all available structures or matching structure field values
## example
```elixir
iex-> #{@module_model}.get_all!(
type_private: :public,
)
iex-> [#{@module_model}] or throw(no_results)
```
"""
def get_all!(item_id_or_opts \\ nil) do
case find_all(item_id_or_opts) do
[] -> throw(%Ecto.NoResultsError{message: "#{inspect(%@module_model{})} not found"})
items -> items
end
end
@doc """
## Update structure with another changeset
iex -> update_with_another_changeset(#{@module_model}, %{update_attrs: ""}, :function_in_changeset)
the third argument is the function that is in the module
"""
def update_with_another_changeset(%@module_model{} = item, opts, function_atom, attrs \\ [])
when is_atom(function_atom) do
opts = ExecuteExtensionEvents.exucute_before_updated!(opts, @extensions_events)
res =
apply(@module_model, function_atom, [item, opts])
|> @repo.update(attrs)
|> ExecuteExtensionEvents.exucute_after_updated!(@extensions_events)
end
@doc """
## Updating a structure with another changeset throws throw
iex -> update_with_another_changeset!(#{@module_model}, %{update_attrs: ""}, :function_in_changeset))
the third argument is the function that is in the module
"""
def update_with_another_changeset!(
%@module_model{} = item,
opts,
function_atom,
attrs \\ []
)
when is_atom(function_atom) do
opts = ExecuteExtensionEvents.exucute_before_updated!(opts, @extensions_events)
res =
apply(@module_model, function_atom, [item, opts])
|> @repo.update!(attrs)
|> ExecuteExtensionEvents.exucute_after_updated!(@extensions_events)
end
@doc """
## Update item %{}
```elixir
iex -> update(#{@module_model}, %{update_attrs: ""}, repo.update.attrs)
```
"""
def update(%@module_model{} = item, opts, attrs \\ []) do
opts = ExecuteExtensionEvents.exucute_before_updated(opts, @extensions_events)
res =
item
|> @module_model.changeset(EctoForge.Helpers.RepoBase.Utls.MapUtls.opts_to_map(opts))
|> @repo.update(attrs)
|> ExecuteExtensionEvents.exucute_after_updated(@extensions_events)
end
@doc """
## Updates item record, %{}, throws exception
iex -> `update!(#{@module_model}, %{update_attrs: ""}, repo.update
"""
def update!(%@module_model{} = item, opts, attrs \\ []) do
opts = ExecuteExtensionEvents.exucute_before_updated!(opts, @extensions_events)
item
|> @module_model.changeset(EctoForge.Helpers.RepoBase.Utls.MapUtls.opts_to_map(opts))
|> @repo.update!(attrs)
|> ExecuteExtensionEvents.exucute_after_updated!(@extensions_events)
end
@doc """
## Gets the structure with #{@module_model}.get(get_opts) and updates it
iex -> update_by_opts(%{id: 1} %{update_attrs: "asd"}, []) third parameter for
## Returns
{:ok, _}
{:error, _}
"""
def update_by_opts(get_opts, update_opts, attrs \\ []) do
with {:ok, item} <- get(get_opts),
{:ok, item} <- update(item, update_opts, attrs) do
{:ok, item}
end
end
@doc """
## Gets the structure with #{@module_model}.get(get_opts) and updates it
iex -> update_by_opts(#{@module_model} %{update_attrs: "asd"}, []) third parameter for the
"""
def update_by_opts!(get_opts, update_opts, attrs \\ []) do
res =
get!(get_opts)
|> update!(update_opts, attrs)
end
@doc """
## delete by #{@module_model}
```elixir
iex -> delete(#{@module_model})
iex -> {:ok, _} # or {:error, _}
```
"""
def delete(%@module_model{} = item) do
item = ExecuteExtensionEvents.exucute_before_deleted(item, @extensions_events)
try do
@repo.delete(item)
|> ExecuteExtensionEvents.exucute_after_deleted(@extensions_events)
rescue
err -> {:error, err}
end
end
@doc """
## delete by #{@module_model}
```elixir
iex -> delete!(#{@module_model})
iex -> ok or throw
```
"""
def delete!(%@module_model{} = item) do
ExecuteExtensionEvents.exucute_before_deleted!(item, @extensions_events)
res =
@repo.delete!(item)
|> ExecuteExtensionEvents.exucute_after_deleted!(@extensions_events)
end
@doc """
## get structure and delete it using functions #{@module_model}.get(%{}) |> #{@module_model}.delete
"""
def delete!(item_id_or_opts) when is_map(item_id_or_opts) or is_binary(item_id_or_opts) do
get!(item_id_or_opts)
|> delete!()
end
@doc """
## get structure and delete it using functions #{@module_model}.get(%{}) |> #{@module_model}.delete
"""
def delete(item_id_or_opts) do
with {:ok, item} <- get(item_id_or_opts),
{:ok, item} <- delete(item) do
{:ok, item}
end
end
defp get_helper_after(result) do
case result do
{:ok, item} ->
ExecuteExtensionEvents.exucute_after_get(item, @extensions_events)
{:error, _} ->
result
[] ->
result
nil ->
result
result ->
ExecuteExtensionEvents.exucute_after_get(result, @extensions_events)
end
end
end
end
end