Skip to content

Commit 028bedf

Browse files
committed
Allow Schema subclasses to inherit settings
1 parent f9b6227 commit 028bedf

13 files changed

+323
-169
lines changed

lib/graphql/schema.rb

Lines changed: 105 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
require "graphql/schema/catchall_middleware"
44
require "graphql/schema/default_parse_error"
55
require "graphql/schema/default_type_error"
6+
require "graphql/schema/find_inherited_value"
67
require "graphql/schema/finder"
78
require "graphql/schema/invalid_type_error"
89
require "graphql/schema/introspection_system"
@@ -81,6 +82,8 @@ class Schema
8182
extend Forwardable
8283
extend GraphQL::Schema::Member::AcceptsDefinition
8384
include GraphQL::Define::InstanceDefinable
85+
extend GraphQL::Schema::FindInheritedValue
86+
8487
accepts_definitions \
8588
:query, :mutation, :subscription,
8689
:query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
@@ -159,7 +162,9 @@ def default_filter
159162
# @see {Query#tracers} for query-specific tracers
160163
attr_reader :tracers
161164

162-
DYNAMIC_FIELDS = ["__type", "__typename", "__schema"]
165+
DYNAMIC_FIELDS = ["__type", "__typename", "__schema"].freeze
166+
EMPTY_ARRAY = [].freeze
167+
EMPTY_HASH = {}.freeze
163168

164169
attr_reader :static_validator, :object_from_id_proc, :id_from_object_proc, :resolve_type_proc
165170

@@ -728,11 +733,11 @@ def graphql_definition
728733
end
729734

730735
def use(plugin, options = {})
731-
plugins << [plugin, options]
736+
own_plugins << [plugin, options]
732737
end
733738

734739
def plugins
735-
@plugins ||= []
740+
find_inherited_value(:plugins, EMPTY_ARRAY) + own_plugins
736741
end
737742

738743
def to_graphql
@@ -746,7 +751,7 @@ def to_graphql
746751
schema_defn.max_depth = max_depth
747752
schema_defn.default_max_page_size = default_max_page_size
748753
schema_defn.orphan_types = orphan_types
749-
schema_defn.disable_introspection_entry_points = @disable_introspection_entry_points
754+
schema_defn.disable_introspection_entry_points = disable_introspection_entry_points?
750755

751756
prepped_dirs = {}
752757
directives.each { |k, v| prepped_dirs[k] = v.graphql_definition}
@@ -758,26 +763,24 @@ def to_graphql
758763
schema_defn.type_error = method(:type_error)
759764
schema_defn.context_class = context_class
760765
schema_defn.cursor_encoder = cursor_encoder
761-
schema_defn.tracers.concat(defined_tracers)
762-
schema_defn.query_analyzers.concat(defined_query_analyzers)
766+
schema_defn.tracers.concat(tracers)
767+
schema_defn.query_analyzers.concat(query_analyzers)
763768

764-
schema_defn.middleware.concat(defined_middleware)
765-
schema_defn.multiplex_analyzers.concat(defined_multiplex_analyzers)
769+
schema_defn.middleware.concat(all_middleware)
770+
schema_defn.multiplex_analyzers.concat(multiplex_analyzers)
766771
schema_defn.query_execution_strategy = query_execution_strategy
767772
schema_defn.mutation_execution_strategy = mutation_execution_strategy
768773
schema_defn.subscription_execution_strategy = subscription_execution_strategy
769-
defined_instrumenters.each do |step, insts|
774+
all_instrumenters.each do |step, insts|
770775
insts.each do |inst|
771776
schema_defn.instrumenters[step] << inst
772777
end
773778
end
774779
lazy_classes.each do |lazy_class, value_method|
775780
schema_defn.lazy_methods.set(lazy_class, value_method)
776781
end
777-
if @rescues
778-
@rescues.each do |err_class, handler|
779-
schema_defn.rescue_from(err_class, &handler)
780-
end
782+
rescues.each do |err_class, handler|
783+
schema_defn.rescue_from(err_class, &handler)
781784
end
782785

783786
if plugins.any?
@@ -806,107 +809,118 @@ def query(new_query_object = nil)
806809
if new_query_object
807810
@query_object = new_query_object
808811
else
809-
@query_object.respond_to?(:graphql_definition) ? @query_object.graphql_definition : @query_object
812+
query_object = @query_object || find_inherited_value(:query)
813+
query_object.respond_to?(:graphql_definition) ? query_object.graphql_definition : query_object
810814
end
811815
end
812816

813817
def mutation(new_mutation_object = nil)
814818
if new_mutation_object
815819
@mutation_object = new_mutation_object
816820
else
817-
@mutation_object.respond_to?(:graphql_definition) ? @mutation_object.graphql_definition : @mutation_object
821+
mutation_object = @mutation_object || find_inherited_value(:mutation)
822+
mutation_object.respond_to?(:graphql_definition) ? mutation_object.graphql_definition : mutation_object
818823
end
819824
end
820825

821826
def subscription(new_subscription_object = nil)
822827
if new_subscription_object
823828
@subscription_object = new_subscription_object
824829
else
825-
@subscription_object.respond_to?(:graphql_definition) ? @subscription_object.graphql_definition : @subscription_object
830+
subscription_object = @subscription_object || find_inherited_value(:subscription)
831+
subscription_object.respond_to?(:graphql_definition) ? subscription_object.graphql_definition : subscription_object
826832
end
827833
end
828834

829835
def introspection(new_introspection_namespace = nil)
830836
if new_introspection_namespace
831837
@introspection = new_introspection_namespace
832838
else
833-
@introspection
839+
@introspection || find_inherited_value(:introspection)
834840
end
835841
end
836842

837843
def cursor_encoder(new_encoder = nil)
838844
if new_encoder
839845
@cursor_encoder = new_encoder
840846
end
841-
@cursor_encoder || Base64Encoder
847+
@cursor_encoder || find_inherited_value(:cursor_encoder, Base64Encoder)
842848
end
843849

844850
def default_max_page_size(new_default_max_page_size = nil)
845851
if new_default_max_page_size
846852
@default_max_page_size = new_default_max_page_size
847853
else
848-
@default_max_page_size
854+
@default_max_page_size || find_inherited_value(:default_max_page_size)
849855
end
850856
end
851857

852858
def query_execution_strategy(new_query_execution_strategy = nil)
853859
if new_query_execution_strategy
854860
@query_execution_strategy = new_query_execution_strategy
855861
else
856-
@query_execution_strategy || self.default_execution_strategy
862+
@query_execution_strategy || find_inherited_value(:query_execution_strategy, self.default_execution_strategy)
857863
end
858864
end
859865

860866
def mutation_execution_strategy(new_mutation_execution_strategy = nil)
861867
if new_mutation_execution_strategy
862868
@mutation_execution_strategy = new_mutation_execution_strategy
863869
else
864-
@mutation_execution_strategy || self.default_execution_strategy
870+
@mutation_execution_strategy || find_inherited_value(:mutation_execution_strategy, self.default_execution_strategy)
865871
end
866872
end
867873

868874
def subscription_execution_strategy(new_subscription_execution_strategy = nil)
869875
if new_subscription_execution_strategy
870876
@subscription_execution_strategy = new_subscription_execution_strategy
871877
else
872-
@subscription_execution_strategy || self.default_execution_strategy
878+
@subscription_execution_strategy || find_inherited_value(:subscription_execution_strategy, self.default_execution_strategy)
873879
end
874880
end
875881

876882
def max_complexity(max_complexity = nil)
877883
if max_complexity
878884
@max_complexity = max_complexity
879885
else
880-
@max_complexity
886+
@max_complexity || find_inherited_value(:max_complexity)
881887
end
882888
end
883889

884890
def error_bubbling(new_error_bubbling = nil)
885891
if !new_error_bubbling.nil?
886892
@error_bubbling = new_error_bubbling
887893
else
888-
@error_bubbling
894+
@error_bubbling.nil? ? find_inherited_value(:error_bubbling) : @error_bubbling
889895
end
890896
end
891897

892898
def max_depth(new_max_depth = nil)
893899
if new_max_depth
894900
@max_depth = new_max_depth
895901
else
896-
@max_depth
902+
@max_depth || find_inherited_value(:max_depth)
897903
end
898904
end
899905

900906
def disable_introspection_entry_points
901907
@disable_introspection_entry_points = true
902908
end
903909

910+
def disable_introspection_entry_points?
911+
if instance_variable_defined?(:@disable_introspection_entry_points)
912+
@disable_introspection_entry_points
913+
else
914+
find_inherited_value(:disable_introspection_entry_points?, false)
915+
end
916+
end
917+
904918
def orphan_types(*new_orphan_types)
905919
if new_orphan_types.any?
906-
@orphan_types = new_orphan_types.flatten
907-
else
908-
@orphan_types || []
920+
own_orphan_types.concat(new_orphan_types.flatten)
909921
end
922+
923+
find_inherited_value(:orphan_types, EMPTY_ARRAY) + own_orphan_types
910924
end
911925

912926
def default_execution_strategy
@@ -921,17 +935,20 @@ def context_class(new_context_class = nil)
921935
if new_context_class
922936
@context_class = new_context_class
923937
else
924-
@context_class || GraphQL::Query::Context
938+
@context_class || find_inherited_value(:context_class, GraphQL::Query::Context)
925939
end
926940
end
927941

928942
def rescue_from(*err_classes, &handler_block)
929-
@rescues ||= {}
930943
err_classes.each do |err_class|
931-
@rescues[err_class] = handler_block
944+
own_rescues[err_class] = handler_block
932945
end
933946
end
934947

948+
def rescues
949+
find_inherited_value(:rescues, EMPTY_HASH).merge(own_rescues)
950+
end
951+
935952
def resolve_type(type, obj, ctx)
936953
if type.kind.object?
937954
type
@@ -1017,19 +1034,20 @@ def instrument(instrument_step, instrumenter, options = {})
10171034
else
10181035
instrument_step
10191036
end
1020-
defined_instrumenters[step] << instrumenter
1037+
1038+
own_instrumenters[step] << instrumenter
10211039
end
10221040

10231041
def directives(new_directives = nil)
10241042
if new_directives
1025-
@directives = new_directives.reduce({}) { |m, d| m[d.name] = d; m }
1043+
new_directives.each {|d| directive(d) }
10261044
end
10271045

1028-
@directives ||= default_directives
1046+
find_inherited_value(:directives, default_directives).merge(own_directives)
10291047
end
10301048

10311049
def directive(new_directive)
1032-
directives[new_directive.graphql_name] = new_directive
1050+
own_directives[new_directive.graphql_name] = new_directive
10331051
end
10341052

10351053
def default_directives
@@ -1041,26 +1059,38 @@ def default_directives
10411059
end
10421060

10431061
def tracer(new_tracer)
1044-
defined_tracers << new_tracer
1062+
own_tracers << new_tracer
1063+
end
1064+
1065+
def tracers
1066+
find_inherited_value(:tracers, EMPTY_ARRAY) + own_tracers
10451067
end
10461068

10471069
def query_analyzer(new_analyzer)
10481070
if new_analyzer == GraphQL::Authorization::Analyzer
10491071
warn("The Authorization query analyzer is deprecated. Authorizing at query runtime is generally a better idea.")
10501072
end
1051-
defined_query_analyzers << new_analyzer
1073+
own_query_analyzers << new_analyzer
1074+
end
1075+
1076+
def query_analyzers
1077+
find_inherited_value(:query_analyzers, EMPTY_ARRAY) + own_query_analyzers
10521078
end
10531079

10541080
def middleware(new_middleware = nil)
10551081
if new_middleware
1056-
defined_middleware << new_middleware
1082+
own_middleware << new_middleware
10571083
else
10581084
graphql_definition.middleware
10591085
end
10601086
end
10611087

10621088
def multiplex_analyzer(new_analyzer)
1063-
defined_multiplex_analyzers << new_analyzer
1089+
own_multiplex_analyzers << new_analyzer
1090+
end
1091+
1092+
def multiplex_analyzers
1093+
find_inherited_value(:multiplex_analyzers, EMPTY_ARRAY) + own_multiplex_analyzers
10641094
end
10651095

10661096
private
@@ -1069,24 +1099,51 @@ def lazy_classes
10691099
@lazy_classes ||= {}
10701100
end
10711101

1072-
def defined_instrumenters
1073-
@defined_instrumenters ||= Hash.new { |h,k| h[k] = [] }
1102+
def own_plugins
1103+
@own_plugins ||= []
1104+
end
1105+
1106+
def own_rescues
1107+
@own_rescues ||= {}
10741108
end
10751109

1076-
def defined_tracers
1077-
@defined_tracers ||= []
1110+
def own_orphan_types
1111+
@own_orphan_types ||= []
10781112
end
10791113

1080-
def defined_query_analyzers
1114+
def own_directives
1115+
@own_directives ||= {}
1116+
end
1117+
1118+
def all_instrumenters
1119+
inherited_instrumenters = find_inherited_value(:all_instrumenters) || Hash.new { |h,k| h[k] = [] }
1120+
inherited_instrumenters.merge(own_instrumenters) do |_step, inherited, own|
1121+
inherited + own
1122+
end
1123+
end
1124+
1125+
def own_instrumenters
1126+
@own_instrumenters ||= Hash.new { |h,k| h[k] = [] }
1127+
end
1128+
1129+
def own_tracers
1130+
@own_tracers ||= []
1131+
end
1132+
1133+
def own_query_analyzers
10811134
@defined_query_analyzers ||= []
10821135
end
10831136

1084-
def defined_middleware
1085-
@defined_middleware ||= []
1137+
def all_middleware
1138+
find_inherited_value(:all_middleware, EMPTY_ARRAY) + own_middleware
1139+
end
1140+
1141+
def own_middleware
1142+
@own_middleware ||= []
10861143
end
10871144

1088-
def defined_multiplex_analyzers
1089-
@defined_multiplex_analyzers ||= []
1145+
def own_multiplex_analyzers
1146+
@own_multiplex_analyzers ||= []
10901147
end
10911148

10921149
# Given this schema member, find the class-based definition object
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
module GraphQL
2+
class Schema
3+
module FindInheritedValue
4+
private
5+
6+
def find_inherited_value(method_name, default_value = nil)
7+
if self.is_a?(Class)
8+
superclass.respond_to?(method_name, true) ? superclass.send(method_name) : default_value
9+
else
10+
ancestors[1..-1].each do |ancestor|
11+
if ancestor.respond_to?(method_name, true)
12+
return ancestor.send(method_name)
13+
end
14+
end
15+
default_value
16+
end
17+
end
18+
end
19+
end
20+
end

0 commit comments

Comments
 (0)