supernova 0.6.7 → 0.6.8

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -6,22 +6,21 @@ source "http://rubygems.org"
6
6
  # Add dependencies to develop your gem here.
7
7
  # Include everything needed to run rake, tests, features, etc.
8
8
 
9
- gem "rsolr"
10
9
  gem "will_paginate"
11
10
  gem "json"
12
11
  gem "activesupport"
13
- gem "typhoeus"
12
+ gem "typhoeus", '0.3.3'
14
13
 
15
14
  group :development do
16
15
  gem "i18n"
17
16
  gem 'activerecord', '~>3.0.7', :require => "active_record"
18
- gem "ruby-debug"
19
- gem "mysql2", "~> 0.2.7"
17
+ gem "ruby-debug#{RUBY_VERSION != "1.8.7" ? "19" : ""}"
18
+ gem "mysql2", "~> 0.2.18"
20
19
  gem "ZenTest", "4.5.0"
21
20
  gem "geokit"
22
21
  gem "autotest"
23
22
  gem "autotest-growl"
24
- gem "rspec", "~> 2.3.0"
23
+ gem "rspec", "~> 2.8.0"
25
24
  gem "bundler", "~> 1.0.0"
26
25
  gem "jeweler", "~> 1.6.0"
27
26
  gem "rcov", ">= 0"
data/Gemfile.lock CHANGED
@@ -12,13 +12,14 @@ GEM
12
12
  arel (~> 2.0.10)
13
13
  tzinfo (~> 0.3.23)
14
14
  activesupport (3.0.9)
15
+ archive-tar-minitar (0.5.2)
15
16
  arel (2.0.10)
16
17
  autotest (4.4.6)
17
18
  ZenTest (>= 4.4.1)
18
19
  autotest-growl (0.2.9)
19
20
  builder (2.1.2)
20
- columnize (0.3.4)
21
- diff-lcs (1.1.2)
21
+ columnize (0.3.6)
22
+ diff-lcs (1.1.3)
22
23
  geokit (1.6.0)
23
24
  git (1.2.5)
24
25
  i18n (0.5.0)
@@ -27,33 +28,34 @@ GEM
27
28
  git (>= 1.2.5)
28
29
  rake
29
30
  json (1.5.3)
30
- linecache (0.46)
31
- rbx-require-relative (> 0.0.4)
32
- mime-types (1.16)
33
- mysql2 (0.2.11)
31
+ linecache19 (0.5.12)
32
+ ruby_core_source (>= 0.1.4)
33
+ mime-types (1.17.2)
34
+ mysql2 (0.2.18)
34
35
  rake (0.9.2)
35
- rbx-require-relative (0.0.5)
36
36
  rcov (0.9.9)
37
- rsolr (1.0.2)
38
- builder (>= 2.1.2)
39
- rspec (2.3.0)
40
- rspec-core (~> 2.3.0)
41
- rspec-expectations (~> 2.3.0)
42
- rspec-mocks (~> 2.3.0)
43
- rspec-core (2.3.1)
44
- rspec-expectations (2.3.0)
37
+ rspec (2.8.0)
38
+ rspec-core (~> 2.8.0)
39
+ rspec-expectations (~> 2.8.0)
40
+ rspec-mocks (~> 2.8.0)
41
+ rspec-core (2.8.0)
42
+ rspec-expectations (2.8.0)
45
43
  diff-lcs (~> 1.1.2)
46
- rspec-mocks (2.3.0)
47
- ruby-debug (0.10.4)
48
- columnize (>= 0.1)
49
- ruby-debug-base (~> 0.10.4.0)
50
- ruby-debug-base (0.10.4)
51
- linecache (>= 0.3)
52
- typhoeus (0.2.4)
53
- mime-types
44
+ rspec-mocks (2.8.0)
45
+ ruby-debug-base19 (0.11.25)
46
+ columnize (>= 0.3.1)
47
+ linecache19 (>= 0.5.11)
48
+ ruby_core_source (>= 0.1.4)
49
+ ruby-debug19 (0.11.6)
50
+ columnize (>= 0.3.1)
51
+ linecache19 (>= 0.5.11)
52
+ ruby-debug-base19 (>= 0.11.19)
53
+ ruby_core_source (0.1.5)
54
+ archive-tar-minitar (>= 0.5.2)
55
+ typhoeus (0.3.3)
54
56
  mime-types
55
57
  tzinfo (0.3.29)
56
- will_paginate (2.3.15)
58
+ will_paginate (3.0.3)
57
59
 
58
60
  PLATFORMS
59
61
  ruby
@@ -69,10 +71,9 @@ DEPENDENCIES
69
71
  i18n
70
72
  jeweler (~> 1.6.0)
71
73
  json
72
- mysql2 (~> 0.2.7)
74
+ mysql2 (~> 0.2.18)
73
75
  rcov
74
- rsolr
75
- rspec (~> 2.3.0)
76
- ruby-debug
77
- typhoeus
76
+ rspec (~> 2.8.0)
77
+ ruby-debug19
78
+ typhoeus (= 0.3.3)
78
79
  will_paginate
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.6.7
1
+ 0.6.8
data/lib/supernova.rb CHANGED
@@ -1,6 +1,7 @@
1
- require "rsolr"
2
1
  require "active_support/core_ext/object/blank"
3
2
  require "active_support/core_ext/hash"
3
+ require "will_paginate/collection"
4
+ require "will_paginate/array"
4
5
 
5
6
  module Supernova
6
7
  KM_TO_METER = 1000.0
@@ -17,12 +17,33 @@ class Supernova::Criteria
17
17
  def select(*args)
18
18
  self.new.send(:select, *args)
19
19
  end
20
+
21
+ def immutable_by_default!
22
+ @immutable_by_default = true
23
+ end
24
+
25
+ def mutable_by_default!
26
+ @immutable_by_default = false
27
+ end
28
+
29
+ def immutable_by_default?
30
+ @immutable_by_default == true
31
+ end
20
32
  end
21
33
 
22
34
  def initialize(clazz = nil)
23
35
  self.clazz = clazz
24
36
  self.filters = {}
25
37
  self.search_options = {}
38
+ self.immutable! if self.class.immutable_by_default?
39
+ end
40
+
41
+ def immutable!
42
+ @immutable = true
43
+ end
44
+
45
+ def immutable?
46
+ @immutable == true
26
47
  end
27
48
 
28
49
  def for_classes(clazzes)
@@ -33,8 +54,8 @@ class Supernova::Criteria
33
54
  merge_search_options :attribute_mapping, mapping
34
55
  end
35
56
 
36
- def order(order_option)
37
- merge_search_options :order, order_option
57
+ def order(*order_options)
58
+ merge_search_options :order, order_options
38
59
  end
39
60
 
40
61
  def limit(limit_option)
@@ -58,12 +79,13 @@ class Supernova::Criteria
58
79
  end
59
80
 
60
81
  def without(filters)
61
- self.filters[:without] ||= Hash.new
62
- filters.each do |key, value|
63
- self.filters[:without][key] ||= Array.new
64
- self.filters[:without][key] << value if !self.filters[:without][key].include?(value)
82
+ self_or_clone.tap do |soc|
83
+ soc.filters[:without] ||= Hash.new
84
+ filters.each do |key, value|
85
+ soc.filters[:without][key] ||= Array.new
86
+ soc.filters[:without][key] << value if !soc.filters[:without][key].include?(value)
87
+ end
65
88
  end
66
- self
67
89
  end
68
90
 
69
91
  def select(*fields)
@@ -115,32 +137,49 @@ class Supernova::Criteria
115
137
  end
116
138
 
117
139
  def merge_filters(key, value)
118
- merge_filters_or_search_options(self.filters, key, value)
140
+ merge_filters_or_search_options(:filters, key, value)
119
141
  end
120
142
 
121
143
  def merge_filters_array(key, fields)
122
- self.search_options[key] ||= Array.new
123
- fields.flatten.each do |field|
124
- self.search_options[key] << field if !self.search_options[key].include?(field)
144
+ self_or_clone.tap do |soc|
145
+ soc.search_options[key] ||= Array.new
146
+ fields.flatten.each do |field|
147
+ soc.search_options[key] << field if !soc.search_options[key].include?(field)
148
+ end
125
149
  end
126
- self
150
+ end
151
+
152
+ def clone
153
+ Marshal.load(Marshal.dump(self))
154
+ end
155
+
156
+ def self_or_clone
157
+ immutable? ? clone : self
127
158
  end
128
159
 
129
160
  def merge_search_options(key, value)
130
- merge_filters_or_search_options(self.search_options, key, value)
161
+ merge_filters_or_search_options(:search_options, key, value)
162
+ end
163
+
164
+ def except(key)
165
+ self_or_clone.tap do |soc|
166
+ soc.search_options.delete(key)
167
+ end
131
168
  end
132
169
 
133
- def merge_filters_or_search_options(reference, key, value)
134
- if value.is_a?(Hash)
135
- reference[key] ||= Hash.new
136
- reference[key].merge!(value)
137
- elsif key == :select
138
- reference[key] ||= Array.new
139
- reference[key] += (value || [])
140
- else
141
- reference[key] = value
170
+ def merge_filters_or_search_options(reference_method, key, value)
171
+ self_or_clone.tap do |soc|
172
+ reference = soc.send(reference_method)
173
+ if value.is_a?(Hash)
174
+ reference[key] ||= Hash.new
175
+ reference[key].merge!(value)
176
+ elsif [:select, :order].include?(key)
177
+ reference[key] ||= Array.new
178
+ reference[key] += (value || [])
179
+ else
180
+ reference[key] = value
181
+ end
142
182
  end
143
- self
144
183
  end
145
184
 
146
185
  def to_parameters
@@ -158,7 +197,7 @@ class Supernova::Criteria
158
197
  end
159
198
 
160
199
  def populated?
161
- instance_variables.include?("@results")
200
+ instance_variables.map(&:to_s).include?("@results")
162
201
  end
163
202
 
164
203
  def execute
@@ -186,17 +225,18 @@ class Supernova::Criteria
186
225
  end
187
226
 
188
227
  def merge(other_criteria)
228
+ ret = self_or_clone
189
229
  other_criteria.filters.each do |key, value|
190
- self.merge_filters(key, value)
230
+ ret = ret.merge_filters(key, value)
191
231
  end
192
232
  other_criteria.search_options.each do |key, value|
193
- self.merge_search_options(key, value)
233
+ ret = ret.merge_search_options(key, value)
194
234
  end
195
- self
235
+ ret
196
236
  end
197
237
 
198
238
  def method_missing(*args, &block)
199
- if Supernova::Collection.instance_methods.include?(args.first.to_s)
239
+ if Supernova::Collection.instance_methods.map(&:to_s).include?(args.first.to_s)
200
240
  populate
201
241
  @results.send(*args, &block)
202
242
  elsif self.named_scope_defined?(args.first)
@@ -1,15 +1,54 @@
1
1
  require "supernova/solr_criteria"
2
2
 
3
3
  module Supernova::Solr
4
+ class ConnectionDummy
5
+ def add(row)
6
+ deprication_warning("add")
7
+ Supernova::Solr.add(row)
8
+ end
9
+
10
+ def commit
11
+ deprication_warning("commit!")
12
+ Supernova::Solr.commit!
13
+ end
14
+
15
+ def deprication_warning(instead)
16
+ puts "DEPRICATION WARNING: calling #{caller.first[/\`(.*?)\'/, 1]} is depricated. Use Supernova::Solr.#{instead} instead. Called from #{filter_callers(caller).at(1)}"
17
+ end
18
+
19
+ def filter_callers(callers)
20
+ callers.reject { |c| c.include?("/gems/")}
21
+ end
22
+ end
23
+
4
24
  class << self
5
25
  attr_accessor :url
6
26
 
27
+ def select_url
28
+ "#{url}/select"
29
+ end
30
+
7
31
  def connection
8
- @connection ||= RSolr.connect(:url => self.url)
32
+ ConnectionDummy.new
33
+ end
34
+
35
+ def update_request(payload)
36
+ Typhoeus::Request.post("#{url}/update",
37
+ :body => %(<?xml version="1.0" encoding="UTF-8"?>#{payload}), :headers => { "Content-Type" => "text/xml"}
38
+ )
9
39
  end
10
40
 
11
41
  def truncate!
12
- connection.delete_by_query("*:*")
42
+ update_request("<delete><query>*:*</query></delete>")
43
+ end
44
+
45
+ def commit!
46
+ update_request("<commit />")
47
+ end
48
+
49
+ # only to be used for testing
50
+ def add(row)
51
+ Supernova::SolrIndexer.new.index_with_json([row])
13
52
  end
14
53
  end
15
54
 
@@ -1,16 +1,17 @@
1
- require "rsolr"
1
+ # -*- encoding : utf-8 -*-
2
2
 
3
3
  class Supernova::SolrCriteria < Supernova::Criteria
4
4
  # move this into separate methods (test each separatly)
5
5
  def to_params
6
6
  solr_options = { :fq => [], :q => "*:*" }
7
+ solr_options[:wt] = search_options[:wt] if search_options[:wt]
7
8
  solr_options[:fq] += fq_from_with(self.filters[:with])
8
9
  if self.filters[:without]
9
10
  self.filters[:without].each do |field, values|
10
11
  solr_options[:fq] += values.map { |value| "!#{solr_field_from_field(field)}:#{value}" }
11
12
  end
12
13
  end
13
- solr_options[:sort] = convert_search_order(self.search_options[:order]) if self.search_options[:order]
14
+ solr_options[:sort] = convert_search_order(self.search_options[:order].join(", ")) if self.search_options[:order]
14
15
  if self.search_options[:search].is_a?(Array)
15
16
  solr_options[:q] = self.search_options[:search].map { |query| "(#{query})" }.join(" AND ")
16
17
  end
@@ -22,7 +23,7 @@ class Supernova::SolrCriteria < Supernova::Criteria
22
23
  solr_options[:fq] << "{!geofilt}"
23
24
  end
24
25
  if self.search_options[:select]
25
- self.search_options[:select] << :id
26
+ self.search_options[:select] << "id" if !self.search_options[:select].map(&:to_s).include?("id")
26
27
  solr_options[:fl] = self.search_options[:select].compact.map { |field| solr_field_from_field(field) }.join(",")
27
28
  end
28
29
  solr_options[:fq] << "type:#{self.clazz}" if self.clazz
@@ -40,13 +41,13 @@ class Supernova::SolrCriteria < Supernova::Criteria
40
41
  end
41
42
 
42
43
  def convert_search_order(order)
43
- asc_or_desc = nil
44
- field = solr_field_from_field(order)
45
- if order.match(/^(.*?) (asc|desc)/i)
46
- field = solr_field_from_field($1)
47
- asc_or_desc = $2
48
- end
49
- [field, asc_or_desc].compact.join(" ")
44
+ order.split(/\s*,\s*/).map do |chunk|
45
+ if chunk.match(/(.*?) (asc|desc)/i)
46
+ "#{solr_field_from_field($1)} #{$2}"
47
+ else
48
+ chunk
49
+ end
50
+ end.join(",")
50
51
  end
51
52
 
52
53
  def solr_field_from_field(field)
@@ -147,6 +148,10 @@ class Supernova::SolrCriteria < Supernova::Criteria
147
148
  end
148
149
  end
149
150
 
151
+ def format(the_format)
152
+ merge_search_options(:wt, the_format)
153
+ end
154
+
150
155
  def set_first_responding_attribute(doc, solr_key, value)
151
156
  [reverse_lookup_solr_field(solr_key), solr_key].each do |key|
152
157
  meth = :"#{key}="
@@ -166,8 +171,12 @@ class Supernova::SolrCriteria < Supernova::Criteria
166
171
  end
167
172
  end
168
173
 
174
+ def execute_raw
175
+ JSON.parse(Typhoeus::Request.post(Supernova::Solr.select_url, :params => to_params.merge(:wt => "json")).body)
176
+ end
177
+
169
178
  def execute
170
- response = Supernova::Solr.connection.post("select", :data => to_params)
179
+ response = execute_raw
171
180
  collection = Supernova::Collection.new(current_page, per_page == 0 ? 1 : per_page, response["response"]["numFound"])
172
181
  collection.original_response = response
173
182
  collection.facets = hashify_facets_from_response(response)
@@ -175,8 +184,13 @@ class Supernova::SolrCriteria < Supernova::Criteria
175
184
  collection
176
185
  end
177
186
 
187
+ def only_ids
188
+ self_or_clone.except(:select).select("id")
189
+ end
190
+
178
191
  def ids
179
- select("id")
180
- execute.map! { |h| h["id"].split("/").last.to_i }
192
+ only_ids.execute.tap do |col|
193
+ col.replace(col.map { |h| h["id"].split("/").last.to_i })
194
+ end
181
195
  end
182
196
  end
@@ -232,6 +232,7 @@ class Supernova::SolrIndexer
232
232
  end
233
233
 
234
234
  def index_with_json(rows)
235
+ return false if rows.empty?
235
236
  options && options[:use_json_file] ? index_with_json_file(rows) : index_with_json_string(rows)
236
237
  end
237
238
 
@@ -246,11 +247,13 @@ class Supernova::SolrIndexer
246
247
  index_rows(query_db(query))
247
248
  end
248
249
 
250
+ # just to be backwards compatible
249
251
  def index_directly(rows)
250
- rows.each do |row|
251
- row = Supernova::Solr.connection.add(row)
252
- end
253
- Supernova::Solr.connection.commit if rows.any?
252
+ index_with_json(rows)
253
+ # rows.each do |row|
254
+ # row = Supernova::Solr.connection.add(row)
255
+ # end
256
+ # Supernova::Solr.connection.commit if rows.any?
254
257
  end
255
258
 
256
259
  def index_with_json_file(rows)