lib/rom/relation.rb in rom-0.6.0.beta3 vs lib/rom/relation.rb in rom-0.6.0.rc1
- old
+ new
@@ -1,7 +1,7 @@
-require 'set'
-require 'rom/relation/registry_reader'
+require 'rom/relation/class_interface'
+
require 'rom/relation/lazy'
require 'rom/relation/curried'
module ROM
# Base relation class
@@ -17,174 +17,54 @@
# for those sub-classes but there is always a vanilla relation instance stored
# in the schema registry.
#
# @api public
class Relation
- extend ClassMacros
+ extend ClassInterface
include Options
include Equalizer.new(:dataset)
- defines :repository, :dataset, :register_as, :exposed_relations
-
- repository :default
-
- attr_reader :name, :dataset, :exposed_relations
-
- # Register adapter relation subclasses during setup phase
+ # Dataset used by the relation
#
- # In adition those subclasses are extended with an interface for accessing
- # relation registry and to define `register_as` setting
+ # This object is provided by the repository during the setup
#
- # @api private
- def self.inherited(klass)
- super
-
- return if self == ROM::Relation
-
- klass.class_eval do
- include ROM::Relation::RegistryReader
-
- dataset(default_name)
- exposed_relations Set.new
-
- def self.register_as(value = Undefined)
- if value == Undefined
- @register_as || dataset
- else
- super
- end
- end
-
- def self.method_added(name)
- super
- exposed_relations << name if public_instance_methods.include?(name)
- end
- end
-
- ROM.register_relation(klass)
- end
-
- # Return adapter-specific relation subclass
+ # @return [Object]
#
- # @example
- # ROM::Relation[:memory]
- # # => ROM::Memory::Relation
- #
- # @return [Class]
- #
- # @api public
- def self.[](type)
- ROM.adapters.fetch(type).const_get(:Relation)
- end
-
- # 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
- def self.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
-
- # Return default relation name used for `register_as` setting
- #
- # @return [Symbol]
- #
# @api private
- def self.default_name
- return unless name
- Inflector.underscore(name).gsub('/', '_').to_sym
- end
+ attr_reader :dataset
- # Build relation registry of specified descendant classes
- #
- # This is used by the setup
- #
- # @param [Hash] repositories
- # @param [Array] descendants a list of relation descendants
- #
- # @return [Hash]
- #
# @api private
- def self.registry(repositories, descendants)
- registry = {}
-
- descendants.each do |klass|
- # TODO: raise a meaningful error here and add spec covering the case
- # where klass' repository points to non-existant repo
- repository = repositories.fetch(klass.repository)
- dataset = repository.dataset(klass.dataset)
-
- relation = klass.new(dataset, __registry__: registry)
-
- name = klass.register_as
-
- if registry.key?(name)
- raise RelationAlreadyDefinedError,
- "Relation with `register_as #{name.inspect}` registered more " \
- "than once"
- end
-
- registry[name] = relation
- end
-
- registry.each_value do |relation|
- relation.class.finalize(registry, relation)
- end
-
- registry
- end
-
- # @api private
def initialize(dataset, options = {})
@dataset = dataset
- @name = self.class.dataset
- @exposed_relations = self.class.exposed_relations
super
end
- # Hook to finalize a relation after its instance was created
- #
- # @api private
- def self.finalize(_env, _relation)
- # noop
- end
-
# Yield dataset tuples
#
# @yield [Hash]
#
# @api private
def each(&block)
return to_enum unless block
dataset.each { |tuple| yield(tuple) }
end
- # Materialize relation into an array
+ # Materialize a relation into an array
#
# @return [Array<Hash>]
#
# @api public
def to_a
to_enum.to_a
end
- # @api private
- def repository
- self.class.repository
- end
-
+ # Turn relation into a lazy-loadable and composable relation
+ #
+ # @see Lazy
+ #
+ # @return [Lazy]
+ #
# @api public
def to_lazy(*args)
Lazy.new(self, *args)
end