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