2809: Merge branch 'master' into 2809-workbench-rails4 refs #2809
[arvados.git] / apps / workbench / app / models / arvados_resource_list.rb
1 class ArvadosResourceList
2   include ArvadosApiClientHelper
3   include Enumerable
4
5   def initialize resource_class=nil
6     @resource_class = resource_class
7   end
8
9   def eager(bool=true)
10     @eager = bool
11     self
12   end
13
14   def limit(max_results)
15     @limit = max_results
16     self
17   end
18
19   def offset(skip)
20     @offset = skip
21     self
22   end
23
24   def order(orderby_spec)
25     @orderby_spec = orderby_spec
26     self
27   end
28
29   def filter _filters
30     @filters ||= []
31     @filters += _filters
32     self
33   end
34
35   def where(cond)
36     cond = cond.dup
37     cond.keys.each do |uuid_key|
38       if cond[uuid_key] and (cond[uuid_key].is_a? Array or
39                              cond[uuid_key].is_a? ArvadosBase)
40         # Coerce cond[uuid_key] to an array of uuid strings.  This
41         # allows caller the convenience of passing an array of real
42         # objects and uuids in cond[uuid_key].
43         if !cond[uuid_key].is_a? Array
44           cond[uuid_key] = [cond[uuid_key]]
45         end
46         cond[uuid_key] = cond[uuid_key].collect do |item|
47           if item.is_a? ArvadosBase
48             item.uuid
49           else
50             item
51           end
52         end
53       end
54     end
55     cond.keys.select { |x| x.match /_kind$/ }.each do |kind_key|
56       if cond[kind_key].is_a? Class
57         cond = cond.merge({ kind_key => 'arvados#' + arvados_api_client.class_kind(cond[kind_key]) })
58       end
59     end
60     api_params = {
61       _method: 'GET',
62       where: cond
63     }
64     api_params[:eager] = '1' if @eager
65     api_params[:limit] = @limit if @limit
66     api_params[:offset] = @offset if @offset
67     api_params[:order] = @orderby_spec if @orderby_spec
68     api_params[:filters] = @filters if @filters
69     res = arvados_api_client.api @resource_class, '', api_params
70     @results = arvados_api_client.unpack_api_response res
71     self
72   end
73
74   def results
75     self.where({}) if !@results
76     @results
77   end
78
79   def results=(r)
80     @results = r
81   end
82
83   def all
84     where({})
85   end
86
87   def each(&block)
88     results.each do |m|
89       block.call m
90     end
91     self
92   end
93
94   def collect
95     results.collect do |m|
96       yield m
97     end
98   end
99
100   def first
101     results.first
102   end
103
104   def last
105     results.last
106   end
107
108   def [](*x)
109     results.send('[]', *x)
110   end
111
112   def |(x)
113     if x.is_a? Hash
114       self.to_hash | x
115     else
116       results | x.to_ary
117     end
118   end
119
120   def to_ary
121     results
122   end
123
124   def to_hash
125     Hash[results.collect { |x| [x.uuid, x] }]
126   end
127
128   def empty?
129     results.empty?
130   end
131
132   def items_available
133     results.items_available if results.respond_to? :items_available
134   end
135
136   def result_limit
137     results.limit if results.respond_to? :limit
138   end
139
140   def result_offset
141     results.offset if results.respond_to? :offset
142   end
143
144   def result_links
145     results.links if results.respond_to? :links
146   end
147
148   # Return links provided with API response that point to the
149   # specified object, and have the specified link_class. If link_class
150   # is false or omitted, return all links pointing to the specified
151   # object.
152   def links_for item_or_uuid, link_class=false
153     return [] if !result_links
154     unless @links_for_uuid
155       @links_for_uuid = {}
156       result_links.each do |link|
157         if link.respond_to? :head_uuid
158           @links_for_uuid[link.head_uuid] ||= []
159           @links_for_uuid[link.head_uuid] << link
160         end
161       end
162     end
163     if item_or_uuid.respond_to? :uuid
164       uuid = item_or_uuid.uuid
165     else
166       uuid = item_or_uuid
167     end
168     (@links_for_uuid[uuid] || []).select do |link|
169       link_class == false or link.link_class == link_class
170     end
171   end
172
173   # Note: this arbitrarily chooses one of (possibly) multiple names.
174   def name_for item_or_uuid
175     links_for(item_or_uuid, 'name').first.andand.name
176   end
177
178 end