1 # Copyright (C) The Arvados Authors. All rights reserved.
3 # SPDX-License-Identifier: AGPL-3.0
5 class ArvadosResourceList
6 include ArvadosApiClientHelper
9 attr_reader :resource_class
11 def initialize resource_class=nil
12 @resource_class = resource_class
13 @fetch_multiple_pages = true
14 @arvados_api_token = Thread.current[:arvados_api_token]
15 @reader_tokens = Thread.current[:reader_tokens]
34 def distinct(bool=true)
39 def include_trash(option=nil)
40 @include_trash = option
44 def recursive(option=nil)
49 def limit(max_results)
50 if not max_results.nil? and not max_results.is_a? Integer
51 raise ArgumentError("argument to limit() must be an Integer or nil")
62 def order(orderby_spec)
63 @orderby_spec = orderby_spec
67 def select(columns=nil)
68 # If no column arguments were given, invoke Enumerable#select.
86 @cond.keys.each do |uuid_key|
87 if @cond[uuid_key] and (@cond[uuid_key].is_a? Array or
88 @cond[uuid_key].is_a? ArvadosBase)
89 # Coerce cond[uuid_key] to an array of uuid strings. This
90 # allows caller the convenience of passing an array of real
91 # objects and uuids in cond[uuid_key].
92 if !@cond[uuid_key].is_a? Array
93 @cond[uuid_key] = [@cond[uuid_key]]
95 @cond[uuid_key] = @cond[uuid_key].collect do |item|
96 if item.is_a? ArvadosBase
104 @cond.keys.select { |x| x.match(/_kind$/) }.each do |kind_key|
105 if @cond[kind_key].is_a? Class
106 @cond = @cond.merge({ kind_key => 'arvados#' + arvados_api_client.class_kind(@cond[kind_key]) })
112 # with_count sets the 'count' parameter to 'exact' or 'none' -- see
113 # https://doc.arvados.org/api/methods.html#index
114 def with_count(count_param='exact')
119 def fetch_multiple_pages(f)
120 @fetch_multiple_pages = f
127 self.each_page do |r|
136 @items_available = r.items_available if r.respond_to? :items_available
137 @result_limit = r.limit if r.respond_to? :limit
138 @result_offset = r.offset if r.respond_to? :offset
148 @results.each(&block)
151 self.each_page do |items|
157 # Cache results only if all were retrieved (block didn't raise
173 results.send('[]', *x)
185 Hash[self.collect { |x| [x.uuid, x] }]
207 # Obsolete method retained during api transition.
208 def links_for item_or_uuid, link_class=false
218 api_params[:count] = @count if @count
219 api_params[:where] = @cond if @cond
220 api_params[:eager] = '1' if @eager
221 api_params[:select] = @select if @select
222 api_params[:order] = @orderby_spec if @orderby_spec
223 api_params[:filters] = @filters if @filters
224 api_params[:distinct] = @distinct if @distinct
225 api_params[:include_trash] = @include_trash if @include_trash
226 if @fetch_multiple_pages
227 # Default limit to (effectively) api server's MAX_LIMIT
228 api_params[:limit] = 2**(0.size*8 - 1) - 1
232 offset = @offset || 0
237 api_params[:offset] = offset
238 api_params[:limit] = (@limit - item_count) if @limit
240 res = arvados_api_client.api(@resource_class, '', api_params,
241 arvados_api_token: @arvados_api_token,
242 reader_tokens: @reader_tokens)
243 items = arvados_api_client.unpack_api_response res
245 @items_available = items.items_available if items.respond_to?(:items_available)
246 @result_limit = items.limit if (@fetch_multiple_pages == false) and items.respond_to?(:limit)
247 @result_offset = items.offset if (@fetch_multiple_pages == false) and items.respond_to?(:offset)
249 break if items.nil? or not items.any?
251 item_count += items.size
252 if items.respond_to?(:offset)
253 offset = items.offset + items.size
260 break if @limit and item_count >= @limit
261 break if items.respond_to? :items_available and offset >= items.items_available
262 end while @fetch_multiple_pages