sunspot 2.4.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: 385375ab001841dcd220a07df21307f581e5ed8d4c41c6907e4d2f05783259e5
4
- data.tar.gz: 0cd9f3eb2a5225b46429988a7a9d10f2ecbd488fd2c824448831a5f908a69c75
3
+ metadata.gz: 179de5f5261bdb69d21038a0b2e36fbd2812e1fc71ef4c1efd77979a03e58179
4
+ data.tar.gz: 1f7f40d9737400cf61c23515c61ebde70140b1c1bf9df800d7e19ce27c3cbd0d
5
5
  SHA512:
6
- metadata.gz: 97c5760b633b1ab3cbfb8a04a3dd49e9c0bd40485151c94b5c8196104a2b0fc47f1fdd97ff2d85b738c4d225820316dc1e42cceb5a19ea8c7f084a9b82e224f0
7
- data.tar.gz: 6ca3b17c3c28f89f56160ebdbaf2c924103976eb939df6832f0755d30a368c757dd912b5491b9a84caf38498e8320252ad14d59cd86ca4e8d071e3b2d95518e1
6
+ metadata.gz: ad59d5868f3461648d29c77b6368d7c5145ef6247ecca38878bf4f03bb3d2ab73fea2decf629936d58282b8067345198f6bff82be1347bb0cc92cb4537722d28
7
+ data.tar.gz: 3c4fd67940331fbdacffd665ca624119038bf12da2aa2b041adbd8260aef3921660b83803a912cf81384c7269f6b46d3b7fad1c883c34e1a1ba2ccbade2fd6dc
@@ -63,7 +63,10 @@ module Sunspot
63
63
  # String:: ID for use in Solr
64
64
  #
65
65
  def index_id #:nodoc:
66
- InstanceAdapter.index_id_for(@instance.class.name, id)
66
+ setup = Sunspot::Setup.for(@instance.class)
67
+ id_prefix = setup ? setup.id_prefix_for(@instance) : nil
68
+
69
+ InstanceAdapter.index_id_for("#{id_prefix}#{@instance.class.name}", id)
67
70
  end
68
71
 
69
72
  class <<self
@@ -55,6 +55,22 @@ module Sunspot
55
55
  @setup.add_document_boost(attr_name, &block)
56
56
  end
57
57
 
58
+ #
59
+ # If you use the compositeId router for shards, you can send documents
60
+ # with a prefix in the document ID which will be used to calculate the
61
+ # hash Solr uses to determine the shard a document is sent to for indexing.
62
+ # The prefix can be anything you’d like it to be (it doesn’t have to be
63
+ # the shard name, for example), but it must be consistent so Solr
64
+ # behaves consistently.
65
+ #
66
+ # ==== Parameters
67
+ #
68
+ # attr_name<Symbol,String>:: Attribute name to call or a string constant
69
+ #
70
+ def id_prefix(attr_name = nil, &block)
71
+ @setup.add_id_prefix(attr_name, &block)
72
+ end
73
+
58
74
  # method_missing is used to provide access to typed fields, because
59
75
  # developers should be able to add new Sunspot::Type implementations
60
76
  # dynamically and have them recognized inside the Fields DSL. Like #text,
@@ -17,6 +17,10 @@ module Sunspot
17
17
  # Class name of object associated with this hit, as string.
18
18
  #
19
19
  attr_reader :class_name
20
+ #
21
+ # ID prefix used for compositeId shard router
22
+ #
23
+ attr_reader :id_prefix
20
24
  #
21
25
  # Keyword relevance score associated with this result. Nil if this hit
22
26
  # is not from a keyword search.
@@ -27,7 +31,8 @@ module Sunspot
27
31
  attr_writer :result #:nodoc:
28
32
 
29
33
  def initialize(raw_hit, highlights, search) #:nodoc:
30
- @class_name, @primary_key = *raw_hit['id'].match(/([^ ]+) (.+)/)[1..2]
34
+ @id_prefix, @class_name, @primary_key =
35
+ *raw_hit['id'].match(/((?:[^!]+!)+)*([^\s]+)\s(.+)/)[1..3]
31
36
  @score = raw_hit['score']
32
37
  @search = search
33
38
  @stored_values = raw_hit
@@ -259,7 +259,7 @@ module Sunspot
259
259
  read_timeout: config.solr.read_timeout,
260
260
  open_timeout: config.solr.open_timeout,
261
261
  proxy: config.solr.proxy,
262
- update_format: config.solr.update_format || :xml
262
+ update_format: update_format_generator
263
263
  )
264
264
  end
265
265
 
@@ -277,5 +277,11 @@ module Sunspot
277
277
  CompositeSetup.for(types)
278
278
  end
279
279
  end
280
+
281
+ def update_format_generator
282
+ if config.solr.update_format && RSolr.version.to_i > 1
283
+ config.solr.update_format.downcase.to_sym == :json ? RSolr::JSON::Generator : RSolr::Xml::Generator
284
+ end
285
+ end
280
286
  end
281
287
  end
@@ -15,6 +15,7 @@ module Sunspot
15
15
  @more_like_this_field_factories_cache = Hash.new { |h, k| h[k] = [] }
16
16
  @dsl = DSL::Fields.new(self)
17
17
  @document_boost_extractor = nil
18
+ @id_prefix_extractor = nil
18
19
  add_field_factory(:class, Type::ClassType.instance)
19
20
  end
20
21
 
@@ -61,6 +62,7 @@ module Sunspot
61
62
  field_factory = FieldFactory::Static.new(name, Type::TextType.instance, options, &block)
62
63
  @text_field_factories[name] = field_factory
63
64
  @text_field_factories_cache[field_factory.name] = field_factory
65
+ @field_factories_cache[field_factory.name] = field_factory
64
66
  if stored
65
67
  @stored_field_factories_cache[field_factory.name] << field_factory
66
68
  end
@@ -81,6 +83,7 @@ module Sunspot
81
83
  field_factory = FieldFactory::Dynamic.new(name, type, options, &block)
82
84
  @dynamic_field_factories[field_factory.signature] = field_factory
83
85
  @dynamic_field_factories_cache[field_factory.name] = field_factory
86
+ @field_factories_cache[field_factory.name] = field_factory
84
87
  if stored
85
88
  @stored_field_factories_cache[field_factory.name] << field_factory
86
89
  end
@@ -107,6 +110,24 @@ module Sunspot
107
110
  end
108
111
  end
109
112
 
113
+ #
114
+ # Add id prefix for compositeId router
115
+ #
116
+ def add_id_prefix(attr_name, &block)
117
+ @id_prefix_extractor =
118
+ case attr_name
119
+ when Symbol
120
+ DataExtractor::AttributeExtractor.new(attr_name)
121
+ when String
122
+ DataExtractor::Constant.new(attr_name)
123
+ when nil
124
+ DataExtractor::BlockExtractor.new(&block) if block_given?
125
+ else
126
+ raise ArgumentError,
127
+ "The ID prefix has to be either a Symbol, a String or a Proc"
128
+ end
129
+ end
130
+
110
131
  #
111
132
  # Builder method for evaluating the setup DSL
112
133
  #
@@ -271,6 +292,16 @@ module Sunspot
271
292
  end
272
293
  end
273
294
 
295
+ def id_prefix_for(model)
296
+ if @id_prefix_extractor
297
+ value = @id_prefix_extractor.value_for(model)
298
+
299
+ if value.is_a?(String) and value.size > 0
300
+ value[-1] == "!" ? value : "#{value}!"
301
+ end
302
+ end
303
+ end
304
+
274
305
  protected
275
306
 
276
307
  #
@@ -1,3 +1,3 @@
1
1
  module Sunspot
2
- VERSION = '2.4.0'
2
+ VERSION = '2.5.0'
3
3
  end
@@ -20,6 +20,19 @@ describe Sunspot::Adapters::InstanceAdapter do
20
20
  Sunspot::Adapters::InstanceAdapter::for(UnseenModel)
21
21
  expect(Sunspot::Adapters::InstanceAdapter::registered_adapter_for(UnseenModel)).to be(AbstractModelInstanceAdapter)
22
22
  end
23
+
24
+ it "appends ID prefix when configured" do
25
+ expect(AbstractModelInstanceAdapter.new(ModelWithPrefixId.new).index_id).to eq "USERDATA!ModelWithPrefixId 1"
26
+ end
27
+
28
+ it "supports nested ID prefixes" do
29
+ expect(AbstractModelInstanceAdapter.
30
+ new(ModelWithNestedPrefixId.new).index_id).to eq "USER!USERDATA!ModelWithNestedPrefixId 1"
31
+ end
32
+
33
+ it "doesn't appends ID prefix when not configured" do
34
+ expect(AbstractModelInstanceAdapter.new(ModelWithoutPrefixId.new).index_id).to eq "ModelWithoutPrefixId 1"
35
+ end
23
36
  end
24
37
 
25
38
  describe Sunspot::Adapters::DataAccessor do
@@ -12,6 +12,20 @@ describe 'hits', :type => :search do
12
12
  end).to eq([['Post', post_1.id.to_s], ['Post', post_2.id.to_s]])
13
13
  end
14
14
 
15
+ it "should return ID prefix when used with compositeId shard router" do
16
+ Sunspot.index!(ModelWithPrefixId.new)
17
+
18
+ expect(Sunspot.search(ModelWithPrefixId).
19
+ hits.map { |h| h.id_prefix }.uniq).to eq ["USERDATA!"]
20
+ end
21
+
22
+ it "should parse nested ID prefixes" do
23
+ Sunspot.index!(ModelWithNestedPrefixId.new)
24
+
25
+ expect(Sunspot.search(ModelWithNestedPrefixId).
26
+ hits.map { |h| h.id_prefix }.uniq).to eq ["USER!USERDATA!"]
27
+ end
28
+
15
29
  it 'returns search total as attribute of hits' do
16
30
  stub_results(Post.new, 4)
17
31
  expect(session.search(Post) do
@@ -24,6 +24,9 @@ describe Sunspot do
24
24
  config_before_reset = Sunspot.config
25
25
  Sunspot.reset!(true)
26
26
  expect(Sunspot.config).to eq(config_before_reset)
27
+
28
+ # Restore sunspot config after test
29
+ Sunspot.reset!(false)
27
30
  end
28
31
  end
29
32
  end
@@ -31,6 +31,22 @@ describe 'fields lists' do
31
31
  end
32
32
  end
33
33
 
34
+ it 'does not raise Sunspot::UnrecognizedFieldError when listing existing text fields' do
35
+ expect do
36
+ Sunspot.search(Post) {
37
+ field_list(:body)
38
+ }
39
+ end.to_not raise_error
40
+ end
41
+
42
+ it 'does raise Sunspot::UnrecognizedFieldError when listing a non-existent text fields' do
43
+ expect do
44
+ Sunspot.search(Post) {
45
+ field_list(:bogus_body)
46
+ }
47
+ end.to raise_error(Sunspot::UnrecognizedFieldError)
48
+ end
49
+
34
50
  it 'does not load any stored fields' do
35
51
  hit = Sunspot.search(Post) { without_stored_fields }.hits.first
36
52
 
@@ -7,7 +7,40 @@ end
7
7
  class UnseenModel < AbstractModel
8
8
  end
9
9
 
10
+ class ModelWithPrefixId < AbstractModel
11
+ def id
12
+ 1
13
+ end
14
+ end
15
+
16
+ Sunspot.setup(ModelWithPrefixId) do
17
+ id_prefix { "USERDATA!" }
18
+ end
19
+
20
+ class ModelWithNestedPrefixId < AbstractModel
21
+ def id
22
+ 1
23
+ end
24
+ end
25
+
26
+ Sunspot.setup(ModelWithNestedPrefixId) do
27
+ id_prefix { "USER!USERDATA!" }
28
+ end
29
+
30
+ class ModelWithoutPrefixId < AbstractModel
31
+ def id
32
+ 1
33
+ end
34
+ end
35
+
36
+ Sunspot.setup(ModelWithoutPrefixId) do
37
+ end
38
+
39
+
10
40
  class AbstractModelInstanceAdapter < Sunspot::Adapters::InstanceAdapter
41
+ def id
42
+ @instance.id
43
+ end
11
44
  end
12
45
 
13
46
  class AbstractModelDataAccessor < Sunspot::Adapters::DataAccessor
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sunspot
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.0
4
+ version: 2.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mat Brown
@@ -30,7 +30,7 @@ authors:
30
30
  autorequire:
31
31
  bindir: bin
32
32
  cert_chain: []
33
- date: 2019-07-05 00:00:00.000000000 Z
33
+ date: 2019-07-12 00:00:00.000000000 Z
34
34
  dependencies:
35
35
  - !ruby/object:Gem::Dependency
36
36
  name: rsolr