X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/e537bd8dd1ac786164f192374e0d076bdc0327f3..ca767f4ed048496a03355d1c695140b6a4ff56ac:/services/api/lib/record_filters.rb diff --git a/services/api/lib/record_filters.rb b/services/api/lib/record_filters.rb index 3f0a845541..01d0ae4da5 100644 --- a/services/api/lib/record_filters.rb +++ b/services/api/lib/record_filters.rb @@ -1,11 +1,20 @@ +# Mixin module providing a method to convert filters into a list of SQL +# fragments suitable to be fed to ActiveRecord #where. +# # Expects: -# @where -# @filters -# +model_class+ +# model_class # Operates on: # @objects module RecordFilters + # Input: + # +filters+ array of conditions, each being [column, operator, operand] + # +ar_table_name+ name of SQL table + # + # Output: + # Hash with two keys: + # :cond_out array of SQL fragments for each filter expression + # :param_out array of values for parameter substitution in cond_out def record_filters filters, ar_table_name cond_out = [] param_out = [] @@ -20,8 +29,11 @@ module RecordFilters raise ArgumentError.new("Invalid attribute '#{attr}' in filter") end case operator.downcase - when '=', '<', '<=', '>', '>=', 'like' + when '=', '<', '<=', '>', '>=', '!=', 'like' if operand.is_a? String + if operator == '!=' + operator = '<>' + end cond_out << "#{ar_table_name}.#{attr} #{operator} ?" if (# any operator that operates on value rather than # representation: @@ -32,14 +44,20 @@ module RecordFilters param_out << operand elsif operand.nil? and operator == '=' cond_out << "#{ar_table_name}.#{attr} is null" + elsif operand.nil? and operator == '!=' + cond_out << "#{ar_table_name}.#{attr} is not null" else raise ArgumentError.new("Invalid operand type '#{operand.class}' "\ "for '#{operator}' operator in filters") end - when 'in' + when 'in', 'not in' if operand.is_a? Array - cond_out << "#{ar_table_name}.#{attr} IN (?)" + cond_out << "#{ar_table_name}.#{attr} #{operator} (?)" param_out << operand + if operator == 'not in' and not operand.include?(nil) + # explicitly allow NULL + cond_out[-1] = "(#{cond_out[-1]} OR #{ar_table_name}.#{attr} IS NULL)" + end else raise ArgumentError.new("Invalid operand type '#{operand.class}' "\ "for '#{operator}' operator in filters")