Skip to content

Commit f70e13c

Browse files
committed
refactor(Query) take except: instead of mask:
1 parent 26210b9 commit f70e13c

File tree

5 files changed

+47
-70
lines changed

5 files changed

+47
-70
lines changed

lib/graphql/query.rb

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ def initialize(names)
1717
end
1818
end
1919

20+
module NullExcept
21+
module_function
22+
23+
def call(member)
24+
false
25+
end
26+
end
27+
2028
attr_reader :schema, :document, :context, :fragments, :operations, :root_value, :max_depth, :query_string, :warden
2129

2230
# Prepare query `query_string` on `schema`
@@ -28,12 +36,12 @@ def initialize(names)
2836
# @param root_value [Object] the object used to resolve fields on the root type
2937
# @param max_depth [Numeric] the maximum number of nested selections allowed for this query (falls back to schema-level value)
3038
# @param max_complexity [Numeric] the maximum field complexity for this query (falls back to schema-level value)
31-
# @param mask [Schema::Mask] A mask for this query
32-
def initialize(schema, query_string = nil, document: nil, context: nil, variables: {}, operation_name: nil, root_value: nil, max_depth: nil, max_complexity: nil, mask: GraphQL::Schema::Mask::NullMask)
39+
# @param except [<#call(schema_member)>] If provided, objects will be hidden from the schema when `.call(schema_member)` returns truthy
40+
def initialize(schema, query_string = nil, document: nil, context: nil, variables: {}, validate: true, operation_name: nil, root_value: nil, max_depth: nil, max_complexity: nil, except: NullExcept)
3341
fail ArgumentError, "a query string or document is required" unless query_string || document
3442

3543
@schema = schema
36-
@warden = GraphQL::Schema::Warden.new(schema, mask)
44+
@warden = GraphQL::Schema::Warden.new(schema, except)
3745
@max_depth = max_depth || schema.max_depth
3846
@max_complexity = max_complexity || schema.max_complexity
3947
@query_analyzers = schema.query_analyzers.dup

lib/graphql/schema.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
require "graphql/schema/catchall_middleware"
22
require "graphql/schema/invalid_type_error"
3-
require "graphql/schema/mask"
43
require "graphql/schema/middleware_chain"
54
require "graphql/schema/possible_types"
65
require "graphql/schema/rescue_middleware"

lib/graphql/schema/mask.rb

Lines changed: 0 additions & 53 deletions
This file was deleted.

lib/graphql/schema/warden.rb

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,35 @@ class Schema
99
# you may show a client something that it shouldn't be allowed to see.
1010
#
1111
# Masks can be provided in {Schema#execute} (or {Query#initialize}) with the `mask:` keyword.
12-
# @see [GraphQL::Schema::Mask] A built-in mask implementation.
12+
#
13+
# @example Hidding private fields
14+
# private_members = -> (member) { member.metadata[:private] }
15+
# result = Schema.execute(query_string, except: private_members)
16+
#
17+
# @example Custom mask implementation
18+
# # It must respond to `#call(member)`.
19+
# class MissingRequiredFlags
20+
# def initialize(user)
21+
# @user = user
22+
# end
23+
#
24+
# # Return `false` if any required flags are missing
25+
# def call(member)
26+
# member.metadata[:required_flags].any? do |flag|
27+
# [email protected]_flag?(flag)
28+
# end
29+
# end
30+
# end
31+
#
32+
# # Then, use the custom filter in query:
33+
# missing_required_flags = MissingRequiredFlags.new(current_user)
34+
#
35+
# # This query can only access members which match the user's flags
36+
# result = Schema.execute(query_string, except: missing_required_flags)
37+
#
1338
class Warden
1439
# @param schema [GraphQL::Schema]
15-
# @param mask [<#visible?(member)>] This object controls access to schema members
40+
# @param mask [<#call(member)>] Objects are hidden when `.call(member)` returns true
1641
def initialize(schema, mask)
1742
@mask = mask
1843
@schema = schema
@@ -79,7 +104,7 @@ def visible_field?(field_defn)
79104
end
80105

81106
def visible?(member)
82-
@mask.visible?(member)
107+
!@mask.call(member)
83108
end
84109
end
85110
end

spec/graphql/schema/mask_spec.rb renamed to spec/graphql/schema/warden_spec.rb

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,12 @@ def self.unit
106106
end
107107

108108
def self.query_with_mask(str, mask)
109-
Schema.execute(str, mask: mask, root_value: Data)
109+
Schema.execute(str, except: mask, root_value: Data)
110110
end
111111
end
112112

113113

114-
describe GraphQL::Schema::Mask do
114+
describe GraphQL::Schema::Warden do
115115
def type_names(introspection_result)
116116
introspection_result["data"]["__schema"]["types"].map { |t| t["name"] }
117117
end
@@ -144,11 +144,9 @@ def error_messages(query_result)
144144
query_result["errors"].map { |err| err["message"] }
145145
end
146146

147-
let(:warden) { mask.apply(GraphQL::Query.new(MaskHelpers::Schema, "{ __typename }")) }
148-
149147
describe "hiding fields" do
150148
let(:mask) {
151-
GraphQL::Schema::Mask.new { |member| member.metadata[:hidden_field] || member.metadata[:hidden_type] }
149+
-> (member) { member.metadata[:hidden_field] || member.metadata[:hidden_type] }
152150
}
153151

154152
it "causes validation errors" do
@@ -194,7 +192,7 @@ def error_messages(query_result)
194192

195193
describe "hiding types" do
196194
let(:mask) {
197-
GraphQL::Schema::Mask.new { |member| member.metadata[:hidden_type] }
195+
-> (member) { member.metadata[:hidden_type] }
198196
}
199197

200198
it "hides types from introspection" do
@@ -280,7 +278,7 @@ def error_messages(query_result)
280278

281279
describe "hiding an abstract type" do
282280
let(:mask) {
283-
GraphQL::Schema::Mask.new { |member| member.metadata[:hidden_abstract_type] }
281+
-> (member) { member.metadata[:hidden_abstract_type] }
284282
}
285283

286284
it "isn't present in a type's interfaces" do
@@ -302,7 +300,7 @@ def error_messages(query_result)
302300

303301
describe "hiding arguments" do
304302
let(:mask) {
305-
GraphQL::Schema::Mask.new { |member| member.metadata[:hidden_argument] || member.metadata[:hidden_input_type] }
303+
-> (member) { member.metadata[:hidden_argument] || member.metadata[:hidden_input_type] }
306304
}
307305

308306
it "isn't present in introspection" do
@@ -338,7 +336,7 @@ def error_messages(query_result)
338336

339337
describe "hidding input types" do
340338
let(:mask) {
341-
GraphQL::Schema::Mask.new { |member| member.metadata[:hidden_input_object_type] }
339+
-> (member) { member.metadata[:hidden_input_object_type] }
342340
}
343341

344342
it "isn't present in introspection" do
@@ -383,7 +381,7 @@ def error_messages(query_result)
383381

384382
describe "hiding enum values" do
385383
let(:mask) {
386-
GraphQL::Schema::Mask.new { |member| member.metadata[:hidden_enum_value] }
384+
-> (member) { member.metadata[:hidden_enum_value] }
387385
}
388386

389387
it "isn't present in introspection" do

0 commit comments

Comments
 (0)