rsolr 1.1.2 → 2.0.0.pre1
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rspec +2 -0
- data/README.rdoc +3 -4
- data/Rakefile +16 -3
- data/lib/rsolr/char.rb +3 -21
- data/lib/rsolr/client.rb +66 -66
- data/lib/rsolr/document.rb +161 -0
- data/lib/rsolr/json.rb +52 -0
- data/lib/rsolr/uri.rb +1 -51
- data/lib/rsolr/version.rb +1 -1
- data/lib/rsolr/xml.rb +24 -98
- data/lib/rsolr.rb +8 -9
- data/rsolr.gemspec +2 -0
- data/spec/api/client_spec.rb +77 -85
- data/spec/api/document_spec.rb +48 -0
- data/spec/api/error_spec.rb +2 -1
- data/spec/api/json_spec.rb +175 -0
- data/spec/api/pagination_spec.rb +3 -9
- data/spec/api/rsolr_spec.rb +3 -11
- data/spec/api/uri_spec.rb +2 -93
- data/spec/api/xml_spec.rb +36 -10
- data/spec/integration/solr5_spec.rb +1 -1
- data/spec/spec_helper.rb +83 -2
- metadata +23 -10
- data/lib/rsolr/connection.rb +0 -74
- data/spec/api/char_spec.rb +0 -23
- data/spec/api/connection_spec.rb +0 -140
- data/tasks/rdoc.rake +0 -11
- data/tasks/rsolr.rake +0 -10
- data/tasks/spec.rake +0 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6615cc15df2d2db90f952215c74c2c1215622f6d
|
4
|
+
data.tar.gz: 3b46e5c7953531a68c6dd596036f8b50d10c99d6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e4de23a7c03b4d3d81a765dd6be91abff61a6f8241bbe5a4e941df9d0c34855715fe077aa5d3b20d54c3e87781aa539a90cd6da8ba3e4cb9b87591c0523e59f7
|
7
|
+
data.tar.gz: d2ad073f1b1814b834facbeaa8268d803076645eae603ed751813fe73684d10172e26cec7d54d232e42e1d5052d159ec519f8be5fee5ec74ea2e309cd5bb37a7
|
data/.gitignore
CHANGED
data/.rspec
ADDED
data/README.rdoc
CHANGED
@@ -155,14 +155,13 @@ Delete by array of queries
|
|
155
155
|
== Response Formats
|
156
156
|
The default response format is Ruby. When the +:wt+ param is set to +:ruby+, the response is eval'd resulting in a Hash. You can get a raw response by setting the +:wt+ to +"ruby"+ - notice, the string -- not a symbol. RSolr will eval the Ruby string ONLY if the :wt value is :ruby. All other response formats are available as expected, +:wt=>'xml'+ etc..
|
157
157
|
|
158
|
-
===Evaluated Ruby
|
158
|
+
===Evaluated Ruby:
|
159
159
|
solr.get 'select', :params => {:wt => :ruby} # notice :ruby is a Symbol
|
160
|
-
===Raw Ruby
|
160
|
+
===Raw Ruby:
|
161
161
|
solr.get 'select', :params => {:wt => 'ruby'} # notice 'ruby' is a String
|
162
|
-
|
163
162
|
===XML:
|
164
163
|
solr.get 'select', :params => {:wt => :xml}
|
165
|
-
===JSON:
|
164
|
+
===JSON (default):
|
166
165
|
solr.get 'select', :params => {:wt => :json}
|
167
166
|
|
168
167
|
==Related Resources & Projects
|
data/Rakefile
CHANGED
@@ -1,6 +1,19 @@
|
|
1
|
-
require 'rake'
|
2
1
|
require 'bundler/gem_tasks'
|
3
2
|
|
4
|
-
|
3
|
+
task default: ['spec']
|
5
4
|
|
6
|
-
|
5
|
+
require 'rspec/core/rake_task'
|
6
|
+
|
7
|
+
RSpec::Core::RakeTask.new(:spec)
|
8
|
+
|
9
|
+
# Rdoc
|
10
|
+
require 'rdoc/task'
|
11
|
+
|
12
|
+
desc 'Generate documentation for the rsolr gem.'
|
13
|
+
RDoc::Task.new(:doc) do |rdoc|
|
14
|
+
rdoc.rdoc_dir = 'doc'
|
15
|
+
rdoc.title = 'RSolr'
|
16
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
17
|
+
rdoc.rdoc_files.include('README.rdoc')
|
18
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
19
|
+
end
|
data/lib/rsolr/char.rb
CHANGED
@@ -1,24 +1,6 @@
|
|
1
|
-
#
|
2
|
-
# @deprecated remove this module when we remove the method (duh)
|
1
|
+
# :nodoc:
|
3
2
|
module RSolr::Char
|
4
|
-
|
5
|
-
|
6
|
-
# that isn't a word character
|
7
|
-
# @deprecated - this is incorrect Solr escaping
|
8
|
-
def escape value
|
9
|
-
warn "[DEPRECATION] `RSolr.escape` is deprecated (and incorrect). Use `RSolr.solr_escape` instead."
|
10
|
-
value.gsub(/(\W)/, '\\\\\1')
|
3
|
+
def self.included(*)
|
4
|
+
warn 'RSolr::Char is deprecated without replacement, and will be removed in RSolr 3.x'
|
11
5
|
end
|
12
|
-
|
13
|
-
# LUCENE_CHAR_RX = /([\+\-\!\(\)\[\]\^\"\~\*\?\:\\]+)/
|
14
|
-
# LUCENE_WORD_RX = /(OR|AND|NOT)/
|
15
|
-
#
|
16
|
-
# # More specific/lucene escape sequence
|
17
|
-
# def lucene_escape string
|
18
|
-
# delim = " "
|
19
|
-
# string.gsub(LUCENE_CHAR_RX, '\\\\\1').split(delim).map { |v|
|
20
|
-
# v.gsub(LUCENE_WORD_RX, '\\\\\1')
|
21
|
-
# }.join(delim)
|
22
|
-
# end
|
23
|
-
|
24
6
|
end
|
data/lib/rsolr/client.rb
CHANGED
@@ -3,11 +3,13 @@ begin
|
|
3
3
|
rescue LoadError
|
4
4
|
end
|
5
5
|
|
6
|
+
require 'faraday'
|
7
|
+
|
6
8
|
class RSolr::Client
|
7
9
|
|
8
10
|
class << self
|
9
11
|
def default_wt
|
10
|
-
@default_wt
|
12
|
+
@default_wt ||= :json
|
11
13
|
end
|
12
14
|
|
13
15
|
def default_wt= value
|
@@ -15,7 +17,7 @@ class RSolr::Client
|
|
15
17
|
end
|
16
18
|
end
|
17
19
|
|
18
|
-
attr_reader :
|
20
|
+
attr_reader :uri, :proxy, :options, :update_path
|
19
21
|
|
20
22
|
def initialize connection, options = {}
|
21
23
|
@proxy = @uri = nil
|
@@ -23,15 +25,16 @@ class RSolr::Client
|
|
23
25
|
unless false === options[:url]
|
24
26
|
url = options[:url] ? options[:url].dup : 'http://127.0.0.1:8983/solr/'
|
25
27
|
url << "/" unless url[-1] == ?/
|
26
|
-
@uri =
|
28
|
+
@uri = ::URI.parse(url)
|
27
29
|
if options[:proxy]
|
28
30
|
proxy_url = options[:proxy].dup
|
29
31
|
proxy_url << "/" unless proxy_url.nil? or proxy_url[-1] == ?/
|
30
|
-
@proxy =
|
32
|
+
@proxy = ::URI.parse proxy_url if proxy_url
|
31
33
|
elsif options[:proxy] == false
|
32
34
|
@proxy = false # used to avoid setting the proxy from the environment.
|
33
35
|
end
|
34
36
|
end
|
37
|
+
@update_format = options.delete(:update_format) || :json
|
35
38
|
@update_path = options.fetch(:update_path, 'update')
|
36
39
|
@options = options
|
37
40
|
end
|
@@ -41,7 +44,7 @@ class RSolr::Client
|
|
41
44
|
base_uri.request_uri if base_uri
|
42
45
|
end
|
43
46
|
|
44
|
-
# returns the
|
47
|
+
# returns the URI uri object.
|
45
48
|
def base_uri
|
46
49
|
@uri
|
47
50
|
end
|
@@ -80,11 +83,14 @@ class RSolr::Client
|
|
80
83
|
#
|
81
84
|
def update opts = {}
|
82
85
|
opts[:headers] ||= {}
|
83
|
-
|
86
|
+
if @update_format == :json
|
87
|
+
opts[:headers]['Content-Type'] ||= 'application/json'
|
88
|
+
else
|
89
|
+
opts[:headers]['Content-Type'] ||= 'text/xml'
|
90
|
+
end
|
84
91
|
post opts.fetch(:path, update_path), opts
|
85
92
|
end
|
86
93
|
|
87
|
-
#
|
88
94
|
# +add+ creates xml "add" documents and sends the xml data to the +update+ method
|
89
95
|
#
|
90
96
|
# http://wiki.apache.org/solr/UpdateXmlMessages#add.2BAC8-update
|
@@ -101,7 +107,7 @@ class RSolr::Client
|
|
101
107
|
#
|
102
108
|
def add doc, opts = {}
|
103
109
|
add_attributes = opts.delete :add_attributes
|
104
|
-
update opts.merge(:data =>
|
110
|
+
update opts.merge(:data => builder.add(doc, add_attributes))
|
105
111
|
end
|
106
112
|
|
107
113
|
# send "commit" xml with opts
|
@@ -110,7 +116,7 @@ class RSolr::Client
|
|
110
116
|
#
|
111
117
|
def commit opts = {}
|
112
118
|
commit_attrs = opts.delete :commit_attributes
|
113
|
-
update opts.merge(:data =>
|
119
|
+
update opts.merge(:data => builder.commit( commit_attrs ))
|
114
120
|
end
|
115
121
|
|
116
122
|
# send "optimize" xml with opts.
|
@@ -119,7 +125,7 @@ class RSolr::Client
|
|
119
125
|
#
|
120
126
|
def optimize opts = {}
|
121
127
|
optimize_attributes = opts.delete :optimize_attributes
|
122
|
-
update opts.merge(:data =>
|
128
|
+
update opts.merge(:data => builder.optimize(optimize_attributes))
|
123
129
|
end
|
124
130
|
|
125
131
|
# send </rollback>
|
@@ -128,14 +134,14 @@ class RSolr::Client
|
|
128
134
|
#
|
129
135
|
# NOTE: solr 1.4 only
|
130
136
|
def rollback opts = {}
|
131
|
-
update opts.merge(:data =>
|
137
|
+
update opts.merge(:data => builder.rollback)
|
132
138
|
end
|
133
139
|
|
134
140
|
# Delete one or many documents by id
|
135
141
|
# solr.delete_by_id 10
|
136
142
|
# solr.delete_by_id([12, 41, 199])
|
137
143
|
def delete_by_id id, opts = {}
|
138
|
-
update opts.merge(:data =>
|
144
|
+
update opts.merge(:data => builder.delete_by_id(id))
|
139
145
|
end
|
140
146
|
|
141
147
|
# delete one or many documents by query.
|
@@ -145,14 +151,25 @@ class RSolr::Client
|
|
145
151
|
# solr.delete_by_query 'available:0'
|
146
152
|
# solr.delete_by_query ['quantity:0', 'manu:"FQ"']
|
147
153
|
def delete_by_query query, opts = {}
|
148
|
-
update opts.merge(:data =>
|
154
|
+
update opts.merge(:data => builder.delete_by_query(query))
|
149
155
|
end
|
150
156
|
|
157
|
+
def builder
|
158
|
+
if @update_format == :json
|
159
|
+
json
|
160
|
+
else
|
161
|
+
xml
|
162
|
+
end
|
163
|
+
end
|
151
164
|
# shortcut to RSolr::Xml::Generator
|
152
165
|
def xml
|
153
166
|
@xml ||= RSolr::Xml::Generator.new
|
154
167
|
end
|
155
168
|
|
169
|
+
def json
|
170
|
+
@json ||= RSolr::JSON::Generator.new
|
171
|
+
end
|
172
|
+
|
156
173
|
# +send_and_receive+ is the main request method responsible for sending requests to the +connection+ object.
|
157
174
|
#
|
158
175
|
# "path" : A string value that usually represents a solr request handler
|
@@ -177,48 +194,21 @@ class RSolr::Client
|
|
177
194
|
|
178
195
|
#
|
179
196
|
def execute request_context
|
197
|
+
raw_response = begin
|
198
|
+
response = connection.send(request_context[:method], request_context[:uri].to_s) do |req|
|
199
|
+
req.body = request_context[:data] if request_context[:method] == :post and request_context[:data]
|
200
|
+
req.headers.merge!(request_context[:headers]) if request_context[:headers]
|
201
|
+
end
|
180
202
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
raw_response = connection.execute self, request_context
|
203
|
+
{ status: response.status.to_i, headers: response.headers, body: response.body.force_encoding('utf-8') }
|
204
|
+
rescue Faraday::ClientError => e
|
205
|
+
raise RSolr::Error::Http.new(request_context, e.response)
|
206
|
+
rescue Errno::ECONNREFUSED
|
207
|
+
raise RSolr::Error::ConnectionRefused, request_context.inspect
|
187
208
|
end
|
188
|
-
|
189
209
|
adapt_response(request_context, raw_response) unless raw_response.nil?
|
190
210
|
end
|
191
211
|
|
192
|
-
def retry_503?(request_context, response)
|
193
|
-
return false if response.nil?
|
194
|
-
status = response[:status] && response[:status].to_i
|
195
|
-
return false unless status == 503
|
196
|
-
retry_503 = request_context[:retry_503]
|
197
|
-
return false unless retry_503 && retry_503 > 0
|
198
|
-
retry_after_limit = request_context[:retry_after_limit] || 1
|
199
|
-
retry_after = retry_after(response)
|
200
|
-
return false unless retry_after && retry_after <= retry_after_limit
|
201
|
-
true
|
202
|
-
end
|
203
|
-
|
204
|
-
# Retry-After can be a relative number of seconds from now, or an RFC 1123 Date.
|
205
|
-
# If the latter, attempt to convert it to a relative time in seconds.
|
206
|
-
def retry_after(response)
|
207
|
-
retry_after = Array(response[:headers]['Retry-After'] || response[:headers]['retry-after']).flatten.first.to_s
|
208
|
-
if retry_after =~ /\A[0-9]+\Z/
|
209
|
-
retry_after = retry_after.to_i
|
210
|
-
else
|
211
|
-
begin
|
212
|
-
retry_after_date = DateTime.parse(retry_after)
|
213
|
-
retry_after = retry_after_date.to_time - Time.now
|
214
|
-
retry_after = nil if retry_after < 0
|
215
|
-
rescue ArgumentError
|
216
|
-
retry_after = retry_after.to_i
|
217
|
-
end
|
218
|
-
end
|
219
|
-
retry_after
|
220
|
-
end
|
221
|
-
|
222
212
|
# +build_request+ accepts a path and options hash,
|
223
213
|
# then prepares a normalized hash to return for sending
|
224
214
|
# to a solr connection driver.
|
@@ -250,10 +240,6 @@ class RSolr::Client
|
|
250
240
|
opts[:path] = path
|
251
241
|
opts[:uri] = base_uri.merge(path.to_s + (query ? "?#{query}" : "")) if base_uri
|
252
242
|
|
253
|
-
[:open_timeout, :read_timeout, :retry_503, :retry_after_limit].each do |k|
|
254
|
-
opts[k] = @options[k]
|
255
|
-
end
|
256
|
-
|
257
243
|
opts
|
258
244
|
end
|
259
245
|
|
@@ -285,7 +271,6 @@ class RSolr::Client
|
|
285
271
|
def adapt_response request, response
|
286
272
|
raise "The response does not have the correct keys => :body, :headers, :status" unless
|
287
273
|
%W(body headers status) == response.keys.map{|k|k.to_s}.sort
|
288
|
-
raise RSolr::Error::Http.new request, response unless [200,302].include? response[:status]
|
289
274
|
|
290
275
|
result = if respond_to? "evaluate_#{request[:params][:wt]}_response", true
|
291
276
|
send "evaluate_#{request[:params][:wt]}_response", request, response
|
@@ -299,6 +284,25 @@ class RSolr::Client
|
|
299
284
|
|
300
285
|
result
|
301
286
|
end
|
287
|
+
|
288
|
+
def connection
|
289
|
+
@connection ||= begin
|
290
|
+
conn_opts = { request: {} }
|
291
|
+
conn_opts[:proxy] = proxy if proxy
|
292
|
+
conn_opts[:request][:open_timeout] = options[:open_timeout] if options[:open_timeout]
|
293
|
+
conn_opts[:request][:timeout] = options[:read_timeout] if options[:read_timeout]
|
294
|
+
conn_opts[:request][:params_encoder] = Faraday::FlatParamsEncoder
|
295
|
+
|
296
|
+
Faraday.new(conn_opts) do |conn|
|
297
|
+
conn.basic_auth(uri.user, uri.password) if uri.user && uri.password
|
298
|
+
conn.response :raise_error
|
299
|
+
conn.request :retry, max: options[:retry_after_limit], interval: 0.05,
|
300
|
+
interval_randomness: 0.5, backoff_factor: 2,
|
301
|
+
exceptions: ['Faraday::Error', 'Timeout::Error'] if options[:retry_503]
|
302
|
+
conn.adapter options[:adapter] || Faraday.default_adapter
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
302
306
|
|
303
307
|
protected
|
304
308
|
|
@@ -319,21 +323,17 @@ class RSolr::Client
|
|
319
323
|
# instead, giving full access to the
|
320
324
|
# request/response objects.
|
321
325
|
def evaluate_ruby_response request, response
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
raise RSolr::Error::InvalidRubyResponse.new request, response
|
326
|
-
end
|
326
|
+
Kernel.eval response[:body].to_s
|
327
|
+
rescue SyntaxError
|
328
|
+
raise RSolr::Error::InvalidRubyResponse.new request, response
|
327
329
|
end
|
328
330
|
|
329
331
|
def evaluate_json_response request, response
|
330
|
-
return response[:body]
|
332
|
+
return if response[:body].nil? || response[:body].empty?
|
331
333
|
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
raise RSolr::Error::InvalidJsonResponse.new request, response
|
336
|
-
end
|
334
|
+
JSON.parse response[:body].to_s
|
335
|
+
rescue JSON::ParserError
|
336
|
+
raise RSolr::Error::InvalidJsonResponse.new request, response
|
337
337
|
end
|
338
338
|
|
339
339
|
def default_wt
|
@@ -0,0 +1,161 @@
|
|
1
|
+
module RSolr
|
2
|
+
class Document
|
3
|
+
CHILD_DOCUMENT_KEY = '_childDocuments_'.freeze
|
4
|
+
|
5
|
+
# "attrs" is a hash for setting the "doc" xml attributes
|
6
|
+
# "fields" is an array of Field objects
|
7
|
+
attr_accessor :attrs, :fields
|
8
|
+
|
9
|
+
# "doc_hash" must be a Hash/Mash object
|
10
|
+
# If a value in the "doc_hash" is an array,
|
11
|
+
# a field object is created for each value...
|
12
|
+
def initialize(doc_hash = {})
|
13
|
+
@fields = []
|
14
|
+
doc_hash.each_pair do |field, values|
|
15
|
+
add_field(field, values)
|
16
|
+
end
|
17
|
+
@attrs={}
|
18
|
+
end
|
19
|
+
|
20
|
+
# returns an array of fields that match the "name" arg
|
21
|
+
def fields_by_name(name)
|
22
|
+
@fields.select{|f|f.name==name}
|
23
|
+
end
|
24
|
+
|
25
|
+
# returns the *first* field that matches the "name" arg
|
26
|
+
def field_by_name(name)
|
27
|
+
@fields.detect{|f|f.name==name}
|
28
|
+
end
|
29
|
+
|
30
|
+
#
|
31
|
+
# Add a field value to the document. Options map directly to
|
32
|
+
# XML attributes in the Solr <field> node.
|
33
|
+
# See http://wiki.apache.org/solr/UpdateXmlMessages#head-8315b8028923d028950ff750a57ee22cbf7977c6
|
34
|
+
#
|
35
|
+
# === Example:
|
36
|
+
#
|
37
|
+
# document.add_field('title', 'A Title', :boost => 2.0)
|
38
|
+
#
|
39
|
+
def add_field(name, values, options = {})
|
40
|
+
wrap(values).each do |v|
|
41
|
+
next if v.nil?
|
42
|
+
|
43
|
+
field_attrs = { name: name }
|
44
|
+
field_attrs[:type] = DocumentField if name.to_s == CHILD_DOCUMENT_KEY
|
45
|
+
|
46
|
+
@fields << RSolr::Field.instance(options.merge(field_attrs), v)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def as_json
|
51
|
+
@fields.group_by(&:name).each_with_object({}) do |(field, values), result|
|
52
|
+
v = values.map(&:as_json)
|
53
|
+
v = v.first if v.length == 1
|
54
|
+
result[field] = v
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def wrap(object)
|
61
|
+
if object.nil?
|
62
|
+
[]
|
63
|
+
elsif object.respond_to?(:to_ary)
|
64
|
+
object.to_ary || [object]
|
65
|
+
elsif object.is_a? Hash
|
66
|
+
[object]
|
67
|
+
elsif object.is_a? Enumerable
|
68
|
+
object
|
69
|
+
else
|
70
|
+
[object]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class Field
|
76
|
+
|
77
|
+
def self.instance(attrs, value)
|
78
|
+
attrs = attrs.dup
|
79
|
+
field_type = attrs.delete(:type) { value.class.name }
|
80
|
+
|
81
|
+
klass = if field_type.is_a? String
|
82
|
+
class_for_field(field_type)
|
83
|
+
elsif field_type.is_a? Class
|
84
|
+
field_type
|
85
|
+
else
|
86
|
+
self
|
87
|
+
end
|
88
|
+
|
89
|
+
klass.new(attrs, value)
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.class_for_field(field_type)
|
93
|
+
potential_class_name = field_type + 'Field'.freeze
|
94
|
+
search_scope = Module.nesting[1]
|
95
|
+
search_scope.const_defined?(potential_class_name, false) ? search_scope.const_get(potential_class_name) : self
|
96
|
+
end
|
97
|
+
private_class_method :class_for_field
|
98
|
+
|
99
|
+
# "attrs" is a hash for setting the "doc" xml attributes
|
100
|
+
# "value" is the text value for the node
|
101
|
+
attr_accessor :attrs, :source_value
|
102
|
+
|
103
|
+
# "attrs" must be a hash
|
104
|
+
# "value" should be something that responds to #_to_s
|
105
|
+
def initialize(attrs, source_value)
|
106
|
+
@attrs = attrs
|
107
|
+
@source_value = source_value
|
108
|
+
end
|
109
|
+
|
110
|
+
# the value of the "name" attribute
|
111
|
+
def name
|
112
|
+
attrs[:name]
|
113
|
+
end
|
114
|
+
|
115
|
+
def value
|
116
|
+
source_value
|
117
|
+
end
|
118
|
+
|
119
|
+
def as_json
|
120
|
+
if attrs[:update]
|
121
|
+
{ attrs[:update] => value }
|
122
|
+
elsif attrs.any? { |k, _| k != :name }
|
123
|
+
hash = attrs.dup
|
124
|
+
hash.delete(:name)
|
125
|
+
hash.merge(value: value)
|
126
|
+
else
|
127
|
+
value
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
class DateField < Field
|
133
|
+
def value
|
134
|
+
Time.utc(source_value.year, source_value.mon, source_value.mday).iso8601
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
class TimeField < Field
|
139
|
+
def value
|
140
|
+
source_value.getutc.strftime('%FT%TZ')
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
class DateTimeField < Field
|
145
|
+
def value
|
146
|
+
source_value.to_time.getutc.iso8601
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
class DocumentField < Field
|
151
|
+
def value
|
152
|
+
return RSolr::Document.new(source_value) if source_value.respond_to? :each_pair
|
153
|
+
|
154
|
+
super
|
155
|
+
end
|
156
|
+
|
157
|
+
def as_json
|
158
|
+
value.as_json
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
data/lib/rsolr/json.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
module RSolr::JSON
|
2
|
+
class Generator
|
3
|
+
def add data, add_attrs = {}
|
4
|
+
add_attrs ||= {}
|
5
|
+
data = [data] unless data.is_a?(Array)
|
6
|
+
|
7
|
+
if add_attrs.empty? && data.none? { |doc| doc.is_a?(RSolr::Document) && !doc.attrs.empty? }
|
8
|
+
data.map do |doc|
|
9
|
+
doc = RSolr::Document.new(doc) if doc.respond_to?(:each_pair)
|
10
|
+
yield doc if block_given?
|
11
|
+
doc.as_json
|
12
|
+
end.to_json
|
13
|
+
else
|
14
|
+
i = 0
|
15
|
+
data.each_with_object({}) do |doc, hash|
|
16
|
+
doc = RSolr::Document.new(doc) if doc.respond_to?(:each_pair)
|
17
|
+
yield doc if block_given?
|
18
|
+
hash["add__UNIQUE_RSOLR_SUFFIX_#{i += 1}"] = add_attrs.merge(doc.attrs).merge(doc: doc.as_json)
|
19
|
+
end.to_json.gsub(/__UNIQUE_RSOLR_SUFFIX_\d+/, '')
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# generates a commit message
|
24
|
+
def commit(opts = {})
|
25
|
+
opts ||= {}
|
26
|
+
{ commit: opts }.to_json
|
27
|
+
end
|
28
|
+
|
29
|
+
# generates a optimize message
|
30
|
+
def optimize(opts = {})
|
31
|
+
opts ||= {}
|
32
|
+
{ optimize: opts }.to_json
|
33
|
+
end
|
34
|
+
|
35
|
+
# generates a rollback message
|
36
|
+
def rollback
|
37
|
+
{ rollback: {} }.to_json
|
38
|
+
end
|
39
|
+
|
40
|
+
# generates a delete message
|
41
|
+
# "ids" can be a single value or array of values
|
42
|
+
def delete_by_id(ids)
|
43
|
+
{ delete: ids }.to_json
|
44
|
+
end
|
45
|
+
|
46
|
+
# generates a delete message
|
47
|
+
# "queries" can be a single value or an array of values
|
48
|
+
def delete_by_query(queries)
|
49
|
+
{ delete: { query: queries } }.to_json
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/rsolr/uri.rb
CHANGED
@@ -1,11 +1,6 @@
|
|
1
1
|
require 'uri'
|
2
2
|
|
3
3
|
module RSolr::Uri
|
4
|
-
|
5
|
-
def create url
|
6
|
-
::URI.parse (url[-1] == '/' || URI.parse(url).query) ? url : "#{url}/"
|
7
|
-
end
|
8
|
-
|
9
4
|
# Creates a Solr based query string.
|
10
5
|
# Keys that have arrays values are set multiple times:
|
11
6
|
# params_to_solr(:q => 'query', :fq => ['a', 'b'])
|
@@ -13,7 +8,7 @@ module RSolr::Uri
|
|
13
8
|
# ?q=query&fq=a&fq=b
|
14
9
|
# @param [boolean] escape false if no URI escaping is to be performed. Default true.
|
15
10
|
# @return [String] Solr query params as a String, suitable for use in a url
|
16
|
-
def params_to_solr(params, escape = true)
|
11
|
+
def self.params_to_solr(params, escape = true)
|
17
12
|
return URI.encode_www_form(params.reject{|k,v| k.to_s.empty? || v.to_s.empty?}) if escape
|
18
13
|
|
19
14
|
# escape = false if we are here
|
@@ -27,49 +22,4 @@ module RSolr::Uri
|
|
27
22
|
end
|
28
23
|
mapped.compact.join("&")
|
29
24
|
end
|
30
|
-
|
31
|
-
# Returns a query string param pair as a string.
|
32
|
-
# Both key and value are URI escaped, unless third param is false
|
33
|
-
# @param [boolean] escape false if no URI escaping is to be performed. Default true.
|
34
|
-
# @deprecated - used to be called from params_to_solr before 2015-02-25
|
35
|
-
def build_param(k, v, escape = true)
|
36
|
-
warn "[DEPRECATION] `RSolr::Uri.build_param` is deprecated. Use `URI.encode_www_form_component` or k=v instead."
|
37
|
-
escape ?
|
38
|
-
"#{URI.encode_www_form_component(k)}=#{URI.encode_www_form_component(v)}" :
|
39
|
-
"#{k}=#{v}"
|
40
|
-
end
|
41
|
-
|
42
|
-
# 2015-02 Deprecated: use URI.encode_www_form_component(s)
|
43
|
-
#
|
44
|
-
# Performs URI escaping so that you can construct proper
|
45
|
-
# query strings faster. Use this rather than the cgi.rb
|
46
|
-
# version since it's faster.
|
47
|
-
# (Stolen from Rack).
|
48
|
-
# http://www.rubydoc.info/github/rack/rack/URI.encode_www_form_component
|
49
|
-
# @deprecated
|
50
|
-
def escape_query_value(s)
|
51
|
-
warn "[DEPRECATION] `RSolr::Uri.escape_query_value` is deprecated. Use `URI.encode_www_form_component` instead."
|
52
|
-
URI.encode_www_form_component(s)
|
53
|
-
# s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/u) {
|
54
|
-
# '%'+$1.unpack('H2'*bytesize($1)).join('%').upcase
|
55
|
-
# }.tr(' ', '+')
|
56
|
-
end
|
57
|
-
|
58
|
-
# Return the bytesize of String; uses String#size under Ruby 1.8 and
|
59
|
-
# String#bytesize under 1.9.
|
60
|
-
# @deprecated as bytesize was only used by escape_query_value which is itself deprecated
|
61
|
-
if ''.respond_to?(:bytesize)
|
62
|
-
def bytesize(string)
|
63
|
-
warn "[DEPRECATION] `RSolr::Uri.bytesize` is deprecated. Use String.bytesize"
|
64
|
-
string.bytesize
|
65
|
-
end
|
66
|
-
else
|
67
|
-
def bytesize(string)
|
68
|
-
warn "[DEPRECATION] `RSolr::Uri.bytesize` is deprecated. Use String.size"
|
69
|
-
string.size
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
extend self
|
74
|
-
|
75
25
|
end
|
data/lib/rsolr/version.rb
CHANGED