I'm currently re-implementing part of a Laravel(PHP) codebase in Elixir 
where I had used the repository pattern 
<http://blog.gauffin.org/2013/01/repository-pattern-done-right/> in only 
some of the data models. In the Elixir implementation, I'd like to use it 
across all the data models mainly because

1. I can swap out the implementation within tests
2. I can swap out the implementation to e.g. go through a cache layer for 
reads
3. I want to able to use different ecto repos for e.g. read and write and 
having abstract repositories would allow this to be done from a central 
place

I worked on an initial implementation this weekend that works like this.

For each data entity, implement a "behaviour" with callbacks for that 
particular entity e.g. a UserRepository where you need to query for a list 
of active users would look like this

defmodule UserRepository do
  use Repository.Base, # parses opts and config and sets @repository to 
configured repository module
    otp_app: :my_app
    repository: MyApp.Repositories.EctoUserRepository # this points to the 
concrete implementation and should be set within the config
  
  @callback save(Ecto.Changeset.t) :: {:ok, User.t} | {:error, 
Ecto.Changeset.t}
  
  @callback get_active(non_neg_integer, non_neg_integer) :: [User.t]
end

The Ecto backed repository implementation would look like this

defmodule EctoUserRepository do
  use Repository.Ecto.Base, # parses the opts and config, sets @repo and 
@read_repo and implements a save function thats common to all Ecto repos
    repo: MyApp.Repo,
    read_repo: MyApp.Repo # could set a different repo for reads
  
  @behaviour UserRepository

  import Ecto.Query, only: [from: 2]

  def get_active(offset, limit) do
    (from u in User,
      where: u.active == true,
      offset: ^offset,
      limit: ^limit)
    |> @read_repo.all()
  end
end

Please share any thoughts on this.

Now this is where I need some help, I want to able to use the repository as

UserRepository.get_active(0, 20)

what I've done at the moment is redefine each function within the 
UserRepository and delegate to whatever repository is configured

defmodule UserRepository do
  ...
  
  @callback save(Ecto.Changeset.t) :: {:ok, User.t} | {:error, 
Ecto.Changeset.t}
  
  @callback get_active(non_neg_integer, non_neg_integer) :: [User.t]

    def save(changeset) do
    @repository.save(changeset)
  end

  def get_active(offset, limit) do
    @repository.get_active(offset, limit)
  end
end


I find that this is quite repetitive and forces the same for all repository 
implementations and functions.


-- 
You received this message because you are subscribed to the Google Groups 
"elixir-lang-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/elixir-lang-talk/47df7f07-0e79-40d7-b551-86839dba22b3%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to