Module: ROM::Relation::ClassInterface

Extended by:
Notifications::Listener
Included in:
ROM::Relation
Defined in:
core/lib/rom/relation/class_interface.rb

Overview

Global class-level API for relation classes

Constant Summary collapse

DEFAULT_DATASET_PROC =
-> * { self }.freeze
INVALID_RELATIONS_NAMES =
[
  :relations
].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#relation_nameObject (readonly)

Raises:



135
136
137
138
139
# File 'core/lib/rom/relation/class_interface.rb', line 135

def relation_name
  raise MissingSchemaError, self unless defined?(@relation_name)

  @relation_name
end

Class Method Details

.subscribe(event_id, query = EMPTY_HASH, &block) ⇒ Object Originally defined in module Notifications::Listener

Subscribe to events

Parameters:

  • event_id (String)

    The event key

  • query (Hash) (defaults to: EMPTY_HASH)

    An optional event filter

Returns:

  • (Object)

    self

Instance Method Details

#[](adapter) ⇒ Class

Return adapter-specific relation subclass

Examples:

ROM::Relation[:memory]
# => ROM::Memory::Relation

Returns:

  • (Class)


47
48
49
50
51
# File 'core/lib/rom/relation/class_interface.rb', line 47

def [](adapter)
  ROM.adapters.fetch(adapter).const_get(:Relation)
rescue KeyError
  raise AdapterNotPresentError.new(adapter, :relation)
end

#dataset(&block) ⇒ Object

Set or get custom dataset block

This block will be evaluated when a relation is instantiated and registered in a relation registry.

Examples:

class Users < ROM::Relation[:memory]
  dataset { sort_by(:id) }
end


64
65
66
67
68
69
70
# File 'core/lib/rom/relation/class_interface.rb', line 64

def dataset(&block)
  if defined?(@dataset)
    @dataset
  else
    @dataset = block || DEFAULT_DATASET_PROC
  end
end

#forward(*methods) ⇒ Object

Dynamically define a method that will forward to the dataset and wrap response in the relation itself

Examples:

class SomeAdapterRelation < ROM::Relation
  forward :super_query
end


235
236
237
238
239
240
241
242
243
# File 'core/lib/rom/relation/class_interface.rb', line 235

def forward(*methods)
  methods.each do |method|
    class_eval <<-RUBY, __FILE__, __LINE__ + 1
      def #{method}(*args, &block)
        new(dataset.__send__(:#{method}, *args, &block))
      end
    RUBY
  end
end

#schema(dataset = nil, as: nil, infer: false, &block) ⇒ Schema

Specify canonical schema for a relation

With a schema defined commands will set up a type-safe input handler automatically

Examples:

class Users < ROM::Relation[:sql]
  schema do
    attribute :id, Types::Serial
    attribute :name, Types::String
  end
end

# access schema from a finalized relation
users.schema

Parameters:

  • dataset (Symbol) (defaults to: nil)

    An optional dataset name

  • infer (Boolean) (defaults to: false)

    Whether to do an automatic schema inferring

Returns:



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'core/lib/rom/relation/class_interface.rb', line 94

def schema(dataset = nil, as: nil, infer: false, &block)
  if defined?(@schema) && !block && !infer
    @schema
  elsif block || infer
    raise MissingSchemaClassError, self unless schema_class

    ds_name = dataset || schema_opts.fetch(:dataset, default_name.dataset)
    relation = as || schema_opts.fetch(:relation, ds_name)

    raise InvalidRelationName, relation if invalid_relation_name?(relation)

    @relation_name = Name[relation, ds_name]

    @schema_proc = proc do |*args, &inner_block|
      schema_dsl.new(
        relation_name,
        schema_class: schema_class,
        attr_class: schema_attr_class,
        inferrer: schema_inferrer.with(enabled: infer),
        &block
      ).call(*args, &inner_block)
    end
  end
end

#use(plugin, **options) ⇒ Object

Include a registered plugin in this relation class

Parameters:

  • plugin (Symbol)
  • options (Hash)

Options Hash (**options):

  • :adapter (Symbol) — default: :default

    first adapter to check for plugin



252
253
254
# File 'core/lib/rom/relation/class_interface.rb', line 252

def use(plugin, **options)
  ROM.plugin_registry[:relation].fetch(plugin, adapter).apply_to(self, **options)
end

#view(name, schema, &block) ⇒ Symbol #view(name, &block) ⇒ Symbol

Define a relation view with a specific schema

This method should only be used in cases where a given adapter doesn't support automatic schema projection at run-time.

It's not needed in rom-sql

Overloads:

  • #view(name, schema, &block) ⇒ Symbol

    Examples:

    View with the canonical schema

    class Users < ROM::Relation[:sql]
      view(:listing, schema) do
        order(:name)
      end
    end

    View with a projected schema

    class Users < ROM::Relation[:sql]
      view(:listing, schema.project(:id, :name)) do
        order(:name)
      end
    end
  • #view(name, &block) ⇒ Symbol

    Examples:

    View with the canonical schema and arguments

    class Users < ROM::Relation[:sql]
      view(:by_name) do |name|
        where(name: name)
      end
    end

    View with projected schema and arguments

    class Users < ROM::Relation[:sql]
      view(:by_name) do
        schema { project(:id, :name) }
        relation { |name| where(name: name) }
      end
    end

    View with a schema extended with foreign attributes

    class Users < ROM::Relation[:sql]
      view(:index) do
        schema { append(relations[:tasks][:title]) }
        relation { |name| where(name: name) }
      end
    end

Returns:

  • (Symbol)

    view method name



190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
# File 'core/lib/rom/relation/class_interface.rb', line 190

def view(*args, &block)
  if args.size == 1 && block.arity > 0
    raise ArgumentError, 'schema attribute names must be provided as the second argument'
  end

  name, new_schema_fn, relation_block =
    if args.size == 1
      ViewDSL.new(*args, schema, &block).call
    else
      [*args, block]
    end

  schemas[name] =
    if args.size == 2
      -> _ { schema.project(*args[1]) }
    else
      new_schema_fn
    end

  if relation_block.arity > 0
    auto_curry_guard do
      define_method(name, &relation_block)

      auto_curry(name) do
        schemas[name].(self)
      end
    end
  else
    define_method(name) do
      schemas[name].(instance_exec(&relation_block))
    end
  end

  name
end