X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/2e5ac62b550f7dd608cf133ae66ef04f801be76b..b7b42350dec7aba073df13c9cd82bafe19a9f594:/services/api/lib/record_filters.rb diff --git a/services/api/lib/record_filters.rb b/services/api/lib/record_filters.rb index 51153fe081..eb8d09b74c 100644 --- a/services/api/lib/record_filters.rb +++ b/services/api/lib/record_filters.rb @@ -1,3 +1,7 @@ +# Copyright (C) The Arvados Authors. All rights reserved. +# +# SPDX-License-Identifier: AGPL-3.0 + # Mixin module providing a method to convert filters into a list of SQL # fragments suitable to be fed to ActiveRecord #where. # @@ -37,19 +41,23 @@ module RecordFilters cond_out = [] - if operator == '@@' # full-text-search + if operator == '@@' + # Full-text search if attrs_in != 'any' raise ArgumentError.new("Full text search on individual columns is not supported") end - attrs = [] # skip the generic per-column operator loop below - # Use to_tsquery since plainto_tsquery does not support prefix search. - # Instead split operand and join the words with ' & ' and add ':*' to the last word - # Thus when searched for "some str", objects containing "some" and "str:*" are found. + if operand.is_a? Array + raise ArgumentError.new("Full text search not supported for array operands") + end + + # Skip the generic per-column operator loop below + attrs = [] + # Use to_tsquery since plainto_tsquery does not support prefix + # search. And, split operand and join the words with ' & ' cond_out << model_class.full_text_tsvector+" @@ to_tsquery(?)" - operand << ':*' param_out << operand.split.join(' & ') - else - attrs.each do |attr| + end + attrs.each do |attr| if !model_class.searchable_columns(operator).index attr.to_s raise ArgumentError.new("Invalid attribute '#{attr}' in filter") end @@ -73,7 +81,12 @@ module RecordFilters "boolean attribute '#{attr}'") end end - cond_out << "#{ar_table_name}.#{attr} #{operator} ?" + if operator == '<>' + # explicitly allow NULL + cond_out << "#{ar_table_name}.#{attr} #{operator} ? OR #{ar_table_name}.#{attr} IS NULL" + else + cond_out << "#{ar_table_name}.#{attr} #{operator} ?" + end if (# any operator that operates on value rather than # representation: operator.match(/[<=>]/) and (attr_type == :datetime)) @@ -117,8 +130,9 @@ module RecordFilters end end cond_out << cond.join(' OR ') + else + raise ArgumentError.new("Invalid operator '#{operator}'") end - end end conds_out << cond_out.join(' OR ') if cond_out.any? end