# frozen_string_literal: true module GraphQL module Compatibility module ExecutionSpecification module SpecificationSchema BOGUS_NODE = OpenStruct.new({ bogus: true }) DATA = { "1001" => OpenStruct.new({ name: "Fannie Lou Hamer", birthdate: Time.new(1917, 10, 6), organization_ids: [], }), "1002" => OpenStruct.new({ name: "John Lewis", birthdate: Time.new(1940, 2, 21), organization_ids: ["2001"], }), "1003" => OpenStruct.new({ name: "Diane Nash", birthdate: Time.new(1938, 5, 15), organization_ids: ["2001", "2002"], }), "1004" => OpenStruct.new({ name: "Ralph Abernathy", birthdate: Time.new(1926, 3, 11), organization_ids: ["2002"], }), "2001" => OpenStruct.new({ name: "SNCC", leader_id: nil, # fail on purpose }), "2002" => OpenStruct.new({ name: "SCLC", leader_id: "1004", }), "2003" => BOGUS_NODE, } # A list object must implement #each class CustomCollection def initialize(storage) @storage = storage end def each @storage.each { |i| yield(i) } end end module TestMiddleware # TODO: Once deprecated `next_middleware` argument becomes unsupported, add `&` to the argument def self.call(parent_type, parent_object, field_definition, field_args, query_context, next_middleware) query_context[:middleware_log] && query_context[:middleware_log] << field_definition.name next_middleware.call end end def self.build(execution_strategy) organization_type = nil timestamp_type = GraphQL::ScalarType.define do name "Timestamp" coerce_input ->(value, _ctx) { Time.at(value.to_i) } coerce_result ->(value, _ctx) { value.to_i } end named_entity_interface_type = GraphQL::InterfaceType.define do name "NamedEntity" field :name, !types.String end person_type = GraphQL::ObjectType.define do name "Person" interfaces [named_entity_interface_type] field :name, !types.String field :birthdate, timestamp_type field :age, types.Int do argument :on, !timestamp_type resolve ->(obj, args, ctx) { if obj.birthdate.nil? nil else age_on = args[:on] age_years = age_on.year - obj.birthdate.year this_year_birthday = Time.new(age_on.year, obj.birthdate.month, obj.birthdate.day) if this_year_birthday > age_on age_years -= 1 end end age_years } end field :organizations, types[organization_type] do resolve ->(obj, args, ctx) { CustomCollection.new(obj.organization_ids.map { |id| DATA[id] }) } end field :first_organization, !organization_type do resolve ->(obj, args, ctx) { DATA[obj.organization_ids.first] } end end organization_type = GraphQL::ObjectType.define do name "Organization" interfaces [named_entity_interface_type] field :name, !types.String field :leader, !person_type do resolve ->(obj, args, ctx) { DATA[obj.leader_id] || (ctx[:return_error] ? ExecutionError.new("Error on Nullable") : nil) } end field :returnedError, types.String do resolve ->(o, a, c) { GraphQL::ExecutionError.new("This error was returned") } end field :raisedError, types.String do resolve ->(o, a, c) { raise GraphQL::ExecutionError.new("This error was raised") } end field :nodePresence, !types[!types.Boolean] do resolve ->(o, a, ctx) { [ ctx.irep_node.is_a?(GraphQL::InternalRepresentation::Node), ctx.ast_node.is_a?(GraphQL::Language::Nodes::AbstractNode), false, # just testing ] } end end node_union_type = GraphQL::UnionType.define do name "Node" possible_types [person_type, organization_type] end query_type = GraphQL::ObjectType.define do name "Query" field :node, node_union_type do argument :id, !types.ID resolve ->(obj, args, ctx) { obj[args[:id]] } end field :requiredNode, node_union_type.to_non_null_type do argument :id, !types.ID resolve ->(obj, args, ctx) { obj[args[:id]] } end field :organization, !organization_type do argument :id, !types.ID resolve ->(obj, args, ctx) { if args[:id].start_with?("2") obj[args[:id]] else # test context.skip ctx.skip end } end field :organizations, types[organization_type] do resolve ->(obj, args, ctx) { [obj["2001"], obj["2002"]] } end end GraphQL::Schema.define do query_execution_strategy execution_strategy query query_type resolve_type ->(type, obj, ctx) { if obj.respond_to?(:birthdate) person_type elsif obj.respond_to?(:leader_id) organization_type else nil end } type_error ->(err, ctx) { ctx[:type_errors] && (ctx[:type_errors] << err.value) ctx[:gobble] || GraphQL::Schema::DefaultTypeError.call(err, ctx) } middleware(TestMiddleware) end end end end end end