2809: Merge branch 'master' into 2809-workbench-rails4 refs #2809
[arvados.git] / services / api / lib / load_param.rb
index dba05825a727862f2c41c96035a5c1a68ef4564e..70387fe9165e34595d9cae9db9c90adee23433ee 100644 (file)
@@ -1,12 +1,15 @@
+# Mixin module for reading out query parameters from request params.
+#
 # Expects:
 #   +params+ Hash
 # Sets:
-#   @where, @filters
-
+#   @where, @filters, @limit, @offset, @orders
 module LoadParam
 
+  # Default limit on number of rows to return in a single query.
   DEFAULT_LIMIT = 100
 
+  # Load params[:where] into @where
   def load_where_param
     if params[:where].nil? or params[:where] == ""
       @where = {}
@@ -23,6 +26,7 @@ module LoadParam
     @where = @where.with_indifferent_access
   end
 
+  # Load params[:filters] into @filters
   def load_filters_param
     @filters ||= []
     if params[:filters].is_a? Array
@@ -38,6 +42,12 @@ module LoadParam
     end
   end
 
+  def default_orders
+    ["#{table_name}.modified_at desc"]
+  end
+
+  # Load params[:limit], params[:offset] and params[:order]
+  # into @limit, @offset, @orders
   def load_limit_offset_order_params
     if params[:limit]
       unless params[:limit].to_s.match(/^\d+$/)
@@ -59,7 +69,22 @@ module LoadParam
 
     @orders = []
     if params[:order]
-      params[:order].split(',').each do |order|
+      od = []
+      (case params[:order]
+       when String
+         if params[:order].starts_with? '['
+           od = Oj.load(params[:order])
+           raise unless od.is_a? Array
+           od
+         else
+           params[:order].split(',')
+         end
+       when Array
+         params[:order]
+       else
+         []
+       end).each do |order|
+        order = order.to_s
         attr, direction = order.strip.split " "
         direction ||= 'asc'
         if attr.match /^[a-z][_a-z0-9]+$/ and
@@ -69,9 +94,34 @@ module LoadParam
         end
       end
     end
+
     if @orders.empty?
-      @orders << "#{table_name}.modified_at desc"
+      @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 or @select.nil?
+      rescue
+        raise ArgumentError.new("Could not parse \"select\" param as an array")
+      end
     end
+
+    if @select
+      # Any ordering columns must be selected when doing select,
+      # otherwise it is an SQL error, so filter out invaliding orderings.
+      @orders.select! { |o|
+        # match select column against order array entry
+        @select.select { |s| /^#{table_name}.#{s}( (asc|desc))?$/.match o }.any?
+      }
+    end
+
+    @distinct = true if (params[:distinct] == true || params[:distinct] == "true")
+    @distinct = false if (params[:distinct] == false || params[:distinct] == "false")
   end