blacklight_oai_provider 6.1.1 → 7.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +21 -50
- data/.rubocop.yml +1 -4
- data/.rubocop_todo.yml +53 -18
- data/.solr_wrapper +0 -1
- data/README.md +24 -3
- data/VERSION +1 -1
- data/blacklight_oai_provider.gemspec +5 -4
- data/lib/blacklight_oai_provider/solr_document_provider.rb +29 -10
- data/lib/blacklight_oai_provider/solr_document_wrapper.rb +60 -28
- data/lib/blacklight_oai_provider/solr_set.rb +6 -2
- data/lib/generators/blacklight_oai_provider/install_generator.rb +2 -2
- data/solr/conf/solrconfig.xml +182 -55
- data/spec/controllers/catalog_controller_spec.rb +1 -1
- data/spec/integration/blacklight_oai_provider/solr_document_wrapper_spec.rb +64 -0
- data/spec/lib/blacklight_oai_provider/solr_document_provider_spec.rb +18 -3
- data/spec/lib/blacklight_oai_provider/solr_document_wrapper_spec.rb +197 -22
- data/spec/requests/identify_spec.rb +1 -1
- data/spec/test_app_templates/lib/generators/test_app_generator.rb +28 -23
- metadata +47 -17
- data/spec/test_app_templates/templates/catalog_controller.rb +0 -196
data/solr/conf/solrconfig.xml
CHANGED
@@ -32,8 +32,6 @@
|
|
32
32
|
|
33
33
|
<lib dir="${solr.install.dir:../../../..}/contrib/analysis-extras/lib" />
|
34
34
|
<lib dir="${solr.install.dir:../../../..}/contrib/analysis-extras/lucene-libs" />
|
35
|
-
<lib dir="${solr.install.dir:../../../..}/contrib/extraction/lib" regex=".*\.jar" />
|
36
|
-
<lib dir="${solr.install.dir:../../../..}/dist/" regex="solr-cell-\d.*\.jar" />
|
37
35
|
|
38
36
|
<directoryFactory name="DirectoryFactory"
|
39
37
|
class="${solr.directoryFactory:solr.NRTCachingDirectoryFactory}">
|
@@ -47,7 +45,7 @@
|
|
47
45
|
<dataDir>${solr.blacklight-core.data.dir:}</dataDir>
|
48
46
|
|
49
47
|
<requestDispatcher handleSelect="true" >
|
50
|
-
<requestParsers enableRemoteStreaming="false" multipartUploadLimitInKB="
|
48
|
+
<requestParsers enableRemoteStreaming="false" multipartUploadLimitInKB="2048" />
|
51
49
|
</requestDispatcher>
|
52
50
|
|
53
51
|
<requestHandler name="/analysis/field" startup="lazy" class="solr.FieldAnalysisRequestHandler" />
|
@@ -57,21 +55,6 @@
|
|
57
55
|
<defaultQuery>*:*</defaultQuery>
|
58
56
|
</admin>
|
59
57
|
|
60
|
-
<updateHandler class="solr.DirectUpdateHandler2">
|
61
|
-
<updateLog>
|
62
|
-
<str name="dir">${solr.ulog.dir:}</str>
|
63
|
-
</updateLog>
|
64
|
-
|
65
|
-
<autoCommit>
|
66
|
-
<maxTime>${solr.autoCommit.maxTime:15000}</maxTime>
|
67
|
-
<openSearcher>false</openSearcher>
|
68
|
-
</autoCommit>
|
69
|
-
|
70
|
-
<autoSoftCommit>
|
71
|
-
<maxTime>${solr.autoSoftCommit.maxTime:-1}</maxTime>
|
72
|
-
</autoSoftCommit>
|
73
|
-
</updateHandler>
|
74
|
-
|
75
58
|
<!-- SearchHandler
|
76
59
|
|
77
60
|
http://wiki.apache.org/solr/SearchHandler
|
@@ -86,54 +69,161 @@
|
|
86
69
|
will be overridden by parameters in the request
|
87
70
|
-->
|
88
71
|
<lst name="defaults">
|
89
|
-
<str name="defType">
|
72
|
+
<str name="defType">dismax</str>
|
90
73
|
<str name="echoParams">explicit</str>
|
74
|
+
<int name="rows">10</int>
|
75
|
+
|
91
76
|
<str name="q.alt">*:*</str>
|
92
77
|
<str name="mm">2<-1 5<-2 6<90%</str>
|
93
|
-
|
94
|
-
<int name="ps">2</int>
|
95
|
-
<float name="tie">0.01</float>
|
78
|
+
|
96
79
|
<!-- this qf and pf are used by default, if not otherwise specified by
|
97
80
|
client. The default blacklight_config will use these for the
|
98
|
-
"keywords" search. See the author_qf/author_pf, title_qf, etc
|
81
|
+
"keywords" search. See the author_qf/author_pf, title_qf, etc
|
99
82
|
below, which the default blacklight_config will specify for
|
100
83
|
those searches. You may also be interested in:
|
101
84
|
http://wiki.apache.org/solr/LocalParams
|
102
85
|
-->
|
103
|
-
<str name="qf">
|
104
|
-
id
|
105
|
-
title_tsim
|
106
|
-
author_tsim
|
107
|
-
subject_ssim
|
108
|
-
</str>
|
109
|
-
<str name="pf">
|
110
|
-
all_text_timv^10
|
111
|
-
</str>
|
112
86
|
|
87
|
+
<str name="qf">
|
88
|
+
title_unstem_search^100000
|
89
|
+
subtitle_unstem_search^50000
|
90
|
+
title_t^25000
|
91
|
+
subtitle_t^10000
|
92
|
+
title_addl_unstem_search^5000
|
93
|
+
title_addl_t^2500
|
94
|
+
title_added_entry_unstem_search^1500
|
95
|
+
title_added_entry_t^1250
|
96
|
+
subject_topic_unstem_search^1000
|
97
|
+
subject_unstem_search^750
|
98
|
+
subject_topic_facet^625
|
99
|
+
subject_t^500
|
100
|
+
author_unstem_search^250
|
101
|
+
author_addl_unstem_search^250
|
102
|
+
author_t^100
|
103
|
+
author_addl_t^50
|
104
|
+
subject_addl_unstem_search^250
|
105
|
+
subject_addl_t^50
|
106
|
+
title_series_unstem_search^25
|
107
|
+
title_series_t^10
|
108
|
+
isbn_t
|
109
|
+
text
|
110
|
+
</str>
|
111
|
+
<str name="pf">
|
112
|
+
title_unstem_search^1000000
|
113
|
+
subtitle_unstem_search^500000
|
114
|
+
title_t^250000
|
115
|
+
subtitle_t^100000
|
116
|
+
title_addl_unstem_search^50000
|
117
|
+
title_addl_t^25000
|
118
|
+
title_added_entry_unstem_search^15000
|
119
|
+
title_added_entry_t^12500
|
120
|
+
subject_topic_unstem_search^10000
|
121
|
+
subject_unstem_search^7500
|
122
|
+
subject_topic_facet^6250
|
123
|
+
subject_t^5000
|
124
|
+
author_unstem_search^2500
|
125
|
+
author_addl_unstem_search^2500
|
126
|
+
author_t^1000
|
127
|
+
author_addl_t^500
|
128
|
+
subject_addl_unstem_search^2500
|
129
|
+
subject_addl_t^500
|
130
|
+
title_series_unstem_search^250
|
131
|
+
title_series_t^100
|
132
|
+
text^10
|
133
|
+
</str>
|
113
134
|
<str name="author_qf">
|
114
|
-
|
135
|
+
author_unstem_search^200
|
136
|
+
author_addl_unstem_search^50
|
137
|
+
author_t^20
|
138
|
+
author_addl_t
|
115
139
|
</str>
|
116
140
|
<str name="author_pf">
|
141
|
+
author_unstem_search^2000
|
142
|
+
author_addl_unstem_search^500
|
143
|
+
author_t^200
|
144
|
+
author_addl_t^10
|
117
145
|
</str>
|
118
146
|
<str name="title_qf">
|
119
|
-
|
147
|
+
title_unstem_search^50000
|
148
|
+
subtitle_unstem_search^25000
|
149
|
+
title_addl_unstem_search^10000
|
150
|
+
title_t^5000
|
151
|
+
subtitle_t^2500
|
152
|
+
title_addl_t^100
|
153
|
+
title_added_entry_unstem_search^50
|
154
|
+
title_added_entry_t^10
|
155
|
+
title_series_unstem_search^5
|
156
|
+
title_series_t
|
120
157
|
</str>
|
121
158
|
<str name="title_pf">
|
159
|
+
title_unstem_search^500000
|
160
|
+
subtitle_unstem_search^250000
|
161
|
+
title_addl_unstem_search^100000
|
162
|
+
title_t^50000
|
163
|
+
subtitle_t^25000
|
164
|
+
title_addl_t^1000
|
165
|
+
title_added_entry_unstem_search^500
|
166
|
+
title_added_entry_t^100
|
167
|
+
title_series_t^50
|
168
|
+
title_series_unstem_search^10
|
122
169
|
</str>
|
123
170
|
<str name="subject_qf">
|
124
|
-
|
171
|
+
subject_topic_unstem_search^200
|
172
|
+
subject_unstem_search^125
|
173
|
+
subject_topic_facet^100
|
174
|
+
subject_t^50
|
175
|
+
subject_addl_unstem_search^10
|
176
|
+
subject_addl_t
|
125
177
|
</str>
|
126
178
|
<str name="subject_pf">
|
179
|
+
subject_topic_unstem_search^2000
|
180
|
+
subject_unstem_search^1250
|
181
|
+
subject_t^1000
|
182
|
+
subject_topic_facet^500
|
183
|
+
subject_addl_unstem_search^100
|
184
|
+
subject_addl_t^10
|
127
185
|
</str>
|
186
|
+
|
187
|
+
<int name="ps">3</int>
|
188
|
+
<float name="tie">0.01</float>
|
128
189
|
|
129
190
|
<str name="fl">
|
130
|
-
|
131
|
-
score
|
191
|
+
id,
|
192
|
+
score,
|
193
|
+
author_display,
|
194
|
+
author_vern_display,
|
195
|
+
format,
|
196
|
+
isbn_t,
|
197
|
+
language_facet,
|
198
|
+
lc_callnum_display,
|
199
|
+
material_type_display,
|
200
|
+
published_display,
|
201
|
+
published_vern_display,
|
202
|
+
pub_date,
|
203
|
+
title_display,
|
204
|
+
title_vern_display,
|
205
|
+
subject_topic_facet,
|
206
|
+
subject_geo_facet,
|
207
|
+
subject_era_facet,
|
208
|
+
subtitle_display,
|
209
|
+
subtitle_vern_display,
|
210
|
+
url_fulltext_display,
|
211
|
+
url_suppl_display,
|
212
|
+
marc_display,
|
132
213
|
</str>
|
133
214
|
|
134
215
|
<str name="facet">true</str>
|
135
216
|
<str name="facet.mincount">1</str>
|
136
|
-
|
217
|
+
<str name="facet.field">format</str>
|
218
|
+
<str name="facet.field">lc_1letter_facet</str>
|
219
|
+
<str name="facet.field">lc_alpha_facet</str>
|
220
|
+
<str name="facet.field">lc_b4cutter_facet</str>
|
221
|
+
<str name="facet.field">language_facet</str>
|
222
|
+
<str name="facet.field">pub_date</str>
|
223
|
+
<str name="facet.field">subject_era_facet</str>
|
224
|
+
<str name="facet.field">subject_geo_facet</str>
|
225
|
+
<str name="facet.field">subject_topic_facet</str>
|
226
|
+
|
137
227
|
<str name="spellcheck">true</str>
|
138
228
|
<str name="spellcheck.dictionary">default</str>
|
139
229
|
<str name="spellcheck.onlyMorePopular">true</str>
|
@@ -142,9 +232,62 @@
|
|
142
232
|
<str name="spellcheck.count">5</str>
|
143
233
|
|
144
234
|
</lst>
|
235
|
+
<!-- In addition to defaults, "appends" params can be specified
|
236
|
+
to identify values which should be appended to the list of
|
237
|
+
multi-val params from the query (or the existing "defaults").
|
238
|
+
-->
|
239
|
+
<!-- In this example, the param "fq=instock:true" would be appended to
|
240
|
+
any query time fq params the user may specify, as a mechanism for
|
241
|
+
partitioning the index, independent of any user selected filtering
|
242
|
+
that may also be desired (perhaps as a result of faceted searching).
|
243
|
+
|
244
|
+
NOTE: there is *absolutely* nothing a client can do to prevent these
|
245
|
+
"appends" values from being used, so don't use this mechanism
|
246
|
+
unless you are sure you always want it.
|
247
|
+
-->
|
248
|
+
<!--
|
249
|
+
<lst name="appends">
|
250
|
+
<str name="fq">inStock:true</str>
|
251
|
+
</lst>
|
252
|
+
-->
|
253
|
+
<!-- "invariants" are a way of letting the Solr maintainer lock down
|
254
|
+
the options available to Solr clients. Any params values
|
255
|
+
specified here are used regardless of what values may be specified
|
256
|
+
in either the query, the "defaults", or the "appends" params.
|
257
|
+
|
258
|
+
In this example, the facet.field and facet.query params would
|
259
|
+
be fixed, limiting the facets clients can use. Faceting is
|
260
|
+
not turned on by default - but if the client does specify
|
261
|
+
facet=true in the request, these are the only facets they
|
262
|
+
will be able to see counts for; regardless of what other
|
263
|
+
facet.field or facet.query params they may specify.
|
264
|
+
|
265
|
+
NOTE: there is *absolutely* nothing a client can do to prevent these
|
266
|
+
"invariants" values from being used, so don't use this mechanism
|
267
|
+
unless you are sure you always want it.
|
268
|
+
-->
|
269
|
+
<!--
|
270
|
+
<lst name="invariants">
|
271
|
+
<str name="facet.field">cat</str>
|
272
|
+
<str name="facet.field">manu_exact</str>
|
273
|
+
<str name="facet.query">price:[* TO 500]</str>
|
274
|
+
<str name="facet.query">price:[500 TO *]</str>
|
275
|
+
</lst>
|
276
|
+
-->
|
277
|
+
<!-- If the default list of SearchComponents is not desired, that
|
278
|
+
list can either be overridden completely, or components can be
|
279
|
+
prepended or appended to the default list. (see below)
|
280
|
+
-->
|
281
|
+
<!--
|
282
|
+
<arr name="components">
|
283
|
+
<str>nameOfCustomComponent1</str>
|
284
|
+
<str>nameOfCustomComponent2</str>
|
285
|
+
</arr>
|
286
|
+
-->
|
145
287
|
<arr name="last-components">
|
146
288
|
<str>spellcheck</str>
|
147
289
|
</arr>
|
290
|
+
|
148
291
|
</requestHandler>
|
149
292
|
|
150
293
|
<!-- Spell Check
|
@@ -233,8 +376,6 @@
|
|
233
376
|
-->
|
234
377
|
</searchComponent>
|
235
378
|
|
236
|
-
<!-- suggest searchComponent and requestHandler disabled by default due to performance penalties -->
|
237
|
-
<!--
|
238
379
|
<searchComponent name="suggest" class="solr.SuggestComponent">
|
239
380
|
<lst name="suggester">
|
240
381
|
<str name="name">mySuggester</str>
|
@@ -255,20 +396,6 @@
|
|
255
396
|
<str>suggest</str>
|
256
397
|
</arr>
|
257
398
|
</requestHandler>
|
258
|
-
|
259
|
-
|
260
|
-
<requestHandler name="/update/extract" class="org.apache.solr.handler.extraction.ExtractingRequestHandler">
|
261
|
-
<lst name="defaults">
|
262
|
-
<str name="fmap.Last-Modified">last_modified</str>
|
263
|
-
<str name="uprefix">ignored_</str>
|
264
|
-
</lst>
|
265
|
-
<!--Optional. Specify a path to a tika configuration file. See the Tika docs for details.-->
|
266
|
-
<!-- <str name="tika.config">/my/path/to/tika.config</str> -->
|
267
|
-
<!-- Optional. Specify one or more date formats to parse. See DateUtil.DEFAULT_DATE_FORMATS
|
268
|
-
for default date formats -->
|
269
|
-
<!-- <lst name="date.formats"> -->
|
270
|
-
<!-- <str>yyyy-MM-dd</str> -->
|
271
|
-
<!-- </lst> -->
|
272
|
-
</requestHandler>
|
399
|
+
|
273
400
|
</config>
|
274
401
|
|
@@ -19,7 +19,7 @@ describe CatalogController do
|
|
19
19
|
it 'returns correct provider configuration' do
|
20
20
|
expect(controller.oai_config).to include(
|
21
21
|
provider: {
|
22
|
-
repository_name: "
|
22
|
+
repository_name: "Catalog Repository",
|
23
23
|
repository_url: "http://localhost/catalog/oai",
|
24
24
|
record_prefix: "oai:test",
|
25
25
|
admin_email: "root@localhost",
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe BlacklightOaiProvider::SolrDocumentWrapper do
|
4
|
+
subject(:wrapper) { described_class.new(controller, options) }
|
5
|
+
|
6
|
+
let(:options) { {} }
|
7
|
+
let(:controller_class) { CatalogController }
|
8
|
+
let(:controller) { controller_class.new }
|
9
|
+
|
10
|
+
before do
|
11
|
+
allow(controller).to receive(:params).and_return({})
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#earliest' do
|
15
|
+
it 'returns the earliest timestamp of all the records' do
|
16
|
+
expect(wrapper.earliest).to eq Time.parse('2014-02-03 18:42:53.056000000 +0000').utc
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#latest' do
|
21
|
+
it 'returns the latest timestamp of all the records' do
|
22
|
+
expect(wrapper.latest).to eq Time.parse('2015-02-03 18:42:53.056000000 +0000').utc
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#find' do
|
27
|
+
context 'when selector is :all' do
|
28
|
+
it 'returns a limited list of all records' do
|
29
|
+
expect(wrapper.find(:all)).to be_a OAI::Provider::PartialResult
|
30
|
+
expect(wrapper.find(:all).records.size).to be 15
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'when selector is an individual record' do
|
35
|
+
let(:search_builder_class) do
|
36
|
+
Class.new(Blacklight::SearchBuilder) do
|
37
|
+
include Blacklight::Solr::SearchBuilderBehavior
|
38
|
+
self.default_processor_chain += [:only_visible]
|
39
|
+
|
40
|
+
def only_visible(solr_parameters)
|
41
|
+
solr_parameters[:fq] ||= []
|
42
|
+
solr_parameters[:fq] << 'visibility_si:"open"'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
let(:controller_class) do
|
47
|
+
stub_const 'VisibilitySearchBuilder', search_builder_class
|
48
|
+
Class.new(CatalogController) do
|
49
|
+
blacklight_config.configure do |config|
|
50
|
+
config.search_builder_class = VisibilitySearchBuilder
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'returns nothing for a restricted work' do
|
56
|
+
expect(wrapper.find('2007020969')).to be_nil
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'returns a single record for a public work' do
|
60
|
+
expect(wrapper.find('2005553155')).to be_a SolrDocument
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -32,19 +32,34 @@ RSpec.describe BlacklightOaiProvider::SolrDocumentProvider do
|
|
32
32
|
end
|
33
33
|
|
34
34
|
context 'with Procs provided as option values' do
|
35
|
+
let(:alternate_controller) { AlternateController.new }
|
36
|
+
let(:alternate_provider) { described_class.new(alternate_controller, options) }
|
37
|
+
let(:alternate_view_context) { instance_double("ViewContext") }
|
35
38
|
let(:options) do
|
36
39
|
{
|
37
40
|
provider: {
|
38
|
-
repository_name: ->(kontroller) { "Hello #{kontroller.
|
39
|
-
repository_url: ->(kontroller) { "Hello #{kontroller.view_context.
|
41
|
+
repository_name: ->(kontroller) { "Hello #{kontroller.controller_name.titleize}" },
|
42
|
+
repository_url: ->(kontroller) { "Hello #{kontroller.view_context.send "oai_#{kontroller.controller_name}_url"}" }
|
40
43
|
}
|
41
44
|
}
|
42
45
|
end
|
43
46
|
|
47
|
+
before do
|
48
|
+
allow(alternate_controller).to receive(:view_context).and_return(alternate_view_context)
|
49
|
+
allow(alternate_view_context).to receive(:oai_alternate_url).and_return(:another_path)
|
50
|
+
allow(alternate_view_context).to receive(:application_name).and_return(:another_name)
|
51
|
+
end
|
52
|
+
|
44
53
|
it 'call()-s the Proc to set the option value' do
|
45
|
-
expect(provider.name).to eq "Hello
|
54
|
+
expect(provider.name).to eq "Hello Catalog"
|
46
55
|
expect(provider.url).to eq "Hello #{controller.view_context.oai_catalog_url}"
|
47
56
|
end
|
57
|
+
|
58
|
+
it 'does not pollute controller configurations from procs' do
|
59
|
+
provider.name
|
60
|
+
expect(alternate_provider.name).to eq "Hello Alternate"
|
61
|
+
expect(provider.name).to eq "Hello Catalog"
|
62
|
+
end
|
48
63
|
end
|
49
64
|
end
|
50
65
|
end
|
@@ -4,10 +4,12 @@ RSpec.describe BlacklightOaiProvider::SolrDocumentWrapper do
|
|
4
4
|
subject(:wrapper) { described_class.new(controller, options) }
|
5
5
|
|
6
6
|
let(:options) { {} }
|
7
|
-
let(:
|
7
|
+
let(:controller_class) { CatalogController }
|
8
|
+
let(:controller) { instance_double(CatalogController) }
|
9
|
+
let(:blacklight_config) { Blacklight::Configuration.new }
|
8
10
|
|
9
11
|
before do
|
10
|
-
allow(controller).to
|
12
|
+
allow(controller).to receive_messages(params: {}, blacklight_config: blacklight_config)
|
11
13
|
end
|
12
14
|
|
13
15
|
describe '#initialize' do
|
@@ -30,51 +32,224 @@ RSpec.describe BlacklightOaiProvider::SolrDocumentWrapper do
|
|
30
32
|
end
|
31
33
|
end
|
32
34
|
|
35
|
+
shared_context "timestamp_searches" do
|
36
|
+
let(:expected_timestamp) { '2014-02-03 18:42:53.056000000 +0000' }
|
37
|
+
let(:repository) { instance_double(Blacklight::Solr::Repository) }
|
38
|
+
let(:search_builder) { instance_double(Blacklight::SearchBuilder) }
|
39
|
+
let(:search_service) { instance_double(Blacklight::SearchService) }
|
40
|
+
let(:documents) { [SolrDocument.new('timestamp' => expected_timestamp)] }
|
41
|
+
let(:response) { OpenStruct.new(documents: documents, total: documents.length) }
|
42
|
+
|
43
|
+
before do
|
44
|
+
allow(controller).to receive(:search_service).and_return(search_service)
|
45
|
+
allow(search_service).to receive_messages(repository: repository, search_builder: search_builder)
|
46
|
+
allow(repository).to receive(:search).with(search_builder).and_return(response)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
33
50
|
describe '#earliest' do
|
51
|
+
include_context "timestamp_searches"
|
52
|
+
|
53
|
+
before do
|
54
|
+
allow(search_builder).to receive(:merge).with(hash_including(sort: "timestamp asc")).and_return(search_builder)
|
55
|
+
end
|
56
|
+
|
34
57
|
it 'returns the earliest timestamp of all the records' do
|
35
|
-
expect(wrapper.earliest).to eq Time.parse(
|
58
|
+
expect(wrapper.earliest).to eq Time.parse(expected_timestamp).utc
|
59
|
+
end
|
60
|
+
|
61
|
+
context "no documents are returned" do
|
62
|
+
let(:documents) { [] }
|
63
|
+
|
64
|
+
it 'returns a default timestamp' do
|
65
|
+
expect(Time.parse(wrapper.earliest).utc).to be_a Time
|
66
|
+
end
|
36
67
|
end
|
37
68
|
end
|
38
69
|
|
39
70
|
describe '#latest' do
|
71
|
+
include_context "timestamp_searches"
|
72
|
+
|
73
|
+
before do
|
74
|
+
allow(search_builder).to receive(:merge).with(hash_including(sort: "timestamp desc")).and_return(search_builder)
|
75
|
+
end
|
76
|
+
|
40
77
|
it 'returns the latest timestamp of all the records' do
|
41
|
-
expect(wrapper.latest).to eq Time.parse(
|
78
|
+
expect(wrapper.latest).to eq Time.parse(expected_timestamp).utc
|
79
|
+
end
|
80
|
+
|
81
|
+
context "no documents are returned" do
|
82
|
+
let(:documents) { [] }
|
83
|
+
|
84
|
+
it 'returns a default timestamp' do
|
85
|
+
expect(Time.parse(wrapper.latest).utc).to be_a Time
|
86
|
+
end
|
42
87
|
end
|
43
88
|
end
|
44
89
|
|
45
90
|
describe '#find' do
|
91
|
+
include_context "timestamp_searches"
|
92
|
+
|
93
|
+
subject(:result) { wrapper.find(selector) }
|
94
|
+
|
46
95
|
context 'when selector is :all' do
|
96
|
+
let(:selector) { :all }
|
97
|
+
let(:query) { {} }
|
98
|
+
let(:limit) { 1 }
|
99
|
+
let(:options) { { limit: limit } }
|
100
|
+
let(:response) { OpenStruct.new(documents: documents, total: limit + 1) }
|
101
|
+
let(:next_response) { OpenStruct.new(documents: documents, total: documents.length) }
|
102
|
+
|
103
|
+
before do
|
104
|
+
allow(search_builder).to receive_messages(merge: search_builder, query: query)
|
105
|
+
allow(repository).to receive(:search).with(query).and_return(response)
|
106
|
+
allow(repository).to receive(:search).with(hash_including(start: 0)).and_return(next_response)
|
107
|
+
end
|
108
|
+
|
47
109
|
it 'returns a limited list of all records' do
|
48
|
-
expect(
|
49
|
-
expect(
|
110
|
+
expect(result).to be_a OAI::Provider::PartialResult
|
111
|
+
expect(result.records.size).to be limit
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context 'when selector is an id value' do
|
116
|
+
let(:selector) { '2007020969' }
|
117
|
+
let(:query) { {} }
|
118
|
+
|
119
|
+
before do
|
120
|
+
allow(search_builder).to receive(:query).and_return(query)
|
121
|
+
allow(repository).to receive(:search).with(query).and_return(response)
|
122
|
+
allow(search_builder).to receive(:where).with(id: selector).and_return(search_builder)
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'searches by id' do
|
126
|
+
expect(result).to be_a(SolrDocument)
|
127
|
+
expect(search_builder).to have_received(:where).with(id: selector)
|
50
128
|
end
|
51
129
|
end
|
130
|
+
end
|
131
|
+
|
132
|
+
describe '#conditions' do
|
133
|
+
include_context "timestamp_searches"
|
52
134
|
|
53
|
-
|
54
|
-
|
135
|
+
subject(:result) { wrapper.conditions(constraints) }
|
136
|
+
|
137
|
+
let(:search_builder_class) do
|
138
|
+
Class.new(Blacklight::SearchBuilder) do
|
55
139
|
include Blacklight::Solr::SearchBuilderBehavior
|
56
|
-
|
140
|
+
end
|
141
|
+
end
|
142
|
+
let(:search_builder) { search_builder_class.new(controller) }
|
57
143
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
144
|
+
context 'time options' do
|
145
|
+
let(:constraints) { { from: Time.utc(2015, 1, 1), until: Time.utc(2015, 1, 2) } }
|
146
|
+
|
147
|
+
it 'sets options when from' do
|
148
|
+
constraints.delete(:until)
|
149
|
+
expect(result).to include(
|
150
|
+
"fq" => ["timestamp:[2015-01-01T00:00:00Z TO *]"],
|
151
|
+
"sort" => "timestamp asc"
|
152
|
+
)
|
62
153
|
end
|
63
154
|
|
64
|
-
|
65
|
-
|
155
|
+
it 'sets options when until' do
|
156
|
+
constraints.delete(:from)
|
157
|
+
expect(result).to include(
|
158
|
+
"fq" => ["timestamp:[* TO 2015-01-02T00:00:00.999Z]"],
|
159
|
+
"sort" => "timestamp asc"
|
160
|
+
)
|
66
161
|
end
|
67
162
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
163
|
+
it 'sets options when range' do
|
164
|
+
expect(result).to include(
|
165
|
+
"fq" => ["timestamp:[2015-01-01T00:00:00Z TO 2015-01-02T00:00:00.999Z]"],
|
166
|
+
"sort" => "timestamp asc"
|
167
|
+
)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
context 'date options' do
|
172
|
+
let(:constraints) { { from: Date.parse('2015-01-01'), until: Date.parse('2015-01-02') } }
|
173
|
+
|
174
|
+
it 'sets options for high granularity' do
|
175
|
+
expect(result).to include(
|
176
|
+
"fq" => ["timestamp:[2015-01-01T00:00:00Z TO 2015-01-02T23:59:59.999Z]"],
|
177
|
+
"sort" => "timestamp asc"
|
178
|
+
)
|
72
179
|
end
|
180
|
+
# rubocop:disable RSpec/NestedGroups
|
181
|
+
context 'low granularity' do
|
182
|
+
let(:options) { { granularity: OAI::Const::Granularity::LOW } }
|
73
183
|
|
74
|
-
|
75
|
-
|
76
|
-
expect(
|
184
|
+
it 'sets options' do
|
185
|
+
expect(wrapper.granularity).to eql(OAI::Const::Granularity::LOW)
|
186
|
+
expect(result).to include(
|
187
|
+
"fq" => ["timestamp:[2015-01-01 TO 2015-01-02]"],
|
188
|
+
"sort" => "timestamp asc"
|
189
|
+
)
|
77
190
|
end
|
191
|
+
context 'same value for endpoints' do
|
192
|
+
let(:constraints) { { from: Date.parse('2015-01-01'), until: Date.parse('2015-01-01') } }
|
193
|
+
|
194
|
+
it 'sets options' do
|
195
|
+
expect(wrapper.granularity).to eql(OAI::Const::Granularity::LOW)
|
196
|
+
expect(result).to include(
|
197
|
+
"fq" => ["timestamp:\"2015-01-01\""],
|
198
|
+
"sort" => "timestamp asc"
|
199
|
+
)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
# rubocop:enable RSpec/NestedGroups
|
204
|
+
end
|
205
|
+
|
206
|
+
context 'string date options' do
|
207
|
+
let(:constraints) { { from: '2015-01-01', until: '2015-01-02' } }
|
208
|
+
|
209
|
+
it 'sets options when from' do
|
210
|
+
constraints.delete(:until)
|
211
|
+
expect(result).to include(
|
212
|
+
"fq" => ["timestamp:[2015-01-01 TO *]"],
|
213
|
+
"sort" => "timestamp asc"
|
214
|
+
)
|
215
|
+
end
|
216
|
+
it 'sets options when until' do
|
217
|
+
constraints.delete(:from)
|
218
|
+
expect(result).to include(
|
219
|
+
"fq" => ["timestamp:[* TO 2015-01-02]"],
|
220
|
+
"sort" => "timestamp asc"
|
221
|
+
)
|
222
|
+
end
|
223
|
+
it 'sets options when range' do
|
224
|
+
expect(result).to include(
|
225
|
+
"fq" => ["timestamp:[2015-01-01 TO 2015-01-02]"],
|
226
|
+
"sort" => "timestamp asc"
|
227
|
+
)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
context 'string time options' do
|
232
|
+
let(:constraints) { { from: '2015-01-01T00:00:00.000Z', until: '2015-01-02T00:00:00.000Z' } }
|
233
|
+
|
234
|
+
it 'sets options when from' do
|
235
|
+
constraints.delete(:until)
|
236
|
+
expect(result).to include(
|
237
|
+
"fq" => ["timestamp:[2015-01-01T00:00:00.000Z TO *]"],
|
238
|
+
"sort" => "timestamp asc"
|
239
|
+
)
|
240
|
+
end
|
241
|
+
it 'sets options when until' do
|
242
|
+
constraints.delete(:from)
|
243
|
+
expect(result).to include(
|
244
|
+
"fq" => ["timestamp:[* TO 2015-01-02T00:00:00.000Z]"],
|
245
|
+
"sort" => "timestamp asc"
|
246
|
+
)
|
247
|
+
end
|
248
|
+
it 'sets options when range' do
|
249
|
+
expect(result).to include(
|
250
|
+
"fq" => ["timestamp:[2015-01-01T00:00:00.000Z TO 2015-01-02T00:00:00.000Z]"],
|
251
|
+
"sort" => "timestamp asc"
|
252
|
+
)
|
78
253
|
end
|
79
254
|
end
|
80
255
|
end
|