From 56d34fd4801bc32c13d64aca880b82b717b2ab81 Mon Sep 17 00:00:00 2001 From: Jason Karns Date: Mon, 18 Mar 2024 11:26:50 -0400 Subject: [PATCH] fix: Enum should allow the conventionally case-sensitive operators (#434) Add eql and not_eql operators to enum for case-sensitive matching, aligning with string behavior and improving polymorphic association ergonomics --------- Co-authored-by: Jeff Keen --- lib/graphiti/adapters/abstract.rb | 2 +- lib/graphiti/adapters/active_record.rb | 2 ++ spec/filtering_spec.rb | 27 ++++++++++++++++++++++++++ spec/fixtures/poro.rb | 13 +++++++++++++ 4 files changed, 43 insertions(+), 1 deletion(-) diff --git a/lib/graphiti/adapters/abstract.rb b/lib/graphiti/adapters/abstract.rb index 92f789cf..8b3dfb96 100644 --- a/lib/graphiti/adapters/abstract.rb +++ b/lib/graphiti/adapters/abstract.rb @@ -39,7 +39,7 @@ def self.default_operators :not_match ], uuid: [:eq, :not_eq], - enum: [:eq, :not_eq], + enum: [:eq, :not_eq, :eql, :not_eql], integer_id: numerical_operators, integer: numerical_operators, big_decimal: numerical_operators, diff --git a/lib/graphiti/adapters/active_record.rb b/lib/graphiti/adapters/active_record.rb index 3cedfae6..c290f92c 100644 --- a/lib/graphiti/adapters/active_record.rb +++ b/lib/graphiti/adapters/active_record.rb @@ -26,6 +26,7 @@ def filter_eq(scope, attribute, value) alias_method :filter_boolean_eq, :filter_eq alias_method :filter_uuid_eq, :filter_eq alias_method :filter_enum_eq, :filter_eq + alias_method :filter_enum_eql, :filter_eq def filter_not_eq(scope, attribute, value) scope.where.not(attribute => value) @@ -37,6 +38,7 @@ def filter_not_eq(scope, attribute, value) alias_method :filter_boolean_not_eq, :filter_not_eq alias_method :filter_uuid_not_eq, :filter_not_eq alias_method :filter_enum_not_eq, :filter_not_eq + alias_method :filter_enum_not_eql, :filter_not_eq def filter_string_eq(scope, attribute, value, is_not: false) column = column_for(scope, attribute) diff --git a/spec/filtering_spec.rb b/spec/filtering_spec.rb index 613aa947..d206ed22 100644 --- a/spec/filtering_spec.rb +++ b/spec/filtering_spec.rb @@ -580,6 +580,33 @@ def self.name end end + context "when filtering on an string_enum field" do + before do + resource.config[:filters] = {} + resource.filter :first_name, :string_enum, single: true, allow: ["William", "Harold"] do + eq do |scope, value| + scope[:conditions][:first_name] = value + scope + end + end + end + + it "accepts values in the allowlist with eq operator" do + params[:filter] = {first_name: {eq: "William"}} + expect(records.map(&:id)).to eq([employee3.id]) + end + + it "accepts values in the allowlist with eql operator" do + params[:filter] = {first_name: {eql: "Harold"}} + expect(records.map(&:id)).to eq([employee4.id]) + end + + it "accepts values in the allowlist with not_eql operator" do + params[:filter] = {first_name: {not_eql: "Harold"}} + expect(records.map(&:id)).to eq([employee1.id, employee2.id, employee3.id]) + end + end + context "when only allowing single values" do before do resource.filter :first_name, :string, single: true do diff --git a/spec/fixtures/poro.rb b/spec/fixtures/poro.rb index 31b0d842..f7d0d64e 100644 --- a/spec/fixtures/poro.rb +++ b/spec/fixtures/poro.rb @@ -74,6 +74,8 @@ def apply_filtering(records, params) end if value.is_a?(Array) value.include?(db_value) + elsif value.is_a?(Hash) && value[:not] + db_value != value[:not] else db_value == value end @@ -305,6 +307,13 @@ def filter(scope, name, value) scope[:conditions][name] = value scope end + + def filter_not_eq(scope, name, value) + scope[:conditions] ||= {} + scope[:conditions][name] = {not: value} + scope + end + alias_method :filter_integer_eq, :filter alias_method :filter_string_eq, :filter alias_method :filter_big_decimal_eq, :filter @@ -314,6 +323,10 @@ def filter(scope, name, value) alias_method :filter_boolean_eq, :filter alias_method :filter_hash_eq, :filter alias_method :filter_array_eq, :filter + alias_method :filter_enum_eq, :filter + alias_method :filter_enum_not_eq, :filter_not_eq + alias_method :filter_enum_eql, :filter + alias_method :filter_enum_not_eql, :filter_not_eq # No need for actual logic to fire def count(scope, attr)