Skip to content

Commit

Permalink
Merge pull request #4669 from rmosolgo/null-context-instance
Browse files Browse the repository at this point in the history
Migrate NullContext to use Singleton
  • Loading branch information
rmosolgo authored Oct 17, 2023
2 parents 1bafe88 + 6909931 commit be52b28
Show file tree
Hide file tree
Showing 19 changed files with 47 additions and 54 deletions.
12 changes: 2 additions & 10 deletions lib/graphql/query/null_context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ module GraphQL
class Query
# This object can be `ctx` in places where there is no query
class NullContext
include Singleton

class NullQuery
def after_lazy(value)
yield(value)
Expand All @@ -27,16 +29,6 @@ def initialize
def interpreter?
true
end

class << self
extend Forwardable

def instance
@instance ||= self.new
end

def_delegators :instance, :query, :warden, :schema, :interpreter?, :dataloader, :[], :fetch, :dig, :key?
end
end
end
end
10 changes: 5 additions & 5 deletions lib/graphql/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ def plugins
# Build a map of `{ name => type }` and return it
# @return [Hash<String => Class>] A dictionary of type classes by their GraphQL name
# @see get_type Which is more efficient for finding _one type_ by name, because it doesn't merge hashes.
def types(context = GraphQL::Query::NullContext)
def types(context = GraphQL::Query::NullContext.instance)
all_types = non_introspection_types.merge(introspection_system.types)
visible_types = {}
all_types.each do |k, v|
Expand All @@ -352,7 +352,7 @@ def types(context = GraphQL::Query::NullContext)

# @param type_name [String]
# @return [Module, nil] A type, or nil if there's no type called `type_name`
def get_type(type_name, context = GraphQL::Query::NullContext)
def get_type(type_name, context = GraphQL::Query::NullContext.instance)
local_entry = own_types[type_name]
type_defn = case local_entry
when nil
Expand Down Expand Up @@ -483,7 +483,7 @@ def warden_class
# @param type [Module] The type definition whose possible types you want to see
# @return [Hash<String, Module>] All possible types, if no `type` is given.
# @return [Array<Module>] Possible types for `type`, if it's given.
def possible_types(type = nil, context = GraphQL::Query::NullContext)
def possible_types(type = nil, context = GraphQL::Query::NullContext.instance)
if type
# TODO duck-typing `.possible_types` would probably be nicer here
if type.kind.union?
Expand Down Expand Up @@ -566,7 +566,7 @@ def type_from_ast(ast_node, context: nil)
GraphQL::Schema::TypeExpression.build_type(type_owner, ast_node)
end

def get_field(type_or_name, field_name, context = GraphQL::Query::NullContext)
def get_field(type_or_name, field_name, context = GraphQL::Query::NullContext.instance)
parent_type = case type_or_name
when LateBoundType
get_type(type_or_name.name, context)
Expand All @@ -589,7 +589,7 @@ def get_field(type_or_name, field_name, context = GraphQL::Query::NullContext)
end
end

def get_fields(type, context = GraphQL::Query::NullContext)
def get_fields(type, context = GraphQL::Query::NullContext.instance)
type.fields(context)
end

Expand Down
2 changes: 1 addition & 1 deletion lib/graphql/schema/directive.rb
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ def initialize(owner, **arguments)
# - lazy resolution
# Probably, those won't be needed here, since these are configuration arguments,
# not runtime arguments.
@arguments = self.class.coerce_arguments(nil, arguments, Query::NullContext)
@arguments = self.class.coerce_arguments(nil, arguments, Query::NullContext.instance)
end

def graphql_name
Expand Down
4 changes: 2 additions & 2 deletions lib/graphql/schema/enum.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def value(*args, **kwargs, &block)
end

# @return [Array<GraphQL::Schema::EnumValue>] Possible values of this enum
def enum_values(context = GraphQL::Query::NullContext)
def enum_values(context = GraphQL::Query::NullContext.instance)
inherited_values = superclass.respond_to?(:enum_values) ? superclass.enum_values(context) : nil
visible_values = []
warden = Warden.from_context(context)
Expand Down Expand Up @@ -110,7 +110,7 @@ def all_enum_value_definitions
end

# @return [Hash<String => GraphQL::Schema::EnumValue>] Possible values of this enum, keyed by name.
def values(context = GraphQL::Query::NullContext)
def values(context = GraphQL::Query::NullContext.instance)
enum_values(context).each_with_object({}) { |val, obj| obj[val.graphql_name] = val }
end

Expand Down
4 changes: 2 additions & 2 deletions lib/graphql/schema/has_single_input_argument.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,11 @@ def dummy
end
end

def field_arguments(context = GraphQL::Query::NullContext)
def field_arguments(context = GraphQL::Query::NullContext.instance)
dummy.arguments(context)
end

def get_field_argument(name, context = GraphQL::Query::NullContext)
def get_field_argument(name, context = GraphQL::Query::NullContext.instance)
dummy.get_argument(name, context)
end

Expand Down
10 changes: 5 additions & 5 deletions lib/graphql/schema/member/has_arguments.rb
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ def remove_argument(arg_defn)
end

# @return [Hash<String => GraphQL::Schema::Argument] Arguments defined on this thing, keyed by name. Includes inherited definitions
def arguments(context = GraphQL::Query::NullContext)
def arguments(context = GraphQL::Query::NullContext.instance)
if own_arguments.any?
own_arguments_that_apply = {}
own_arguments.each do |name, args_entry|
Expand All @@ -133,7 +133,7 @@ def inherited(child_class)
end

module InheritedArguments
def arguments(context = GraphQL::Query::NullContext)
def arguments(context = GraphQL::Query::NullContext.instance)
own_arguments = super
inherited_arguments = superclass.arguments(context)

Expand Down Expand Up @@ -166,7 +166,7 @@ def all_argument_definitions
end


def get_argument(argument_name, context = GraphQL::Query::NullContext)
def get_argument(argument_name, context = GraphQL::Query::NullContext.instance)
warden = Warden.from_context(context)
for ancestor in ancestors
if ancestor.respond_to?(:own_arguments) &&
Expand All @@ -181,7 +181,7 @@ def get_argument(argument_name, context = GraphQL::Query::NullContext)
end

module FieldConfigured
def arguments(context = GraphQL::Query::NullContext)
def arguments(context = GraphQL::Query::NullContext.instance)
own_arguments = super
if @resolver_class
inherited_arguments = @resolver_class.field_arguments(context)
Expand Down Expand Up @@ -236,7 +236,7 @@ def all_argument_definitions
end

# @return [GraphQL::Schema::Argument, nil] Argument defined on this thing, fetched by name.
def get_argument(argument_name, context = GraphQL::Query::NullContext)
def get_argument(argument_name, context = GraphQL::Query::NullContext.instance)
warden = Warden.from_context(context)
if (arg_config = own_arguments[argument_name]) && (visible_arg = Warden.visible_entry?(:visible_argument?, arg_config, context, warden))
visible_arg
Expand Down
8 changes: 4 additions & 4 deletions lib/graphql/schema/member/has_fields.rb
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ def all_field_definitions
end

module InterfaceMethods
def get_field(field_name, context = GraphQL::Query::NullContext)
def get_field(field_name, context = GraphQL::Query::NullContext.instance)
warden = Warden.from_context(context)
for ancestor in ancestors
if ancestor.respond_to?(:own_fields) &&
Expand All @@ -110,7 +110,7 @@ def get_field(field_name, context = GraphQL::Query::NullContext)
end

# @return [Hash<String => GraphQL::Schema::Field>] Fields on this object, keyed by name, including inherited fields
def fields(context = GraphQL::Query::NullContext)
def fields(context = GraphQL::Query::NullContext.instance)
warden = Warden.from_context(context)
# Local overrides take precedence over inherited fields
visible_fields = {}
Expand All @@ -130,7 +130,7 @@ def fields(context = GraphQL::Query::NullContext)
end

module ObjectMethods
def get_field(field_name, context = GraphQL::Query::NullContext)
def get_field(field_name, context = GraphQL::Query::NullContext.instance)
# Objects need to check that the interface implementation is visible, too
warden = Warden.from_context(context)
ancs = ancestors
Expand All @@ -148,7 +148,7 @@ def get_field(field_name, context = GraphQL::Query::NullContext)
end

# @return [Hash<String => GraphQL::Schema::Field>] Fields on this object, keyed by name, including inherited fields
def fields(context = GraphQL::Query::NullContext)
def fields(context = GraphQL::Query::NullContext.instance)
# Objects need to check that the interface implementation is visible, too
warden = Warden.from_context(context)
# Local overrides take precedence over inherited fields
Expand Down
4 changes: 2 additions & 2 deletions lib/graphql/schema/member/has_interfaces.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def inherited(child_class)
end

module InheritedInterfaces
def interfaces(context = GraphQL::Query::NullContext)
def interfaces(context = GraphQL::Query::NullContext.instance)
visible_interfaces = super
inherited_interfaces = superclass.interfaces(context)
if visible_interfaces.any?
Expand Down Expand Up @@ -99,7 +99,7 @@ def interface_type_memberships
end

# param context [Query::Context] If omitted, skip filtering.
def interfaces(context = GraphQL::Query::NullContext)
def interfaces(context = GraphQL::Query::NullContext.instance)
warden = Warden.from_context(context)
visible_interfaces = nil
own_interface_type_memberships.each do |type_membership|
Expand Down
6 changes: 3 additions & 3 deletions lib/graphql/schema/member/validates_input.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ def validate_input(val, ctx, max_errors: nil)
end

def valid_isolated_input?(v)
valid_input?(v, GraphQL::Query::NullContext)
valid_input?(v, GraphQL::Query::NullContext.instance)
end

def coerce_isolated_input(v)
coerce_input(v, GraphQL::Query::NullContext)
coerce_input(v, GraphQL::Query::NullContext.instance)
end

def coerce_isolated_result(v)
coerce_result(v, GraphQL::Query::NullContext)
coerce_result(v, GraphQL::Query::NullContext.instance)
end
end
end
Expand Down
6 changes: 3 additions & 3 deletions lib/graphql/schema/resolver.rb
Original file line number Diff line number Diff line change
Expand Up @@ -205,20 +205,20 @@ def load_arguments(args)
end
end

def get_argument(name, context = GraphQL::Query::NullContext)
def get_argument(name, context = GraphQL::Query::NullContext.instance)
self.class.get_argument(name, context)
end

class << self
def field_arguments(context = GraphQL::Query::NullContext)
def field_arguments(context = GraphQL::Query::NullContext.instance)
arguments(context)
end

def any_field_arguments?
any_arguments?
end

def get_field_argument(name, context = GraphQL::Query::NullContext)
def get_field_argument(name, context = GraphQL::Query::NullContext.instance)
get_argument(name, context)
end

Expand Down
2 changes: 1 addition & 1 deletion lib/graphql/schema/union.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def inherited(child_class)
super
end

def possible_types(*types, context: GraphQL::Query::NullContext, **options)
def possible_types(*types, context: GraphQL::Query::NullContext.instance, **options)
if types.any?
types.each do |t|
assert_valid_union_member(t)
Expand Down
2 changes: 1 addition & 1 deletion lib/graphql/subscriptions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def trigger(event_name, args, object, scope: nil, context: {})

# Normalize symbol-keyed args to strings, try camelizing them
# Should this accept a real context somehow?
normalized_args = normalize_arguments(normalized_event_name, field, args, GraphQL::Query::NullContext)
normalized_args = normalize_arguments(normalized_event_name, field, args, GraphQL::Query::NullContext.instance)

event = Subscriptions::Event.new(
name: normalized_event_name,
Expand Down
2 changes: 1 addition & 1 deletion lib/graphql/subscriptions/event.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def initialize(name:, arguments:, field: nil, context: nil, scope: nil)
end

# @return [String] an identifier for this unit of subscription
def self.serialize(_name, arguments, field, scope:, context: GraphQL::Query::NullContext)
def self.serialize(_name, arguments, field, scope:, context: GraphQL::Query::NullContext.instance)
subscription = field.resolver || GraphQL::Schema::Subscription
normalized_args = stringify_args(field, arguments.to_h, context)
subscription.topic_for(arguments: normalized_args, field: field, scope: scope)
Expand Down
13 changes: 7 additions & 6 deletions spec/graphql/query/null_context_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,36 @@
require "spec_helper"

describe GraphQL::Query::NullContext do
let(:null_context) { GraphQL::Query::NullContext.instance }
describe "#[]" do
it "returns nil" do
assert_nil(GraphQL::Query::NullContext[:foo])
assert_nil(null_context[:foo])
end
end

describe "#fetch" do
it "returns the default value argument" do
assert_equal(:default, GraphQL::Query::NullContext.fetch(:foo, :default))
assert_equal(:default, null_context.fetch(:foo, :default))
end

it "returns the block result" do
assert_equal(:default, GraphQL::Query::NullContext.fetch(:foo) { :default })
assert_equal(:default, null_context.fetch(:foo) { :default })
end

it "raises a KeyError when not passed a default value or a block" do
assert_raises(KeyError) { GraphQL::Query::NullContext.fetch(:foo) }
assert_raises(KeyError) { null_context.fetch(:foo) }
end
end

describe "#key?" do
it "returns false" do
assert(!GraphQL::Query::NullContext.key?(:foo))
assert(!null_context.key?(:foo))
end
end

describe "#dig?" do
it "returns nil" do
assert_nil(GraphQL::Query::NullContext.dig(:foo, :bar, :baz))
assert_nil(null_context.dig(:foo, :bar, :baz))
end
end
end
2 changes: 1 addition & 1 deletion spec/graphql/schema/enum_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ def names(things:)

describe "validate_input with bad input" do
it "returns an invalid result" do
result = enum.validate_input("bad enum", GraphQL::Query::NullContext)
result = enum.validate_input("bad enum", GraphQL::Query::NullContext.instance)
assert(!result.valid?)
assert_equal(
result.problems.first['explanation'],
Expand Down
2 changes: 1 addition & 1 deletion spec/graphql/schema/input_object_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -807,7 +807,7 @@ def f(arg:)
let(:input_object) { Dummy::DairyProductInput }

def validate_isolated_input(t, input)
t.validate_input(input, GraphQL::Query::NullContext)
t.validate_input(input, GraphQL::Query::NullContext.instance)
end

describe "input validation" do
Expand Down
6 changes: 3 additions & 3 deletions spec/graphql/schema/scalar_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -147,15 +147,15 @@ class Query < GraphQL::Schema::Object


describe "validate_input with good input" do
let(:result) { GraphQL::Types::Int.validate_input(150, GraphQL::Query::NullContext) }
let(:result) { GraphQL::Types::Int.validate_input(150, GraphQL::Query::NullContext.instance) }

it "returns a valid result" do
assert(result.valid?)
end
end

describe "validate_input with bad input" do
let(:result) { GraphQL::Types::Int.validate_input("bad num", GraphQL::Query::NullContext) }
let(:result) { GraphQL::Types::Int.validate_input("bad num", GraphQL::Query::NullContext.instance) }

it "returns an invalid result for bad input" do
assert(!result.valid?)
Expand Down Expand Up @@ -206,7 +206,7 @@ def self.coerce_result(value, _ctx)
end

describe "custom scalar errors" do
let(:result) { custom_scalar.validate_input("xyz", GraphQL::Query::NullContext) }
let(:result) { custom_scalar.validate_input("xyz", GraphQL::Query::NullContext.instance) }

it "returns an invalid result" do
assert !result.valid?
Expand Down
2 changes: 1 addition & 1 deletion spec/integration/rails/graphql/input_object_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
nil,
ruby_kwargs: { source: 'COW', fatContent: 0.8 },
defaults_used: Set.new,
context: GraphQL::Query::NullContext)
context: GraphQL::Query::NullContext.instance)
end

describe '#to_json' do
Expand Down
4 changes: 2 additions & 2 deletions spec/integration/rails/graphql/schema_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,15 @@
describe "#resolve_type" do
describe "when the return value is nil" do
it "returns nil" do
result = relay_schema.resolve_type(123, nil, GraphQL::Query::NullContext)
result = relay_schema.resolve_type(123, nil, GraphQL::Query::NullContext.instance)
assert_equal([nil, nil], result)
end
end

describe "when the return value is not a BaseType" do
it "raises an error " do
err = assert_raises(RuntimeError) {
relay_schema.resolve_type(nil, :test_error, GraphQL::Query::NullContext)
relay_schema.resolve_type(nil, :test_error, GraphQL::Query::NullContext.instance)
}
assert_includes err.message, "not_a_type (Symbol)"
end
Expand Down

0 comments on commit be52b28

Please sign in to comment.