Class: Supernova::SolrCriteria

Inherits:
Criteria
  • Object
show all
Defined in:
lib/supernova/solr_criteria.rb

Constant Summary

Constants inherited from Criteria

Criteria::DEFAULT_PER_PAGE, Criteria::FIRST_PAGE

Instance Attribute Summary

Attributes inherited from Criteria

#clazz, #filters, #results, #search_options

Instance Method Summary collapse

Methods inherited from Criteria

#attribute_mapping, #clone, #conditions, #current_page, #except, #facet_fields, #facet_queries, #for_classes, #group_by, #immutable!, #immutable?, immutable_by_default!, immutable_by_default?, #implement_in_subclass, #initialize, #limit, #merge, #merge_filters, #merge_filters_array, #merge_filters_or_search_options, #merge_search_options, method_missing, #method_missing, mutable_by_default!, #named_scope_class, #named_scope_defined?, #near, #normalize_coordinates, #options, #order, #paginate, #pagination_attribute_when_greater_zero, #per_page, #populate, #populated?, #read_first_attribute, #rows, #search, #select, select, #self_or_clone, #start, #to_a, #to_parameters, #valid_with_filter?, #where, #with, #within, #without

Constructor Details

This class inherits a constructor from Supernova::Criteria

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Supernova::Criteria

Instance Method Details

#build_doc(hash) ⇒ Object



181
182
183
184
185
186
187
# File 'lib/supernova/solr_criteria.rb', line 181

def build_doc(hash)
  if hash["type"].respond_to?(:constantize)
    Supernova.build_ar_like_record(hash["type"].constantize, convert_doc_attributes(hash), hash)
  else
    hash
  end
end

#build_doc_method(method) ⇒ Object



177
178
179
# File 'lib/supernova/solr_criteria.rb', line 177

def build_doc_method(method)
  merge_search_options :build_doc_method, method
end

#build_docs(docs) ⇒ Object



171
172
173
174
175
# File 'lib/supernova/solr_criteria.rb', line 171

def build_docs(docs)
  docs.map do |hash|
    self.search_options[:build_doc_method] ? self.search_options[:build_doc_method].call(hash) : build_doc(hash)
  end
end

#collection_from_body(body) ⇒ Object



255
256
257
# File 'lib/supernova/solr_criteria.rb', line 255

def collection_from_body(body)
  collection_from_json(JSON.parse(body))
end

#collection_from_json(json) ⇒ Object



259
260
261
262
263
264
265
266
# File 'lib/supernova/solr_criteria.rb', line 259

def collection_from_json(json)
  collection = Supernova::Collection.new(current_page, per_page == 0 ? 1 : per_page, json["response"]["numFound"])
  collection.original_criteria = self.clone
  collection.original_response = json
  collection.facets = hashify_facets_from_response(json)
  collection.replace(build_docs(json["response"]["docs"]))
  collection
end

#convert_doc_attributes(hash) ⇒ Object

called in build doc, all hashes have strings as keys!!!



190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/supernova/solr_criteria.rb', line 190

def convert_doc_attributes(hash)
  converted_hash = hash.inject({}) do |ret, (key, value)|
    if key == "id"
      ret["id"] = value.to_s.split("/").last
    else
      ret[reverse_lookup_solr_field(key).to_s] = value
    end
    ret
  end
  self.select_fields.each do |select_field|
    converted_hash[select_field.to_s] = nil if !converted_hash.has_key?(select_field.to_s)
  end
  converted_hash
end

#convert_search_order(order) ⇒ Object



99
100
101
102
103
104
105
106
107
# File 'lib/supernova/solr_criteria.rb', line 99

def convert_search_order(order)
  order.split(/\s*,\s*/).map do |chunk|
    if chunk.match(/(.*?) (asc|desc)/i)
      "#{solr_field_from_field($1)} #{$2}"
    else
      chunk
    end
  end.join(",")
end

#executeObject



251
252
253
# File 'lib/supernova/solr_criteria.rb', line 251

def execute
  collection_from_body(typhoeus_response.body)
end

#execute_async(&block) ⇒ Object



268
269
270
271
272
273
274
# File 'lib/supernova/solr_criteria.rb', line 268

def execute_async(&block)
  request = typhoeus_request
  request.on_complete do |response|
    block.call(collection_from_body(response.body))
  end
  hydra.queue(request)
end

#format(the_format) ⇒ Object



213
214
215
# File 'lib/supernova/solr_criteria.rb', line 213

def format(the_format)
  merge_search_options(:wt, the_format)
end

#fq_filter_for_key_and_value(key, value) ⇒ Object



153
154
155
156
157
158
159
160
161
# File 'lib/supernova/solr_criteria.rb', line 153

def fq_filter_for_key_and_value(key, value)
  if value.nil?
    "!#{key}:[* TO *]"
  elsif value.is_a?(Range)
    "#{key}:[#{value_for_fq_filter(value.first)} TO #{value_for_fq_filter(value.last)}]"
  else
    "#{key}:#{value_for_fq_filter(value)}"
  end
end

#fq_from_with(with) ⇒ Object



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/supernova/solr_criteria.rb', line 122

def fq_from_with(with)
  if with.blank?
    []
  else
    with.map do |with_part|
      if with_part.is_a?(Hash)
        with_part.map do |key_or_condition, values|
          values_from_key_or_condition_and_values(key_or_condition, values).map do |value|
            if key_or_condition.respond_to?(:solr_filter_for)
              key_or_condition.key = solr_field_from_field(key_or_condition.key)
              key_or_condition.solr_filter_for(value)
            else
              fq_filter_for_key_and_value(solr_field_from_field(key_or_condition), value)
            end
          end
        end
      else
        with_part
      end
    end.flatten
  end
end

#geo_attributes_from_center_distance_in_meters_and_key(center, distance_in_meters, key) ⇒ Object



32
33
34
35
36
37
38
39
40
# File 'lib/supernova/solr_criteria.rb', line 32

def geo_attributes_from_center_distance_in_meters_and_key(center, distance_in_meters, key)
  if center && distance_in_meters
    {
      :pt => "#{center.lat},#{center.lng}",
      :d => (distance_in_meters.to_f / Supernova::KM_TO_METER),
      :sfield => solr_field_from_field(key)
    }
  end
end

#geo_centerObject



20
21
22
23
24
25
26
# File 'lib/supernova/solr_criteria.rb', line 20

def geo_center
  if hash = self.search_options[:geo_center]
    Supernova::Coordinate.new(hash)
  else
    geo_center_from_with
  end
end

#geo_center_from_withObject



8
9
10
# File 'lib/supernova/solr_criteria.rb', line 8

def geo_center_from_with
  geo_circle_from_with.center if geo_circle_from_with
end

#geo_circle_from_withObject



4
5
6
# File 'lib/supernova/solr_criteria.rb', line 4

def geo_circle_from_with
  geo_filter_in_with.at(1) if geo_filter_in_with
end

#geo_distance_in_metersObject



16
17
18
# File 'lib/supernova/solr_criteria.rb', line 16

def geo_distance_in_meters
  self.search_options[:geo_distance] || geo_distance_in_meters_from_with
end

#geo_distance_in_meters_from_withObject



12
13
14
# File 'lib/supernova/solr_criteria.rb', line 12

def geo_distance_in_meters_from_with
  geo_circle_from_with.radius_in_meters if geo_circle_from_with
end

#geo_filed_keyObject



28
29
30
# File 'lib/supernova/solr_criteria.rb', line 28

def geo_filed_key
  geo_filter_in_with ? geo_filter_in_with.first : :location
end

#geo_filter_in_withObject



84
85
86
87
88
89
90
91
92
93
# File 'lib/supernova/solr_criteria.rb', line 84

def geo_filter_in_with
  (search_options[:with] || []).each do |option|
    if option.is_a?(Hash)
      option.each do |condition, value|
        return [condition.key, value] if value.is_a?(Supernova::Circle)
      end
    end
  end
  nil
end

#hashify_facets_from_response(response) ⇒ Object



227
228
229
230
231
232
233
234
# File 'lib/supernova/solr_criteria.rb', line 227

def hashify_facets_from_response(response)
  if response["facet_counts"] && response["facet_counts"]["facet_fields"]
    response["facet_counts"]["facet_fields"].inject({}) do |hash, (key, values)|
      hash[reverse_lookup_solr_field(key)] = Hash[*values]
      hash
    end
  end
end

#hydraObject



243
244
245
# File 'lib/supernova/solr_criteria.rb', line 243

def hydra
  Typhoeus::Hydra.hydra
end

#idsObject



280
281
282
# File 'lib/supernova/solr_criteria.rb', line 280

def ids
  only_ids.execute.ids
end

#include_facets?Boolean

Returns:

  • (Boolean)


95
96
97
# File 'lib/supernova/solr_criteria.rb', line 95

def include_facets?
  self.search_options[:facets] || self.search_options[:facet_queries]
end

#only_idsObject



276
277
278
# File 'lib/supernova/solr_criteria.rb', line 276

def only_ids
  self_or_clone.except(:select).select("id")
end

#reverse_lookup_solr_field(solr_field) ⇒ Object



113
114
115
116
117
118
119
120
# File 'lib/supernova/solr_criteria.rb', line 113

def reverse_lookup_solr_field(solr_field)
  if search_options[:attribute_mapping]
    search_options[:attribute_mapping].each do |field, options|
      return field if solr_field.to_s == solr_field_from_field(field)
    end
  end
  solr_field
end

#select_fieldsObject



205
206
207
208
209
210
211
# File 'lib/supernova/solr_criteria.rb', line 205

def select_fields
  if self.search_options[:select].present?
    self.search_options[:select]
  else
    self.search_options[:named_scope_class].respond_to?(:select_fields) ? self.search_options[:named_scope_class].select_fields : []
  end
end

#set_first_responding_attribute(doc, solr_key, value) ⇒ Object



217
218
219
220
221
222
223
224
225
# File 'lib/supernova/solr_criteria.rb', line 217

def set_first_responding_attribute(doc, solr_key, value)
  [reverse_lookup_solr_field(solr_key), solr_key].each do |key|
    meth = :"#{key}="
    if doc.respond_to?(meth)
      doc.send(meth, value)
      return
    end
  end
end

#solr_field_from_field(field) ⇒ Object



109
110
111
# File 'lib/supernova/solr_criteria.rb', line 109

def solr_field_from_field(field)
  Supernova::SolrIndexer.solr_field_for_field_name_and_mapping(field, search_options[:attribute_mapping])
end

#to_paramsObject

move this into separate methods (test each separatly)



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
77
78
79
80
81
82
# File 'lib/supernova/solr_criteria.rb', line 43

def to_params
  solr_options = { :fq => [], :q => "*:*" }
  solr_options[:wt] = search_options[:wt] if search_options[:wt]
  solr_options[:fq] += fq_from_with(self.search_options[:with])
  if self.filters[:without]
   self.filters[:without].each do |field, values| 
     solr_options[:fq] += values.map { |value| "!#{solr_field_from_field(field)}:#{value}" }
   end
  end
  solr_options[:sort] = convert_search_order(self.search_options[:order].join(", ")) if self.search_options[:order]
  if self.search_options[:search].is_a?(Array)
    solr_options[:q] = self.search_options[:search].map { |query| "(#{query})" }.join(" AND ")
  end
  
  if geo_options = geo_attributes_from_center_distance_in_meters_and_key(geo_center, geo_distance_in_meters, geo_filed_key)
    solr_options.merge!(geo_options)
    solr_options[:fq] << "{!geofilt}"
  end
  
  if self.search_options[:select]
    self.search_options[:select] << "id" if !self.search_options[:select].map(&:to_s).include?("id")
    solr_options[:fl] = self.search_options[:select].compact.map { |field| solr_field_from_field(field) }.join(",") 
  end
  solr_options[:fq] << "type:#{self.clazz}" if self.clazz
  
  solr_options[:facet] = true if include_facets?
  if self.search_options[:facets]
    solr_options["facet.field"] = self.search_options[:facets].compact.map { |field| solr_field_from_field(field) }
  end
  
  if self.search_options[:facet_queries]
    solr_options["facet.query"] = self.search_options[:facet_queries].values
  end
  
  if self.search_options[:pagination] || search_options[:rows] || search_options[:start]
    solr_options[:rows] = self.search_options[:rows] || per_page
    solr_options[:start] = search_options[:start] || ((current_page - 1) * solr_options[:rows])
  end
  solr_options
end

#typhoeus_requestObject



247
248
249
# File 'lib/supernova/solr_criteria.rb', line 247

def typhoeus_request
  Typhoeus::Request.new(Supernova::Solr.select_url, :params => to_params.merge(:wt => "json"), :method => :get)
end

#typhoeus_responseObject



236
237
238
239
240
241
# File 'lib/supernova/solr_criteria.rb', line 236

def typhoeus_response
  request = typhoeus_request
  hydra.queue(request)
  hydra.run
  request.response
end

#value_for_fq_filter(value) ⇒ Object



163
164
165
166
167
168
169
# File 'lib/supernova/solr_criteria.rb', line 163

def value_for_fq_filter(value)
  if value.is_a?(Date)
    Time.utc(value.year, value.month, value.day).iso8601
  else
    value
  end
end

#values_from_key_or_condition_and_values(key_or_condition, values) ⇒ Object



145
146
147
148
149
150
151
# File 'lib/supernova/solr_criteria.rb', line 145

def values_from_key_or_condition_and_values(key_or_condition, values)
  if key_or_condition.is_a?(Supernova::Condition) && values.is_a?(Array) && [:nin, :in].include?(key_or_condition.type)
    [values]
  else
    [values].flatten
  end
end