module ROM::Relation::ClassInterface

Global class-level API for relation classes

@api public

Constants

DEFAULT_DATASET_PROC
INVALID_RELATIONS_NAMES

Attributes

schema_proc[R]

@api private

Public Instance Methods

[](adapter) click to toggle source

Return adapter-specific relation subclass

@example

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

@return [Class]

@api public

# 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
curried() click to toggle source

@api private

# File lib/rom/relation/class_interface.rb, line 275
def curried
  Curried
end
dataset(&block) click to toggle source

Set or get custom dataset block

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

@example

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

@api public

# 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() click to toggle source

Return default relation name used in schemas

@return [Name]

@api private

# File lib/rom/relation/class_interface.rb, line 297
def default_name
  Name[Inflector.underscore(name).tr('/', '_').to_sym]
end
default_schema(klass = self) click to toggle source

@api private

# File lib/rom/relation/class_interface.rb, line 302
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) click to toggle source

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

@example

class SomeAdapterRelation < ROM::Relation
  forward :super_query
end

@api public

# 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) click to toggle source

Build default mapper registry

@return [MapperRegistry]

@api private

# 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
name() click to toggle source

@api private

Calls superclass method
# File lib/rom/relation/class_interface.rb, line 312
def name
  super || superclass.name
end
relation_name() click to toggle source

@!attribute [r] relation_name

@return [Name] Qualified relation name
# File lib/rom/relation/class_interface.rb, line 135
def relation_name
  raise MissingSchemaError, self unless defined?(@relation_name)

  @relation_name
end
schema(dataset = nil, as: nil, infer: false, &block) click to toggle source

Specify canonical schema for a relation

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

@example

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

@return [Schema]

@param [Symbol] dataset An optional dataset name @param [Boolean] infer Whether to do an automatic schema inferring

@api public

# 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 |*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
schemas() click to toggle source

@api private

# File lib/rom/relation/class_interface.rb, line 288
def schemas
  @schemas ||= {}
end
set_schema!(schema) click to toggle source

Assign a schema to a relation class

@param [Schema] schema

@return [Schema]

@api private

# File lib/rom/relation/class_interface.rb, line 126
def set_schema!(schema)
  @schema = schema
end
use(plugin, **options) click to toggle source

Include a registered plugin in this relation class

@param [Symbol] plugin @param [Hash] options @option options [Symbol] :adapter (:default) first adapter to check for plugin

@api public

# 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(*args, &block) click to toggle source

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**

@overload view(name, schema, &block)

@example View with the canonical schema
  class Users < ROM::Relation[:sql]
    view(:listing, schema) do
      order(:name)
    end
  end

@example View with a projected schema
  class Users < ROM::Relation[:sql]
    view(:listing, schema.project(:id, :name)) do
      order(:name)
    end
  end

@overload view(name, &block)

@example View with the canonical schema and arguments
  class Users < ROM::Relation[:sql]
    view(:by_name) do |name|
      where(name: name)
    end
  end

@example 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

@example 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

@return [Symbol] view method name

@api public

# 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_methods() click to toggle source

@api private

# 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

Private Instance Methods

invalid_relation_name?(relation) click to toggle source
# File lib/rom/relation/class_interface.rb, line 318
def invalid_relation_name?(relation)
  INVALID_RELATIONS_NAMES.include?(relation.to_sym)
end