telvue-rsolr 2.2.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 8206df30839209477712ca57220df5bc89ffef4502b343b7160a08ead5e18328
4
+ data.tar.gz: 173b7730bb208f49a3fa4745c06b087e9047437ca42393c48f41001b872c4582
5
+ SHA512:
6
+ metadata.gz: 841eb4744fb76c3cf57490b90cf27532191a3bf3400c4dd1c39fa28261ea46810f23843aecb0a95ae870b96afc080f36e15e79f27d21dbb1e2dc3a807e46fc28
7
+ data.tar.gz: a02c86754b9bda6a4469dc22b3d8f0b5074e04dc4602380efea3dd78a2e8856f2b9e9c807b5a9695e5826163c74e3074ee7709a48a298515bdf34542e4f8a62e
@@ -0,0 +1,13 @@
1
+ .DS_Store
2
+ .yardoc/
3
+ pkg/*
4
+ apache-solr-3.3.0/
5
+ coverage/
6
+ doc/
7
+ example/
8
+
9
+ Gemfile.lock
10
+
11
+ *.gem
12
+ .bundle
13
+ /spec/examples.txt
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
@@ -0,0 +1,14 @@
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
@@ -0,0 +1,47 @@
1
+ 2.0.0.pre1
2
+
3
+ In this release, we've added many new features, including:
4
+
5
+ - a new JSON request generator (enabled by default, replacing the XML-based requests) (@mootprinter)
6
+ - using Faraday for added flexibility for HTTP configuration
7
+ - native support for nested child documents and atomic updates in RSolr::Document and RSolr::Client.add
8
+ - better support for custom field value converters (@solenko)
9
+ - removing code deprecated in RSolr 1.x (@vipulnsward, and others)
10
+
11
+
12
+ 1.0.12
13
+ - Fix bug where specifying the wt property as a string, would add the supplied value to the default ('ruby') rather than overriding it.
14
+
15
+ 1.0.11
16
+ - add RSolr.solr_escape method and add deprecation messages to RSolr.escape (ndushay)
17
+ - use stdlib URI.escape methods instead of homegrown in RSolr::URI (ndushay)
18
+ - fix bug with Rsolr::Uri.create adding trailing slash if query params (ndushay)
19
+ - update rake tasks (cbeer)
20
+ - add Ruby 2.2.0 to travis ci build (ndushay)
21
+ - Housekeeping (badges to README, license in gemspec, correct url in gemspec ...) (ndushay)
22
+ - Improve rdoc styling (udaykadaboina)
23
+ - Support setting default_wt per connection via its options. (jcoleman)
24
+ - eliminates the usage of per-instance `extend` (jcoleman)
25
+ - Upgrade to RSpec 3 (blackwinter, adamjonas, cbeer)
26
+ - Fixed RSolr::Error to_s (PofMagicfingers)
27
+ 1.0.10 xxx
28
+
29
+ 1.0.8
30
+ - Fix connection refused errors in specs + add basic auth support (Denis Goeury)
31
+ - Ability to set :retry_503, the number of retry attempts for a 503 response
32
+ with a Retry-After header.
33
+ 1.0.7
34
+ - Response body encoding is set to response charset in Ruby >= 1.9
35
+ - Ability to set :read_timeout and :open_timeout when creating new instance of RSolr
36
+ 1.0.6
37
+ - More dependency fixups
38
+ 1.0.5
39
+ - Dependency fixups
40
+ 1.0.4
41
+ - The "builder" gem dependency is less strict: ~> 2.1.2
42
+ - RSolr.version is no longer read from a file
43
+ - Gemspec updated -- less strict dev/test versions
44
+ - Jeweler is no longer used for building the gemspec
45
+ 1.0.3
46
+ - Proper encodings in Ruby 1.9
47
+ - Applied pull request from https://github.com/mwmitchell/rsolr/pull/20
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem "builder", ">= 2.1.2"
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2008-2010 Matt Mitchell
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
@@ -0,0 +1,229 @@
1
+ == This is a TelVue Corp fork of the rsolr gem
2
+
3
+ =RSolr
4
+ {<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]
5
+
6
+
7
+ A simple, extensible Ruby client for Apache Solr.
8
+
9
+ ==Documentation
10
+ The code docs http://www.rubydoc.info/gems/rsolr
11
+
12
+ == Installation:
13
+ gem install telvue-rsolr
14
+
15
+ == Example:
16
+ require 'rsolr'
17
+
18
+ # Direct connection
19
+ solr = RSolr.connect :url => 'http://solrserver.com'
20
+
21
+ # Connecting over a proxy server
22
+ solr = RSolr.connect :url => 'http://solrserver.com', :proxy=>'http://user:pass@proxy.example.com:8080'
23
+
24
+ # Using an alternate Faraday adapter
25
+ solr = RSolr.connect :url => 'http://solrserver.com', :adapter => :em_http
26
+
27
+ # Using a custom Faraday connection
28
+ conn = Faraday.new do |faraday|
29
+ faraday.response :logger # log requests to STDOUT
30
+ faraday.adapter Faraday.default_adapter # make requests with Net::HTTP
31
+ end
32
+ solr = RSolr.connect conn, :url => 'http://solrserver.com'
33
+
34
+ # send a request to /select
35
+ response = solr.get 'select', :params => {:q => '*:*'}
36
+
37
+ # send a request to /catalog
38
+ response = solr.get 'catalog', :params => {:q => '*:*'}
39
+
40
+ When the Solr +:wt+ is +:ruby+, then the response will be a Hash. This Hash is the same object returned by Solr, but evaluated as Ruby. If the +:wt+ is not +:ruby+, then the response will be a String.
41
+
42
+ The response also exposes 2 attribute readers (for any +:wt+ value), +:request+ and +:response+. Both are Hash objects with symbolized keys.
43
+
44
+ The +:request+ attribute contains the original request context. You can use this for debugging or logging. Some of the keys this object contains are +:uri+, +:query+, +:method+ etc..
45
+
46
+ The +:response+ attribute contains the original response. This object contains the +:status+, +:body+ and +:headers+ keys.
47
+
48
+ == Request formats
49
+
50
+ By default, RSolr uses the Solr JSON command format for all requests.
51
+
52
+ RSolr.connect :url => 'http://solrserver.com', update_format: :json # the default
53
+ # or
54
+ RSolr.connect :url => 'http://solrserver.com', update_format: :xml
55
+
56
+ == Timeouts
57
+ The read and connect timeout settings can be set when creating a new instance of RSolr:
58
+ solr = RSolr.connect(:read_timeout => 120, :open_timeout => 120)
59
+
60
+ == Retry 503s
61
+ 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.
62
+
63
+ Only requests which specify a Retry-After header will be retried, after waiting the indicated retry interval, otherwise RSolr will treat the request as a 500. You may specify a maximum Retry-After interval to wait with the +:retry_after_limit+ option (default: one second).
64
+ solr = RSolr.connect(:retry_503 => 1, :retry_after_limit => 1)
65
+
66
+ For additional control, consider using a custom Faraday connection (see above) using its `retry` middleware.
67
+
68
+ == Querying
69
+ Use the #get / #post method to send search requests to the /select handler:
70
+ response = solr.get 'select', :params => {
71
+ :q=>'washington',
72
+ :start=>0,
73
+ :rows=>10
74
+ }
75
+ response["response"]["docs"].each{|doc| puts doc["id"] }
76
+
77
+ 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.
78
+ When an array is used, multiple parameters *with the same name* are generated for the Solr query. Example:
79
+
80
+ solr.get 'select', :params => {:q=>'roses', :fq=>['red', 'violet']}
81
+
82
+ The above statement generates this Solr query:
83
+
84
+ select?q=roses&fq=red&fq=violet
85
+
86
+ ===Pagination
87
+ To paginate through a set of Solr documents, use the paginate method:
88
+ solr.paginate 1, 10, "select", :params => {:q => "test"}
89
+
90
+ The first argument is the current page, the second is how many documents to return for each page. In other words, "page" is the "start" Solr param and "per-page" is the "rows" Solr param.
91
+
92
+ The paginate method returns WillPaginate ready "docs" objects, so for example in a Rails application, paginating is as simple as:
93
+ <%= will_paginate @solr_response["response"]["docs"] %>
94
+
95
+ ===Method Missing
96
+ The +RSolr::Client+ class also uses +method_missing+ for setting the request handler/path:
97
+
98
+ solr.paintings :params => {:q=>'roses', :fq=>['red', 'violet']}
99
+
100
+ This is sent to Solr as:
101
+ paintings?q=roses&fq=red&fq=violet
102
+
103
+ This works with pagination as well:
104
+
105
+ solr.paginate_paintings 1, 10, {:q=>'roses', :fq=>['red', 'violet']}
106
+
107
+ ===Using POST for Search Queries
108
+ There may be cases where the query string is too long for a GET request. RSolr solves this issue by converting hash objects into form-encoded strings:
109
+ response = solr.music :data => {:q => "*:*"}
110
+
111
+ The +:data+ hash is serialized as a form-encoded query string, and the correct content-type headers are sent along to Solr.
112
+
113
+ ===Sending HEAD Requests
114
+ There may be cases where you'd like to send a HEAD request to Solr:
115
+ solr.head("admin/ping").response[:status] == 200
116
+
117
+ ==Sending HTTP Headers
118
+ Solr responds to the request headers listed here: http://wiki.apache.org/solr/SolrAndHTTPCaches
119
+ To send header information to Solr using RSolr, just use the +:headers+ option:
120
+ response = solr.head "admin/ping", :headers => {"Cache-Control" => "If-None-Match"}
121
+
122
+ ===Building a Request
123
+ +RSolr::Client+ provides a method for building a request context, which can be useful for debugging or logging etc.:
124
+ request_context = solr.build_request "select", :data => {:q => "*:*"}, :method => :post, :headers => {}
125
+
126
+ To build a paginated request use build_paginated_request:
127
+ request_context = solr.build_paginated_request 1, 10, "select", ...
128
+
129
+ == Updating Solr
130
+ 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.
131
+
132
+ Single document via #add
133
+ solr.add :id=>1, :price=>1.00
134
+
135
+ Multiple documents via #add
136
+ documents = [{:id=>1, :price=>1.00}, {:id=>2, :price=>10.50}]
137
+ solr.add documents
138
+
139
+ The optional +:add_attributes+ hash can also be used to set Solr "add" document attributes:
140
+ solr.add documents, :add_attributes => {:commitWithin => 10}
141
+
142
+ Raw commands via #update
143
+ solr.update data: '<commit/>', headers: { 'Content-Type' => 'text/xml' }
144
+ solr.update data: { optimize: true }.to_json, headers: { 'Content-Type' => 'application/json' }
145
+
146
+ 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:
147
+
148
+ doc = {:id=>1, :price=>1.00}
149
+ add_attributes = {:allowDups=>false, :commitWithin=>10}
150
+ add_xml = solr.xml.add(doc, add_attributes) do |doc|
151
+ # boost each document
152
+ doc.attrs[:boost] = 1.5
153
+ # boost the price field:
154
+ doc.field_by_name(:price).attrs[:boost] = 2.0
155
+ end
156
+
157
+ Now the "add_xml" object can be sent to Solr like:
158
+ solr.update :data => add_xml
159
+
160
+ ===Deleting
161
+ Delete by id
162
+ solr.delete_by_id 1
163
+ or an array of ids
164
+ solr.delete_by_id [1, 2, 3, 4]
165
+
166
+ Delete by query:
167
+ solr.delete_by_query 'price:1.00'
168
+ Delete by array of queries
169
+ solr.delete_by_query ['price:1.00', 'price:10.00']
170
+
171
+ ===Commit / Optimize
172
+ solr.commit, :commit_attributes => {}
173
+ solr.optimize, :optimize_attributes => {}
174
+
175
+ == Response Formats
176
+ 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..
177
+
178
+ ===Evaluated Ruby:
179
+ solr.get 'select', :params => {:wt => :ruby} # notice :ruby is a Symbol
180
+ ===Raw Ruby:
181
+ solr.get 'select', :params => {:wt => 'ruby'} # notice 'ruby' is a String
182
+ ===XML:
183
+ solr.get 'select', :params => {:wt => :xml}
184
+ ===JSON (default):
185
+ solr.get 'select', :params => {:wt => :json}
186
+
187
+ ==Related Resources & Projects
188
+ * {RSolr Google Group}[http://groups.google.com/group/rsolr] -- The RSolr discussion group
189
+ * {rsolr-ext}[http://github.com/mwmitchell/rsolr-ext] -- An extension kit for RSolr
190
+ * {rsolr-direct}[http://github.com/mwmitchell/rsolr-direct] -- JRuby direct connection for RSolr
191
+ * {rsolr-nokogiri}[http://github.com/mwmitchell/rsolr-nokogiri] -- Gives RSolr Nokogiri for XML generation.
192
+ * {SunSpot}[http://github.com/sunspot/sunspot] -- An awesome Solr DSL, built with RSolr
193
+ * {Blacklight}[http://blacklightopac.org] -- A "next generation" Library OPAC, built with RSolr
194
+ * {java_bin}[http://github.com/kennyj/java_bin] -- Provides javabin/binary parsing for RSolr
195
+ * {Solr}[http://lucene.apache.org/solr/] -- The Apache Solr project
196
+ * {solr-ruby}[http://wiki.apache.org/solr/solr-ruby] -- The original Solr Ruby Gem!
197
+
198
+ == Note on Patches/Pull Requests
199
+ * Fork the project.
200
+ * Make your feature addition or bug fix.
201
+ * Add tests for it. This is important so I don't break it in a future version unintentionally.
202
+ * Commit, do not mess with rakefile, version, or history
203
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
204
+ * Send me a pull request. Bonus points for topic branches.
205
+
206
+ ==Contributors
207
+ * Nathan Witmer
208
+ * Magnus Bergmark
209
+ * shima
210
+ * Randy Souza
211
+ * Mat Brown
212
+ * Jeremy Hinegardner
213
+ * Denis Goeury
214
+ * shairon toledo
215
+ * Rob Di Marco
216
+ * Peter Kieltyka
217
+ * Mike Perham
218
+ * Lucas Souza
219
+ * Dmitry Lihachev
220
+ * Antoine Latter
221
+ * Naomi Dushay
222
+
223
+ ==Author
224
+
225
+ Matt Mitchell <mailto:goodieboy@gmail.com>
226
+
227
+ ==Copyright
228
+
229
+ Copyright (c) 2008-2010 Matt Mitchell. See LICENSE for details.
@@ -0,0 +1,19 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ task default: ['spec']
4
+
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
@@ -0,0 +1,52 @@
1
+ module RSolr
2
+ require 'rsolr/version'
3
+
4
+ autoload :Char, 'rsolr/char'
5
+ autoload :Client, 'rsolr/client'
6
+ autoload :Document, 'rsolr/document'
7
+ autoload :Error, 'rsolr/error'
8
+ autoload :Field, 'rsolr/field'
9
+ autoload :Generator, 'rsolr/generator'
10
+ autoload :HashWithResponse, 'rsolr/response'
11
+ autoload :JSON, 'rsolr/json'
12
+ autoload :Response, 'rsolr/response'
13
+ autoload :Uri, 'rsolr/uri'
14
+ autoload :Xml, 'rsolr/xml'
15
+
16
+ def self.connect *args
17
+ opts = args.pop if args.last.is_a?(::Hash)
18
+ opts ||= {}
19
+
20
+ connection = args.first
21
+
22
+ Client.new connection, opts
23
+ end
24
+
25
+ # backslash escape characters that have special meaning to Solr query parser
26
+ # per http://lucene.apache.org/core/4_0_0/queryparser/org/apache/lucene/queryparser/classic/package-summary.html#Escaping_Special_Characters
27
+ # + - & | ! ( ) { } [ ] ^ " ~ * ? : \ /
28
+ # see also http://svn.apache.org/repos/asf/lucene/dev/tags/lucene_solr_4_9_1/solr/solrj/src/java/org/apache/solr/client/solrj/util/ClientUtils.java
29
+ # escapeQueryChars method
30
+ # @return [String] str with special chars preceded by a backslash
31
+ def self.solr_escape(str)
32
+ # note that the gsub will parse the escaped backslashes, as will the ruby code sending the query to Solr
33
+ # so the result sent to Solr is ultimately a single backslash in front of the particular character
34
+ str.gsub(/([+\-&|!\(\)\{\}\[\]\^"~\*\?:\\\/])/, '\\\\\1')
35
+ end
36
+
37
+ module Array
38
+ def self.wrap(object)
39
+ if object.nil?
40
+ [nil]
41
+ elsif object.respond_to?(:to_ary)
42
+ object.to_ary || [object]
43
+ elsif object.is_a? Hash
44
+ [object]
45
+ elsif object.is_a? Enumerable
46
+ object
47
+ else
48
+ [object]
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,6 @@
1
+ # :nodoc:
2
+ module RSolr::Char
3
+ def self.included(*)
4
+ warn 'RSolr::Char is deprecated without replacement, and will be removed in RSolr 3.x'
5
+ end
6
+ end
@@ -0,0 +1,342 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'faraday'
5
+ require 'uri'
6
+
7
+ class RSolr::Client
8
+ DEFAULT_URL = 'http://127.0.0.1:8983/solr/'
9
+
10
+ class << self
11
+ def default_wt
12
+ @default_wt ||= :json
13
+ end
14
+
15
+ def default_wt= value
16
+ @default_wt = value
17
+ end
18
+ end
19
+
20
+ attr_reader :uri, :proxy, :update_format, :options, :update_path
21
+
22
+ def initialize connection, options = {}
23
+ @proxy = @uri = nil
24
+ @connection = connection
25
+ unless false === options[:url]
26
+ @uri = extract_url_from_options(options)
27
+ if options[:proxy]
28
+ proxy_url = options[:proxy].dup
29
+ proxy_url << "/" unless proxy_url.nil? or proxy_url[-1] == ?/
30
+ @proxy = ::URI.parse proxy_url if proxy_url
31
+ elsif options[:proxy] == false
32
+ @proxy = false # used to avoid setting the proxy from the environment.
33
+ end
34
+ end
35
+ @update_format = options.delete(:update_format) || RSolr::JSON::Generator
36
+ @update_path = options.fetch(:update_path, 'update')
37
+ @options = options
38
+ end
39
+
40
+ def extract_url_from_options(options)
41
+ url = options[:url] ? options[:url].dup : DEFAULT_URL
42
+ url << "/" unless url[-1] == ?/
43
+ uri = ::URI.parse(url)
44
+ # URI::HTTPS is a subclass of URI::HTTP, so this check accepts HTTP(S)
45
+ raise ArgumentError, "You must provide an HTTP(S) url." unless uri.kind_of?(URI::HTTP)
46
+ uri
47
+ end
48
+
49
+ # returns the request uri object.
50
+ def base_request_uri
51
+ base_uri.request_uri if base_uri
52
+ end
53
+
54
+ # returns the URI uri object.
55
+ def base_uri
56
+ @uri
57
+ end
58
+
59
+ # Create the get, post, and head methods
60
+ %W(get post head).each do |meth|
61
+ class_eval <<-RUBY
62
+ def #{meth} path, opts = {}, &block
63
+ send_and_receive path, opts.merge(:method => :#{meth}), &block
64
+ end
65
+ RUBY
66
+ end
67
+
68
+ # A paginated request method.
69
+ # Converts the page and per_page
70
+ # arguments into "rows" and "start".
71
+ def paginate page, per_page, path, opts = nil
72
+ opts ||= {}
73
+ opts[:params] ||= {}
74
+ raise "'rows' or 'start' params should not be set when using +paginate+" if ["start", "rows"].include?(opts[:params].keys)
75
+ execute build_paginated_request(page, per_page, path, opts)
76
+ end
77
+
78
+ # POST XML messages to /update with optional params.
79
+ #
80
+ # http://wiki.apache.org/solr/UpdateXmlMessages#add.2BAC8-update
81
+ #
82
+ # If not set, opts[:headers] will be set to a hash with the key
83
+ # 'Content-Type' set to 'text/xml'
84
+ #
85
+ # +opts+ can/should contain:
86
+ #
87
+ # :data - posted data
88
+ # :headers - http headers
89
+ # :params - solr query parameter hash
90
+ #
91
+ def update opts = {}
92
+ opts[:headers] ||= {}
93
+ opts[:headers]['Content-Type'] ||= builder.content_type
94
+ post opts.fetch(:path, update_path), opts
95
+ end
96
+
97
+ # +add+ creates xml "add" documents and sends the xml data to the +update+ method
98
+ #
99
+ # http://wiki.apache.org/solr/UpdateXmlMessages#add.2BAC8-update
100
+ #
101
+ # single record:
102
+ # solr.add(:id=>1, :name=>'one')
103
+ #
104
+ # add using an array
105
+ #
106
+ # solr.add(
107
+ # [{:id=>1, :name=>'one'}, {:id=>2, :name=>'two'}],
108
+ # :add_attributes => {:boost=>5.0, :commitWithin=>10}
109
+ # )
110
+ #
111
+ def add doc, opts = {}
112
+ add_attributes = opts.delete :add_attributes
113
+ update opts.merge(:data => builder.add(doc, add_attributes))
114
+ end
115
+
116
+ # send "commit" xml with opts
117
+ #
118
+ # http://wiki.apache.org/solr/UpdateXmlMessages#A.22commit.22_and_.22optimize.22
119
+ #
120
+ def commit opts = {}
121
+ commit_attrs = opts.delete :commit_attributes
122
+ update opts.merge(:data => builder.commit( commit_attrs ))
123
+ end
124
+
125
+ # send "optimize" xml with opts.
126
+ #
127
+ # http://wiki.apache.org/solr/UpdateXmlMessages#A.22commit.22_and_.22optimize.22
128
+ #
129
+ def optimize opts = {}
130
+ optimize_attributes = opts.delete :optimize_attributes
131
+ update opts.merge(:data => builder.optimize(optimize_attributes))
132
+ end
133
+
134
+ # send </rollback>
135
+ #
136
+ # http://wiki.apache.org/solr/UpdateXmlMessages#A.22rollback.22
137
+ #
138
+ # NOTE: solr 1.4 only
139
+ def rollback opts = {}
140
+ update opts.merge(:data => builder.rollback)
141
+ end
142
+
143
+ # Delete one or many documents by id
144
+ # solr.delete_by_id 10
145
+ # solr.delete_by_id([12, 41, 199])
146
+ def delete_by_id id, opts = {}
147
+ update opts.merge(:data => builder.delete_by_id(id))
148
+ end
149
+
150
+ # delete one or many documents by query.
151
+ #
152
+ # http://wiki.apache.org/solr/UpdateXmlMessages#A.22delete.22_by_ID_and_by_Query
153
+ #
154
+ # solr.delete_by_query 'available:0'
155
+ # solr.delete_by_query ['quantity:0', 'manu:"FQ"']
156
+ def delete_by_query query, opts = {}
157
+ update opts.merge(:data => builder.delete_by_query(query))
158
+ end
159
+
160
+ def builder
161
+ @builder ||= if update_format.is_a? Class
162
+ update_format.new
163
+ elsif update_format == :json
164
+ RSolr::JSON::Generator.new
165
+ elsif update_format == :xml
166
+ RSolr::Xml::Generator.new
167
+ else
168
+ update_format
169
+ end
170
+ end
171
+
172
+ # +send_and_receive+ is the main request method responsible for sending requests to the +connection+ object.
173
+ #
174
+ # "path" : A string value that usually represents a solr request handler
175
+ # "opts" : A hash, which can contain the following keys:
176
+ # :method : required - the http method (:get, :post or :head)
177
+ # :params : optional - the query string params in hash form
178
+ # :data : optional - post data -- if a hash is given, it's sent as "application/x-www-form-urlencoded; charset=UTF-8"
179
+ # :headers : optional - hash of request headers
180
+ # All other options are passed right along to the connection's +send_and_receive+ method (:get, :post, or :head)
181
+ #
182
+ # +send_and_receive+ returns either a string or hash on a successful ruby request.
183
+ # When the :params[:wt] => :ruby, the response will be a hash, else a string.
184
+ #
185
+ # creates a request context hash,
186
+ # sends it to the connection's +execute+ method
187
+ # which returns a simple hash,
188
+ # then passes the request/response into +adapt_response+.
189
+ def send_and_receive path, opts
190
+ request_context = build_request path, opts
191
+ execute request_context
192
+ end
193
+
194
+ #
195
+ def execute request_context
196
+ raw_response = begin
197
+ response = connection.send(request_context[:method], request_context[:uri].to_s) do |req|
198
+ req.body = request_context[:data] if request_context[:method] == :post and request_context[:data]
199
+ req.headers.merge!(request_context[:headers]) if request_context[:headers]
200
+ end
201
+
202
+ { status: response.status.to_i, headers: response.headers, body: response.body.dup.force_encoding('utf-8') }
203
+ rescue Errno::ECONNREFUSED, Faraday::Error::ConnectionFailed
204
+ raise RSolr::Error::ConnectionRefused, request_context.inspect
205
+ rescue Faraday::Error => e
206
+ raise RSolr::Error::Http.new(request_context, e.response)
207
+ end
208
+ adapt_response(request_context, raw_response) unless raw_response.nil?
209
+ end
210
+
211
+ # +build_request+ accepts a path and options hash,
212
+ # then prepares a normalized hash to return for sending
213
+ # to a solr connection driver.
214
+ # +build_request+ sets up the uri/query string
215
+ # and converts the +data+ arg to form-urlencoded,
216
+ # if the +data+ arg is a hash.
217
+ # returns a hash with the following keys:
218
+ # :method
219
+ # :params
220
+ # :headers
221
+ # :data
222
+ # :uri
223
+ # :path
224
+ # :query
225
+ def build_request path, opts
226
+ raise "path must be a string or symbol, not #{path.inspect}" unless [String,Symbol].include?(path.class)
227
+ path = path.to_s
228
+ opts[:proxy] = proxy unless proxy.nil?
229
+ opts[:method] ||= :get
230
+ raise "The :data option can only be used if :method => :post" if opts[:method] != :post and opts[:data]
231
+ opts[:params] = params_with_wt(opts[:params])
232
+ query = RSolr::Uri.params_to_solr(opts[:params]) unless opts[:params].empty?
233
+ opts[:query] = query
234
+ if opts[:data].is_a? Hash
235
+ opts[:data] = RSolr::Uri.params_to_solr opts[:data]
236
+ opts[:headers] ||= {}
237
+ opts[:headers]['Content-Type'] ||= 'application/x-www-form-urlencoded; charset=UTF-8'
238
+ end
239
+ opts[:path] = path
240
+ opts[:uri] = base_uri.merge(path.to_s + (query ? "?#{query}" : "")) if base_uri
241
+
242
+ opts
243
+ end
244
+
245
+ def params_with_wt(params)
246
+ return { wt: default_wt } if params.nil?
247
+ return params if params.key?(:wt) || params.key?('wt')
248
+ { wt: default_wt }.merge(params)
249
+ end
250
+
251
+ def build_paginated_request page, per_page, path, opts
252
+ per_page = per_page.to_s.to_i
253
+ page = page.to_s.to_i-1
254
+ page = page < 1 ? 0 : page
255
+ opts[:params]["start"] = page * per_page
256
+ opts[:params]["rows"] = per_page
257
+ build_request path, opts
258
+ end
259
+
260
+ # This method will evaluate the :body value
261
+ # if the params[:uri].params[:wt] == :ruby
262
+ # ... otherwise, the body is returned as is.
263
+ # The return object has methods attached, :request and :response.
264
+ # These methods give you access to the original
265
+ # request and response from the connection.
266
+ #
267
+ # +adapt_response+ will raise an InvalidRubyResponse
268
+ # if :wt == :ruby and the body
269
+ # couldn't be evaluated.
270
+ def adapt_response request, response
271
+ raise "The response does not have the correct keys => :body, :headers, :status" unless
272
+ %W(body headers status) == response.keys.map{|k|k.to_s}.sort
273
+
274
+ result = if respond_to? "evaluate_#{request[:params][:wt]}_response", true
275
+ send "evaluate_#{request[:params][:wt]}_response", request, response
276
+ else
277
+ response[:body]
278
+ end
279
+
280
+ if result.is_a?(Hash) || request[:method] == :head
281
+ result = RSolr::HashWithResponse.new(request, response, result)
282
+ end
283
+
284
+ result
285
+ end
286
+
287
+ def connection
288
+ @connection ||= begin
289
+ conn_opts = { request: {} }
290
+ conn_opts[:url] = uri.to_s
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
306
+
307
+ protected
308
+
309
+ # converts the method name for the solr request handler path.
310
+ def method_missing name, *args
311
+ if name.to_s =~ /^paginated?_(.+)$/
312
+ paginate args[0], args[1], $1, *args[2..-1]
313
+ else
314
+ send_and_receive name, *args
315
+ end
316
+ end
317
+
318
+ # evaluates the response[:body],
319
+ # attempts to bring the ruby string to life.
320
+ # If a SyntaxError is raised, then
321
+ # this method intercepts and raises a
322
+ # RSolr::Error::InvalidRubyResponse
323
+ # instead, giving full access to the
324
+ # request/response objects.
325
+ def evaluate_ruby_response request, response
326
+ Kernel.eval response[:body].to_s
327
+ rescue SyntaxError
328
+ raise RSolr::Error::InvalidRubyResponse.new request, response
329
+ end
330
+
331
+ def evaluate_json_response request, response
332
+ return if response[:body].nil? || response[:body].empty?
333
+
334
+ JSON.parse response[:body].to_s
335
+ rescue JSON::ParserError
336
+ raise RSolr::Error::InvalidJsonResponse.new request, response
337
+ end
338
+
339
+ def default_wt
340
+ self.options[:default_wt] || self.class.default_wt
341
+ end
342
+ end