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