lib/axiom/adapter/mongo/gateway.rb
# encoding: utf-8
module Axiom
module Adapter
class Mongo
# A relation backed by mongo adapter
class Gateway < ::Axiom::Relation
DECORATED_CLASS = superclass
# Poor man forwardable for now.
(DECORATED_CLASS.public_instance_methods(false).map(&:to_s) - %w[ materialize one ]).each do |method|
class_eval(<<-RUBY, __FILE__,__LINE__+1)
def #{method}(*args, &block)
relation.public_send(:#{method}, *args,&block)
end
RUBY
end
# Return inspected stub to fight against inspect related errors in spec printouts
#
# @return [String]
#
# @api private
#
# TODO: Remove this.
#
def inspect; 'GATEWAY'; end
MAP = [
Relation::Operation::Order,
Relation::Operation::Offset,
Relation::Operation::Limit,
Algebra::Restriction
].each_with_object({}) do |operation, map|
operation::Methods.public_instance_methods(false).each do |method|
method = method.to_sym
map[method]=operation if method != :last
end
end
MAP.each_key do |method|
class_eval(<<-RUBY, __FILE__,__LINE__+1)
def #{method}(*args, &block)
unless supported?(:#{method})
return super
end
response = @relation.send(:#{method}, *args,&block)
self.class.new(adapter, response, @operations + [response.class])
end
RUBY
end
# The adapter the gateway will use to fetch results
#
# @return [Adapter::Mongo]
#
# @api private
#
attr_reader :adapter
protected :adapter
# The relation the gateway will use to generate Query
#
# @return [Relation]
#
# @api private
#
attr_reader :relation
protected :relation
# Initialize a Gateway
#
# @param [Adapter::DataObjects] adapter
#
# @param [Relation] relation
#
# @return [undefined]
#
# @api private
#
def initialize(adapter, relation, operations=Set.new)
@adapter = adapter
@relation = relation
@operations = operations
end
# Iterate over each row in the results
#
# @example
# gateway = Gateway.new(adapter, relation)
# gateway.each { |tuple| ... }
#
# @yield [tuple]
#
# @yieldparam [Tuple] tuple
# each tuple in the results
#
# @return [self]
#
# @api public
#
def each
return to_enum unless block_given?
tuples.each { |tuple| yield tuple }
self
end
private
# Return if method is supported in this gateway
#
# @param [Symbol] method
#
# @return [true|false]
#
# @api private
#
def supported?(method)
!@operations.include?(MAP.fetch(method))
end
# Return a list of tuples to iterate over
#
# @return [#each]
#
# @api private
#
def tuples
relation = self.relation
return relation if materialized?
DECORATED_CLASS.new(header, adapter.read(relation))
end
end
end # class Gateway
end # class Relation
end # module Axiom