Skip to content

Commit cd90bfd

Browse files
authored
Merge pull request #96 from code4lib/resumption-token-incomplete-list
Include blank resumption token element in final partial list response
2 parents d676c18 + 1a47add commit cd90bfd

File tree

8 files changed

+42
-37
lines changed

8 files changed

+42
-37
lines changed

lib/oai/provider/model.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ module OAI::Provider
2929
# see the ResumptionToken class for more details.
3030
#
3131
class Model
32-
attr_reader :timestamp_field, :identifier_field
32+
attr_reader :timestamp_field, :identifier_field, :limit
3333

3434
def initialize(limit = nil, timestamp_field = 'updated_at', identifier_field = 'id')
3535
@limit = limit

lib/oai/provider/model/activerecord_caching_wrapper.rb

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,7 @@ def next_set(token_string)
7878
raise ResumptionTokenException.new unless @limit
7979

8080
token = ResumptionToken.parse(token_string)
81-
total = model.where(token_conditions(token)).count
82-
83-
if token.last * @limit + @limit < total
84-
select_partial(token)
85-
else
86-
select_partial(token).records
87-
end
81+
select_partial(token)
8882
end
8983

9084
# select a subset of the result set, and return it with a
@@ -102,10 +96,13 @@ def select_partial(token)
10296

10397
raise ResumptionTokenException.new unless oaitoken
10498

99+
total = model.where(token_conditions(token)).count
100+
# token offset should be nil if this is the last set
101+
offset = (token.last * @limit + @limit >= total) ? nil : token.last + 1
105102
PartialResult.new(
106103
hydrate_records(
107104
oaitoken.entries.limit(@limit).offset(token.last * @limit)),
108-
token.next(token.last + 1)
105+
token.next(offset)
109106
)
110107
end
111108

lib/oai/provider/model/activerecord_wrapper.rb

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -129,15 +129,7 @@ def next_set(find_scope, token_string)
129129
raise OAI::ResumptionTokenException.new unless @limit
130130

131131
token = ResumptionToken.parse(token_string)
132-
total = find_scope.where(token_conditions(token)).count
133-
134-
if @limit < total
135-
select_partial(find_scope, token)
136-
else # end of result set
137-
find_scope.where(token_conditions(token))
138-
.limit(@limit)
139-
.order("#{identifier_field} asc")
140-
end
132+
select_partial(find_scope, token)
141133
end
142134

143135
# select a subset of the result set, and return it with a
@@ -147,8 +139,10 @@ def select_partial(find_scope, token)
147139
.limit(@limit)
148140
.order("#{identifier_field} asc")
149141
raise OAI::ResumptionTokenException.new unless records
150-
offset = records.last.send(identifier_field)
151142

143+
total = find_scope.where(token_conditions(token)).count
144+
# token offset should be nil if this is the last set
145+
offset = (@limit >= total) ? nil : records.last.send(identifier_field)
152146
PartialResult.new(records, token.next(offset))
153147
end
154148

lib/oai/provider/resumption_token.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class ResumptionToken
3636
attr_reader :prefix, :set, :from, :until, :last, :last_str, :expiration, :total
3737

3838
# parses a token string and returns a ResumptionToken
39-
def self.parse(token_string)
39+
def self.parse(token_string, expiration = nil, total = nil)
4040
begin
4141
options = {}
4242
matches = /(.+):([^ :]+)$/.match(token_string)
@@ -54,7 +54,7 @@ def self.parse(token_string)
5454
options[:until] = Time.parse(part.sub(/^u\(/, '').sub(/\)$/, '')).localtime
5555
end
5656
end
57-
self.new(options)
57+
self.new(options, expiration, total)
5858
rescue => err
5959
raise OAI::ResumptionTokenException.new
6060
end
@@ -122,6 +122,8 @@ def last=(value)
122122
end
123123

124124
def encode_conditions
125+
return "" if last_str.nil? || last_str.to_s.strip.eql?("")
126+
125127
encoded_token = @prefix.to_s.dup
126128
encoded_token << ".s(#{set})" if set
127129
encoded_token << ".f(#{self.from.utc.xmlschema})" if self.from

test/activerecord_provider/tc_caching_paging_provider.rb

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ def test_full_harvest
1717
token = doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
1818
assert_equal 26, doc.elements["/OAI-PMH/ListRecords"].size
1919
doc = Document.new(@provider.list_records(:resumption_token => token))
20-
assert_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
21-
assert_equal 25, doc.elements["/OAI-PMH/ListRecords"].size
20+
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
21+
assert_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
22+
assert_equal 26, doc.elements["/OAI-PMH/ListRecords"].to_a.size
2223
end
2324

2425
def test_from_and_until
@@ -37,8 +38,9 @@ def test_from_and_until
3738
token = doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
3839
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
3940
doc = Document.new(@provider.list_records(:resumption_token => token))
40-
assert_equal 25, doc.elements["/OAI-PMH/ListRecords"].size
41-
assert_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
41+
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
42+
assert_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
43+
assert_equal 26, doc.elements["/OAI-PMH/ListRecords"].to_a.size
4244
end
4345

4446
def setup

test/activerecord_provider/tc_simple_paging_provider.rb

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ def test_full_harvest
2020
assert_equal 26, doc.elements["/OAI-PMH/ListRecords"].to_a.size
2121

2222
doc = Document.new(@provider.list_records(:resumption_token => token))
23-
assert_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
24-
assert_equal 25, doc.elements["/OAI-PMH/ListRecords"].to_a.size
23+
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
24+
assert_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
25+
assert_equal 26, doc.elements["/OAI-PMH/ListRecords"].to_a.size
2526
end
2627

2728
def test_non_integer_identifiers_resumption
@@ -58,8 +59,9 @@ def test_from_and_until
5859
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
5960
token = doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
6061
doc = Document.new(@provider.list_records(:resumption_token => token))
61-
assert_equal 25, doc.elements["/OAI-PMH/ListRecords"].to_a.size
62-
assert_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
62+
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
63+
assert_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
64+
assert_equal 26, doc.elements["/OAI-PMH/ListRecords"].to_a.size
6365
end
6466

6567
def setup

test/provider/models.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ def find(selector, opts={})
6868
if token.last < @groups.size - 1
6969
PartialResult.new(@groups[token.last], token.next(token.last + 1))
7070
else
71-
@groups[token.last]
71+
PartialResult.new(@groups[token.last], token.next(nil))
7272
end
7373
rescue
7474
raise OAI::ResumptionTokenException.new

test/provider/tc_functional_tokens.rb

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ class ResumptionTokenFunctionalTest < Test::Unit::TestCase
55

66
def setup
77
@provider = ComplexProvider.new
8+
@provider.model.instance_variable_set(:@limit, 120)
9+
end
10+
11+
def teardown
12+
@provider.model.instance_variable_set(:@limit, 100)
813
end
914

1015
def test_resumption_tokens
@@ -13,15 +18,15 @@ def test_resumption_tokens
1318
end
1419
doc = Document.new(@provider.list_records(:metadata_prefix => 'oai_dc'))
1520
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
16-
assert_equal 101, doc.elements["/OAI-PMH/ListRecords"].to_a.size
21+
assert_equal (@provider.model.limit + 1), doc.elements["/OAI-PMH/ListRecords"].to_a.size
1722
token = doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
1823
doc = Document.new(@provider.list_records(:resumption_token => token))
1924
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
20-
assert_equal 101, doc.elements["/OAI-PMH/ListRecords"].to_a.size
25+
assert_equal (@provider.model.limit + 1), doc.elements["/OAI-PMH/ListRecords"].to_a.size
2126
end
2227

2328
def test_from_and_until_with_resumption_tokens
24-
# Should return 300 records broken into 3 groups of 100.
29+
# Should return 300 records broken into 3 groups of 120, 120, and 60.
2530
assert_nothing_raised do
2631
Document.new(@provider.list_records(:metadata_prefix => 'oai_dc'))
2732
end
@@ -31,17 +36,20 @@ def test_from_and_until_with_resumption_tokens
3136
:from => Time.parse("September 1 2004"),
3237
:until => Time.parse("November 30 2004"))
3338
)
34-
assert_equal 101, doc.elements["/OAI-PMH/ListRecords"].to_a.size
39+
assert_equal (@provider.model.limit + 1), doc.elements["/OAI-PMH/ListRecords"].to_a.size
40+
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
3541
token = doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
3642

3743
doc = Document.new(@provider.list_records(:resumption_token => token))
3844
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
39-
assert_equal 101, doc.elements["/OAI-PMH/ListRecords"].to_a.size
45+
assert_equal (@provider.model.limit + 1), doc.elements["/OAI-PMH/ListRecords"].to_a.size
4046
token = doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
4147

4248
doc = Document.new(@provider.list_records(:resumption_token => token))
43-
assert_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
44-
assert_equal 100, doc.elements["/OAI-PMH/ListRecords"].to_a.size
49+
# assert that ListRecords includes remaining records and an empty resumption token
50+
assert_equal (301 % @provider.model.limit), doc.elements["/OAI-PMH/ListRecords"].to_a.size
51+
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
52+
assert_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
4553
end
4654

4755
end

0 commit comments

Comments
 (0)