| Class | SearchApi::TextCriterion |
| In: |
lib/search_api/text_criterion.rb
|
| Parent: | Object |
Utility class that implements fulltext search.
Includes some Google-like features.
| mandatory_keywords | [RW] | |
| meta_keywords | [RW] | |
| negative_keywords | [RW] | |
| optional_keywords | [RW] |
# File lib/search_api/text_criterion.rb, line 21
21: def initialize(inSearchString='', inOptions= {})
22: # inOptions may contain :
23: # :exclude => string, Regexp, or list of Strings and Regexp to exclude (strings are case insensitive)
24:
25: @options = inOptions
26: @options[:exclude] = [@options[:exclude]] unless @options[:exclude].nil? || (@options[:exclude].is_a?(Enumerable) && !@options[:exclude].is_a?(String))
27: @options[:parse_meta?] = true if @options[:parse_meta?].nil?
28:
29: @meta_keywords = {}
30: @mandatory_keywords = []
31: @negative_keywords = []
32: @optional_keywords = []
33:
34: unless inSearchString.blank?
35:
36: currentMeta = nil
37:
38: splitter = /
39: (
40: [-+]?\b[^ ":]+\b:?
41: )
42: |
43: (
44: [-+]?"[^"]*"
45: )
46: /x
47:
48: inSearchString.gsub(/\s+/, ' ').scan(splitter).each { |keyword|
49: keyword=(keyword[0]||keyword[1]).gsub(/"/, '')
50:
51: if currentMeta
52: @meta_keywords[currentMeta] ||= []
53: @meta_keywords[currentMeta] << keyword
54: currentMeta = nil
55: else
56: case keyword
57: when /^-/
58: @negative_keywords << keyword[1..-1] unless exclude_keyword?(keyword[1..-1])
59: when /^\+/
60: @mandatory_keywords << keyword[1..-1] unless exclude_keyword?(keyword[1..-1])
61: when /:$/
62: if @options[:parse_meta?]
63: currentMeta = keyword[0..-2]
64: else
65: @optional_keywords << keyword unless exclude_keyword?(keyword)
66: end
67: else
68: @optional_keywords << keyword unless exclude_keyword?(keyword)
69: end
70: end
71: }
72:
73: # if everything is excluded, look for the whole search string
74: @optional_keywords << inSearchString if @meta_keywords.empty? && @mandatory_keywords.empty? && @negative_keywords.empty? && @optional_keywords.empty?
75: end
76: end
# File lib/search_api/text_criterion.rb, line 99
99: def condition(inFields)
100: conditions = SqlFragment.new
101:
102: conditions << (@mandatory_keywords.inject(SqlFragment.new) { |cv, value|
103: value = "%#{value}%"
104: cv.and(inFields.inject(SqlFragment.new) { |cf, field|
105: cf.or(["#{field} like ?", value])
106: })
107: })
108:
109: conditions << (@negative_keywords.inject(SqlFragment.new) { |cv, value|
110: value = "%#{value}%"
111: cv.and(inFields.inject(SqlFragment.new) { |cf, field|
112: cf.or(["#{field} is not null AND #{field} like ?", value])
113: })
114: }.not)
115:
116: conditions << (@optional_keywords.inject(SqlFragment.new) { |cv, value|
117: value = "%#{value}%"
118: cv.or(inFields.inject(SqlFragment.new) { |cf, field|
119: cf.or(["#{field} like ?", value])
120: })
121: })
122:
123: conditions
124: end
# File lib/search_api/text_criterion.rb, line 95
95: def positive_keywords
96: @mandatory_keywords + @optional_keywords
97: end
# File lib/search_api/text_criterion.rb, line 78
78: def to_s
79: chunks = []
80: chunks += @mandatory_keywords.map { |x| (x =~ / /) ? "+\"#{x}\"" : "+#{x}" } unless @mandatory_keywords.blank?
81: chunks += @negative_keywords.map { |x| (x =~ / /) ? "-\"#{x}\"" : "-#{x}" } unless @negative_keywords.blank?
82: chunks += @optional_keywords.map { |x| (x =~ / /) ? "\"#{x}\"" : x.to_s } unless @optional_keywords.blank?
83: chunks += @meta_keywords.inject([]) { |s, key_value|
84: key, value = key_value
85: if value.is_a?(Array)
86: s += value.map { |x| (x =~ / /) ? "#{key}:\"#{x}\"" : "#{key}:#{x}" }
87: else
88: s << ((value =~ / /) ? "#{key}:\"#{value}\"" : "#{key}:#{value}")
89: end
90: s
91: } if @meta_keywords
92: chunks.join(' ')
93: end