class ArvadosResourceList
+ include ArvadosApiClientHelper
include Enumerable
+ attr_reader :resource_class
+
def initialize resource_class=nil
@resource_class = resource_class
+ @fetch_multiple_pages = true
+ @arvados_api_token = Thread.current[:arvados_api_token]
+ @reader_tokens = Thread.current[:reader_tokens]
end
def eager(bool=true)
self
end
+ def distinct(bool=true)
+ @distinct = bool
+ self
+ end
+
def limit(max_results)
+ if not max_results.nil? and not max_results.is_a? Integer
+ raise ArgumentError("argument to limit() must be an Integer or nil")
+ end
@limit = max_results
self
end
self
end
+ def select(columns=nil)
+ # If no column arguments were given, invoke Enumerable#select.
+ if columns.nil?
+ super()
+ else
+ @select ||= []
+ @select += columns
+ self
+ end
+ end
+
def filter _filters
@filters ||= []
@filters += _filters
end
def where(cond)
- cond = cond.dup
- cond.keys.each do |uuid_key|
- if cond[uuid_key] and (cond[uuid_key].is_a? Array or
- cond[uuid_key].is_a? ArvadosBase)
+ @cond = cond.dup
+ @cond.keys.each do |uuid_key|
+ if @cond[uuid_key] and (@cond[uuid_key].is_a? Array or
+ @cond[uuid_key].is_a? ArvadosBase)
# Coerce cond[uuid_key] to an array of uuid strings. This
# allows caller the convenience of passing an array of real
# objects and uuids in cond[uuid_key].
- if !cond[uuid_key].is_a? Array
- cond[uuid_key] = [cond[uuid_key]]
+ if !@cond[uuid_key].is_a? Array
+ @cond[uuid_key] = [@cond[uuid_key]]
end
- cond[uuid_key] = cond[uuid_key].collect do |item|
+ @cond[uuid_key] = @cond[uuid_key].collect do |item|
if item.is_a? ArvadosBase
item.uuid
else
end
end
end
- cond.keys.select { |x| x.match /_kind$/ }.each do |kind_key|
- if cond[kind_key].is_a? Class
- cond = cond.merge({ kind_key => 'arvados#' + $arvados_api_client.class_kind(cond[kind_key]) })
+ @cond.keys.select { |x| x.match /_kind$/ }.each do |kind_key|
+ if @cond[kind_key].is_a? Class
+ @cond = @cond.merge({ kind_key => 'arvados#' + arvados_api_client.class_kind(@cond[kind_key]) })
end
end
- api_params = {
- _method: 'GET',
- where: cond
- }
- api_params[:eager] = '1' if @eager
- api_params[:limit] = @limit if @limit
- api_params[:offset] = @offset if @offset
- api_params[:order] = @orderby_spec if @orderby_spec
- api_params[:filters] = @filters if @filters
- res = $arvados_api_client.api @resource_class, '', api_params
- @results = $arvados_api_client.unpack_api_response res
+ self
+ end
+
+ def fetch_multiple_pages(f)
+ @fetch_multiple_pages = f
self
end
def results
- self.where({}) if !@results
+ if !@results
+ @results = []
+ self.each_page do |r|
+ @results.concat r
+ end
+ end
@results
end
def results=(r)
@results = r
+ @items_available = r.items_available if r.respond_to? :items_available
+ @result_limit = r.limit if r.respond_to? :limit
+ @result_offset = r.offset if r.respond_to? :offset
+ @results
end
- def all
- where({})
+ def to_ary
+ results
end
def each(&block)
- results.each do |m|
- block.call m
+ if not @results.nil?
+ @results.each &block
+ else
+ self.each_page do |items|
+ items.each do |i|
+ block.call i
+ end
+ end
end
self
end
end
end
- def to_ary
- results
- end
-
def to_hash
- Hash[results.collect { |x| [x.uuid, x] }]
+ Hash[self.collect { |x| [x.uuid, x] }]
end
def empty?
- results.empty?
+ self.first.nil?
end
def items_available
- results.items_available if results.respond_to? :items_available
+ results
+ @items_available
end
def result_limit
- results.limit if results.respond_to? :limit
+ results
+ @result_limit
end
def result_offset
- results.offset if results.respond_to? :offset
+ results
+ @result_offset
end
- def result_links
- results.links if results.respond_to? :links
+ # Obsolete method retained during api transition.
+ def links_for item_or_uuid, link_class=false
+ []
end
- # Return links provided with API response that point to the
- # specified object, and have the specified link_class. If link_class
- # is false or omitted, return all links pointing to the specified
- # object.
- def links_for item_or_uuid, link_class=false
- return [] if !result_links
- unless @links_for_uuid
- @links_for_uuid = {}
- result_links.each do |link|
- if link.respond_to? :head_uuid
- @links_for_uuid[link.head_uuid] ||= []
- @links_for_uuid[link.head_uuid] << link
- end
+ protected
+
+ def each_page
+ api_params = {
+ _method: 'GET'
+ }
+ api_params[:where] = @cond if @cond
+ api_params[:eager] = '1' if @eager
+ api_params[:select] = @select if @select
+ api_params[:order] = @orderby_spec if @orderby_spec
+ api_params[:filters] = @filters if @filters
+ api_params[:distinct] = @distinct if @distinct
+
+
+ item_count = 0
+ offset = @offset || 0
+ @result_limit = nil
+ @result_offset = nil
+
+ begin
+ api_params[:offset] = offset
+ api_params[:limit] = (@limit - item_count) if @limit
+
+ res = arvados_api_client.api(@resource_class, '', api_params,
+ arvados_api_token: @arvados_api_token,
+ reader_tokens: @reader_tokens)
+ items = arvados_api_client.unpack_api_response res
+
+ @items_available = items.items_available if items.respond_to?(:items_available)
+ @result_limit = items.limit if (@fetch_multiple_pages == false) and items.respond_to?(:limit)
+ @result_offset = items.offset if (@fetch_multiple_pages == false) and items.respond_to?(:offset)
+
+ break if items.nil? or not items.any?
+
+ item_count += items.size
+ if items.respond_to?(:offset)
+ offset = items.offset + items.size
+ else
+ offset = item_count
end
- end
- if item_or_uuid.respond_to? :uuid
- uuid = item_or_uuid.uuid
- else
- uuid = item_or_uuid
- end
- (@links_for_uuid[uuid] || []).select do |link|
- link_class == false or link.link_class == link_class
- end
- end
- # Note: this arbitrarily chooses one of (possibly) multiple names.
- def name_for item_or_uuid
- links_for(item_or_uuid, 'name').first.andand.name
+ yield items
+
+ break if @limit and item_count >= @limit
+ break if items.respond_to? :items_available and offset >= items.items_available
+ end while @fetch_multiple_pages
+ self
end
end