class ReactiveRecord::ScopeDescription

Keeps track of the details (client side) of a scope. The main point is to provide knowledge of what models the scope is joined with, and the client side filter proc

Attributes

name[R]

Public Class Methods

find(target_model, name) click to toggle source
# File lib/reactive_record/scope_description.rb, line 20
def self.find(target_model, name)
  name = name.gsub(/!$/,'')
  target_model.send "_#{name}_synchromesh_scope_description_"
rescue
  nil
end
new(model, name, opts) click to toggle source
# File lib/reactive_record/scope_description.rb, line 7
def initialize(model, name, opts)
  sself = self
  @filter_proc = filter_proc(opts)
  @name = name
  model.singleton_class.send(:define_method, "_#{@name}_synchromesh_scope_description_") do
    sself
  end
  @model = model
  build_joins opts[:joins]
end

Public Instance Methods

build_error(path, model, attribute) click to toggle source
# File lib/reactive_record/scope_description.rb, line 96
def build_error(path, model, attribute)
  "Could not find joins association '#{model.name}.#{attribute}' "\
  "for '#{path}' while processing scope #{@model.name}.#{@name}."
end
build_joins(joins_list) click to toggle source
# File lib/reactive_record/scope_description.rb, line 69
def build_joins(joins_list)
  if !@filter_proc || joins_list == []
    @joins = { all: [] }
  elsif joins_list.nil?
    @joins = { @model => [[]], all: [] }
  elsif joins_list == :all
    @joins = { all: [[]] }
  else
    joins_list = [joins_list] unless joins_list.is_a? Array
    map_joins_path joins_list
  end
end
collector?() click to toggle source
# File lib/reactive_record/scope_description.rb, line 31
def collector?
  @is_collector
end
crawl(item, method = nil, *vector) click to toggle source
# File lib/reactive_record/scope_description.rb, line 101
def crawl(item, method = nil, *vector)
  if !method && item.is_a?(Collection)
    item.all
  elsif !method
    item
  elsif item.respond_to? :collect
    item.collect { |record| crawl(record.send(method), *vector) }
  else
    crawl(item.send(method), *vector)
  end
end
filter?() click to toggle source
# File lib/reactive_record/scope_description.rb, line 27
def filter?
  @filter_proc.respond_to?(:call)
end
filter_proc(opts) click to toggle source

private methods

# File lib/reactive_record/scope_description.rb, line 61
def filter_proc(opts)
  return true unless opts.key?(:client) || opts.key?(:select)
  client_opt = opts[:client] || opts[:select]
  @is_collector = opts.key?(:select)
  return client_opt if !client_opt || client_opt.respond_to?(:call)
  raise 'Scope option :client or :select must be a proc, false, or nil'
end
filter_records(related_records, args) click to toggle source
# File lib/reactive_record/scope_description.rb, line 49
def filter_records(related_records, args)
  if collector?
    Set.new(related_records.to_a.instance_exec(*args, &@filter_proc))
  else
    Set.new(related_records.select { |r| r.instance_exec(*args, &@filter_proc) })
  end
rescue Exception => e
  raise "Client side scope #{@model}.#{@name} raised error: #{e.message}"
end
joins_with?(record) click to toggle source
# File lib/reactive_record/scope_description.rb, line 35
def joins_with?(record)
  @joins.detect do |klass, vector|
    vector.any? && (klass == :all || record.class == klass || record.class < klass)
  end
end
map_joins_path(paths) click to toggle source
# File lib/reactive_record/scope_description.rb, line 82
def map_joins_path(paths)
  @joins = Hash.new { |h, k| h[k] = Array.new }.merge(@model => [[]])
  paths.each do |path|
    vector = []
    path.split('.').inject(@model) do |model, attribute|
      association = model.reflect_on_association(attribute)
      raise build_error(path, model, attribute) unless association
      vector = [association.inverse_of, *vector]
      @joins[association.klass] << vector
      association.klass
    end
  end
end