Class: ROM::Repository

Inherits:
Object
  • Object
show all
Extended by:
ClassInterface
Defined in:
lib/rom/repository.rb,
lib/rom/repository/root.rb,
lib/rom/repository/version.rb,
lib/rom/repository/command_proxy.rb,
lib/rom/repository/header_builder.rb,
lib/rom/repository/mapper_builder.rb,
lib/rom/repository/relation_proxy.rb,
lib/rom/repository/struct_builder.rb,
lib/rom/repository/class_interface.rb,
lib/rom/repository/command_compiler.rb,
lib/rom/repository/relation_proxy/wrap.rb,
lib/rom/repository/relation_proxy/combine.rb

Overview

Abstract repository class to inherit from

A repository provides access to composable relations, commands and changesets. Its job is to provide application-specific data that is already materialized, so that relations don’t leak into your application layer.

Typically, you’re going to work with Repository::Root that is configured to use a single relation as its root, and compose aggregates and use changesets and commands against the root relation.

Examples:

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

  conf.default.create_table(:tasks) do
    primary_key :id
    column :user_id, Integer
    column :title, String
  end

  conf.relation(:users) do
    associations do
      has_many :tasks
    end
  end
end

class UserRepo < ROM::Repository[:users]
  relations :tasks

  def users_with_tasks
    aggregate(:tasks).to_a
  end
end

user_repo = UserRepo.new(rom)
user_repo.users_with_tasks

See Also:

Direct Known Subclasses

Root

Defined Under Namespace

Modules: ClassInterface Classes: CommandCompiler, CommandProxy, HeaderBuilder, MapperBuilder, RelationProxy, Root, StructBuilder

Constant Summary collapse

CHANGESET_TYPES =

Mapping for supported changeset classes used in #changeset(type => relation) method

{
  create: Changeset::Create,
  update: Changeset::Update,
  delete: Changeset::Delete
}.freeze
VERSION =
'1.0.1'.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(container) ⇒ Repository

Initializes a new repo by establishing configured relation proxies from the passed container

Parameters:

  • container (ROM::Container)

    The rom container with relations and optional commands



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/rom/repository.rb', line 89

def initialize(container)
  @container = container
  @mappers = MapperBuilder.new
  @relations = RelationRegistry.new do |registry, relations|
    self.class.relations.each do |name|
      relation = container.relation(name)

      proxy = RelationProxy.new(
        relation, name: name, mappers: mappers, registry: registry
      )

      instance_variable_set("@#{name}", proxy)

      relations[name] = proxy
    end
  end
  @command_compiler = method(:command)
end

Instance Attribute Details

#command_compilerObject (readonly)



81
82
83
# File 'lib/rom/repository.rb', line 81

def command_compiler
  @command_compiler
end

#commmand_compilerMethod (readonly)

Returns Function for compiling commands bound to a repo instance.

Returns:

  • (Method)

    Function for compiling commands bound to a repo instance



81
# File 'lib/rom/repository.rb', line 81

attr_reader :command_compiler

#containerObject (readonly)



69
70
71
# File 'lib/rom/repository.rb', line 69

def container
  @container
end

#mappersObject (readonly)



77
78
79
# File 'lib/rom/repository.rb', line 77

def mappers
  @mappers
end

#relationsObject (readonly)



73
74
75
# File 'lib/rom/repository.rb', line 73

def relations
  @relations
end

Class Method Details

.[](name) ⇒ Class Originally defined in module ClassInterface

Create a root-repository class and set its root relation

Examples:

# where :users is the relation name in your rom container
class UserRepo < ROM::Repository[:users]
end

Parameters:

  • name (Symbol)

    The relation ‘register_as` value

Returns:

  • (Class)

    descendant of ROM::Repository::Root

.commands(*names, mapper: nil, use: nil, **opts) ⇒ Array<Symbol> Originally defined in module ClassInterface

Defines command methods on a root repository

Examples:

class UserRepo < ROM::Repository[:users]
  commands :create, update: :by_pk, delete: :by_pk
end

# with custom command plugin
class UserRepo < ROM::Repository[:users]
  commands :create, plugin: :my_command_plugin
end

# with custom mapper
class UserRepo < ROM::Repository[:users]
  commands :create, mapper: :my_custom_mapper
end

Parameters:

  • names (Array<Symbol>)

    A list of command names

  • :mapper (Hash)

    a customizable set of options

  • :use (Hash)

    a customizable set of options

Returns:

  • (Array<Symbol>)

    A list of defined command names

.inherited(klass) ⇒ Object Originally defined in module ClassInterface

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Inherits configured relations and commands

.relations(*names) ⇒ Array<Symbol> Originally defined in module ClassInterface

Define which relations your repository is going to use

Examples:

class MyRepo < ROM::Repository
  relations :users, :tasks
end

my_repo = MyRepo.new(rom)

my_repo.users
my_repo.tasks

Returns:

  • (Array<Symbol>)

Instance Method Details

#changeset(name, attributes) ⇒ Changeset::Create #changeset(name, primary_key, attributes) ⇒ Changeset::Update #changeset(changeset_class) ⇒ Changeset #changeset(opts) ⇒ Changeset

Return a changeset for a relation

Overloads:

  • #changeset(name, attributes) ⇒ Changeset::Create

    Return a create changeset for a given relation identifier

    Examples:

    repo.changeset(:users, name: "Jane")

    Parameters:

    • name (Symbol)

      The relation container identifier

    • attributes (Hash)

    Returns:

  • #changeset(name, primary_key, attributes) ⇒ Changeset::Update

    Return an update changeset for a given relation identifier

    Examples:

    repo.changeset(:users, 1, name: "Jane Doe")

    Parameters:

    • name (Symbol)

      The relation container identifier

    • restriction_arg (Object)

      The argument passed to restricted view

    Returns:

  • #changeset(changeset_class) ⇒ Changeset

    Return a changeset object using provided class

    Examples:

    repo.changeset(NewUserChangeset).data(attributes)

    Parameters:

    • changeset_class (Class)

      Custom changeset class

    Returns:

  • #changeset(opts) ⇒ Changeset

    Return a changeset object using provided changeset type and relation

    Examples:

    repo.changeset(delete: repo.users.where { id > 10 })

    Parameters:

    • Hash<Symbol=>Relation] (Hash<Symbol=>Relation] opts Command type => Relation config)

      opts Command type => Relation config

    Returns:



202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
# File 'lib/rom/repository.rb', line 202

def changeset(*args)
  opts = { command_compiler: command_compiler }

  if args.size == 2
    name, data = args
  elsif args.size == 3
    name, pk, data = args
  elsif args.size == 1
    if args[0].is_a?(Class)
      klass = args[0]

      if klass < Changeset
        return klass.new(relations[klass.relation], opts)
      else
        raise ArgumentError, "+#{klass.name}+ is not a Changeset subclass"
      end
    else
      type, relation = args[0].to_a[0]
    end
  else
    raise ArgumentError, 'Repository#changeset accepts 1-3 arguments'
  end

  if type
    klass = CHANGESET_TYPES.fetch(type) {
      raise ArgumentError, "+#{type.inspect}+ is not a valid changeset type. Must be one of: #{CHANGESET_TYPES.keys.inspect}"
    }

    klass.new(relation, opts)
  else
    relation = relations[name]

    if pk
      Changeset::Update.new(relation.by_pk(pk), opts.update(__data__: data))
    else
      Changeset::Create.new(relation, opts.update(__data__: data))
    end
  end
end

#command(type, relation) ⇒ ROM::Command #command(options) ⇒ ROM::Command #command(rel_name) ⇒ CommandRegistry #command(rel_name, &block) ⇒ ROM::Command

Return a command for a relation

Overloads:

  • #command(type, relation) ⇒ ROM::Command

    Returns a command for a relation

    Examples:

    repo.command(:create, repo.users)

    Parameters:

    • type (Symbol)

      The command type (:create, :update or :delete)

    • relation (RelationProxy)

      The relation for which command should be built for

  • #command(options) ⇒ ROM::Command

    Builds a command for a given relation identifier

    Examples:

    repo.command(create: :users)

    Parameters:

    • options (Hash<Symbol=>Symbol>)

      A type => rel_name map

  • #command(rel_name) ⇒ CommandRegistry

    Returns command registry for a given relation identifier

    Examples:

    repo.command(:users)[:my_custom_command]

    Parameters:

    • rel_name (Symbol)

      The relation identifier from the container

    Returns:

    • (CommandRegistry)
  • #command(rel_name, &block) ⇒ ROM::Command

    Yields a command graph composer for a given relation identifier

    Parameters:

    • rel_name (Symbol)

      The relation identifier from the container

Returns:

  • (ROM::Command)


145
146
147
148
149
150
151
152
153
154
155
# File 'lib/rom/repository.rb', line 145

def command(*args, **opts, &block)
  all_args = args + opts.to_a.flatten

  if all_args.size > 1
    commands.fetch_or_store(all_args.hash) do
      compile_command(*args, **opts)
    end
  else
    container.command(*args, &block)
  end
end

#inspectString

Return a string representation of a repository object

Returns:

  • (String)


271
272
273
# File 'lib/rom/repository.rb', line 271

def inspect
  %(#<#{self.class} relations=[#{self.class.relations.map(&:inspect).join(' ')}]>)
end

#transaction(&block) ⇒ Object

Open a database transaction

Examples:

commited transaction

user = transaction do |t|
  create(changeset(name: 'Jane'))
end

user
# => #<ROM::Struct[User] id=1 name="Jane">

with a rollback

user = transaction do |t|
  changeset(name: 'Jane').commit
  t.rollback!
end

user
# nil


262
263
264
# File 'lib/rom/repository.rb', line 262

def transaction(&block)
  container.gateways[:default].transaction(&block)
end