Skip to content

Commit faf814f

Browse files
committed
✨ Add partial fetch modifier to uid_fetch
1 parent 68286f8 commit faf814f

File tree

2 files changed

+60
-4
lines changed

2 files changed

+60
-4
lines changed

lib/net/imap.rb

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,7 @@ module Net
537537
# ==== RFC9394: +PARTIAL+
538538
# - Updates #search, #uid_search with the +PARTIAL+ return option which adds
539539
# ESearchResult#partial return data.
540-
# - TODO: Updates #uid_fetch with the +partial+ modifier.
540+
# - Updates #uid_fetch with the +partial+ modifier.
541541
#
542542
# == References
543543
#
@@ -2439,7 +2439,7 @@ def fetch(...)
24392439
end
24402440

24412441
# :call-seq:
2442-
# uid_fetch(set, attr, changedsince: nil) -> array of FetchData
2442+
# uid_fetch(set, attr, changedsince: nil, partial: nil) -> array of FetchData
24432443
#
24442444
# Sends a {UID FETCH command [IMAP4rev1 §6.4.8]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.8]
24452445
# to retrieve data associated with a message in the mailbox.
@@ -2456,11 +2456,42 @@ def fetch(...)
24562456
#
24572457
# +changedsince+ (optional) behaves the same as with #fetch.
24582458
#
2459+
# +partial+ is an optional range to limit the number of results returned.
2460+
# It's useful when +set+ contains an unknown number of messages.
2461+
# <tt>1..500</tt> returns the first 500 messages in +set+ (in mailbox
2462+
# order), <tt>501..1000</tt> the second 500, and so on. +partial+ may also
2463+
# be negative: <tt>-500..-1</tt> selects the last 500 messages in +set+.
2464+
# <em>Requires the +PARTIAL+ capabability.</em>
2465+
# {[RFC9394]}[https://rfc-editor.org/rfc/rfc9394]
2466+
#
2467+
# For example:
2468+
#
2469+
# # Without partial, the size of the results may be unknown beforehand:
2470+
# results = imap.uid_fetch(next_uid_to_fetch.., %w(UID FLAGS))
2471+
# # ... maybe wait for a long time ... and allocate a lot of memory ...
2472+
# results.size # => 0..2**32-1
2473+
# process results # may also take a long time and use a lot of memory...
2474+
#
2475+
# # Using partial, the results may be paginated:
2476+
# loop do
2477+
# results = imap.uid_fetch(next_uid_to_fetch.., %w(UID FLAGS),
2478+
# partial: 1..500)
2479+
# # fetch should return quickly and allocate little memory
2480+
# results.size # => 0..500
2481+
# break if results.empty?
2482+
# next_uid_to_fetch = results.last.uid + 1
2483+
# process results
2484+
# end
2485+
#
24592486
# Related: #fetch, FetchData
24602487
#
24612488
# ==== Capabilities
24622489
#
2463-
# Same as #fetch.
2490+
# The server's capabilities must include +PARTIAL+
2491+
# {[RFC9394]}[https://rfc-editor.org/rfc/rfc9394] in order to use the
2492+
# +partial+ argument.
2493+
#
2494+
# Otherwise, the same as #fetch.
24642495
def uid_fetch(...)
24652496
fetch_internal("UID FETCH", ...)
24662497
end
@@ -3435,8 +3466,12 @@ def search_internal(cmd, ...)
34353466
end
34363467
end
34373468

3438-
def fetch_internal(cmd, set, attr, mod = nil, changedsince: nil)
3469+
def fetch_internal(cmd, set, attr, mod = nil, partial: nil, changedsince: nil)
34393470
set = SequenceSet[set]
3471+
if partial
3472+
mod ||= []
3473+
mod << "PARTIAL" << partial_range(partial)
3474+
end
34403475
if changedsince
34413476
mod ||= []
34423477
mod << "CHANGEDSINCE" << Integer(changedsince)

test/net/imap/test_imap.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1164,6 +1164,27 @@ def test_enable
11641164
end
11651165
end
11661166

1167+
test "#uid_fetch with partial" do
1168+
with_fake_server select: "inbox" do |server, imap|
1169+
server.on("UID FETCH", &:done_ok)
1170+
imap.uid_fetch 1.., "FAST", partial: 1..500
1171+
assert_equal("RUBY0002 UID FETCH 1:* FAST (PARTIAL 1:500)",
1172+
server.commands.pop.raw.strip)
1173+
imap.uid_fetch 1.., "FAST", partial: 1...501
1174+
assert_equal("RUBY0003 UID FETCH 1:* FAST (PARTIAL 1:500)",
1175+
server.commands.pop.raw.strip)
1176+
imap.uid_fetch 1.., "FAST", partial: -500..-1
1177+
assert_equal("RUBY0004 UID FETCH 1:* FAST (PARTIAL -500:-1)",
1178+
server.commands.pop.raw.strip)
1179+
imap.uid_fetch 1.., "FAST", partial: -500...-1
1180+
assert_equal("RUBY0005 UID FETCH 1:* FAST (PARTIAL -500:-2)",
1181+
server.commands.pop.raw.strip)
1182+
imap.uid_fetch 1.., "FAST", partial: 1..20, changedsince: 1234
1183+
assert_equal("RUBY0006 UID FETCH 1:* FAST (PARTIAL 1:20 CHANGEDSINCE 1234)",
1184+
server.commands.pop.raw.strip)
1185+
end
1186+
end
1187+
11671188
test "#store with unchangedsince" do
11681189
with_fake_server select: "inbox" do |server, imap|
11691190
server.on("STORE", &:done_ok)

0 commit comments

Comments
 (0)