class GraphQL::Schema::Visibility::Migration
You can use this to see how GraphQL::Schema::Warden and GraphQL::Schema::Visibility::Profile handle .visible? differently in your schema.
It runs the same method on both implementations and raises an error when the results diverge.
To fix the error, modify your schema so that both implementations return the same thing. Or, open an issue on GitHub to discuss the difference.
This plugin adds overhead to runtime and may cause unexpected crashes β donβt use it in production!
This plugin adds two keys to context when running:
-
visibility_migration_running: true -
For the
Schema::Wardenwhich it instantiates, it addsvisibility_migration_warden_running: true.
Use those keys to modify your visible? behavior as needed.
Also, in a pinch, you can set skip_visibility_migration_error: true in context to turn off this behavior per-query. (In that case, it uses Profile directly.)
Examples
Example: Adding this plugin
use GraphQL::Schema::Visibility, migration_errors: true
Constants
- PUBLIC_PROFILE_METHODS
Public Class Methods
# File lib/graphql/schema/visibility/migration.rb, line 84 def initialize(context:, schema:, name: nil, visibility:) @name = name @skip_error = context[:skip_visibility_migration_error] || context.is_a?(Query::NullContext) || context.is_a?(Hash) @profile_types = GraphQL::Schema::Visibility::Profile.new(context: context, schema: schema, visibility: visibility) if !@skip_error context[:visibility_migration_running] = true warden_ctx_vals = context.to_h.dup warden_ctx_vals[:visibility_migration_warden_running] = true if schema.const_defined?(:WardenCompatSchema, false) # don't use a defn from a superclass warden_schema = schema.const_get(:WardenCompatSchema, false) else warden_schema = Class.new(schema) #: as singleton(GraphQL::Schema) warden_schema.use_visibility_profile = false # TODO public API warden_schema.send(:add_type_and_traverse, [warden_schema.query, warden_schema.mutation, warden_schema.subscription].compact, root: true) warden_schema.send(:add_type_and_traverse, warden_schema.directives.values + warden_schema.orphan_types, root: false) schema.const_set(:WardenCompatSchema, warden_schema) end warden_ctx = GraphQL::Query::Context.new(query: context.query, values: warden_ctx_vals) warden_ctx.warden = GraphQL::Schema::Warden.new(schema: warden_schema, context: warden_ctx) warden_ctx.warden.skip_warning = true warden_ctx.types = @warden_types = warden_ctx.warden.visibility_profile end end
Public Instance Methods
# File lib/graphql/schema/visibility/migration.rb, line 142 def call_method_and_compare(method, args) res_1 = @profile_types.public_send(method, *args) if @skip_error return res_1 end res_2 = @warden_types.public_send(method, *args) normalized_res_1 = res_1.is_a?(Array) ? Set.new(res_1) : res_1 normalized_res_2 = res_2.is_a?(Array) ? Set.new(res_2) : res_2 if !equivalent_schema_members?(normalized_res_1, normalized_res_2) # Raise the errors with the orignally returned values: err = RuntimeTypesMismatchError.new(method, res_2, res_1, args) raise err else res_1 end end
# File lib/graphql/schema/visibility/migration.rb, line 160 def equivalent_schema_members?(member1, member2) if member1.class != member2.class return false end case member1 when Set member1_array = member1.to_a.sort_by(&:graphql_name) member2_array = member2.to_a.sort_by(&:graphql_name) member1_array.each_with_index do |inner_member1, idx| inner_member2 = member2_array[idx] equivalent_schema_members?(inner_member1, inner_member2) end when GraphQL::Schema::Field member1.ensure_loaded member2.ensure_loaded if member1.introspection? && member2.introspection? member1.inspect == member2.inspect else member1 == member2 end when Module member1 = member1 #: as GraphQL::Schema::Member::type_definition if member1.introspection? && member2.introspection? member1.graphql_name == member2.graphql_name else member1 == member2 end else member1 == member2 end end
Source
# File lib/graphql/schema/visibility/migration.rb, line 109 def loaded_types @profile_types.loaded_types end