Skip to content

Commit

Permalink
chore: move repo config logic to EctoShorts.Config (#59)
Browse files Browse the repository at this point in the history
* chore: move repo config logic to EctoShorts.Config

* add @doc since: 2.5.0

* update replica function error message

* fix error message typos
  • Loading branch information
cylkdev authored Oct 17, 2024
1 parent 648805f commit 9beaa71
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 53 deletions.
1 change: 1 addition & 0 deletions config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Config

config :ecto_shorts,
repo: nil,
replica: nil,
error_module: EctoShorts.Actions.Error

if Mix.env() === :test do
Expand Down
50 changes: 13 additions & 37 deletions lib/ecto_shorts/actions.ex
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ defmodule EctoShorts.Actions do
id :: id()
) :: schema() | nil
def get(query, id, opts \\ []) do
replica!(opts).get(query, id, opts)
Config.replica!(opts).get(query, id, opts)
end

@doc """
Expand Down Expand Up @@ -212,7 +212,7 @@ defmodule EctoShorts.Actions do

query
|> CommonFilters.convert_params_to_filter(params)
|> replica!(opts).all(opts)
|> Config.replica!(opts).all(opts)
end

@doc """
Expand Down Expand Up @@ -262,7 +262,7 @@ defmodule EctoShorts.Actions do

query
|> CommonFilters.convert_params_to_filter(params)
|> replica!(opts).one(opts)
|> Config.replica!(opts).one(opts)
|> case do
nil ->
{:error, Error.call(:not_found, "no records found", %{
Expand Down Expand Up @@ -302,7 +302,7 @@ defmodule EctoShorts.Actions do
def create(query, params, opts \\ []) do
query
|> build_changeset(params, opts)
|> repo!(opts).insert(opts)
|> Config.repo!(opts).insert(opts)
end

@doc """
Expand Down Expand Up @@ -506,7 +506,7 @@ defmodule EctoShorts.Actions do
def update(query, schema_data, update_params, opts) do
query
|> build_changeset(schema_data, update_params, opts)
|> repo!(opts).update(opts)
|> Config.repo!(opts).update(opts)
end

@doc """
Expand Down Expand Up @@ -554,7 +554,7 @@ defmodule EctoShorts.Actions do
id :: id()
) :: {:ok, schema()} | {:error, any()}
def delete(%Ecto.Changeset{} = changeset, opts) do
case repo!(opts).delete(changeset, opts) do
case Config.repo!(opts).delete(changeset, opts) do
{:error, changeset} ->
{:error, Error.call(
:internal_server_error,
Expand All @@ -568,7 +568,7 @@ defmodule EctoShorts.Actions do
def delete(%queryable{} = schema_data, opts) do
changeset = build_changeset(queryable, schema_data, %{}, opts)

case repo!(opts).delete(changeset, opts) do
case Config.repo!(opts).delete(changeset, opts) do
{:error, changeset} ->
{:error, Error.call(
:internal_server_error,
Expand Down Expand Up @@ -616,7 +616,7 @@ defmodule EctoShorts.Actions do
) :: {:ok, schema()} | {:error, any()}
def delete(query, id, opts) when (is_integer(id) or is_binary(id)) do
with {:ok, schema_data} <- find(query, %{id: id}, opts) do
repo!(opts).delete(schema_data, opts)
Config.repo!(opts).delete(schema_data, opts)
end
end

Expand Down Expand Up @@ -655,7 +655,7 @@ defmodule EctoShorts.Actions do
query
|> CommonSchemas.get_schema_query()
|> CommonFilters.convert_params_to_filter(params)
|> replica!(opts).stream(opts)
|> Config.replica!(opts).stream(opts)
end

@doc """
Expand Down Expand Up @@ -697,7 +697,7 @@ defmodule EctoShorts.Actions do
query
|> CommonSchemas.get_schema_query()
|> CommonFilters.convert_params_to_filter(params)
|> replica!(opts).aggregate(aggregate, field, opts)
|> Config.replica!(opts).aggregate(aggregate, field, opts)
end

@doc """
Expand Down Expand Up @@ -735,7 +735,7 @@ defmodule EctoShorts.Actions do

query
|> multi_insert(param_list, create_params, opts)
|> repo!(opts).transaction()
|> Config.repo!(opts).transaction()
|> case do
{:ok, created_map} -> {:ok, merge_found(created_map, found_results)}
error -> error
Expand Down Expand Up @@ -827,31 +827,7 @@ defmodule EctoShorts.Actions do
{status, Enum.reverse(res)}
end

defp repo!(opts) do
with nil <- repo(opts) do
raise ArgumentError, message: "ecto shorts must be configured with a repo. For further guidence consult the docs. https://hexdocs.pm/ecto_shorts/EctoShorts.html#module-config"
end
defp default_opts do
[repo: Config.repo(), replica: Config.replica()]
end

# `replica!/1` will attempt to retrieve a repo from the replica key and default to
# returning the value under the repo: key if no replica is found. If no repos are configured
# an ArgumentError will be raised.
defp replica!(opts) do
with nil <- Keyword.get(opts, :replica),
nil <- repo(opts) do
raise ArgumentError, message: "ecto shorts must be configured with a repo. For further guidence consult the docs. https://hexdocs.pm/ecto_shorts/EctoShorts.html#module-config"
end
end

defp repo([]) do
Config.repo()
end

defp repo(opts) do
default_opts()
|> Keyword.merge(opts)
|> Keyword.get(:repo)
end

defp default_opts, do: [repo: Config.repo()]
end
8 changes: 2 additions & 6 deletions lib/ecto_shorts/common_changes.ex
Original file line number Diff line number Diff line change
Expand Up @@ -165,16 +165,14 @@ defmodule EctoShorts.CommonChanges do
def preload_changeset_assoc(changeset, key, opts \\ [])

def preload_changeset_assoc(changeset, key, opts) do
opts = Keyword.merge(default_opts(), opts)

if opts[:ids] do
schema = changeset_relationship_schema(changeset, key)

preloaded_data = Actions.all(schema, %{ids: opts[:ids]}, repo: opts[:repo])
preloaded_data = Actions.all(schema, %{ids: opts[:ids]}, opts)

Map.update!(changeset, :data, &Map.put(&1, key, preloaded_data))
else
Map.update!(changeset, :data, &opts[:repo].preload(&1, key, opts))
Map.update!(changeset, :data, &Config.repo!(opts).preload(&1, key, opts))
end
end

Expand Down Expand Up @@ -263,6 +261,4 @@ defmodule EctoShorts.CommonChanges do

defp relationship_exists?({:assoc, _}), do: true
defp relationship_exists?(_), do: false

def default_opts, do: [repo: Config.repo()]
end
124 changes: 124 additions & 0 deletions lib/ecto_shorts/config.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,131 @@ defmodule EctoShorts.Config do

@app :ecto_shorts

@doc """
Returns the value of `ecto_shorts` config key `:repo`.
### Examples
iex> EctoShorts.Config.repo()
EctoShorts.Support.Repo
"""
@spec repo :: Ecto.Repo.t() | nil
def repo do
Application.get_env(@app, :repo)
end

@doc """
Returns the value of `ecto_shorts` config key `:replica`.
### Examples
iex> EctoShorts.Config.replica()
nil
"""
@doc since: "2.5.0"
@spec replica :: Ecto.Repo.t() | nil
def replica do
Application.get_env(@app, :replica)
end

@doc """
Returns a `Ecto.Repo` module.
Raises if the key `:repo` is not specified in configuration
and the option `:repo` is not specified at runtime.
### Examples
iex> EctoShorts.Config.repo!()
EctoShorts.Support.Repo
iex> EctoShorts.Config.repo!(repo: YourApp.Repo)
YourApp.Repo
"""
@doc since: "2.5.0"
@spec repo!(opts :: keyword()) :: Ecto.Repo.t()
@spec repo! :: Ecto.Repo.t()
def repo!(opts \\ []) do
with nil <- Keyword.get(opts, :repo, repo()) do
raise ArgumentError, """
EctoShorts repo not configured!
Expected one of the following:
* The option `:repo` is specified at runtime.
```
EctoShorts.Actions.all(YourApp.Schema, %{id: [1, 2, 3]}, repo: YourApp.Repo)
```
* The option `:repo` is set in configuration.
```
# config.exs
import Config
config :ecto_shorts, :repo, YourApp.Repo
```
"""
end
end

@doc """
Returns a `Ecto.Repo` module.
Raises if the key `:replica` and `:repo` is not specified in
configuration and the option `:replica` and `:repo` is not
specified at runtime.
### Examples
iex> EctoShorts.Config.replica!()
EctoShorts.Support.Repo
iex> EctoShorts.Config.replica!(replica: YourApp.Repo.Replica)
YourApp.Repo.Replica
"""
@doc since: "2.5.0"
@spec replica!(opts :: keyword()) :: Ecto.Repo.t()
@spec replica! :: Ecto.Repo.t()
def replica!(opts \\ []) do
with nil <- Keyword.get(opts, :replica, replica()),
nil <- Keyword.get(opts, :repo, repo()) do
raise ArgumentError, """
EctoShorts replica and repo not configured!
Expected one of the following:
* The option `:replica` is specified at runtime.
```
EctoShorts.Actions.all(YourApp.Schema, %{id: [1, 2, 3]}, replica: YourApp.Repo.Replica)
```
* The option `:replica` is set in configuration.
```
# config.exs
import Config
config :ecto_shorts, :replica, YourApp.Repo.Replica
```
* The option `:repo` is specified at runtime.
```
EctoShorts.Actions.all(YourApp.Schema, %{id: [1, 2, 3]}, repo: YourApp.Repo)
```
* The option `:repo` is set in configuration.
```
# config.exs
import Config
config :ecto_shorts, :repo, YourApp.Repo
```
"""
end
end
end
10 changes: 5 additions & 5 deletions test/ecto_shorts/actions_abstract_schema_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ defmodule EctoShorts.ActionsAbstractSchemaTest do
UserAvatarNoConstraint
}

test "raises if repo not configured" do
assert_raise ArgumentError, ~r|ecto shorts must be configured with a repo|, fn ->
test "raise when :repo not set in option and configuration" do
assert_raise ArgumentError, ~r|EctoShorts repo not configured!|, fn ->
Actions.create({"file_info_user_avatars", FileInfo}, %{}, repo: nil)
end
end

test "raises if repo not configured for replica" do
assert_raise ArgumentError, ~r|ecto shorts must be configured with a repo|, fn ->
Actions.all({"file_info_user_avatars", FileInfo}, %{}, repo: nil)
test "raise when :repo and :replica not set in option and configuration" do
assert_raise ArgumentError, ~r|EctoShorts replica and repo not configured!|, fn ->
Actions.all({"file_info_user_avatars", FileInfo}, %{}, repo: nil, replica: nil)
end
end

Expand Down
10 changes: 5 additions & 5 deletions test/ecto_shorts/actions_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ defmodule EctoShorts.ActionsTest do
Post
}

test "raises if repo not configured" do
assert_raise ArgumentError, ~r|ecto shorts must be configured with a repo|, fn ->
test "raise when :repo not set in option and configuration" do
assert_raise ArgumentError, ~r|EctoShorts repo not configured!|, fn ->
Actions.create(Comment, %{}, repo: nil)
end
end

test "raises if repo not configured for replica" do
assert_raise ArgumentError, ~r|ecto shorts must be configured with a repo|, fn ->
Actions.all(Comment, %{}, repo: nil)
test "raise when :repo and :replica not set in option and configuration" do
assert_raise ArgumentError, ~r|EctoShorts replica and repo not configured!|, fn ->
Actions.all(Comment, %{}, repo: nil, replica: nil)
end
end

Expand Down
4 changes: 4 additions & 0 deletions test/ecto_shorts/config_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
defmodule EctoShorts.ConfigTest do
use ExUnit.Case, async: true
doctest EctoShorts.Config
end

0 comments on commit 9beaa71

Please sign in to comment.