limit data page to 1-3000 collections
[arvados.git] / app / models / orvos_base.rb
index c009caf886b64c2bc28e98cc76356447f5f18e22..96016059cad97d232c5a177698cafaf117cc5cc5 100644 (file)
@@ -1,10 +1,11 @@
 class OrvosBase < ActiveRecord::Base
-  @@orvos_v1_base = Rails.configuration.orvos_v1_base
+  self.abstract_class = true
+
   def self.columns
     return @columns unless @columns.nil?
     @columns = []
-    return @columns if orvos_schema[self.to_s.to_sym].nil?
-    orvos_schema[self.to_s.to_sym].each do |coldef|
+    return @columns if $orvos_api_client.orvos_schema[self.to_s.to_sym].nil?
+    $orvos_api_client.orvos_schema[self.to_s.to_sym].each do |coldef|
       k = coldef[:name].to_sym
       if coldef[:type] == coldef[:type].downcase
         @columns << column(k, coldef[:type].to_sym)
@@ -21,19 +22,23 @@ class OrvosBase < ActiveRecord::Base
   def self.column(name, sql_type = nil, default = nil, null = true)
     ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default, sql_type.to_s, null)
   end
-  def self.all
-    thelist = api('')
-    thelist[:items].collect { |x| new(x) }
-  end
   def self.find(uuid)
-    new(api('/' + uuid))
-  end
-  def self.where(cond)
-    all.select do |o|
-      0 == cond.select do |k,v|
-        o.send(k) != v
-      end.size
+    if uuid.class != String or uuid.length < 27 then
+      raise 'argument to find() must be a uuid string. Acceptable formats: warehouse locator or string with format xxxxx-xxxxx-xxxxxxxxxxxxxxx'
     end
+    new.private_reload(uuid)
+  end
+  def self.where(*args)
+    OrvosResourceList.new(self).where(*args)
+  end
+  def self.limit(*args)
+    OrvosResourceList.new(self).limit(*args)
+  end
+  def self.eager(*args)
+    OrvosResourceList.new(self).eager(*args)
+  end
+  def self.all(*args)
+    OrvosResourceList.new(self).all(*args)
   end
   def save
     obdata = {}
@@ -45,9 +50,9 @@ class OrvosBase < ActiveRecord::Base
     postdata = { self.class.to_s.underscore => obdata }
     if etag
       postdata['_method'] = 'PUT'
-      resp = self.class.api('/' + uuid, postdata)
+      resp = $orvos_api_client.api(self.class, '/' + uuid, postdata)
     else
-      resp = self.class.api('', postdata)
+      resp = $orvos_api_client.api(self.class, '', postdata)
     end
     return false if !resp[:etag] || !resp[:uuid]
     @etag = resp[:etag]
@@ -58,46 +63,79 @@ class OrvosBase < ActiveRecord::Base
   def save!
     self.save or raise Exception.new("Save failed")
   end
-  def initialize(h={})
-    @etag = h.delete :etag
-    @kind = h.delete :kind
-    super
-  end
-
-  def kind_uuid
-    self.kind + '#' + self.uuid
-  end
-
-  protected
-  def self.api(action, data=nil, o={})
-    dataargs = []
-    if !data.nil?
-      data.each do |k,v|
-        dataargs << '-d'
-        if v.is_a? String
-          dataargs << "#{k}=#{v}"
-        else
-          dataargs << "#{k}=#{JSON.generate v}"
+  def links(*args)
+    o = {}
+    o.merge!(args.pop) if args[-1].is_a? Hash
+    o[:link_class] ||= args.shift
+    o[:name] ||= args.shift
+    o[:head_kind] ||= args.shift
+    o[:tail_kind] = self.kind
+    o[:tail_uuid] = self.uuid
+    if all_links
+      return all_links.select do |m|
+        ok = true
+        o.each do |k,v|
+          if !v.nil?
+            test_v = m.send(k)
+            if (v.respond_to?(:uuid) ? v.uuid : v.to_s) != (test_v.respond_to?(:uuid) ? test_v.uuid : test_v.to_s)
+              ok = false
+            end
+          end
         end
+        ok
       end
     end
-    json = nil
-    IO.popen([ENV,
-              'curl',
-              '-sk',
-              *dataargs,
-              "#{@@orvos_v1_base}/#{o[:resource_path] || self.to_s.underscore.pluralize}#{action}"],
-             'r') do |io|
-      json = io.read
+    @links = $orvos_api_client.api Link, '', { _method: 'GET', where: o, eager: true }
+    @links = $orvos_api_client.unpack_api_response(@links)
+  end
+  def all_links
+    return @all_links if @all_links
+    res = $orvos_api_client.api Link, '', {
+      _method: 'GET',
+      where: {
+        tail_kind: self.kind,
+        tail_uuid: self.uuid
+      },
+      eager: true
+    }
+    @all_links = $orvos_api_client.unpack_api_response(res)
+  end
+  def reload
+    private_reload(self.uuid)
+  end
+  def private_reload(uuid_or_hash)
+    raise "No such object" if !uuid_or_hash
+    if uuid_or_hash.is_a? Hash
+      hash = uuid_or_hash
+    else
+      hash = $orvos_api_client.api(self.class, '/' + uuid_or_hash)
     end
-    resp = JSON.parse json, :symbolize_names => true
-    if resp[:errors]
-      raise "API errors:\n#{resp[:errors].join "\n"}\n"
+    hash.each do |k,v|
+      if self.respond_to?(k.to_s + '=')
+        self.send(k.to_s + '=', v)
+      else
+        # When OrvosApiClient#schema starts telling us what to expect
+        # in API responses (not just the server side database
+        # columns), this sort of awfulness can be avoided:
+        self.instance_variable_set('@' + k.to_s, v)
+        if !self.respond_to? k
+          singleton = class << self; self end
+          singleton.send :define_method, k, lambda { instance_variable_get('@' + k.to_s) }
+        end
+      end
     end
-    resp
+    @all_links = nil
+    self
+  end
+  def dup
+    super.forget_uuid!
   end
 
-  def self.orvos_schema
-    $orvos_schema ||= api '', nil, {resource_path: 'schema'}
+  protected
+
+  def forget_uuid!
+    self.uuid = nil
+    @etag = nil
+    self
   end
 end