Module: ROM::Relation::ClassInterface

Extended by:
Notifications::Listener
Included in:
ROM::Relation
Defined in:
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, :schema
].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 'lib/rom/relation/class_interface.rb', line 135

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

  @relation_name
end

#schema_procObject (readonly)

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.


131
132
133
# File 'lib/rom/relation/class_interface.rb', line 131

def schema_proc
  @schema_proc
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 '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

#curriedObject

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.


275
276
277
# File 'lib/rom/relation/class_interface.rb', line 275

def curried
  Curried
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 'lib/rom/relation/class_interface.rb', line 64

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

#default_name(inflector = Inflector) ⇒ Name

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.

Return default relation name used in schemas

Returns:


297
298
299
# File 'lib/rom/relation/class_interface.rb', line 297

def default_name(inflector = Inflector)
  Name[inflector.underscore(name).tr("/", "_").to_sym]
end

#default_schema(klass = self, inflector: Inflector) ⇒ Object

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.


302
303
304
305
306
307
308
309
# File 'lib/rom/relation/class_interface.rb', line 302

def default_schema(klass = self, inflector: Inflector)
  klass.schema ||
    if klass.schema_proc
      klass.set_schema!(klass.schema_proc.(inflector: inflector))
    else
      klass.schema_class.define(klass.default_name)
    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 '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

#mapper_registry(opts = EMPTY_HASH) ⇒ MapperRegistry

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.

Build default mapper registry

Returns:


261
262
263
264
265
266
267
268
269
270
271
272
# File 'lib/rom/relation/class_interface.rb', line 261

def mapper_registry(opts = EMPTY_HASH)
  adapter_ns = ROM.adapters[adapter]

  compiler =
    if adapter_ns&.const_defined?(:MapperCompiler)
      adapter_ns.const_get(:MapperCompiler)
    else
      MapperCompiler
    end

  MapperRegistry.new({}, compiler: compiler.new(**opts), **opts)
end

#nameObject

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.


312
313
314
# File 'lib/rom/relation/class_interface.rb', line 312

def name
  super || superclass.name
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 '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 |**kwargs, &inner_block|
      schema_dsl.new(
        relation_name,
        schema_class: schema_class,
        attr_class: schema_attr_class,
        inferrer: schema_inferrer.with(enabled: infer),
        &block
      ).call(**kwargs, &inner_block)
    end
  end
end

#schemasObject

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.


288
289
290
# File 'lib/rom/relation/class_interface.rb', line 288

def schemas
  @schemas ||= {}
end

#set_schema!(schema) ⇒ Schema

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.

Assign a schema to a relation class

Parameters:

Returns:


126
127
128
# File 'lib/rom/relation/class_interface.rb', line 126

def set_schema!(schema)
  @schema = schema
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 '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 '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

#view_methodsObject

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.


280
281
282
283
284
285
# File 'lib/rom/relation/class_interface.rb', line 280

def view_methods
  ancestor_methods = ancestors.reject { |klass| klass == self }
    .map(&:instance_methods).flatten(1)

  instance_methods - ancestor_methods + auto_curried_methods.to_a
end