Version 4.0

Repositories » Reading Simple Objects

It's best to create multiple Repository classes that each focus on a segment of the data. One rough guideline is to make a repository for each concept within your app:

# Assuming a database with tables 'users' and 'projects'
rom = ROM.container(:sql, 'sqlite::memory') do |config|
  config.relation(:users) do
    schema(infer: true)
    auto_struct true
  end
  config.relation(:projects) do
    schema(infer: true)
    auto_struct true
  end
end

# Perhaps one Repo to handle users
class UserRepo < ROM::Repository[:users]
end

# Another repository could handle the projects
class ProjectRepo < ROM::Repository[:projects]
end

user_repo = UserRepo.new(rom)
project_repo = ProjectRepo.new(rom)

Repository Interface

While defining a repository, you will also define its interface for domain-specific queries. These are called selector methods.

They use the querying methods provided by the relations to accomplish their task. For example, the rom-sql adapter provides methods like Relation#where.

class UserRepo < ROM::Repository[:users]
  # find all users with the given attributes
  def query(conditions)
    users.where(conditions)
  end

  # collect a list of all user ids
  def ids
    users.pluck(:id)
  end
end

Read your adapter's documentation to see the full listing of its Relation methods.

Full Example

This short example demonstrates using selector methods, #one, and #to_a.

require 'rom-repository'

rom = ROM.container(:sql, 'sqlite::memory') do |config|
  config.default.connection.create_table(:users) do
    primary_key :id
    column :name, String, null: false
    column :email, String, null: false
  end

  config.relation(:users) do
    schema(infer: true)
  end
end

class UserRepo < ROM::Repository[:users]
  def query(conditions)
    users.where(conditions).to_a
  end

  def by_id(id)
    users.by_pk(id).one!
  end

  # ... etc
end

user_repo = UserRepo.new(rom)

Notice that users.where and users.by_pk are SQL-specific interfaces that should not leak into your application domain layer, that's why we hide them behind our own repository interface.

And then in our app we can use the selector methods:

# assuming that there is already data present

user_repo.query(first_name: 'Malcolm', last_name: 'Reynolds')
#=> [ROM::Struct[User] , ROM::Struct[User], ...]

user_repo.by_id(1)
#=> {id: 1, first_name: 'Malcolm', last_name: 'Reynolds'}

Next

Now we can read simple structs. Next, learn how to read complex, aggregate data.