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 +4 -5
- data/Gemfile.lock +30 -29
- data/VERSION +1 -1
- data/lib/supernova.rb +2 -1
- data/lib/supernova/criteria.rb +68 -28
- data/lib/supernova/solr.rb +41 -2
- data/lib/supernova/solr_criteria.rb +27 -13
- data/lib/supernova/solr_indexer.rb +7 -4
- data/spec/integration/solr_spec.rb +27 -12
- data/spec/spec_helper.rb +1 -0
- data/spec/supernova/criteria_spec.rb +158 -10
- data/spec/supernova/solr_criteria_spec.rb +77 -20
- data/spec/supernova/solr_indexer_spec.rb +21 -7
- data/spec/supernova/solr_spec.rb +13 -26
- data/spec/supernova_spec.rb +2 -2
- data/supernova.gemspec +20 -24
- metadata +144 -233
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.
|
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.
|
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.
|
21
|
-
diff-lcs (1.1.
|
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
|
-
|
31
|
-
|
32
|
-
mime-types (1.
|
33
|
-
mysql2 (0.2.
|
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
|
-
|
38
|
-
|
39
|
-
|
40
|
-
rspec-
|
41
|
-
|
42
|
-
|
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.
|
47
|
-
ruby-debug (0.
|
48
|
-
columnize (>= 0.1)
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
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 (
|
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.
|
74
|
+
mysql2 (~> 0.2.18)
|
73
75
|
rcov
|
74
|
-
|
75
|
-
|
76
|
-
|
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.
|
1
|
+
0.6.8
|
data/lib/supernova.rb
CHANGED
data/lib/supernova/criteria.rb
CHANGED
@@ -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(
|
37
|
-
merge_search_options :order,
|
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
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
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(
|
140
|
+
merge_filters_or_search_options(:filters, key, value)
|
119
141
|
end
|
120
142
|
|
121
143
|
def merge_filters_array(key, fields)
|
122
|
-
|
123
|
-
|
124
|
-
|
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
|
-
|
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(
|
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(
|
134
|
-
|
135
|
-
reference
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
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
|
-
|
230
|
+
ret = ret.merge_filters(key, value)
|
191
231
|
end
|
192
232
|
other_criteria.search_options.each do |key, value|
|
193
|
-
|
233
|
+
ret = ret.merge_search_options(key, value)
|
194
234
|
end
|
195
|
-
|
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)
|
data/lib/supernova/solr.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
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 =
|
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
|
-
|
180
|
-
|
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
|
251
|
-
|
252
|
-
|
253
|
-
|
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)
|