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