Merge branch '13561-trashed-collection-versions-fix'
[arvados.git] / services / api / lib / record_filters.rb
index 9ff21d596958562d675141633f05c8a12ae8635b..dc427c12c1f82cfc76d8b53a13ad1d7b8a88c032 100644 (file)
@@ -63,11 +63,17 @@ module RecordFilters
       attrs.each do |attr|
         subproperty = attr.split(".", 2)
 
-        if !model_class.searchable_columns(operator).index subproperty[0]
-          raise ArgumentError.new("Invalid attribute '#{subproperty[0]}' in filter")
-        end
+        col = model_class.columns.select { |c| c.name == subproperty[0] }.first
 
         if subproperty.length == 2
+          if col.nil? or col.type != :jsonb
+            raise ArgumentError.new("Invalid attribute '#{subproperty[0]}' for subproperty filter")
+          end
+
+          if subproperty[1][0] == "<" and subproperty[1][-1] == ">"
+            subproperty[1] = subproperty[1][1..-2]
+          end
+
         # jsonb search
           case operator.downcase
           when '=', '!='
@@ -102,20 +108,30 @@ module RecordFilters
               raise ArgumentError.new("Invalid operand type '#{operand.class}' "\
                                       "for '#{operator}' operator in filters")
             end
-          when 'exists', 'not exists'
-          if operand
-            raise ArgumentError.new("Invalid operand for subproperty existence filter, should be empty or null")
-          end
-          if operator.downcase[0..2] == "not" then
+          when 'exists'
+          if operand == true
+            cond_out << "jsonb_exists(#{ar_table_name}.#{subproperty[0]}, ?)"
+          elsif operand == false
             cond_out << "(NOT jsonb_exists(#{ar_table_name}.#{subproperty[0]}, ?)) OR #{ar_table_name}.#{subproperty[0]} is NULL"
           else
-            cond_out << "jsonb_exists(#{ar_table_name}.#{subproperty[0]}, ?)"
+            raise ArgumentError.new("Invalid operand '#{operand}' for '#{operator}' must be true or false")
           end
           param_out << subproperty[1]
           else
             raise ArgumentError.new("Invalid operator for subproperty search '#{operator}'")
           end
+        elsif operator.downcase == "exists"
+          if col.type != :jsonb
+            raise ArgumentError.new("Invalid attribute '#{subproperty[0]}' for operator '#{operator}' in filter")
+          end
+
+          cond_out << "jsonb_exists(#{ar_table_name}.#{subproperty[0]}, ?)"
+          param_out << operand
         else
+          if !model_class.searchable_columns(operator).index subproperty[0]
+            raise ArgumentError.new("Invalid attribute '#{subproperty[0]}' in filter")
+          end
+
           case operator.downcase
           when '=', '<', '<=', '>', '>=', '!=', 'like', 'ilike'
             attr_type = model_class.attribute_column(attr).type