Class: SearchApi::TextCriterion

Inherits:
Object
  • Object
show all
Defined in:
lib/search_api/text_criterion.rb

Overview

Utility class that implements fulltext search.

Includes some Google-like features.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(inSearchString = '', inOptions = {}) ⇒ TextCriterion

Returns a new instance of TextCriterion.



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/search_api/text_criterion.rb', line 21

def initialize(inSearchString='', inOptions= {})
  # inOptions may contain :
  # :exclude => string, Regexp, or list of Strings and Regexp to exclude (strings are case insensitive)

  @options = inOptions
  @options[:exclude] = [@options[:exclude]] unless @options[:exclude].nil? || (@options[:exclude].is_a?(Enumerable) && !@options[:exclude].is_a?(String))
  @options[:parse_meta?] = true if @options[:parse_meta?].nil?

  @meta_keywords = {}
  @mandatory_keywords = []
  @negative_keywords = []
  @optional_keywords = []

  unless inSearchString.blank?

    currentMeta = nil
  
    splitter = /
          (
              [-+]?\b[^ ":]+\b:?
          )
          |
          (
              [-+]?"[^"]*"
          )
        /x

    inSearchString.gsub(/\s+/, ' ').scan(splitter).each { |keyword|
      keyword=(keyword[0]||keyword[1]).gsub(/"/, '')
  
      if currentMeta
        @meta_keywords[currentMeta] ||= []
        @meta_keywords[currentMeta] << keyword
        currentMeta = nil
      else
        case keyword
        when /^-/
          @negative_keywords << keyword[1..-1] unless exclude_keyword?(keyword[1..-1])
        when /^\+/
          @mandatory_keywords << keyword[1..-1] unless exclude_keyword?(keyword[1..-1])
        when /:$/
          if @options[:parse_meta?]
            currentMeta = keyword[0..-2]
          else
            @optional_keywords << keyword unless exclude_keyword?(keyword)
          end
        else
          @optional_keywords << keyword unless exclude_keyword?(keyword)
        end
      end
    }

    # if everything is excluded, look for the whole search string
    @optional_keywords << inSearchString if @meta_keywords.empty? && @mandatory_keywords.empty? && @negative_keywords.empty? && @optional_keywords.empty?
  end
end

Instance Attribute Details

#mandatory_keywordsObject

Returns the value of attribute mandatory_keywords.



17
18
19
# File 'lib/search_api/text_criterion.rb', line 17

def mandatory_keywords
  @mandatory_keywords
end

#meta_keywordsObject

Returns the value of attribute meta_keywords.



16
17
18
# File 'lib/search_api/text_criterion.rb', line 16

def meta_keywords
  @meta_keywords
end

#negative_keywordsObject

Returns the value of attribute negative_keywords.



18
19
20
# File 'lib/search_api/text_criterion.rb', line 18

def negative_keywords
  @negative_keywords
end

#optional_keywordsObject

Returns the value of attribute optional_keywords.



19
20
21
# File 'lib/search_api/text_criterion.rb', line 19

def optional_keywords
  @optional_keywords
end

Instance Method Details

#condition(inFields) ⇒ Object



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/search_api/text_criterion.rb', line 99

def condition(inFields)
  conditions = SqlFragment.new

  conditions << (@mandatory_keywords.inject(SqlFragment.new) { |cv, value|
    value = "%#{value}%"
    cv.and(inFields.inject(SqlFragment.new) { |cf, field|
      cf.or(["#{field} like ?", value])
    })
  })
  
  conditions << (@negative_keywords.inject(SqlFragment.new) { |cv, value|
    value = "%#{value}%"
    cv.and(inFields.inject(SqlFragment.new) { |cf, field|
      cf.or(["#{field} is not null AND #{field} like ?", value])
    })
  }.not)
  
  conditions << (@optional_keywords.inject(SqlFragment.new) { |cv, value|
    value = "%#{value}%"
    cv.or(inFields.inject(SqlFragment.new) { |cf, field|
      cf.or(["#{field} like ?", value])
    })
  })

  conditions
end

#positive_keywordsObject



95
96
97
# File 'lib/search_api/text_criterion.rb', line 95

def positive_keywords
  @mandatory_keywords + @optional_keywords
end

#to_sObject



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/search_api/text_criterion.rb', line 78

def to_s
  chunks = []
  chunks += @mandatory_keywords.map { |x| (x =~ / /) ? "+\"#{x}\"" : "+#{x}" } unless @mandatory_keywords.blank?
  chunks += @negative_keywords.map { |x| (x =~ / /) ? "-\"#{x}\"" : "-#{x}" } unless @negative_keywords.blank?
  chunks += @optional_keywords.map { |x| (x =~ / /) ? "\"#{x}\"" : x.to_s } unless @optional_keywords.blank?
  chunks += @meta_keywords.inject([]) { |s, key_value|
    key, value = key_value
    if value.is_a?(Array)
      s += value.map { |x| (x =~ / /) ? "#{key}:\"#{x}\"" : "#{key}:#{x}" }
    else
      s << ((value =~ / /) ? "#{key}:\"#{value}\"" : "#{key}:#{value}")
    end
    s
  } if @meta_keywords
  chunks.join(' ')
end