mwmitchell-rsolr 0.7.1 → 0.8.0
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/CHANGES.txt +9 -0
- data/README.rdoc +28 -43
- data/Rakefile +1 -2
- data/examples/direct.rb +8 -9
- data/examples/http.rb +9 -8
- data/lib/rsolr.rb +10 -14
- data/lib/rsolr/adapter.rb +6 -0
- data/lib/rsolr/{connection/adapter → adapter}/direct.rb +3 -4
- data/lib/rsolr/{connection/adapter → adapter}/http.rb +4 -11
- data/lib/rsolr/connection.rb +104 -3
- data/lib/rsolr/http_client.rb +28 -14
- data/lib/rsolr/http_client/adapter/net_http.rb +1 -1
- data/lib/rsolr/message.rb +5 -6
- data/test/connection/direct_test.rb +19 -20
- data/test/connection/http_test.rb +3 -4
- data/test/connection/test_methods.rb +40 -50
- data/test/http_client/curb_test.rb +3 -4
- data/test/http_client/net_http_test.rb +3 -4
- data/test/http_client/test_methods.rb +1 -1
- data/test/http_client/util_test.rb +1 -1
- data/test/message_test.rb +8 -7
- metadata +6 -20
- data/lib/rsolr/connection/adapter.rb +0 -7
- data/lib/rsolr/connection/adapter/common_methods.rb +0 -50
- data/lib/rsolr/connection/base.rb +0 -101
- data/lib/rsolr/query.rb +0 -58
- data/lib/rsolr/response.rb +0 -8
- data/lib/rsolr/response/base.rb +0 -25
- data/lib/rsolr/response/index_info.rb +0 -33
- data/lib/rsolr/response/query.rb +0 -163
- data/lib/rsolr/response/update.rb +0 -4
- data/test/query_helper_test.rb +0 -30
- data/test/response/base_test.rb +0 -38
- data/test/response/pagination_test.rb +0 -47
- data/test/response/query_test.rb +0 -44
- data/test/test_helpers.rb +0 -61
@@ -1,101 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# Connection adapter decorator
|
3
|
-
#
|
4
|
-
class RSolr::Connection::Base
|
5
|
-
|
6
|
-
attr_reader :adapter, :opts
|
7
|
-
|
8
|
-
# "adapter" is instance of:
|
9
|
-
# RSolr::Adapter::HTTP
|
10
|
-
# RSolr::Adapter::Direct (jRuby only)
|
11
|
-
def initialize(adapter, opts={})
|
12
|
-
@adapter = adapter
|
13
|
-
@opts = opts
|
14
|
-
end
|
15
|
-
|
16
|
-
# send request (no param mapping) to the select handler
|
17
|
-
# params is hash with valid solr request params (:q, :fl, :qf etc..)
|
18
|
-
# if params[:wt] is not set, the default is :ruby (see opts[:global_params])
|
19
|
-
# if :wt is something other than :ruby, the raw response body is returned
|
20
|
-
# otherwise, an instance of RSolr::Response::Query is returned
|
21
|
-
# NOTE: to get raw ruby, use :wt=>'ruby'
|
22
|
-
# There is NO param mapping here, what you put it is what gets sent to Solr
|
23
|
-
def query(*args)
|
24
|
-
params = map_params(args.extract_options!)
|
25
|
-
args << params
|
26
|
-
response = @adapter.query(*args)
|
27
|
-
params[:wt] == :ruby ? RSolr::Response::Query::Base.new(response) : response
|
28
|
-
end
|
29
|
-
|
30
|
-
# Finds a document by its id
|
31
|
-
def find_by_id(*args)
|
32
|
-
params = map_params(args.extract_options!)
|
33
|
-
params[:q] = 'id:"#{id}"'
|
34
|
-
args << params
|
35
|
-
self.query(*args)
|
36
|
-
end
|
37
|
-
|
38
|
-
#
|
39
|
-
def update(*args)
|
40
|
-
params = map_params(args.extract_options!)
|
41
|
-
args << params
|
42
|
-
response = @adapter.update(*args)
|
43
|
-
params[:wt] == :ruby ? RSolr::Response::Update.new(response) : response
|
44
|
-
end
|
45
|
-
|
46
|
-
def index_info(*args)
|
47
|
-
params = map_params(args.extract_options!)
|
48
|
-
args << params
|
49
|
-
response = @adapter.index_info(*args)
|
50
|
-
params[:wt] == :ruby ? RSolr::Response::IndexInfo.new(response) : response
|
51
|
-
end
|
52
|
-
|
53
|
-
def add(*args, &block)
|
54
|
-
update message.add(*args, &block)
|
55
|
-
end
|
56
|
-
|
57
|
-
# send </commit>
|
58
|
-
def commit(*args)
|
59
|
-
update message.commit, *args
|
60
|
-
end
|
61
|
-
|
62
|
-
# send </optimize>
|
63
|
-
def optimize(*args)
|
64
|
-
update message.optimize, *args
|
65
|
-
end
|
66
|
-
|
67
|
-
# send </rollback>
|
68
|
-
# NOTE: solr 1.4 only
|
69
|
-
def rollback(*args)
|
70
|
-
update message.rollback, *args
|
71
|
-
end
|
72
|
-
|
73
|
-
# Delete one or many documents by id
|
74
|
-
# solr.delete_by_id 10
|
75
|
-
# solr.delete_by_id([12, 41, 199])
|
76
|
-
def delete_by_id(*args)
|
77
|
-
update message.delete_by_id(args.shift), *args
|
78
|
-
end
|
79
|
-
|
80
|
-
# delete one or many documents by query
|
81
|
-
# solr.delete_by_query 'available:0'
|
82
|
-
# solr.delete_by_query ['quantity:0', 'manu:"FQ"']
|
83
|
-
def delete_by_query(*args)
|
84
|
-
update message.delete_by_query(args.shift), *args
|
85
|
-
end
|
86
|
-
|
87
|
-
protected
|
88
|
-
|
89
|
-
# shortcut to solr::message
|
90
|
-
def message
|
91
|
-
RSolr::Message
|
92
|
-
end
|
93
|
-
|
94
|
-
# sets default params etc.. - could be used as a mapping hook
|
95
|
-
# type of request should be passed in here? -> map_params(:query, {})
|
96
|
-
def map_params(params)
|
97
|
-
params||={}
|
98
|
-
{:wt=>:ruby}.merge(params)
|
99
|
-
end
|
100
|
-
|
101
|
-
end
|
data/lib/rsolr/query.rb
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
module RSolr::Query
|
2
|
-
|
3
|
-
module HelperMethods
|
4
|
-
|
5
|
-
# returns a quoted or non-quoted string
|
6
|
-
# "value" should be a string
|
7
|
-
# "quote" should be true/false
|
8
|
-
def prep_value(value, quote)
|
9
|
-
quote ? %("#{value}") : value
|
10
|
-
end
|
11
|
-
|
12
|
-
# value can be a string, array, hash or symbol
|
13
|
-
# symbols are treated as strings
|
14
|
-
# arrays are recursed through #build_query
|
15
|
-
# keys for hashes are fields for fielded queries, the values are recused through #build_query
|
16
|
-
# strings/symbols are sent to #prep_value for possible quoting
|
17
|
-
#
|
18
|
-
# opts can have:
|
19
|
-
# :quote=>bool - default false
|
20
|
-
# :join=>string - default ' '
|
21
|
-
def build_query(value, opts={})
|
22
|
-
opts[:join]||=' '
|
23
|
-
opts[:quote]||=false
|
24
|
-
result = (
|
25
|
-
case value
|
26
|
-
when Array
|
27
|
-
value.collect do |item|
|
28
|
-
build_query item, opts
|
29
|
-
end.flatten
|
30
|
-
when String,Symbol
|
31
|
-
[prep_value(value.to_s, opts[:quote])]
|
32
|
-
when Hash
|
33
|
-
value.collect do |(k,v)|
|
34
|
-
"#{k}:#{build_query(v, opts)}"
|
35
|
-
end.flatten
|
36
|
-
else
|
37
|
-
[prep_value(value.to_s, opts[:quote])]
|
38
|
-
end
|
39
|
-
)
|
40
|
-
opts[:join] ? result.join(opts[:join]) : result
|
41
|
-
end
|
42
|
-
|
43
|
-
# start_for(2, 10)
|
44
|
-
# calculates the :start value for pagination etc..
|
45
|
-
def start_for(current_page, per_page)
|
46
|
-
page = current_page.to_s.to_i
|
47
|
-
page = page > 0 ? page : 1
|
48
|
-
((page - 1) * (per_page || 0))
|
49
|
-
end
|
50
|
-
|
51
|
-
end # end HelperMethods
|
52
|
-
|
53
|
-
# Easy access: RSolr::Query::Helper.start_for(page=1, per_page=10)
|
54
|
-
class Helper
|
55
|
-
extend HelperMethods
|
56
|
-
end
|
57
|
-
|
58
|
-
end
|
data/lib/rsolr/response.rb
DELETED
data/lib/rsolr/response/base.rb
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
# default/base response object
|
2
|
-
# This is where the ruby "eval" happens
|
3
|
-
# So far, all response classes extend this
|
4
|
-
class RSolr::Response::Base
|
5
|
-
|
6
|
-
# the object that contains the original :body, :params, full solr :query, post :data etc.
|
7
|
-
attr_reader :input
|
8
|
-
|
9
|
-
attr_reader :data, :header, :params, :status, :query_time
|
10
|
-
|
11
|
-
def initialize(input)
|
12
|
-
input = {:body=>input} if input.is_a?(String)
|
13
|
-
@input = input
|
14
|
-
@data = Kernel.eval(input[:body]).to_mash
|
15
|
-
@header = @data[:responseHeader]
|
16
|
-
@params = @header[:params]
|
17
|
-
@status = @header[:status]
|
18
|
-
@query_time = @header[:QTime]
|
19
|
-
end
|
20
|
-
|
21
|
-
def ok?
|
22
|
-
self.status == 0
|
23
|
-
end
|
24
|
-
|
25
|
-
end
|
@@ -1,33 +0,0 @@
|
|
1
|
-
# response for /admin/luke
|
2
|
-
class RSolr::Response::IndexInfo < RSolr::Response::Base
|
3
|
-
|
4
|
-
attr_reader :index, :directory, :has_deletions, :optimized, :current, :max_doc, :num_docs, :version
|
5
|
-
|
6
|
-
alias :has_deletions? :has_deletions
|
7
|
-
alias :optimized? :optimized
|
8
|
-
alias :current? :current
|
9
|
-
|
10
|
-
def initialize(data)
|
11
|
-
super(data)
|
12
|
-
@index = @data[:index]
|
13
|
-
@directory = @data[:directory]
|
14
|
-
# index fields
|
15
|
-
@has_deletions = @index[:hasDeletions]
|
16
|
-
@optimized = @index[:optimized]
|
17
|
-
@current = @index[:current]
|
18
|
-
@max_doc = @index[:maxDoc]
|
19
|
-
@num_docs = @index[:numDocs]
|
20
|
-
@version = @index[:version]
|
21
|
-
end
|
22
|
-
|
23
|
-
# Returns an array of fields from the index
|
24
|
-
# An optional rule can be used for "grepping" field names:
|
25
|
-
# field_list(/_facet$/)
|
26
|
-
def field_list(rule=nil)
|
27
|
-
@data[:fields].select do |k,v|
|
28
|
-
rule ? k =~ rule : true
|
29
|
-
end.collect{|k,v|k}
|
30
|
-
end
|
31
|
-
|
32
|
-
|
33
|
-
end
|
data/lib/rsolr/response/query.rb
DELETED
@@ -1,163 +0,0 @@
|
|
1
|
-
# response module for queries
|
2
|
-
module RSolr::Response::Query
|
3
|
-
|
4
|
-
# module for adding helper methods to each Hash document
|
5
|
-
module DocExt
|
6
|
-
|
7
|
-
# Helper method to check if value/multi-values exist for a given key.
|
8
|
-
# The value can be a string, or a RegExp
|
9
|
-
# Example:
|
10
|
-
# doc.has?(:location_facet)
|
11
|
-
# doc.has?(:location_facet, 'Clemons')
|
12
|
-
# doc.has?(:id, 'h009', /^u/i)
|
13
|
-
def has?(k, *values)
|
14
|
-
return if self[k].nil?
|
15
|
-
return true if self.key?(k) and values.empty?
|
16
|
-
target = self[k]
|
17
|
-
if target.is_a?(Array)
|
18
|
-
values.each do |val|
|
19
|
-
return target.any?{|tv| val.is_a?(Regexp) ? (tv =~ val) : (tv==val)}
|
20
|
-
end
|
21
|
-
else
|
22
|
-
return values.any? {|val| val.is_a?(Regexp) ? (target =~ val) : (target == val)}
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
# helper
|
27
|
-
# key is the name of the field
|
28
|
-
# opts is a hash with the following valid keys:
|
29
|
-
# - :sep - a string used for joining multivalued field values
|
30
|
-
# - :default - a value to return when the key doesn't exist
|
31
|
-
# if :sep is nil and the field is a multivalued field, the array is returned
|
32
|
-
def get(key, opts={:sep=>', ', :default=>nil})
|
33
|
-
if self.key? key
|
34
|
-
val = self[key]
|
35
|
-
(val.is_a?(Array) and opts[:sep]) ? val.join(opts[:sep]) : val
|
36
|
-
else
|
37
|
-
opts[:default]
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
end
|
42
|
-
|
43
|
-
# from the delsolr project -> http://github.com/avvo/delsolr/tree/master/lib/delsolr/response.rb
|
44
|
-
module Facets
|
45
|
-
|
46
|
-
class FacetValue
|
47
|
-
attr_reader :value,:hits
|
48
|
-
def initialize(value,hits)
|
49
|
-
@value,@hits=value,hits
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
class Facet
|
54
|
-
attr_reader :field
|
55
|
-
attr_accessor :values
|
56
|
-
def initialize(field)
|
57
|
-
@field=field
|
58
|
-
@values=[]
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
# @response.facet_fields.each do |facet|
|
63
|
-
# facet.field
|
64
|
-
# end
|
65
|
-
# "caches" the result in the @facets instance var
|
66
|
-
def facets
|
67
|
-
@facets ||= (
|
68
|
-
facet_fields.inject([]) do |acc,(facet_field_name,values_and_hits_list)|
|
69
|
-
acc << facet = Facet.new(facet_field_name)
|
70
|
-
# the values_and_hits_list is an array where a value is immediately followed by it's hit count
|
71
|
-
# so we shift off an item (the value)
|
72
|
-
while value = values_and_hits_list.shift
|
73
|
-
# and then shift off the next to get the hit value
|
74
|
-
facet.values << FacetValue.new(value, values_and_hits_list.shift)
|
75
|
-
# repeat until there are no more pairs in the values_and_hits_list array
|
76
|
-
end
|
77
|
-
acc
|
78
|
-
end
|
79
|
-
)
|
80
|
-
end
|
81
|
-
|
82
|
-
# pass in a facet field name and get back a Facet instance
|
83
|
-
def facet_by_field_name(name)
|
84
|
-
facets.detect{|facet|facet.field.to_s == name.to_s}
|
85
|
-
end
|
86
|
-
|
87
|
-
def facet_counts
|
88
|
-
@facets ||= data['facet_counts'] || {}
|
89
|
-
end
|
90
|
-
|
91
|
-
# Returns the hash of all the facet_fields (ie: {'instock_b' => ['true', 123, 'false', 20]}
|
92
|
-
def facet_fields
|
93
|
-
@facet_fields ||= facet_counts['facet_fields'] || {}
|
94
|
-
end
|
95
|
-
|
96
|
-
# Returns all of the facet queries
|
97
|
-
def facet_queries
|
98
|
-
@facet_queries ||= facet_counts['facet_queries'] || {}
|
99
|
-
end
|
100
|
-
|
101
|
-
end
|
102
|
-
|
103
|
-
#
|
104
|
-
#
|
105
|
-
#
|
106
|
-
module Pagination
|
107
|
-
|
108
|
-
# alias to the Solr param, 'rows'
|
109
|
-
def per_page
|
110
|
-
@per_page ||= params['rows'].to_s.to_i
|
111
|
-
end
|
112
|
-
|
113
|
-
# Returns the current page calculated from 'rows' and 'start'
|
114
|
-
# WillPaginate hook
|
115
|
-
def current_page
|
116
|
-
@current_page ||= (self.start / self.per_page).ceil + 1
|
117
|
-
end
|
118
|
-
|
119
|
-
# Calcuates the total pages from 'numFound' and 'rows'
|
120
|
-
# WillPaginate hook
|
121
|
-
def total_pages
|
122
|
-
@total_pages ||= self.per_page > 0 ? (self.total / self.per_page.to_f).ceil : 1
|
123
|
-
end
|
124
|
-
|
125
|
-
# returns the previous page number or 1
|
126
|
-
# WillPaginate hook
|
127
|
-
def previous_page
|
128
|
-
@previous_page ||= (current_page > 1) ? current_page - 1 : 1
|
129
|
-
end
|
130
|
-
|
131
|
-
# returns the next page number or the last
|
132
|
-
# WillPaginate hook
|
133
|
-
def next_page
|
134
|
-
@next_page ||= (current_page < total_pages) ? current_page + 1 : total_pages
|
135
|
-
end
|
136
|
-
|
137
|
-
end
|
138
|
-
|
139
|
-
# The base query response class
|
140
|
-
# adds to the Solr::Response::Base class by defining a few more attributes,
|
141
|
-
# includes the Pagination module, and extends each of the doc hashes
|
142
|
-
# with Solr::Response::Query::DocExt
|
143
|
-
class Base < RSolr::Response::Base
|
144
|
-
|
145
|
-
include RSolr::Response::Query::Pagination
|
146
|
-
include RSolr::Response::Query::Facets
|
147
|
-
|
148
|
-
attr_reader :response, :docs, :num_found, :start
|
149
|
-
|
150
|
-
alias :total :num_found
|
151
|
-
alias :offset :start
|
152
|
-
|
153
|
-
def initialize(data)
|
154
|
-
super(data)
|
155
|
-
@response = @data[:response]
|
156
|
-
@docs = @response[:docs].collect{ |d| d=d.to_mash; d.extend(DocExt); d }
|
157
|
-
@num_found = @response[:numFound]
|
158
|
-
@start = @response[:start]
|
159
|
-
end
|
160
|
-
|
161
|
-
end
|
162
|
-
|
163
|
-
end
|
data/test/query_helper_test.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), 'test_helpers.rb')
|
2
|
-
|
3
|
-
class RSolrQueryHelperTest < RSolrBaseTest
|
4
|
-
|
5
|
-
H = RSolr::Query::Helper
|
6
|
-
|
7
|
-
test 'pre_value' do
|
8
|
-
value = 'the man'
|
9
|
-
assert_equal 'the man', H.prep_value(value, false)
|
10
|
-
assert_equal "\"the man\"", H.prep_value(value, :quote=>true)
|
11
|
-
end
|
12
|
-
|
13
|
-
test 'build_query' do
|
14
|
-
assert_equal 'testing', H.build_query('testing')
|
15
|
-
assert_equal '"testing"', H.build_query('testing', :quote=>true)
|
16
|
-
assert_equal 'testing again', H.build_query(['testing', 'again'])
|
17
|
-
assert_equal '"testing" "again"', H.build_query(['testing', 'again'], :quote=>true)
|
18
|
-
assert_equal 'name:whatever', H.build_query({:name=>'whatever'})
|
19
|
-
assert_equal 'name:"whatever"', H.build_query({:name=>'whatever'}, :quote=>true)
|
20
|
-
assert_equal 'sam name:whatever i am', H.build_query(['sam', {:name=>'whatever'}, 'i', 'am'])
|
21
|
-
assert_equal 'testing AND blah', H.build_query(['testing', 'blah'], :join=>' AND ')
|
22
|
-
end
|
23
|
-
|
24
|
-
test 'start_for' do
|
25
|
-
per_page = 8
|
26
|
-
current_page = 2
|
27
|
-
assert_equal 8, H.start_for(current_page, per_page)
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|
data/test/response/base_test.rb
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), '..', 'test_helpers')
|
2
|
-
|
3
|
-
class ResponseBaseTest < RSolrBaseTest
|
4
|
-
|
5
|
-
def test_accessors
|
6
|
-
|
7
|
-
adapter_response = {:body=>mock_query_response}
|
8
|
-
|
9
|
-
r = RSolr::Response::Base.new(adapter_response)
|
10
|
-
|
11
|
-
assert_class Mash, r.data
|
12
|
-
assert_class Mash, r.params
|
13
|
-
assert_class Mash, r.header
|
14
|
-
|
15
|
-
# make sure the incoming adapter response is the same as the response.input
|
16
|
-
assert_equal adapter_response, r.input
|
17
|
-
|
18
|
-
assert_equal r.query_time, r.header[:QTime]
|
19
|
-
assert_equal r.query_time, r.header['QTime']
|
20
|
-
|
21
|
-
assert_equal r.params, r.header[:params]
|
22
|
-
assert_equal r.params, r.header['params']
|
23
|
-
|
24
|
-
assert_equal '*:*', r.params[:q]
|
25
|
-
assert_equal '*:*', r.params['q']
|
26
|
-
|
27
|
-
assert_equal 0, r.status
|
28
|
-
assert_equal r.status, r.header[:status]
|
29
|
-
assert_equal r.status, r.header['status']
|
30
|
-
|
31
|
-
assert_equal r.header, r.data[:responseHeader]
|
32
|
-
assert_equal r.header, r.data['responseHeader']
|
33
|
-
|
34
|
-
assert r.ok?
|
35
|
-
|
36
|
-
end
|
37
|
-
|
38
|
-
end
|