@@ -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 #
@@ -2437,14 +2437,37 @@ def fetch(...)
24372437 end
24382438
24392439 # :call-seq:
2440- # uid_fetch(set, attr, changedsince: nil) -> array of FetchData
2440+ # uid_fetch(set, attr, changedsince: nil, partial: nil ) -> array of FetchData
24412441 #
24422442 # Sends a {UID FETCH command [IMAP4rev1 §6.4.8]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.4.8]
24432443 # to retrieve data associated with a message in the mailbox.
24442444 #
24452445 # Similar to #fetch, but the +set+ parameter contains unique identifiers
24462446 # instead of message sequence numbers.
24472447 #
2448+ # When #uid_fetch may also be given a +partial+ range, which can be used to
2449+ # limit the number of results. <em>Requires the +PARTIAL+
2450+ # capabability.</em> {[RFC9394]}[https://rfc-editor.org/rfc/rfc9394]
2451+ #
2452+ # For example:
2453+ #
2454+ # # Without partial, the size of the results may be unknown beforehand:
2455+ # results = imap.uid_fetch(next_uid_to_fetch.., %w(UID FLAGS))
2456+ # # ... maybe wait for a long time ... and allocate a lot of memory ...
2457+ # results.size # => 0..2**32-1
2458+ # process results # may also take a long time and use a lot of memory...
2459+ #
2460+ # # Using partial, the results may be paginated:
2461+ # loop do
2462+ # results = imap.uid_fetch(next_uid_to_fetch.., %w(UID FLAGS),
2463+ # partial: 1..500)
2464+ # # fetch should return quickly and allocate little memory
2465+ # results.size # => 0..500
2466+ # break if results.empty?
2467+ # next_uid_to_fetch = results.last.uid + 1
2468+ # process results
2469+ # end
2470+ #
24482471 # >>>
24492472 # *Note:* Servers _MUST_ implicitly include the +UID+ message data item as
24502473 # part of any +FETCH+ response caused by a +UID+ command, regardless of
@@ -3412,8 +3435,26 @@ def search_internal(cmd, ...)
34123435 end
34133436 end
34143437
3415- def fetch_internal ( cmd , set , attr , mod = nil , changedsince : nil )
3438+ def partial_range ( range )
3439+ case range
3440+ in /\a (?:\d +:\d +|-\d +:-\d +)\z /
3441+ range
3442+ in Range
3443+ minmax = range . minmax . map { Integer _1 }
3444+ if minmax . all? ( 1 ..2 **32 -1 ) || minmax . all? ( -2 **32 ..-1 )
3445+ minmax . join ( ":" )
3446+ else
3447+ raise ArgumentError , "invalid partial-range"
3448+ end
3449+ end
3450+ end
3451+
3452+ def fetch_internal ( cmd , set , attr , mod = nil , partial : nil , changedsince : nil )
34163453 set = SequenceSet [ set ]
3454+ if partial
3455+ mod ||= [ ]
3456+ mod << "PARTIAL" << partial_range ( partial )
3457+ end
34173458 if changedsince
34183459 mod ||= [ ]
34193460 mod << "CHANGEDSINCE" << Integer ( changedsince )
0 commit comments