lib/search_cop.rb
require "search_cop/version"
require "search_cop/helpers"
require "search_cop/search_scope"
require "search_cop/query_info"
require "search_cop/query_builder"
require "search_cop/grammar_parser"
require "search_cop/hash_parser"
require "search_cop/visitors"
module SearchCop
class Error < StandardError; end
class SpecificationError < Error; end
class UnknownAttribute < SpecificationError; end
class UnknownDefaultOperator < SpecificationError; end
class RuntimeError < Error; end
class UnknownColumn < RuntimeError; end
class NoSearchableAttributes < RuntimeError; end
class IncompatibleDatatype < RuntimeError; end
class ParseError < RuntimeError; end
module Parser
def self.parse(query, query_info, query_options = {})
if query.is_a?(Hash)
SearchCop::HashParser.new(query_info).parse(query, query_options)
else
SearchCop::GrammarParser.new(query_info).parse(query, query_options)
end
end
end
def self.included(base)
base.extend ClassMethods
base.class_attribute :search_scopes
base.search_scopes = {}
end
module ClassMethods
def search_scope(name, &block)
self.search_scopes = search_scopes.dup
search_scopes[name] = SearchScope.new(name, self)
search_scopes[name].instance_exec(&block)
send(:define_singleton_method, name) { |query, query_options = {}| search_cop(query, name, query_options) }
send(:define_singleton_method, "unsafe_#{name}") { |query, query_options = {}| unsafe_search_cop(query, name, query_options) }
end
def search_reflection(scope_name)
search_scopes[scope_name].reflection
end
def search_cop(query, scope_name, query_options)
unsafe_search_cop(query, scope_name, query_options)
rescue SearchCop::RuntimeError
respond_to?(:none) ? none : where("1 = 0")
end
def unsafe_search_cop(query, scope_name, query_options)
return respond_to?(:scoped) ? scoped : all if query.blank?
query_builder = QueryBuilder.new(self, query, search_scopes[scope_name], query_options)
scope = instance_exec(&search_scopes[scope_name].reflection.scope) if search_scopes[scope_name].reflection.scope
scope ||= eager_load(query_builder.associations) if query_builder.associations.any?
(scope || self).where(query_builder.sql)
end
end
end