X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/40d5d40955a88dbd5cd7c25292268f1ab4536bda..cec011b7718536de42ebd683aa96bee92cbca06c:/services/api/lib/record_filters.rb diff --git a/services/api/lib/record_filters.rb b/services/api/lib/record_filters.rb index 9ff21d5969..831e357b42 100644 --- a/services/api/lib/record_filters.rb +++ b/services/api/lib/record_filters.rb @@ -63,12 +63,18 @@ 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 - # jsonb search + 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 '=', '!=' not_in = if operator.downcase == "!=" then "NOT " else "" end @@ -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 - 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]}, ?)" - end - param_out << subproperty[1] + 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 + 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 @@ -181,8 +197,17 @@ module RecordFilters operand.each do |op| cl = ArvadosModel::kind_class op if cl - cond << "#{ar_table_name}.#{attr} like ?" - param_out << cl.uuid_like_pattern + if attr == 'uuid' + if model_class.uuid_prefix == cl.uuid_prefix + cond << "1=1" + else + cond << "1=0" + end + else + # Use a substring query to support remote uuids + cond << "substring(#{ar_table_name}.#{attr}, 7, 5) = ?" + param_out << cl.uuid_prefix + end else cond << "1=0" end