add tabular /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     new.private_reload(uuid)
27   end
28   def self.where(*args)
29     OrvosResourceList.new(self).where(*args)
30   end
31   def self.eager(*args)
32     OrvosResourceList.new(self).eager(*args)
33   end
34   def self.all(*args)
35     OrvosResourceList.new(self).all(*args)
36   end
37   def save
38     obdata = {}
39     self.class.columns.each do |col|
40       obdata[col.name.to_sym] = self.send(col.name.to_sym)
41     end
42     obdata.delete :id
43     obdata.delete :uuid
44     postdata = { self.class.to_s.underscore => obdata }
45     if etag
46       postdata['_method'] = 'PUT'
47       resp = $orvos_api_client.api(self.class, '/' + uuid, postdata)
48     else
49       resp = $orvos_api_client.api(self.class, '', postdata)
50     end
51     return false if !resp[:etag] || !resp[:uuid]
52     @etag = resp[:etag]
53     @kind = resp[:kind]
54     self.uuid ||= resp[:uuid]
55     self
56   end
57   def save!
58     self.save or raise Exception.new("Save failed")
59   end
60   def links(*args)
61     o = {}
62     o.merge!(args.pop) if args[-1].is_a? Hash
63     o[:link_class] ||= args.shift
64     o[:name] ||= args.shift
65     o[:head_kind] ||= args.shift
66     o[:tail_kind] = self.kind
67     o[:tail_uuid] = self.uuid
68     if all_links
69       return all_links.select do |m|
70         ok = true
71         o.each do |k,v|
72           if !v.nil?
73             test_v = m.send(k)
74             if (v.respond_to?(:uuid) ? v.uuid : v.to_s) != (test_v.respond_to?(:uuid) ? test_v.uuid : test_v.to_s)
75               ok = false
76             end
77           end
78         end
79         ok
80       end
81     end
82     @links = $orvos_api_client.api Link, '', { _method: 'GET', where: o, eager: true }
83     @links = $orvos_api_client.unpack_api_response(@links)
84   end
85   def all_links
86     return @all_links if @all_links
87     res = $orvos_api_client.api Link, '', {
88       _method: 'GET',
89       where: {
90         tail_kind: self.kind,
91         tail_uuid: self.uuid
92       },
93       eager: true
94     }
95     @all_links = $orvos_api_client.unpack_api_response(res)
96   end
97   def reload
98     private_reload(self.uuid)
99   end
100   def private_reload(uuid_or_hash)
101     raise "No such object" if !uuid_or_hash
102     if uuid_or_hash.is_a? Hash
103       hash = uuid_or_hash
104     else
105       hash = $orvos_api_client.api(self.class, '/' + uuid_or_hash)
106     end
107     hash.each do |k,v|
108       if self.respond_to?(k.to_s + '=')
109         self.send(k.to_s + '=', v)
110       else
111         # When OrvosApiClient#schema starts telling us what to expect
112         # in API responses (not just the server side database
113         # columns), this sort of awfulness can be avoided:
114         self.instance_variable_set('@' + k.to_s, v)
115         if !self.respond_to? k
116           singleton = class << self; self end
117           singleton.send :define_method, k, lambda { instance_variable_get('@' + k.to_s) }
118         end
119       end
120     end
121     @all_links = nil
122     self
123   end
124   def dup
125     super.forget_uuid!
126   end
127
128   protected
129
130   def forget_uuid!
131     self.uuid = nil
132     @etag = nil
133     self
134   end
135 end