From f91c73aba940adf1e9fbd530d102931af45a63c5 Mon Sep 17 00:00:00 2001 From: Tom Clegg Date: Wed, 7 May 2014 00:12:12 -0400 Subject: [PATCH] Document "filters" feature. Add missing "!=" and "not in" operators. --- doc/api/methods.html.textile.liquid | 39 ++++++++++++++++--- services/api/lib/record_filters.rb | 13 +++++-- .../arvados/v1/jobs_controller_test.rb | 36 +++++++++++++++++ 3 files changed, 78 insertions(+), 10 deletions(-) diff --git a/doc/api/methods.html.textile.liquid b/doc/api/methods.html.textile.liquid index 57d058e157..da15df8b92 100644 --- a/doc/api/methods.html.textile.liquid +++ b/doc/api/methods.html.textile.liquid @@ -24,12 +24,39 @@ filters=[["owner_uuid","=","xyzzy-tpzed-a4lcehql0dv2u25"]] table(table table-bordered table-condensed). |*Parameter name*|*Value*|*Description*| -|limit |integer|Maximum number of resources to return| -|offset |integer|Skip the first 'offset' objects| -|filters |array |Conditions for selecting resources to return| -|order |array |List of fields to use to determine sorting order for returned objects| -|select |array |Specify which fields to return| -|distinct|boolean|true: (default) do not return duplicate objects
false: permitted to return duplicates| +|limit |integer|Maximum number of resources to return.| +|offset |integer|Skip the first 'offset' resources that match the given filter conditions.| +|filters |array |Conditions for selecting resources to return (see below).| +|order |array |Attributes to use as sort keys to determine the order resources are returned, each optionally followed by @asc@ or @desc@ to indicate ascending or descending order. +Example: @["head_uuid asc","modified_at desc"]@ +Default: @["created_at desc"]@| +|select |array |Set of attributes to include in the response. +Example: @["head_uuid","tail_uuid"]@ +Default: all available attributes, minus "manifest_text" in the case of collections.| +|distinct|boolean|@true@: (default) do not return duplicate objects +@false@: permitted to return duplicates| + +h3. Filters + +The value of the @filters@ parameter is an array of conditions. The @list@ method returns only the resources that satisfy all of the given conditions. In other words, the conjunction @AND@ is implicit. + +Each condition is expressed as an array with three elements: @[attribute, operator, operand]@. + +table(table table-bordered table-condensed). +|_. Index|_. Element|_. Type|_. Description|_. Examples| +|0|attribute|string|Name of the attribute to compare|@script_version@, @head_uuid@| +|1|operator|string|Comparison operator|@>@, @>=@, @like@, @not in@| +|2|operand|string, array, or null|Value to compare with the resource attribute|@"d00220fb%"@, @"1234"@, @["foo","bar"]@, @nil@| + +The following operators are available. + +table(table table-bordered table-condensed). +|_. Operator|_. Operand type|_. Example| +|@<@, @<=@, @>=@, @>@, @like@|string|@["script_version","like","d00220fb%"]@| +|@=@, @!=@|string or null|@["tail_uuid","=","xyzzy-j7d0g-fffffffffffffff"]@ +@["tail_uuid","!=",null]@| +|@in@, @not in@|array of strings|@["script_version","in",["master","d00220fb38d4b85ca8fc28a8151702a2b9d1dec5"]]@| +|@is_a@|string|@["head_uuid","is_a","arvados#pipelineInstance"]@| h2. Create diff --git a/services/api/lib/record_filters.rb b/services/api/lib/record_filters.rb index d7e556b197..d3727d30f3 100644 --- a/services/api/lib/record_filters.rb +++ b/services/api/lib/record_filters.rb @@ -8,7 +8,7 @@ module RecordFilters # Input: - # +filters+ Arvados filters as list of lists. + # +filters+ array of conditions, each being [column, operator, operand] # +ar_table_name+ name of SQL table # # Output: @@ -29,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: @@ -41,13 +44,15 @@ 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 else raise ArgumentError.new("Invalid operand type '#{operand.class}' "\ diff --git a/services/api/test/functional/arvados/v1/jobs_controller_test.rb b/services/api/test/functional/arvados/v1/jobs_controller_test.rb index af8f72902b..d671e949ff 100644 --- a/services/api/test/functional/arvados/v1/jobs_controller_test.rb +++ b/services/api/test/functional/arvados/v1/jobs_controller_test.rb @@ -177,6 +177,42 @@ class Arvados::V1::JobsControllerTest < ActionController::TestCase 'zzzzz-8i9sb-pshmckwoma9plh7'] end + test "search jobs by uuid with 'not in' query" do + authorize_with :active + get :index, { + filters: [['uuid', 'not in', ['zzzzz-8i9sb-pshmckwoma9plh7']]] + } + assert_response :success + found = assigns(:objects).collect(&:uuid) + assert_not_equal [], found, "'not in' query returned nothing" + assert_not_includes found, 'zzzzz-8i9sb-pshmckwoma9plh7', + "'not in' query returned the very thing I did not want" + end + + test "search jobs by uuid with '!=' query" do + authorize_with :active + get :index, { + filters: [['uuid', '!=', 'zzzzz-8i9sb-pshmckwoma9plh7']] + } + assert_response :success + found = assigns(:objects).collect(&:uuid) + assert_not_equal [], found, "'!=' query returned nothing" + assert_not_includes found, 'zzzzz-8i9sb-pshmckwoma9plh7', + "'!=' query returned the very thing I did not want" + end + + test "search jobs by output with '!= nil' query" do + authorize_with :active + get :index, { + filters: [['output', '!=', nil]] + } + assert_response :success + found = assigns(:objects).collect(&:output) + assert_not_equal [], found, "'!= nil' query returned nothing" + assert_not_includes found, nil, + "'!= nil' query returned the very thing I did not want" + end + test "search jobs by started_at with < query" do authorize_with :active get :index, { -- 2.30.2