require "search_cop_grammar/attributes" require "search_cop_grammar/nodes" module SearchCopGrammar class BaseNode < Treetop::Runtime::SyntaxNode attr_writer :query_info, :query_options def query_info (@query_info ||= nil) || parent.query_info end def query_options (@query_options ||= nil) || parent.query_options end def evaluate elements.collect(&:evaluate).inject(:and) end def elements super.reject { |element| element.instance_of?(Treetop::Runtime::SyntaxNode) } end def collection_for(key) raise(SearchCop::UnknownColumn, "Unknown column #{key}") if query_info.scope.reflection.attributes[key].nil? Attributes::Collection.new query_info, key end end class OperatorNode < Treetop::Runtime::SyntaxNode def evaluate text_value end end class ComplexExpression < BaseNode; end class ParenthesesExpression < BaseNode; end class ComparativeExpression < BaseNode def evaluate elements[0].collection.send elements[1].method_name, elements[2].text_value end end class IncludesOperator < OperatorNode def method_name :matches end end class EqualOperator < OperatorNode def method_name :eq end end class UnequalOperator < OperatorNode def method_name :not_eq end end class GreaterEqualOperator < OperatorNode def method_name :gteq end end class GreaterOperator < OperatorNode def method_name :gt end end class LessEqualOperator < OperatorNode def method_name :lteq end end class LessOperator < OperatorNode def method_name :lt end end class AnywhereExpression < BaseNode def evaluate queries = query_info.scope.reflection.default_attributes.keys.collect { |key| collection_for key }.select { |collection| collection.compatible? text_value }.collect { |collection| collection.matches text_value } raise SearchCop::NoSearchableAttributes if queries.empty? queries.flatten.inject(:or) end end class SingleQuotedAnywhereExpression < AnywhereExpression def text_value super.gsub(/^'|'$/, "") end end class DoubleQuotedAnywhereExpression < AnywhereExpression def text_value super.gsub(/^"|"$/, "") end end class AndExpression < BaseNode def evaluate [elements.first.evaluate, elements.last.evaluate].inject(:and) end end class AndOrExpression < BaseNode def evaluate default_operator = SearchCop::Helpers.sanitize_default_operator(query_options) [elements.first.evaluate, elements.last.evaluate].inject(default_operator) end end class OrExpression < BaseNode def evaluate [elements.first.evaluate, elements.last.evaluate].inject(:or) end end class NotExpression < BaseNode def evaluate elements.first.evaluate.not end end class Column < BaseNode def collection collection_for text_value end end class SingleQuotedValue < BaseNode def text_value super.gsub(/^'|'$/, "") end end class DoubleQuotedValue < BaseNode def text_value super.gsub(/^"|"$/, "") end end class Value < BaseNode; end end