rsolr 2.2.0 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3b30bc226e290ec41e124233b38c4ff9e3e2a262d7d25fb940c10952c04cdbbe
4
- data.tar.gz: 2b0a15cdee7a2c61f9732381f7e38cd0b1345bd2d9f25efc48e57a9609af32ec
3
+ metadata.gz: f44e7e34b8e615204b49052907e322c46387d858f147b7e34bd4c53edf6b336e
4
+ data.tar.gz: b5ad262ba4b5777f18b817c529f9cb8768843972f394420a4798191f92a11b17
5
5
  SHA512:
6
- metadata.gz: 168b8ba13fa7eedfdba1de36af07e1a65d59545506368573423470a075740d47b5e025dc6ba9f78b74fc6b945d24f3a9bca8b3fdf97469644e7480459db1c115
7
- data.tar.gz: 2f4b142ff6b729451bfbac58c49775c8bc221dbaee074e9417ce1edd28ebaf5f8c07687286b001ef5411d35e6a9915fa48d4d3db585a6b6b90ac2b1c25b16129
6
+ metadata.gz: c230788c63b34623fa05608af73c25c5c7bd6fbab106afc62c63b1347a688bf302d0b03323204b0efd047f01ddc2d957722cd5ed0f98553ec3974b7ed2653c79
7
+ data.tar.gz: 606324146e3acb8cb86c726a528550fefd0bd57fdebce977fc260c5a38caf4b1c5aeca7c3f23637dcf4bf04e8fbc196e60e4cc63f9827ee7e88af01e816ce3a4
@@ -0,0 +1,44 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+ branches: [ master ]
8
+
9
+ jobs:
10
+ tests:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ ruby: [jruby-9.3.3.0, 2.7, '3.0', '3.1']
15
+ faraday: ['~> 0.17', '~> 1', '~>2']
16
+ steps:
17
+ - uses: actions/checkout@v2
18
+ - name: Set up Ruby
19
+ uses: ruby/setup-ruby@v1
20
+ with:
21
+ ruby-version: ${{ matrix.ruby }}
22
+ - name: Install dependencies
23
+ run: bundle install
24
+ env:
25
+ FARADAY_VERSION: ${{ matrix.faraday}}
26
+ - name: Run tests
27
+ run: bundle exec rake
28
+ env:
29
+ FARADAY_VERSION: ${{ matrix.faraday}}
30
+ legacy_tests:
31
+ runs-on: ubuntu-latest
32
+ strategy:
33
+ matrix:
34
+ ruby: [jruby-9.2.20.0, 2.4, 2.5, 2.6, 2.7]
35
+ steps:
36
+ - uses: actions/checkout@v2
37
+ - name: Set up Ruby
38
+ uses: ruby/setup-ruby@v1
39
+ with:
40
+ ruby-version: ${{ matrix.ruby }}
41
+ - name: Install dependencies
42
+ run: bundle install
43
+ - name: Run tests
44
+ run: bundle exec rake
data/CHANGES.txt CHANGED
@@ -1,3 +1,29 @@
1
+ 2.4.0
2
+
3
+ - Raise specific timeout error for solr timeouts. https://github.com/rsolr/rsolr/pull/214
4
+ - Pass `timeout` RSolr configuration through to Faraday, deprecate `read_timeout` Rsolr configuration. https://github.com/rsolr/rsolr/pull/215
5
+ - Better visibility of Solr error message in `RSolr::Error`. https://github.com/rsolr/rsolr/pull/222
6
+ - Add soft-commit function https://github.com/rsolr/rsolr/pull/210 (thanks @giteshnandre)
7
+ - Avoid encoding exception in error message display https://github.com/rsolr/rsolr/pull/208 (thanks @expajp)
8
+ - Fix JSON generator for atomic updates of array fields https://github.com/rsolr/rsolr/pull/201 (thanks @serggl)
9
+
10
+
11
+ 2.3.0
12
+
13
+ - Sorry, not human-edited: https://github.com/rsolr/rsolr/compare/v2.2.0...v2.3.0
14
+
15
+ 2.2.0
16
+
17
+ - Sorry, not human-edited: https://github.com/rsolr/rsolr/compare/v2.1.0...v2.2.0
18
+
19
+ 2.1.0
20
+
21
+ - Sorry, not human-edited: https://github.com/rsolr/rsolr/compare/v2.0.0...v2.1.0
22
+
23
+ 2.0.0
24
+
25
+ - Sorry, not human-edited: https://github.com/rsolr/rsolr/compare/v2.0.0.pre1...v2.0.0
26
+
1
27
  2.0.0.pre1
2
28
 
3
29
  In this release, we've added many new features, including:
data/Gemfile CHANGED
@@ -3,3 +3,11 @@ source "https://rubygems.org"
3
3
  gemspec
4
4
 
5
5
  gem "builder", ">= 2.1.2"
6
+
7
+ if defined? JRUBY_VERSION
8
+ # HTTP.rb (used by solr_wrapper to download solr for integration testing) fails
9
+ # to download the full contents of files (under jruby)?
10
+ gem "http", '< 5', platforms: :jruby
11
+ end
12
+
13
+ gem 'faraday', ENV['FARADAY_VERSION'] if ENV['FARADAY_VERSION']
data/README.rdoc CHANGED
@@ -1,6 +1,4 @@
1
1
  =RSolr
2
- {<img src="https://travis-ci.org/rsolr/rsolr.svg?branch=master" alt="Build Status" />}[https://travis-ci.org/rsolr/rsolr] {<img src="https://badge.fury.io/rb/rsolr.svg" alt="Gem Version" />}[http://badge.fury.io/rb/rsolr]
3
-
4
2
 
5
3
  A simple, extensible Ruby client for Apache Solr.
6
4
 
@@ -12,26 +10,26 @@ The code docs http://www.rubydoc.info/gems/rsolr
12
10
 
13
11
  == Example:
14
12
  require 'rsolr'
15
-
13
+
16
14
  # Direct connection
17
15
  solr = RSolr.connect :url => 'http://solrserver.com'
18
-
16
+
19
17
  # Connecting over a proxy server
20
18
  solr = RSolr.connect :url => 'http://solrserver.com', :proxy=>'http://user:pass@proxy.example.com:8080'
21
19
 
22
20
  # Using an alternate Faraday adapter
23
21
  solr = RSolr.connect :url => 'http://solrserver.com', :adapter => :em_http
24
-
22
+
25
23
  # Using a custom Faraday connection
26
24
  conn = Faraday.new do |faraday|
27
25
  faraday.response :logger # log requests to STDOUT
28
26
  faraday.adapter Faraday.default_adapter # make requests with Net::HTTP
29
27
  end
30
28
  solr = RSolr.connect conn, :url => 'http://solrserver.com'
31
-
29
+
32
30
  # send a request to /select
33
31
  response = solr.get 'select', :params => {:q => '*:*'}
34
-
32
+
35
33
  # send a request to /catalog
36
34
  response = solr.get 'catalog', :params => {:q => '*:*'}
37
35
 
@@ -52,8 +50,10 @@ By default, RSolr uses the Solr JSON command format for all requests.
52
50
  RSolr.connect :url => 'http://solrserver.com', update_format: :xml
53
51
 
54
52
  == Timeouts
55
- The read and connect timeout settings can be set when creating a new instance of RSolr:
56
- solr = RSolr.connect(:read_timeout => 120, :open_timeout => 120)
53
+ The read and connect timeout settings can be set when creating a new instance of RSolr, and will
54
+ be passed on to underlying Faraday instance:
55
+
56
+ solr = RSolr.connect(:timeout => 120, :open_timeout => 120)
57
57
 
58
58
  == Retry 503s
59
59
  A 503 is usually a temporary error which RSolr may retry if requested. You may specify the number of retry attempts with the +:retry_503+ option.
@@ -74,11 +74,11 @@ Use the #get / #post method to send search requests to the /select handler:
74
74
 
75
75
  The +:params+ sent into the method are sent to Solr as-is, which is to say they are converted to Solr url style, but no special mapping is used.
76
76
  When an array is used, multiple parameters *with the same name* are generated for the Solr query. Example:
77
-
77
+
78
78
  solr.get 'select', :params => {:q=>'roses', :fq=>['red', 'violet']}
79
79
 
80
80
  The above statement generates this Solr query:
81
-
81
+
82
82
  select?q=roses&fq=red&fq=violet
83
83
 
84
84
  ===Pagination
@@ -92,14 +92,14 @@ The paginate method returns WillPaginate ready "docs" objects, so for example in
92
92
 
93
93
  ===Method Missing
94
94
  The +RSolr::Client+ class also uses +method_missing+ for setting the request handler/path:
95
-
95
+
96
96
  solr.paintings :params => {:q=>'roses', :fq=>['red', 'violet']}
97
-
97
+
98
98
  This is sent to Solr as:
99
99
  paintings?q=roses&fq=red&fq=violet
100
100
 
101
101
  This works with pagination as well:
102
-
102
+
103
103
  solr.paginate_paintings 1, 10, {:q=>'roses', :fq=>['red', 'violet']}
104
104
 
105
105
  ===Using POST for Search Queries
@@ -120,10 +120,10 @@ To send header information to Solr using RSolr, just use the +:headers+ option:
120
120
  ===Building a Request
121
121
  +RSolr::Client+ provides a method for building a request context, which can be useful for debugging or logging etc.:
122
122
  request_context = solr.build_request "select", :data => {:q => "*:*"}, :method => :post, :headers => {}
123
-
123
+
124
124
  To build a paginated request use build_paginated_request:
125
125
  request_context = solr.build_paginated_request 1, 10, "select", ...
126
-
126
+
127
127
  == Updating Solr
128
128
  Updating is done using native Ruby objects. Hashes are used for single documents and arrays are used for a collection of documents (hashes). These objects get turned into simple XML "messages". Raw XML strings can also be used.
129
129
 
@@ -142,7 +142,7 @@ Raw commands via #update
142
142
  solr.update data: { optimize: true }.to_json, headers: { 'Content-Type' => 'application/json' }
143
143
 
144
144
  When adding, you can also supply "add" xml element attributes and/or a block for manipulating other "add" related elements (docs and fields) by calling the +xml+ method directly:
145
-
145
+
146
146
  doc = {:id=>1, :price=>1.00}
147
147
  add_attributes = {:allowDups=>false, :commitWithin=>10}
148
148
  add_xml = solr.xml.add(doc, add_attributes) do |doc|
data/lib/rsolr/client.rb CHANGED
@@ -35,6 +35,10 @@ class RSolr::Client
35
35
  @update_format = options.delete(:update_format) || RSolr::JSON::Generator
36
36
  @update_path = options.fetch(:update_path, 'update')
37
37
  @options = options
38
+
39
+ if options[:read_timeout]
40
+ warn "DEPRECATION: Rsolr.new/connect option `read_timeout` is deprecated and will be removed in Rsolr 3. `timeout` is currently a synonym, use that instead."
41
+ end
38
42
  end
39
43
 
40
44
  def extract_url_from_options(options)
@@ -122,6 +126,14 @@ class RSolr::Client
122
126
  update opts.merge(:data => builder.commit( commit_attrs ))
123
127
  end
124
128
 
129
+ # soft commit
130
+ #
131
+ # https://lucene.apache.org/solr/guide/updatehandlers-in-solrconfig.html#commit-and-softcommit
132
+ #
133
+ def soft_commit opts = {}
134
+ commit(opts.merge params: { softCommit: true })
135
+ end
136
+
125
137
  # send "optimize" xml with opts.
126
138
  #
127
139
  # http://wiki.apache.org/solr/UpdateXmlMessages#A.22commit.22_and_.22optimize.22
@@ -200,7 +212,9 @@ class RSolr::Client
200
212
  end
201
213
 
202
214
  { status: response.status.to_i, headers: response.headers, body: response.body.force_encoding('utf-8') }
203
- rescue Errno::ECONNREFUSED, Faraday::Error::ConnectionFailed
215
+ rescue Faraday::TimeoutError => e
216
+ raise RSolr::Error::Timeout.new(request_context, e.response)
217
+ rescue Errno::ECONNREFUSED, defined?(Faraday::ConnectionFailed) ? Faraday::ConnectionFailed : Faraday::Error::ConnectionFailed
204
218
  raise RSolr::Error::ConnectionRefused, request_context.inspect
205
219
  rescue Faraday::Error => e
206
220
  raise RSolr::Error::Http.new(request_context, e.response)
@@ -283,23 +297,39 @@ class RSolr::Client
283
297
 
284
298
  result
285
299
  end
286
-
300
+
287
301
  def connection
288
302
  @connection ||= begin
289
303
  conn_opts = { request: {} }
290
304
  conn_opts[:url] = uri.to_s
291
305
  conn_opts[:proxy] = proxy if proxy
292
306
  conn_opts[:request][:open_timeout] = options[:open_timeout] if options[:open_timeout]
293
- conn_opts[:request][:timeout] = options[:read_timeout] if options[:read_timeout]
307
+
308
+ if options[:read_timeout] || options[:timeout]
309
+ # read_timeout was being passed to faraday as timeout since Rsolr 2.0,
310
+ # it's now deprecated, just use `timeout` directly.
311
+ conn_opts[:request][:timeout] = options[:timeout] || options[:read_timeout]
312
+ end
313
+
294
314
  conn_opts[:request][:params_encoder] = Faraday::FlatParamsEncoder
295
315
 
296
316
  Faraday.new(conn_opts) do |conn|
297
- conn.basic_auth(uri.user, uri.password) if uri.user && uri.password
317
+ if uri.user && uri.password
318
+ case Faraday::VERSION
319
+ when /^0/
320
+ conn.basic_auth uri.user, uri.password
321
+ when /^1/
322
+ conn.request :basic_auth, uri.user, uri.password
323
+ else
324
+ conn.request :authorization, :basic_auth, uri.user, uri.password
325
+ end
326
+ end
327
+
298
328
  conn.response :raise_error
299
329
  conn.request :retry, max: options[:retry_after_limit], interval: 0.05,
300
330
  interval_randomness: 0.5, backoff_factor: 2,
301
331
  exceptions: ['Faraday::Error', 'Timeout::Error'] if options[:retry_503]
302
- conn.adapter options[:adapter] || Faraday.default_adapter
332
+ conn.adapter options[:adapter] || Faraday.default_adapter || :net_http
303
333
  end
304
334
  end
305
335
  end
@@ -1,6 +1,7 @@
1
1
  module RSolr
2
2
  class Document
3
3
  CHILD_DOCUMENT_KEY = '_childDocuments_'.freeze
4
+ ATOMIC_MULTI_VALUE_OPERATIONS = %i[set add add-distinct remove]
4
5
 
5
6
  # "attrs" is a hash for setting the "doc" xml attributes
6
7
  # "fields" is an array of Field objects
@@ -48,8 +49,14 @@ module RSolr
48
49
  def as_json
49
50
  @fields.group_by(&:name).each_with_object({}) do |(field, values), result|
50
51
  v = values.map(&:as_json)
51
- if v.length > 1 && v.first.is_a?(Hash) && v.first[:value]
52
- v = v.first.merge(value: v.map { |single| single[:value] })
52
+ if v.length > 1 && v.first.is_a?(Hash)
53
+ if v.first.key?(:value)
54
+ v = v.first.merge(value: v.map { |single| single[:value] })
55
+ else
56
+ (v.first.keys & ATOMIC_MULTI_VALUE_OPERATIONS).each do |op|
57
+ v = [{ op => v.map { |single| single[op] } }]
58
+ end
59
+ end
53
60
  end
54
61
  v = v.first if v.length == 1 && field.to_s != CHILD_DOCUMENT_KEY
55
62
  result[field] = v
data/lib/rsolr/error.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'json'
2
+
1
3
  module RSolr::Error
2
4
 
3
5
  module SolrContext
@@ -24,6 +26,18 @@ module RSolr::Error
24
26
 
25
27
  def parse_solr_error_response body
26
28
  begin
29
+ # Default JSON response, try to parse and retrieve error message
30
+ if response[:headers] && response[:headers]["content-type"].start_with?("application/json")
31
+ begin
32
+ parsed_body = JSON.parse(body)
33
+ info = parsed_body && parsed_body["error"] && parsed_body["error"]["msg"]
34
+ rescue JSON::ParserError
35
+ end
36
+ end
37
+ return info if info
38
+
39
+ # legacy analysis, I think trying to handle wt=ruby responses without
40
+ # a full parse?
27
41
  if body =~ /<pre>/
28
42
  info = body.scan(/<pre>(.*)<\/pre>/mi)[0]
29
43
  elsif body =~ /'msg'=>/
@@ -110,9 +124,16 @@ module RSolr::Error
110
124
  }
111
125
 
112
126
  def initialize request, response
127
+ response = response_with_force_encoded_body(response)
113
128
  @request, @response = request, response
114
129
  end
115
130
 
131
+ private
132
+
133
+ def response_with_force_encoded_body(response)
134
+ response[:body] = response[:body].force_encoding('UTF-8') if response
135
+ response
136
+ end
116
137
  end
117
138
 
118
139
  # Thrown if the :wt is :ruby
@@ -121,6 +142,15 @@ module RSolr::Error
121
142
 
122
143
  end
123
144
 
145
+ # Subclasses Rsolr::Error::Http for legacy backwards compatibility
146
+ # purposes, because earlier RSolr 2 didn't distinguish these
147
+ # from Http errors.
148
+ #
149
+ # In RSolr 3, it could make sense to `< Timeout::Error` instead,
150
+ # analagous to ConnectionRefused above
151
+ class Timeout < Http
152
+ end
153
+
124
154
  # Thrown if the :wt is :ruby
125
155
  # but the body wasn't succesfully parsed/evaluated
126
156
  class InvalidJsonResponse < InvalidResponse
data/lib/rsolr/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module RSolr
2
- VERSION = "2.2.0"
2
+ VERSION = "2.5.0"
3
3
 
4
4
  def self.version
5
5
  VERSION
data/rsolr.gemspec CHANGED
@@ -23,18 +23,17 @@ Gem::Specification.new do |s|
23
23
  s.email = ["goodieboy@gmail.com"]
24
24
  s.license = 'Apache-2.0'
25
25
  s.homepage = "https://github.com/rsolr/rsolr"
26
- s.rubyforge_project = "rsolr"
27
26
  s.files = `git ls-files`.split("\n")
28
27
  s.test_files = `git ls-files -- {spec}/*`.split("\n")
29
28
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
30
29
  s.require_paths = ["lib"]
31
-
30
+
32
31
  s.required_ruby_version = '>= 1.9.3'
33
-
32
+
34
33
  s.requirements << 'Apache Solr'
35
34
 
36
35
  s.add_dependency 'builder', '>= 2.1.2'
37
- s.add_dependency 'faraday', '>= 0.9.0'
36
+ s.add_dependency 'faraday', '>= 0.9', '!= 2.0.0', '< 3'
38
37
 
39
38
  s.add_development_dependency 'activesupport'
40
39
  s.add_development_dependency 'nokogiri', '>= 1.4.0'
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  RSpec.describe RSolr::Client do
4
4
  let(:connection) { nil }
5
5
  let(:url) { "http://localhost:9999/solr" }
6
- let(:connection_options) { { url: url, read_timeout: 42, open_timeout: 43, update_format: :xml } }
6
+ let(:connection_options) { { url: url, update_format: :xml } }
7
7
 
8
8
  let(:client) do
9
9
  RSolr::Client.new connection, connection_options
@@ -71,6 +71,14 @@ RSpec.describe RSolr::Client do
71
71
  end
72
72
  end
73
73
 
74
+ context "execute" do
75
+ it "maps Faraday::TimeoutError to an RSolr::Error::Timeout" do
76
+ allow(client.connection).to receive(:send).and_raise(Faraday::TimeoutError)
77
+
78
+ expect{ client.execute({}) }.to raise_error RSolr::Error::Timeout
79
+ end
80
+ end
81
+
74
82
  context "post" do
75
83
  it "should pass the expected params to the connection's #execute method" do
76
84
  request_opts = {:data => "the data", :method=>:post, :headers => {"Content-Type" => "text/plain"}}
@@ -109,7 +117,7 @@ RSpec.describe RSolr::Client do
109
117
 
110
118
  context 'when the client is configured for json updates' do
111
119
  let(:client) do
112
- RSolr::Client.new nil, :url => "http://localhost:9999/solr", :read_timeout => 42, :open_timeout=>43, :update_format => :json
120
+ RSolr::Client.new nil, :url => "http://localhost:9999/solr", :update_format => :json
113
121
  end
114
122
  it "should send json to the connection's #post method" do
115
123
  expect(client).to receive(:execute).
@@ -279,6 +287,48 @@ RSpec.describe RSolr::Client do
279
287
 
280
288
  end
281
289
 
290
+ context "commit" do
291
+ it "should add hard commit params for hard commit request" do
292
+ expect(client).to receive(:execute).
293
+ with(
294
+ hash_including({
295
+ :path => "update",
296
+ :headers => {"Content-Type"=>"text/xml"},
297
+ :method => :post,
298
+ :data => "<?xml version=\"1.0\" encoding=\"UTF-8\"?><commit/>",
299
+ :params => {:wt=>:json},
300
+ :query => "wt=json"
301
+ })
302
+ ).
303
+ and_return(
304
+ :body => "",
305
+ :status => 200,
306
+ :headers => {"Content-Type"=>"text/xml"}
307
+ )
308
+ client.commit
309
+ end
310
+
311
+ it "should add soft commit params for soft commit request" do
312
+ expect(client).to receive(:execute).
313
+ with(
314
+ hash_including({
315
+ :path => "update",
316
+ :headers => {"Content-Type"=>"text/xml"},
317
+ :method => :post,
318
+ :data => "<?xml version=\"1.0\" encoding=\"UTF-8\"?><commit/>",
319
+ :params => {:softCommit=>true, :wt=>:json},
320
+ :query => "wt=json&softCommit=true"
321
+ })
322
+ ).
323
+ and_return(
324
+ :body => "",
325
+ :status => 200,
326
+ :headers => {"Content-Type"=>"text/xml"}
327
+ )
328
+ client.soft_commit
329
+ end
330
+ end
331
+
282
332
  context "indifferent access" do
283
333
  it "should raise a RuntimeError if the #with_indifferent_access extension isn't loaded" do
284
334
  hide_const("::RSolr::HashWithIndifferentAccessWithResponse")
@@ -342,7 +392,7 @@ RSpec.describe RSolr::Client do
342
392
  expect(subject[:headers]).to eq({"Content-Type" => "application/x-www-form-urlencoded; charset=UTF-8"})
343
393
  end
344
394
  end
345
-
395
+
346
396
  it "should properly handle proxy configuration" do
347
397
  result = client_with_proxy.build_request('select',
348
398
  :method => :post,
@@ -43,5 +43,107 @@ RSpec.describe RSolr::Error do
43
43
  let(:response_body) { (response_lines << "'error'=>{'msg'=> #{msg}").join("\n") }
44
44
  it { should include msg }
45
45
  end
46
+
47
+ context "when the response body is made of multi-byte chars and encoded by ASCII-8bit" do
48
+ let (:response_lines) { (1..15).to_a.map { |i| "レスポンス #{i}".b } }
49
+
50
+ it "encodes errorlogs by UTF-8" do
51
+ expect(subject.encoding.to_s).to eq 'UTF-8'
52
+ end
53
+ end
54
+ end
55
+
56
+ context "when response is JSON" do
57
+ let(:response) {{
58
+ :body => response_body,
59
+ :status => 500,
60
+ :headers => {
61
+ "content-type" => "application/json;charset=utf-8"
62
+ }
63
+
64
+ }}
65
+
66
+ context "and contains a msg key" do
67
+ let(:msg) { "field 'description_text4_tesim' was indexed without offsets, cannot highlight" }
68
+ let(:response_body) {<<~EOS
69
+ {
70
+ "responseHeader":{
71
+ "status":500,
72
+ "QTime":11,
73
+ "params":{
74
+ "q":"supercali",
75
+ "hl":"true",
76
+ "hl:fl":"description_text4_tesim",
77
+ "hl.method":"unified",
78
+ "hl.offsetSource":"postings"
79
+ }
80
+ },
81
+ "response":{"numFound":0,"start":0,"maxScore":127.32743,"numFoundExact":true,"docs":[]},
82
+ "facet_counts":{
83
+ "facet_queries":{},
84
+ "facet_fields":{}
85
+ },
86
+ "error":{
87
+ "msg":"#{msg}",
88
+ "trace":"java.lang.IllegalArgumentException: field 'description_text4_tesim' was indexed without offsets, cannot highlight\\n\\tat org.apache.lucene.search.uhighlight.FieldHighlighter.highlightOffsetsEnums(FieldHighlighter.java:149)\\n\\tat org.apache.lucene.search.uhighlight.FieldHighlighter.highlightFieldForDoc(FieldHighlighter.java:79)\\n\\tat org.apache.lucene.search.uhighlight.UnifiedHighlighter.highlightFieldsAsObjects(UnifiedHighlighter.java:641)\\n\\tat org.apache.lucene.search.uhighlight.UnifiedHighlighter.highlightFields(UnifiedHighlighter.java:510)\\n\\tat org.apache.solr.highlight.UnifiedSolrHighlighter.doHighlighting(UnifiedSolrHighlighter.java:149)\\n\\tat org.apache.solr.handler.component.HighlightComponent.process(HighlightComponent.java:172)\\n\\tat org.apache.solr.handler.component.SearchHandler.handleRequestBody(SearchHandler.java:331)\\n\\tat org.apache.solr.handler.RequestHandlerBase.handleRequest(RequestHandlerBase.java:214)\\n\\tat org.apache.solr.core.SolrCore.execute(SolrCore.java:2606)\\n\\tat org.apache.solr.servlet.HttpSolrCall.execute(HttpSolrCall.java:815)\\n\\tat org.apache.solr.servlet.HttpSolrCall.call(HttpSolrCall.java:588)\\n\\tat org.apache.solr.servlet.SolrDispatchFilter.doFilter(SolrDispatchFilter.java:415)\\n\\tat org.apache.solr.servlet.SolrDispatchFilter.doFilter(SolrDispatchFilter.java:345)\\n\\tat org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1596)\\n\\tat org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:545)\\n\\tat org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)\\n\\tat org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:590)\\n\\tat org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)\\n\\tat org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:235)\\n\\tat org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1610)\\n\\tat org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233)\\n\\tat org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1300)\\n\\tat org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188)\\n\\tat org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:485)\\n\\tat org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1580)\\n\\tat org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186)\\n\\tat org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1215)\\n\\tat org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)\\n\\tat org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:221)\\n\\tat org.eclipse.jetty.server.handler.InetAccessHandler.handle(InetAccessHandler.java:177)\\n\\tat org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:146)\\n\\tat org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)\\n\\tat org.eclipse.jetty.rewrite.handler.RewriteHandler.handle(RewriteHandler.java:322)\\n\\tat org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)\\n\\tat org.eclipse.jetty.server.Server.handle(Server.java:500)\\n\\tat org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:383)\\n\\tat org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:547)\\n\\tat org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:375)\\n\\tat org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:273)\\n\\tat org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311)\\n\\tat org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103)\\n\\tat org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:117)\\n\\tat org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:336)\\n\\tat org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:313)\\n\\tat org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:171)\\n\\tat org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:129)\\n\\tat org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:375)\\n\\tat org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:806)\\n\\tat org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:938)\\n\\tat java.base/java.lang.Thread.run(Thread.java:834)\\n",
89
+ "code":500
90
+ }
91
+ }
92
+ EOS
93
+ }
94
+ it {
95
+ should include msg
96
+ }
97
+ end
98
+
99
+ context "and does not contain a msg key" do
100
+ let(:response_body) {<<~EOS
101
+ {
102
+ "responseHeader":{
103
+ "status":500,
104
+ "QTime":11,
105
+ "params":{
106
+ "q":"supercali",
107
+ "hl":"true",
108
+ "hl:fl":"description_text4_tesim",
109
+ "hl.method":"unified",
110
+ "hl.offsetSource":"postings"
111
+ }
112
+ },
113
+ "response":{"numFound":0,"start":0,"maxScore":127.32743,"numFoundExact":true,"docs":[]},
114
+ "facet_counts":{
115
+ "facet_queries":{},
116
+ "facet_fields":{}
117
+ },
118
+ }
119
+ EOS
120
+ }
121
+ it "shows the first eleven lines of the response" do
122
+ expect(subject).to include(response_body.split("\n")[0..10].join("\n"))
123
+ expect(subject).not_to include(response_body.split("\n")[11])
124
+ end
125
+ end
126
+
127
+ context "and is not parseable json" do
128
+ let(:response_body) {<<~EOS
129
+ one
130
+ two
131
+ three
132
+ four
133
+ five
134
+ six
135
+ seven
136
+ eight
137
+ nine
138
+ ten
139
+ eleven
140
+ twelve
141
+ EOS
142
+ }
143
+ end
144
+ it "shows the first eleven lines of the response" do
145
+ expect(subject).to include(response_body.split("\n")[0..10].join("\n"))
146
+ expect(subject).not_to include(response_body.split("\n")[11])
147
+ end
46
148
  end
47
149
  end
@@ -150,11 +150,62 @@ RSpec.describe RSolr::JSON do
150
150
  end
151
151
 
152
152
  it 'should create multiple fields from array values with options' do
153
+ test_values = [nil, 'matt1', 'matt2']
153
154
  message = JSON.parse(
154
- generator.add(id: '1') { |doc| doc.add_field(:name, %w[matt1 matt2], boost: 3) },
155
+ generator.add(id: '1') { |doc| doc.add_field(:name, test_values, boost: 3) },
155
156
  symbolize_names: true
156
157
  )
157
- expect(message).to eq [{ id: '1', name: { boost: 3, value: %w[matt1 matt2] } }]
158
+ expect(message).to eq [{ id: '1', name: { boost: 3, value: test_values } }]
159
+ end
160
+
161
+ context 'for atomic updates with arrays' do
162
+ let(:test_values) { %w[value1 value2] }
163
+
164
+ it 'creates single field from array values on SET' do
165
+ expect(
166
+ JSON.parse(
167
+ generator.add(id: 'set-id') { |doc| doc.add_field(:name, test_values, update: :set) },
168
+ symbolize_names: true
169
+ )
170
+ ).to eq [{ id: 'set-id', name: { set: test_values } }]
171
+ end
172
+
173
+ it 'creates single field from array values on ADD' do
174
+ expect(
175
+ JSON.parse(
176
+ generator.add(id: 'add-id') { |doc| doc.add_field(:name, test_values, update: :add) },
177
+ symbolize_names: true
178
+ )
179
+ ).to eq [{ id: 'add-id', name: { add: test_values } }]
180
+ end
181
+
182
+ it 'creates single field from array values on ADD-DISTINCT' do
183
+ expect(
184
+ JSON.parse(
185
+ generator.add(id: 'add-distinct-id') { |doc| doc.add_field(:name, test_values, update: :'add-distinct') },
186
+ symbolize_names: true
187
+ )
188
+ ).to eq [{ id: 'add-distinct-id', name: { 'add-distinct': test_values } }]
189
+ end
190
+
191
+ it 'creates single field from array values on REMOVE' do
192
+ expect(
193
+ JSON.parse(
194
+ generator.add(id: 'remove-id') { |doc| doc.add_field(:name, test_values, update: :remove) },
195
+ symbolize_names: true
196
+ )
197
+ ).to eq [{ id: 'remove-id', name: { remove: test_values } }]
198
+ end
199
+
200
+ it 'creates single field from array values for child document update' do
201
+ test_nested_values = [{id: 1, name: 'value1'}, {id: 1, name: 'value2'}]
202
+ expect(
203
+ JSON.parse(
204
+ generator.add(id: 'set-id') { |doc| doc.add_field(:child_documents, test_nested_values, update: :set) },
205
+ symbolize_names: true
206
+ )
207
+ ).to eq [{ id: 'set-id', child_documents: { set: test_nested_values } }]
208
+ end
158
209
  end
159
210
 
160
211
  describe '#commit' do
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe RSolr::Client do
4
+ describe "#connection" do
5
+ it "accepts a timeout parameter it passes to Faraday" do
6
+ client = described_class.new(nil, timeout: 1000)
7
+
8
+ expect(client.connection.options[:timeout]).to eq 1000
9
+ end
10
+ it "accepts a deprecated read_timeout" do
11
+ client = nil
12
+ expect do
13
+ client = described_class.new(nil, read_timeout: 1000)
14
+ end.to output(/`read_timeout` is deprecated/).to_stderr
15
+
16
+ expect(client.connection.options[:timeout]).to eq 1000
17
+ end
18
+ end
19
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rsolr
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.0
4
+ version: 2.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Antoine Latter
@@ -26,10 +26,10 @@ authors:
26
26
  - Nathan Witmer
27
27
  - Naomi Dushay
28
28
  - '"shima"'
29
- autorequire:
29
+ autorequire:
30
30
  bindir: bin
31
31
  cert_chain: []
32
- date: 2018-05-09 00:00:00.000000000 Z
32
+ date: 2022-02-11 00:00:00.000000000 Z
33
33
  dependencies:
34
34
  - !ruby/object:Gem::Dependency
35
35
  name: builder
@@ -51,14 +51,26 @@ dependencies:
51
51
  requirements:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: 0.9.0
54
+ version: '0.9'
55
+ - - "!="
56
+ - !ruby/object:Gem::Version
57
+ version: 2.0.0
58
+ - - "<"
59
+ - !ruby/object:Gem::Version
60
+ version: '3'
55
61
  type: :runtime
56
62
  prerelease: false
57
63
  version_requirements: !ruby/object:Gem::Requirement
58
64
  requirements:
59
65
  - - ">="
60
66
  - !ruby/object:Gem::Version
61
- version: 0.9.0
67
+ version: '0.9'
68
+ - - "!="
69
+ - !ruby/object:Gem::Version
70
+ version: 2.0.0
71
+ - - "<"
72
+ - !ruby/object:Gem::Version
73
+ version: '3'
62
74
  - !ruby/object:Gem::Dependency
63
75
  name: activesupport
64
76
  requirement: !ruby/object:Gem::Requirement
@@ -165,9 +177,9 @@ executables: []
165
177
  extensions: []
166
178
  extra_rdoc_files: []
167
179
  files:
180
+ - ".github/workflows/ruby.yml"
168
181
  - ".gitignore"
169
182
  - ".rspec"
170
- - ".travis.yml"
171
183
  - CHANGES.txt
172
184
  - Gemfile
173
185
  - LICENSE
@@ -203,12 +215,13 @@ files:
203
215
  - spec/fixtures/basic_configs/stopwords.txt
204
216
  - spec/fixtures/basic_configs/synonyms.txt
205
217
  - spec/integration/solr5_spec.rb
218
+ - spec/lib/rsolr/client_spec.rb
206
219
  - spec/spec_helper.rb
207
220
  homepage: https://github.com/rsolr/rsolr
208
221
  licenses:
209
222
  - Apache-2.0
210
223
  metadata: {}
211
- post_install_message:
224
+ post_install_message:
212
225
  rdoc_options: []
213
226
  require_paths:
214
227
  - lib
@@ -224,9 +237,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
224
237
  version: '0'
225
238
  requirements:
226
239
  - Apache Solr
227
- rubyforge_project: rsolr
228
- rubygems_version: 2.7.6
229
- signing_key:
240
+ rubygems_version: 3.3.3
241
+ signing_key:
230
242
  specification_version: 4
231
243
  summary: A Ruby client for Apache Solr
232
244
  test_files: []
data/.travis.yml DELETED
@@ -1,14 +0,0 @@
1
- language: ruby
2
- sudo: false
3
- rvm:
4
- - 2.4.0
5
- - 2.3.3
6
- - 2.2.6
7
- - jruby-9.1.7.0
8
-
9
- env:
10
- global:
11
- - JRUBY_OPTS="-J-Xms512m -J-Xmx1024m"
12
- - NOKOGIRI_USE_SYSTEM_LIBRARIES=true
13
-
14
- jdk: oraclejdk8