Merge remote-tracking branch 'origin/master' into 2035-arv-mount-tags-folders
authorPeter Amstutz <peter.amstutz@curoverse.com>
Thu, 1 May 2014 20:26:09 +0000 (16:26 -0400)
committerPeter Amstutz <peter.amstutz@curoverse.com>
Thu, 1 May 2014 20:26:09 +0000 (16:26 -0400)
Conflicts:
services/api/app/controllers/application_controller.rb

services/api/app/controllers/application_controller.rb
services/api/app/controllers/arvados/v1/schema_controller.rb
services/api/lib/load_param.rb
services/api/test/integration/select_test.rb [new file with mode: 0644]

index 4b5a27d99621d4d25e4c66fcb30581fadace4186..30027c8c78c9db764bb1744541cb5bfd563bcf05 100644 (file)
@@ -1,3 +1,16 @@
+module ApiTemplateOverride
+  def allowed_to_render?(fieldset, field, model, options)
+    if options[:select]
+      return options[:select].include? field.to_s
+    end
+    super
+  end
+end
+
+class ActsAsApi::ApiTemplate
+  prepend ApiTemplateOverride
+end
+
 require 'load_param'
 require 'record_filters'
 
@@ -9,6 +22,7 @@ class ApplicationController < ActionController::Base
 
   ERROR_ACTIONS = [:render_error, :render_not_found]
 
+
   respond_to :json
   protect_from_forgery
 
@@ -33,7 +47,7 @@ class ApplicationController < ActionController::Base
   attr_accessor :resource_attrs
 
   def index
-    @objects.uniq!(&:id)
+    @objects.uniq!(&:id) if @select.nil? or @select.include? "id"
     if params[:eager] and params[:eager] != '0' and params[:eager] != 0 and params[:eager] != ''
       @objects.each(&:eager_load_associations)
     end
@@ -246,6 +260,8 @@ class ApplicationController < ActionController::Base
       end
     end
 
+    @objects = @objects.select(@select.map { |s| "#{table_name}.#{ActiveRecord::Base.connection.quote_column_name s.to_s}" }.join ", ") if @select
+    @objects = @objects.uniq(ActiveRecord::Base.connection.quote_column_name @distinct.to_s) if @distinct
     @objects = @objects.order(@orders.join ", ") if @orders.any?
     @objects = @objects.limit(@limit)
     @objects = @objects.offset(@offset)
@@ -403,7 +419,7 @@ class ApplicationController < ActionController::Base
       :self_link => "",
       :offset => @offset,
       :limit => @limit,
-      :items => @objects.as_api_response(nil)
+      :items => @objects.as_api_response(nil, {select: @select})
     }
     if @objects.respond_to? :except
       @object_list[:items_available] = @objects.
index a15f9a0d05234f17ce6506e014eba82986d67b82..a0f4fce1e06ba3ba3e93e5e4a8317ca88c75fcda 100644 (file)
@@ -231,6 +231,16 @@ class Arvados::V1::SchemaController < ApplicationController
                   type: "string",
                   description: "Order in which to return matching #{k.to_s.underscore.pluralize}.",
                   location: "query"
+                },
+                select: {
+                  type: "array",
+                  description: "Select which fields to return",
+                  location: "query"
+                },
+                distinct: {
+                  type: "string",
+                  description: "Return each distinct value exactly once for the specified column (may skip rows)",
+                  location: "query"
                 }
               },
               response: {
index e01063d1530a89a8e5918510a01a0523a5fc9d8f..14dbf1eb1f2be31d9d62935ef124009f79739c6c 100644 (file)
@@ -82,6 +82,23 @@ module LoadParam
     if @orders.empty?
       @orders << default_orders
     end
+
+    case params[:select]
+    when Array
+      @select = params[:select]
+    when String
+      begin
+        @select = Oj.load params[:select]
+        raise unless @select.is_a? Array
+      rescue
+        raise ArgumentError.new("Could not parse \"select\" param as an array")
+      end
+    end
+
+    if params[:distinct].is_a? String
+      @distinct = params[:distinct]
+      @orders.select! { |o| @select.include? o } if @select
+    end
   end
 
 
diff --git a/services/api/test/integration/select_test.rb b/services/api/test/integration/select_test.rb
new file mode 100644 (file)
index 0000000..522daa7
--- /dev/null
@@ -0,0 +1,18 @@
+require 'test_helper'
+
+class SelectTest < ActionDispatch::IntegrationTest
+  test "should select just two columns" do
+    get "/arvados/v1/links", {:format => :json, :select => ['uuid', 'link_class']}, auth(:active)
+    assert_response :success
+    assert_equal json_response['items'].count, json_response['items'].select { |i|
+      i['uuid'] != nil and i['link_class'] != nil and i['head_uuid'] == nil and i['tail_uuid'] == nil
+    }.count
+  end
+
+  test "should only get distinct values" do
+    get "/arvados/v1/links", {:format => :json, :select => ['link_class'], :distinct => "link_class"}, auth(:active)
+    assert_response :success
+    assert_equal json_response['items'].uniq.count, json_response['items'].count
+  end
+
+end