solr4r 0.2.0 → 0.3.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.
@@ -5,7 +5,7 @@
5
5
  # #
6
6
  # solr4r -- A Ruby client for Apache Solr #
7
7
  # #
8
- # Copyright (C) 2014-2015 Jens Wille #
8
+ # Copyright (C) 2014-2016 Jens Wille #
9
9
  # #
10
10
  # solr4r is free software: you can redistribute it and/or modify it under the #
11
11
  # terms of the GNU Affero General Public License as published by the Free #
@@ -30,6 +30,7 @@ module Solr4R
30
30
  MATCH_ALL_QUERY = '*:*'
31
31
 
32
32
  DEFAULT_SELECT_PATH = 'select'
33
+ DEFAULT_SPELL_PATH = 'spell'
33
34
  DEFAULT_MLT_PATH = 'mlt'
34
35
 
35
36
  MLT_DEFAULT_FL = '*,score'
@@ -45,7 +46,7 @@ module Solr4R
45
46
  minwl
46
47
  ], type: :mlt, qf: '$mlt.fl')
47
48
 
48
- module Query
49
+ module QueryMixin
49
50
 
50
51
  def count(
51
52
  params = {}, options = {}, path = DEFAULT_SELECT_PATH, &block)
@@ -96,7 +97,7 @@ module Solr4R
96
97
 
97
98
  end
98
99
 
99
- include Query
100
+ include QueryMixin
100
101
 
101
102
  end
102
103
 
@@ -5,7 +5,7 @@
5
5
  # #
6
6
  # solr4r -- A Ruby client for Apache Solr #
7
7
  # #
8
- # Copyright (C) 2014-2015 Jens Wille #
8
+ # Copyright (C) 2014-2016 Jens Wille #
9
9
  # #
10
10
  # solr4r is free software: you can redistribute it and/or modify it under the #
11
11
  # terms of the GNU Affero General Public License as published by the Free #
@@ -33,7 +33,7 @@ module Solr4R
33
33
 
34
34
  DEFAULT_UPDATE_PATH = 'update'
35
35
 
36
- module Update
36
+ module UpdateMixin
37
37
 
38
38
  def update(data,
39
39
  params = {}, options = {},
@@ -51,18 +51,12 @@ module Solr4R
51
51
  update(builder.add(doc, attributes), params, options, &block)
52
52
  end
53
53
 
54
- def add_batch(docs, attributes = {},
55
- params = {}, options = {}, batch_size = DEFAULT_BATCH_SIZE, &block)
56
-
57
- failed = []
58
-
59
- docs.each_slice(batch_size) { |batch|
60
- add(batch, attributes, params, options, &block).success? ||
61
- failed.concat(batch_size == 1 ? batch : add_batch(batch,
62
- attributes, params, options, batch_size / 10, &block))
63
- }
54
+ def add_batch(docs, *args, &block)
55
+ batch(*args, &block).batch(docs).flush
56
+ end
64
57
 
65
- failed
58
+ def batch(*args, &block)
59
+ Batch.new(self, *args, &block)
66
60
  end
67
61
 
68
62
  # See Builder#commit.
@@ -118,7 +112,7 @@ module Solr4R
118
112
 
119
113
  end
120
114
 
121
- include Update
115
+ include UpdateMixin
122
116
 
123
117
  end
124
118
 
data/lib/solr4r/client.rb CHANGED
@@ -5,7 +5,7 @@
5
5
  # #
6
6
  # solr4r -- A Ruby client for Apache Solr #
7
7
  # #
8
- # Copyright (C) 2014-2015 Jens Wille #
8
+ # Copyright (C) 2014-2016 Jens Wille #
9
9
  # #
10
10
  # solr4r is free software: you can redistribute it and/or modify it under the #
11
11
  # terms of the GNU Affero General Public License as published by the Free #
@@ -44,88 +44,20 @@ module Solr4R
44
44
 
45
45
  class << self
46
46
 
47
+ extend Forwardable
48
+
49
+ def_delegators Query, :escape, :query_string, :local_params_string
50
+
47
51
  def default_uri(options = {})
48
52
  DEFAULT_URI % [
49
53
  options.fetch(:host, DEFAULT_HOST),
50
54
  options.fetch(:port, DEFAULT_PORT),
51
55
  options.fetch(:path, DEFAULT_PATH),
52
- options.fetch(:core, DEFAULT_CORE)
56
+ options.fetch(:collection) {
57
+ options.fetch(:core, DEFAULT_CORE) }
53
58
  ]
54
59
  end
55
60
 
56
- def query_string(query, escape = true)
57
- case query
58
- when nil
59
- # ignore
60
- when String
61
- escape(query, escape) unless query.empty?
62
- when Array
63
- if query.last.is_a?(Hash)
64
- lp, qs = query_from_hash((query = query.dup).pop, escape)
65
- query << qs if qs
66
- end
67
-
68
- query_with_params(lp, query_string(query.join(' '), escape))
69
- when Hash
70
- query_with_params(*query_from_hash(query, escape))
71
- else
72
- type_error(query)
73
- end
74
- end
75
-
76
- def local_params_string(local_params, hash = {}, escape = true)
77
- case local_params = expand_local_params(local_params, hash.dup)
78
- when nil
79
- # ignore
80
- when String
81
- escape("{!#{local_params}}", escape) unless local_params.empty?
82
- when Array
83
- local_params_string(local_params.join(' '), {}, escape)
84
- when Hash
85
- local_params_string(local_params.map { |key, value|
86
- "#{key}=#{value =~ /\s/ ? %Q{"#{value}"} : value}" }, {}, escape)
87
- else
88
- type_error(local_params)
89
- end
90
- end
91
-
92
- def escape(string, escape = true)
93
- escape ? string.gsub('&', '%26') : string
94
- end
95
-
96
- private
97
-
98
- def query_from_hash(query, escape)
99
- local_params = query.key?(lp = :_) &&
100
- local_params_string((query = query.dup).delete(lp), {}, escape)
101
-
102
- [local_params, query_string(query.flat_map { |key, values|
103
- Array(values).map { |value| "#{key}:#{value}" } }, escape)]
104
- end
105
-
106
- def query_with_params(local_params, query_string)
107
- local_params ? local_params + query_string : query_string
108
- end
109
-
110
- def expand_local_params(local_params, hash)
111
- case type = hash[:type]
112
- when nil
113
- local_params
114
- when String, Symbol
115
- type_error(local_params, Array) unless local_params.is_a?(Array)
116
-
117
- local_params.each { |param| hash[param] = "$#{type}.#{param}" }
118
- hash
119
- else
120
- type_error(type, %w[String Symbol])
121
- end
122
- end
123
-
124
- def type_error(obj, types = %w[String Array Hash])
125
- types = Array(types).join(' or ')
126
- raise TypeError, "#{types} expected, got #{obj.class}", caller(1)
127
- end
128
-
129
61
  end
130
62
 
131
63
  def initialize(options = {})
@@ -152,6 +84,8 @@ module Solr4R
152
84
 
153
85
  def_delegators 'self.class', :query_string, :local_params_string, :escape
154
86
 
87
+ def_delegators :request, :request_line, :execute
88
+
155
89
  def json(path,
156
90
  params = {}, options = {}, &block)
157
91
 
@@ -181,7 +115,7 @@ module Solr4R
181
115
 
182
116
  def inspect
183
117
  '#<%s:0x%x @default_params=%p %s>' % [
184
- self.class, object_id, default_params, request.request_line
118
+ self.class, object_id, default_params, request_line
185
119
  ]
186
120
  end
187
121
 
@@ -191,23 +125,19 @@ module Solr4R
191
125
  self.class.default_uri(options)
192
126
  end
193
127
 
194
- def amend_options_hash(options, key, value)
195
- options.merge(key => value.merge(options.fetch(key, {})))
196
- end
197
-
198
- def amend_options_array(options, key, *value)
199
- options.merge(key => Array(options[key]) + value)
200
- end
201
-
202
128
  def send_request(path, options, &block)
203
- request.execute(path, amend_options_hash(
129
+ execute(path, amend_options_hash(
204
130
  options, :params, default_params), &block)
205
131
  end
206
132
 
133
+ def amend_options_hash(options, key, value)
134
+ options.merge(key => value.merge(options.fetch(key, {})))
135
+ end
136
+
207
137
  end
208
138
 
209
139
  end
210
140
 
211
- require_relative 'client/update'
212
- require_relative 'client/query'
213
- require_relative 'client/admin'
141
+ require_relative 'client/update_mixin'
142
+ require_relative 'client/query_mixin'
143
+ require_relative 'client/admin_mixin'
@@ -5,7 +5,7 @@
5
5
  # #
6
6
  # solr4r -- A Ruby client for Apache Solr #
7
7
  # #
8
- # Copyright (C) 2014-2015 Jens Wille #
8
+ # Copyright (C) 2014-2016 Jens Wille #
9
9
  # #
10
10
  # solr4r is free software: you can redistribute it and/or modify it under the #
11
11
  # terms of the GNU Affero General Public License as published by the Free #
@@ -33,6 +33,9 @@ module Solr4R
33
33
 
34
34
  def initialize(result, hash)
35
35
  @result, @hash = result, hash
36
+
37
+ hash.each { |key, val|
38
+ define_singleton_method(key) { val } unless respond_to?(key, true) }
36
39
  end
37
40
 
38
41
  attr_reader :result
@@ -5,7 +5,7 @@
5
5
  # #
6
6
  # solr4r -- A Ruby client for Apache Solr #
7
7
  # #
8
- # Copyright (C) 2014-2015 Jens Wille #
8
+ # Copyright (C) 2014-2016 Jens Wille #
9
9
  # #
10
10
  # solr4r is free software: you can redistribute it and/or modify it under the #
11
11
  # terms of the GNU Affero General Public License as published by the Free #
@@ -42,6 +42,13 @@ module Solr4R
42
42
  case path
43
43
  when nil
44
44
  # ignore
45
+ when Symbol
46
+ register(path.to_s, options)
47
+ when Array
48
+ path.each { |args| register(*args) }
49
+ when Hash
50
+ path.each { |_path, _options| register(_path,
51
+ _options.is_a?(Hash) ? _options : { path: _options }) }
45
52
  when String
46
53
  name, path = File.basename(path), options.fetch(:path, path).to_s
47
54
 
@@ -54,15 +61,8 @@ module Solr4R
54
61
  client.send(:send_request, path, options.merge(_options.merge(
55
62
  params: options.fetch(:params, {}).merge(_params))), &block)
56
63
  }
57
- when Symbol
58
- register(path.to_s, options)
59
- when Array
60
- path.each { |args| register(*args) }
61
- when Hash
62
- path.each { |_path, _options| register(_path,
63
- _options.is_a?(Hash) ? _options : { path: _options }) }
64
64
  else
65
- client.class.send(:type_error, path, %w[String Symbol Array Hash])
65
+ raise TypeError, "unexpected type #{path.class}"
66
66
  end
67
67
 
68
68
  self
@@ -0,0 +1,181 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ ###############################################################################
5
+ # #
6
+ # solr4r -- A Ruby client for Apache Solr #
7
+ # #
8
+ # Copyright (C) 2014-2016 Jens Wille #
9
+ # #
10
+ # solr4r is free software: you can redistribute it and/or modify it under the #
11
+ # terms of the GNU Affero General Public License as published by the Free #
12
+ # Software Foundation, either version 3 of the License, or (at your option) #
13
+ # any later version. #
14
+ # #
15
+ # solr4r is distributed in the hope that it will be useful, but WITHOUT ANY #
16
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS #
17
+ # FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for #
18
+ # more details. #
19
+ # #
20
+ # You should have received a copy of the GNU Affero General Public License #
21
+ # along with solr4r. If not, see <http://www.gnu.org/licenses/>. #
22
+ # #
23
+ ###############################################################################
24
+ #++
25
+
26
+ require 'time'
27
+
28
+ module Solr4R
29
+
30
+ class Query
31
+
32
+ LOCAL_PARAMS_KEY = :_
33
+
34
+ class << self
35
+
36
+ def query_string(*args)
37
+ new(*args).to_s
38
+ end
39
+
40
+ def local_params_string(*args)
41
+ new.local_params_string(*args)
42
+ end
43
+
44
+ def escape(string, escape = true)
45
+ escape ? string.gsub('&', '%26') : string
46
+ end
47
+
48
+ def quote(string)
49
+ string =~ /\s/ ? %Q{"#{string}"} : string
50
+ end
51
+
52
+ def convert_value(value, escape = true)
53
+ case value
54
+ when DateTime
55
+ convert_value(value.to_time, escape)
56
+ when Time
57
+ value.getutc.xmlschema.tap { |string|
58
+ string.gsub!(/:/, '\\\\\&') if escape }
59
+ when Range
60
+ '[' << [value.begin, value.end].map { |v|
61
+ convert_value(v, false) }.join(' TO ') << ']'
62
+ else
63
+ value.to_s
64
+ end
65
+ end
66
+
67
+ end
68
+
69
+ def initialize(query = '', escape = true)
70
+ @query, @escape = query, escape
71
+ end
72
+
73
+ attr_reader :query
74
+
75
+ attr_writer :escape
76
+
77
+ def escape?
78
+ @escape
79
+ end
80
+
81
+ def escape(string, escape = escape?)
82
+ self.class.escape(string, escape)
83
+ end
84
+
85
+ def quote(string)
86
+ self.class.quote(string)
87
+ end
88
+
89
+ def convert_value(*args)
90
+ self.class.convert_value(*args)
91
+ end
92
+
93
+ def to_s(escape = escape?)
94
+ query_string(query, escape)
95
+ end
96
+
97
+ def query_string(query = query(), escape = escape?)
98
+ case query
99
+ when nil
100
+ # ignore
101
+ when String
102
+ escape(query, escape) unless query.empty?
103
+ when Array
104
+ if query.last.is_a?(Hash)
105
+ query = query.dup
106
+
107
+ local_params, query_string = query_from_hash(query.pop, escape)
108
+ query << query_string if query_string
109
+ end
110
+
111
+ query_with_params(local_params, query_from_array(query, escape))
112
+ when Hash
113
+ query_with_params(*query_from_hash(query, escape))
114
+ else
115
+ type_error(query)
116
+ end
117
+ end
118
+
119
+ def local_params_string(local_params, hash = {}, escape = escape?)
120
+ case local_params = expand_local_params(local_params, hash)
121
+ when nil
122
+ # ignore
123
+ when String
124
+ escape("{!#{local_params}}", escape) unless local_params.empty?
125
+ when Array
126
+ local_params_string(local_params.join(' '), {}, escape)
127
+ when Hash
128
+ local_params_string(local_params.map { |key, value|
129
+ "#{key}=#{quote(value)}" }, {}, escape)
130
+ else
131
+ type_error(local_params)
132
+ end
133
+ end
134
+
135
+ private
136
+
137
+ def query_from_array(query, escape)
138
+ query_string(query.map { |value| convert_value(value) }.join(' '), escape)
139
+ end
140
+
141
+ def query_from_hash(query, escape)
142
+ if query.key?(LOCAL_PARAMS_KEY)
143
+ query = query.dup
144
+
145
+ local_params = local_params_string(
146
+ query.delete(LOCAL_PARAMS_KEY), {}, escape)
147
+ end
148
+
149
+ query = query.flat_map { |key, values|
150
+ block = lambda { |value| "#{key}:#{convert_value(value)}" }
151
+ values.respond_to?(:to_ary) ? values.map(&block) : block[values] }
152
+
153
+ [local_params, query_string(query, escape)]
154
+ end
155
+
156
+ def query_with_params(local_params, query_string)
157
+ local_params ? local_params + query_string : query_string
158
+ end
159
+
160
+ def expand_local_params(local_params, hash)
161
+ case type = hash[:type]
162
+ when nil
163
+ local_params
164
+ when String, Symbol
165
+ type_error(local_params) unless local_params.is_a?(Array)
166
+
167
+ hash = hash.dup
168
+ local_params.each { |param| hash[param] = "$#{type}.#{param}" }
169
+ hash
170
+ else
171
+ type_error(type)
172
+ end
173
+ end
174
+
175
+ def type_error(obj)
176
+ raise TypeError, "unexpected type #{obj.class}", caller(1)
177
+ end
178
+
179
+ end
180
+
181
+ end
data/lib/solr4r/result.rb CHANGED
@@ -5,7 +5,7 @@
5
5
  # #
6
6
  # solr4r -- A Ruby client for Apache Solr #
7
7
  # #
8
- # Copyright (C) 2014-2015 Jens Wille #
8
+ # Copyright (C) 2014-2016 Jens Wille #
9
9
  # #
10
10
  # solr4r is free software: you can redistribute it and/or modify it under the #
11
11
  # terms of the GNU Affero General Public License as published by the Free #
@@ -37,18 +37,22 @@ module Solr4R
37
37
 
38
38
  extend Forwardable
39
39
 
40
- def self.types_for(hash, mix = Nuggets::String::CamelscoreMixin)
41
- constants.map { |const|
42
- if hash.key?(const.to_s.extend(mix).underscore!)
43
- mod = const_get(const)
44
- mod if mod.is_a?(Module)
45
- end
46
- }.compact
40
+ def self.types
41
+ @types ||= constants.each_with_object({}) { |const, hash|
42
+ mod, key = const_get(const), const.to_s; next unless mod.is_a?(Module)
43
+ hash[key.extend(Nuggets::String::CamelscoreMixin).underscore!] = mod
44
+ }
47
45
  end
48
46
 
49
47
  def initialize(response, hash)
50
- types = self.class.types_for(hash); extend(*types) unless types.empty?
51
48
  @response, @hash = response, hash.extend(Nuggets::Hash::DeepFetchMixin)
49
+
50
+ self.class.types.each { |key, mod|
51
+ extend(mod) if val = hash.key?(key)
52
+
53
+ respond_to?(meth = "#{key}?", true) or
54
+ define_singleton_method(meth) { val }
55
+ }
52
56
  end
53
57
 
54
58
  attr_reader :response
@@ -73,10 +77,6 @@ module Solr4R
73
77
  to_i.zero?
74
78
  end
75
79
 
76
- def error?
77
- is_a?(Error)
78
- end
79
-
80
80
  private
81
81
 
82
82
  def _each
@@ -102,6 +102,18 @@ module Solr4R
102
102
 
103
103
  end
104
104
 
105
+ module Debug
106
+
107
+ def debug
108
+ fetch(__method__.to_s)
109
+ end
110
+
111
+ def debug_explain
112
+ debug.fetch('explain')
113
+ end
114
+
115
+ end
116
+
105
117
  module Terms
106
118
 
107
119
  def to_i
@@ -142,6 +154,30 @@ module Solr4R
142
154
 
143
155
  end
144
156
 
157
+ module Highlighting
158
+
159
+ def highlighting
160
+ fetch(__method__.to_s)
161
+ end
162
+
163
+ end
164
+
165
+ module Spellcheck
166
+
167
+ def spellcheck
168
+ fetch(__method__.to_s)
169
+ end
170
+
171
+ def spellcheck_collations
172
+ return enum_for(__method__) unless block_given?
173
+
174
+ spellcheck.fetch('collations').each_slice(2) { |_, collation|
175
+ yield collation.values_at('collationQuery', 'hits')
176
+ }
177
+ end
178
+
179
+ end
180
+
145
181
  end
146
182
 
147
183
  end
@@ -3,7 +3,7 @@ module Solr4R
3
3
  module Version
4
4
 
5
5
  MAJOR = 0
6
- MINOR = 2
6
+ MINOR = 3
7
7
  TINY = 0
8
8
 
9
9
  class << self
data/lib/solr4r.rb CHANGED
@@ -5,7 +5,7 @@
5
5
  # #
6
6
  # solr4r -- A Ruby client for Apache Solr #
7
7
  # #
8
- # Copyright (C) 2014-2015 Jens Wille #
8
+ # Copyright (C) 2014-2016 Jens Wille #
9
9
  # #
10
10
  # solr4r is free software: you can redistribute it and/or modify it under the #
11
11
  # terms of the GNU Affero General Public License as published by the Free #
@@ -41,4 +41,6 @@ require_relative 'solr4r/builder'
41
41
  require_relative 'solr4r/request'
42
42
  require_relative 'solr4r/response'
43
43
  require_relative 'solr4r/endpoints'
44
+ require_relative 'solr4r/query'
45
+ require_relative 'solr4r/batch'
44
46
  require_relative 'solr4r/client'
@@ -1,7 +1,5 @@
1
1
  describe Solr4R::Builder do
2
2
 
3
- subject { described_class.new(Solr4R::Client.new) }
4
-
5
3
  describe '#add' do
6
4
 
7
5
  example do
@@ -100,6 +98,39 @@ describe Solr4R::Builder do
100
98
  EOT
101
99
  end
102
100
 
101
+ example do
102
+ expect(subject.add(date: Date.new(1992, 03, 15))).to eq(<<-EOT)
103
+ <?xml version="1.0" encoding="UTF-8"?>
104
+ <add>
105
+ <doc>
106
+ <field name="date">1992-03-15T00:00:00Z</field>
107
+ </doc>
108
+ </add>
109
+ EOT
110
+ end
111
+
112
+ example do
113
+ expect(subject.add(time: Time.new(1992, 03, 15, 16, 23, 55, 3600))).to eq(<<-EOT)
114
+ <?xml version="1.0" encoding="UTF-8"?>
115
+ <add>
116
+ <doc>
117
+ <field name="time">1992-03-15T15:23:55Z</field>
118
+ </doc>
119
+ </add>
120
+ EOT
121
+ end
122
+
123
+ example do
124
+ expect(subject.add(datetime: DateTime.new(1992, 03, 15, 16, 23, 55, '+1'))).to eq(<<-EOT)
125
+ <?xml version="1.0" encoding="UTF-8"?>
126
+ <add>
127
+ <doc>
128
+ <field name="datetime">1992-03-15T15:23:55Z</field>
129
+ </doc>
130
+ </add>
131
+ EOT
132
+ end
133
+
103
134
  end
104
135
 
105
136
  describe '#commit' do
@@ -46,6 +46,20 @@ describe Solr4R::Client do
46
46
  ['title:foo -author%26:bar -author%26:baz', title: 'foo', '-author&' => %w[bar baz]],
47
47
  ['title:foo -author&:bar -author&:baz', { title: 'foo', '-author&' => %w[bar baz] }, false],
48
48
 
49
+ ['date:1992-03-15', date: Date.new(1992, 03, 15)],
50
+ ['time:1992-03-15T15\:23\:55Z', time: Time.new(1992, 03, 15, 16, 23, 55, 3600)],
51
+ ['datetime:1992-03-15T15\:23\:55Z', datetime: DateTime.new(1992, 03, 15, 16, 23, 55, '+1')],
52
+
53
+ ['stringrange:[a TO z]', stringrange: 'a'..'z'],
54
+ ['integerrange:[15 TO 25]', integerrange: 15..25],
55
+ ['floatrange:[-1.5 TO 2.5]', floatrange: -1.5..2.5],
56
+ ['daterange:[1992-03-15 TO 1992-04-25]',
57
+ daterange: Date.new(1992, 03, 15)..Date.new(1992, 04, 25)],
58
+ ['timerange:[1992-03-15T15:23:55Z TO 1992-04-25T15:23:55Z]',
59
+ timerange: Time.new(1992, 03, 15, 16, 23, 55, 3600)..Time.new(1992, 04, 25, 16, 23, 55, 3600)],
60
+ ['datetimerange:[1992-03-15T15:23:55Z TO 1992-04-25T15:23:55Z]',
61
+ datetimerange: DateTime.new(1992, 03, 15, 16, 23, 55, '+1')..DateTime.new(1992, 04, 25, 16, 23, 55, '+1')],
62
+
49
63
  ['{!q.op=AND}title:foo', title: 'foo', _: 'q.op=AND'],
50
64
  ['{!q.op=AND}title:foo author:bar', ['title:foo', author: 'bar', _: 'q.op=AND']],
51
65
  ['{!q.op=AND df=title}foo', ['foo', _: 'q.op=AND df=title']],