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
].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Notifications::Listener

subscribe

Instance Attribute Details

#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.



129
130
131
# File 'lib/rom/relation/class_interface.rb', line 129

def schema_proc
  @schema_proc
end

Instance Method Details

#[](adapter) ⇒ Class

Return adapter-specific relation subclass

Examples:

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

Returns:

  • (Class)


45
46
47
48
49
# File 'lib/rom/relation/class_interface.rb', line 45

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.



272
273
274
# File 'lib/rom/relation/class_interface.rb', line 272

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


62
63
64
65
66
67
68
# File 'lib/rom/relation/class_interface.rb', line 62

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

#default_nameName

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:



294
295
296
# File 'lib/rom/relation/class_interface.rb', line 294

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

#default_schema(klass = self) ⇒ 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.



299
300
301
302
303
304
305
306
# File 'lib/rom/relation/class_interface.rb', line 299

def default_schema(klass = self)
  klass.schema ||
    if klass.schema_proc
      klass.set_schema!(klass.schema_proc.call)
    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


232
233
234
235
236
237
238
239
240
# File 'lib/rom/relation/class_interface.rb', line 232

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:



258
259
260
261
262
263
264
265
266
267
268
269
# File 'lib/rom/relation/class_interface.rb', line 258

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

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

  MapperRegistry.new({}, { compiler: compiler.new(opts) }.merge(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.



309
310
311
# File 'lib/rom/relation/class_interface.rb', line 309

def name
  super || superclass.name
end

#relation_nameObject

!@attribute [r] relation_name

@return [Name] Qualified relation name

Raises:



133
134
135
136
# File 'lib/rom/relation/class_interface.rb', line 133

def relation_name
  raise MissingSchemaError.new(self) unless defined?(@relation_name)
  @relation_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:



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

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

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

    raise InvalidRelationName.new(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

#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.



285
286
287
# File 'lib/rom/relation/class_interface.rb', line 285

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:



124
125
126
# File 'lib/rom/relation/class_interface.rb', line 124

def set_schema!(schema)
  @schema = schema
end

#use(plugin, options = EMPTY_HASH) ⇒ Object

Include a registered plugin in this relation class

Parameters:

  • plugin (Symbol)
  • options (Hash) (defaults to: EMPTY_HASH)

Options Hash (options):

  • :adapter (Symbol) — default: :default

    first adapter to check for plugin



249
250
251
# File 'lib/rom/relation/class_interface.rb', line 249

def use(plugin, options = EMPTY_HASH)
  ROM.plugin_registry.relations.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



187
188
189
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
# File 'lib/rom/relation/class_interface.rb', line 187

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.



277
278
279
280
281
282
# File 'lib/rom/relation/class_interface.rb', line 277

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