limit data page to 1-3000 collections
[arvados.git] / app / models / orvos_base.rb
1 class OrvosBase < ActiveRecord::Base
2   self.abstract_class = true
3
4   def self.columns
5     return @columns unless @columns.nil?
6     @columns = []
7     return @columns if $orvos_api_client.orvos_schema[self.to_s.to_sym].nil?
8     $orvos_api_client.orvos_schema[self.to_s.to_sym].each do |coldef|
9       k = coldef[:name].to_sym
10       if coldef[:type] == coldef[:type].downcase
11         @columns << column(k, coldef[:type].to_sym)
12       else
13         @columns << column(k, :text)
14         serialize k, coldef[:type].constantize
15       end
16       attr_accessible k
17     end
18     attr_reader :etag
19     attr_reader :kind
20     @columns
21   end
22   def self.column(name, sql_type = nil, default = nil, null = true)
23     ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default, sql_type.to_s, null)
24   end
25   def self.find(uuid)
26     if uuid.class != String or uuid.length < 27 then
27       raise 'argument to find() must be a uuid string. Acceptable formats: warehouse locator or string with format xxxxx-xxxxx-xxxxxxxxxxxxxxx'
28     end
29     new.private_reload(uuid)
30   end
31   def self.where(*args)
32     OrvosResourceList.new(self).where(*args)
33   end
34   def self.limit(*args)
35     OrvosResourceList.new(self).limit(*args)
36   end
37   def self.eager(*args)
38     OrvosResourceList.new(self).eager(*args)
39   end
40   def self.all(*args)
41     OrvosResourceList.new(self).all(*args)
42   end
43   def save
44     obdata = {}
45     self.class.columns.each do |col|
46       obdata[col.name.to_sym] = self.send(col.name.to_sym)
47     end
48     obdata.delete :id
49     obdata.delete :uuid
50     postdata = { self.class.to_s.underscore => obdata }
51     if etag
52       postdata['_method'] = 'PUT'
53       resp = $orvos_api_client.api(self.class, '/' + uuid, postdata)
54     else
55       resp = $orvos_api_client.api(self.class, '', postdata)
56     end
57     return false if !resp[:etag] || !resp[:uuid]
58     @etag = resp[:etag]
59     @kind = resp[:kind]
60     self.uuid ||= resp[:uuid]
61     self
62   end
63   def save!
64     self.save or raise Exception.new("Save failed")
65   end
66   def links(*args)
67     o = {}
68     o.merge!(args.pop) if args[-1].is_a? Hash
69     o[:link_class] ||= args.shift
70     o[:name] ||= args.shift
71     o[:head_kind] ||= args.shift
72     o[:tail_kind] = self.kind
73     o[:tail_uuid] = self.uuid
74     if all_links
75       return all_links.select do |m|
76         ok = true
77         o.each do |k,v|
78           if !v.nil?
79             test_v = m.send(k)
80             if (v.respond_to?(:uuid) ? v.uuid : v.to_s) != (test_v.respond_to?(:uuid) ? test_v.uuid : test_v.to_s)
81               ok = false
82             end
83           end
84         end
85         ok
86       end
87     end
88     @links = $orvos_api_client.api Link, '', { _method: 'GET', where: o, eager: true }
89     @links = $orvos_api_client.unpack_api_response(@links)
90   end
91   def all_links
92     return @all_links if @all_links
93     res = $orvos_api_client.api Link, '', {
94       _method: 'GET',
95       where: {
96         tail_kind: self.kind,
97         tail_uuid: self.uuid
98       },
99       eager: true
100     }
101     @all_links = $orvos_api_client.unpack_api_response(res)
102   end
103   def reload
104     private_reload(self.uuid)
105   end
106   def private_reload(uuid_or_hash)
107     raise "No such object" if !uuid_or_hash
108     if uuid_or_hash.is_a? Hash
109       hash = uuid_or_hash
110     else
111       hash = $orvos_api_client.api(self.class, '/' + uuid_or_hash)
112     end
113     hash.each do |k,v|
114       if self.respond_to?(k.to_s + '=')
115         self.send(k.to_s + '=', v)
116       else
117         # When OrvosApiClient#schema starts telling us what to expect
118         # in API responses (not just the server side database
119         # columns), this sort of awfulness can be avoided:
120         self.instance_variable_set('@' + k.to_s, v)
121         if !self.respond_to? k
122           singleton = class << self; self end
123           singleton.send :define_method, k, lambda { instance_variable_get('@' + k.to_s) }
124         end
125       end
126     end
127     @all_links = nil
128     self
129   end
130   def dup
131     super.forget_uuid!
132   end
133
134   protected
135
136   def forget_uuid!
137     self.uuid = nil
138     @etag = nil
139     self
140   end
141 end