module RailsConnector # This class provides an implementation for accessing the Verity based search server. # It should be customized by subclassing. class VeritySearchRequest attr_reader :query_string # Sanitizes the given +query_string+ and takes +options+ for accessing the SES. # # +query_string+ is a VQL search query. # +options+ is a hash and may be used to tweek the query. # # Options: # :host:: The SES server host, default: 'localhost' # :port:: The SES server port, default: 3011 # :offset:: The search offset, default: 0 # :limit:: The maximum number of hits in the SearchResult, default: 10 # :min_relevance:: The minimum relevance in percent, default: 50 # :max_docs:: The maximum number of documents to be searched, default: 'unlimited' # :parser:: The VQL query parser to be used, default: 'simple' # :sort_order:: The sort order of the hits, a list of key-value pairs, each consisting of the sortkey and the sort direction ("asc"=ascending, "desc"=descending), default: [["score", "desc"], ["name", "asc"]] # :collections:: The collections to be searched, default: ['cm-contents'] # :base_query:: The VQL base query, default: nil def initialize(query_string, options=nil) @query_string = self.class.sanitize(query_string) @options = Configuration.search_options.merge(options || {}) end # Accesses the SES and fetches search hits. # # Uses the #base_query and +options+ given in #new. def fetch_hits SES::VerityAccessor.new(vql_query_for(@query_string), {:base_query => base_query}.merge(@options)).search end # Removes unwanted characters from +text+. def self.sanitize(text) #:nodoc: text.strip.gsub(/[<>"'ยด`,()\[\]{}=!@\\]/, '') end def vql_query_for(query_string = '') words = query_string.split(/\s+/).map do |word| word unless %w(and or not).include?(word.downcase) end.compact.join(", ") "<#AND> (#{words})" end # Combines base query conditions to a single base query (see #base_query_conditions). # # A base query is used to reduce the number of documents before executing the actual query. # By default, all base query conditions must be met, they are combined using the +AND+ operator. def base_query "<#AND> (#{base_query_conditions.values.compact.join(', ')})" end # A hash of conditions, combined to a base query by #base_query. # Note that all values of the hash must be valid VQL syntax. # The keys have no meaning and exist only so single conditions can be replaced # in a subclass: # # class SearchRequest < VeritySearchRequest # def base_query_conditions # super.merge(:content => '("edited" <#IN> state)' # end # end def base_query_conditions conditions = {} conditions[:objTypes] = '<#ANY> ( ("generic" <#IN> objType), ("document" <#IN> objType), ("publication" <#IN> objType) )' conditions[:content] = '("released" <#IN> state)' conditions[:suppressExport] = '("0" <#IN> suppressExport)' conditions[:validFrom] = "(validFrom < #{Time.now.to_iso})" conditions[:validUntil] = %!<#OR> ( (validUntil = ""), (validUntil > #{Time.now.to_iso}) )! conditions end end end