cflipse / rom-repository

Repository abstraction on top of ROM

Home Page:http://rom-rb.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ROM::Repository

Gem Version Build Status Dependency Status Code Climate Test Coverage Inline docs

Repository for ROM with auto-mapping and relation extensions.

Conventions & Definitions

Repositories in ROM are simple objects that allow you to compose rich relation views specific to your application layer. Every repository can access multiple relations that you define and use them to build more complex views.

Repository relations are enhanced with a couple of extra features on top of ROM relations:

  • Every relation has an auto-generated mapper which turns raw data into simple, immutable structs
  • Relation#combine can accept a simple hash defining what other relations should be joined
  • Relation#combine_parents automatically joins parents using eager-loading
  • Relation#combine_children automatically joins children using eager-loading
  • Relation#wrap_parent automatically joins a parent using inner join

Relation Views

A relation view is a result of some query which returns results specific to your application. You can define them using a simple DSL where you specify a name, what attributes resulting tuples will have and of course the query itself:

class Users < ROM::Relation[:sql]
  view(:by_id, [:id, :name]) do |id|
    where(id: id).select(:id, :name)
  end

  view(:listing, [:id, :name, :email, :created_at]) do
    select(:id, :name, :email, :created_at).order(:name)
  end
end

This way we can explicitly define all our relation view that our application will depend on. It encapsulates access to application-specific data structures and allows you to easily test individual views in isolation.

Thanks to explicit definition of attributes mappers are derived automatically.

Auto-combine & Auto-wrap

Repository relations support automatic combine and wrap by using a simple convention that every relation defines for_combine(keys, other) and for_wrap(keys, other).

You can override the default behavior for combine by defining for_other_rel_name in example, if you combine tasks with users you can define Tasks#for_users and this will be used instead of the generic for_combine.

Mapping & Structs

Currently repositories map to ROM::Struct by default. In the near future this will be configurable.

ROM structs are simple and don't expose an interface to mutate them; however, they are not being frozen (at least not yet, we could add a feature for freezing them).

They are coercible to Hash so it should be possible to map them further in some special cases using ROM mappers.

class Users < ROM::Relation[:sql]
  view(:by_id, [:id, :name]) do |id|
    where(id: id).select(:id, :name)
  end

  view(:listing, [:id, :name, :email, :created_at]) do
    select(:id, :name, :email, :created_at).order(:name)
  end
end

class UserRepository < ROM::Repository::Base
  relations :users, :tasks

  def by_id(id)
    users.by_id(id)
  end

  def with_tasks(id)
    users.by_id(id).combine_children(many: tasks)
  end
end

rom = ROM.finalize.env

user_repo = UserRepository.new(rom)

puts user_repo.by_id(1).to_a.inspect
# [#<ROM::Struct[User] id=1 name="Jane">]

puts user_repo.with_tasks.to_a.inspect
# [#<ROM::Struct[User] id=1 name="Jane" tasks=[#<ROM::Struct[Task] id=2 user_id=1 title="Jane Task">]>, #<ROM::Struct[User] id=2 name="Joe" tasks=[#<ROM::Struct[Task] id=1 user_id=2 title="Joe Task">]>]

Decorating Structs

Nothing is stopping you from decorating your structs using registered mappers and custom decorator models:

class UserStructMapper < ROM::Mapper
  register_as :ui_presenter
  model UI::UserPresenter
end

user_repo.by_id(1).as(:ui_presenter)

Limitations

This is an early alpha and works only with rom-sql for now. There are a couple improvements waiting to be done in the rom core and then rom-repository will receive more love and features.

Stay tuned.

License

See LICENSE file.

About

Repository abstraction on top of ROM

http://rom-rb.org

License:MIT License


Languages

Language:Ruby 100.0%