supernova 0.6.7 → 0.6.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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)