Skip to content

Commit 3416a32

Browse files
authored
Merge pull request #217 from agworld/feature/deny_empty
Add option to deny empty filter values.
2 parents d940ef8 + 3cd6a3b commit 3416a32

File tree

6 files changed

+64
-7
lines changed

6 files changed

+64
-7
lines changed

lib/graphiti/errors.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,13 @@ def initialize(resource, filter, value)
143143
def message
144144
allow = @filter.values[0][:allow]
145145
deny = @filter.values[0][:deny]
146+
value_string = if @value == "(empty)"
147+
"empty value"
148+
else
149+
"value #{@value.inspect}"
150+
end
146151
msg = <<-MSG
147-
#{@resource.class.name}: tried to filter on #{@filter.keys[0].inspect}, but passed invalid value #{@value.inspect}.
152+
#{@resource.class.name}: tried to filter on #{@filter.keys[0].inspect}, but passed invalid #{value_string}.
148153
MSG
149154
msg << "\nAllowlist: #{allow.inspect}" if allow
150155
msg << "\nDenylist: #{deny.inspect}" if deny

lib/graphiti/resource/configuration.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ class << self
8282
:attributes_schema_by_default,
8383
:relationships_readable_by_default,
8484
:relationships_writable_by_default,
85-
:filters_accept_nil_by_default
85+
:filters_accept_nil_by_default,
86+
:filters_deny_empty_by_default
8687

8788
class << self
8889
prepend Overrides
@@ -104,6 +105,7 @@ def self.inherited(klass)
104105
default(klass, :relationships_readable_by_default, true)
105106
default(klass, :relationships_writable_by_default, true)
106107
default(klass, :filters_accept_nil_by_default, false)
108+
default(klass, :filters_deny_empty_by_default, false)
107109

108110
unless klass.config[:attributes][:id]
109111
klass.attribute :id, :integer_id

lib/graphiti/resource/dsl.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ def filter(name, *args, &blk)
3232
dependencies: opts[:dependent],
3333
required: required,
3434
operators: operators.to_hash,
35-
allow_nil: opts.fetch(:allow_nil, filters_accept_nil_by_default)
35+
allow_nil: opts.fetch(:allow_nil, filters_accept_nil_by_default),
36+
deny_empty: opts.fetch(:deny_empty, filters_deny_empty_by_default)
3637
}
3738
elsif (type = args[0])
3839
attribute name, type, only: [:filterable], allow: opts[:allow]

lib/graphiti/scoping/filter.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ def each_filter
5454
unless type[:canonical_name] == :hash || !value.is_a?(String)
5555
value = parse_string_value(filter.values[0], value)
5656
end
57+
58+
check_deny_empty_filters!(resource, filter, value)
5759
value = parse_string_null(filter.values[0], value)
5860
validate_singular(resource, filter, value)
5961
value = coerce_types(filter.values[0], param_name.to_sym, value)
@@ -200,5 +202,13 @@ def parse_string_null(filter, value)
200202

201203
value
202204
end
205+
206+
def check_deny_empty_filters!(resource, filter, value)
207+
return unless filter.values[0][:deny_empty]
208+
209+
if value.nil? || value.empty? || value == "null"
210+
raise Errors::InvalidFilterValue.new(resource, filter, "(empty)")
211+
end
212+
end
203213
end
204214
end

spec/filtering_spec.rb

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,38 @@ def self.name
313313
end
314314
end
315315

316+
context "when passed an empty value when deny_empty is true" do
317+
before do
318+
resource.filter :first_name, deny_empty: true
319+
employee2.update_attributes(first_name: value)
320+
params[:filter] = {first_name: "null"}
321+
end
322+
323+
context 'via explicit string value "null"' do
324+
let(:value) { "null" }
325+
326+
it "raises an invalid filter value error " do
327+
expect { records.map(&:id) }.to raise_error(Graphiti::Errors::InvalidFilterValue)
328+
end
329+
end
330+
331+
context "via empty value" do
332+
let(:value) { "" }
333+
334+
it "raises an invalid filter value error " do
335+
expect { records.map(&:id) }.to raise_error(Graphiti::Errors::InvalidFilterValue)
336+
end
337+
end
338+
339+
context "via empty array" do
340+
let(:value) { "[]" }
341+
342+
it "raises an invalid filter value error " do
343+
expect { records.map(&:id) }.to raise_error(Graphiti::Errors::InvalidFilterValue)
344+
end
345+
end
346+
end
347+
316348
context "when passed comma, but filter marked single: true" do
317349
before do
318350
resource.filter :first_name, single: true

spec/resource_spec.rb

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
expect(klass.attributes_schema_by_default).to eq(true)
2525
expect(klass.relationships_readable_by_default).to eq(true)
2626
expect(klass.relationships_writable_by_default).to eq(true)
27+
expect(klass.filters_accept_nil_by_default).to eq(false)
28+
expect(klass.filters_deny_empty_by_default).to eq(false)
2729
end
2830

2931
it "does not have serializer, type, or model" do
@@ -68,6 +70,7 @@
6870
expect(klass.relationships_readable_by_default).to eq(true)
6971
expect(klass.relationships_writable_by_default).to eq(true)
7072
expect(klass.filters_accept_nil_by_default).to eq(false)
73+
expect(klass.filters_deny_empty_by_default).to eq(false)
7174
end
7275

7376
context "when rails" do
@@ -153,7 +156,8 @@ def self.name
153156
self.attributes_schema_by_default = false
154157
self.relationships_readable_by_default = false
155158
self.relationships_writable_by_default = false
156-
self.filters_accept_nil_by_default = false
159+
self.filters_accept_nil_by_default = true
160+
self.filters_deny_empty_by_default = true
157161
end
158162
end
159163

@@ -168,7 +172,8 @@ def self.name
168172
expect(klass.attributes_schema_by_default).to eq(false)
169173
expect(klass.relationships_readable_by_default).to eq(false)
170174
expect(klass.relationships_writable_by_default).to eq(false)
171-
expect(klass.filters_accept_nil_by_default).to eq(false)
175+
expect(klass.filters_accept_nil_by_default).to eq(true)
176+
expect(klass.filters_deny_empty_by_default).to eq(true)
172177
end
173178
end
174179

@@ -310,7 +315,8 @@ class TestResourceOverrideSerializer < PORO::ApplicationSerializer
310315
self.attributes_schema_by_default = false
311316
self.relationships_readable_by_default = false
312317
self.relationships_writable_by_default = false
313-
self.filters_accept_nil_by_default = false
318+
self.filters_accept_nil_by_default = true
319+
self.filters_deny_empty_by_default = true
314320
end
315321
end
316322

@@ -325,7 +331,8 @@ class TestResourceOverrideSerializer < PORO::ApplicationSerializer
325331
expect(klass2.attributes_schema_by_default).to eq(false)
326332
expect(klass2.relationships_readable_by_default).to eq(false)
327333
expect(klass2.relationships_writable_by_default).to eq(false)
328-
expect(klass2.filters_accept_nil_by_default).to eq(false)
334+
expect(klass2.filters_accept_nil_by_default).to eq(true)
335+
expect(klass2.filters_deny_empty_by_default).to eq(true)
329336
end
330337
end
331338

0 commit comments

Comments
 (0)