diff options
Diffstat (limited to 'spec/support/graphql/field_selection.rb')
-rw-r--r-- | spec/support/graphql/field_selection.rb | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/spec/support/graphql/field_selection.rb b/spec/support/graphql/field_selection.rb new file mode 100644 index 00000000000..e2a3334acac --- /dev/null +++ b/spec/support/graphql/field_selection.rb @@ -0,0 +1,73 @@ +# frozen_string_literal: true + +module Graphql + class FieldSelection + delegate :empty?, :blank?, :to_h, to: :selection + delegate :size, to: :paths + + attr_reader :selection + + def initialize(selection = {}) + @selection = selection.to_h + end + + def to_s + serialize_field_selection(selection) + end + + def paths + selection.flat_map do |field, subselection| + paths_in([field], subselection) + end + end + + private + + def paths_in(path, leaves) + return [path] if leaves.nil? + + leaves.to_a.flat_map do |k, v| + paths_in([k], v).map { |tail| path + tail } + end + end + + def serialize_field_selection(hash, level = 0) + indent = ' ' * level + + hash.map do |field, subselection| + if subselection.nil? + "#{indent}#{field}" + else + subfields = serialize_field_selection(subselection, level + 1) + "#{indent}#{field} {\n#{subfields}\n#{indent}}" + end + end.join("\n") + end + + NO_SKIP = ->(_name, _field) { false } + + def self.select_fields(type, skip = NO_SKIP, parent_types = Set.new, max_depth = 3) + return new if max_depth <= 0 + + new(type.fields.flat_map do |name, field| + next [] if skip[name, field] + + inspected = ::Graphql::FieldInspection.new(field) + singular_field_type = inspected.type + + # If field type is the same as parent type, then we're hitting into + # mutual dependency. Break it from infinite recursion + next [] if parent_types.include?(singular_field_type) + + if inspected.nested_fields? + subselection = select_fields(singular_field_type, skip, parent_types | [type], max_depth - 1) + next [] if subselection.empty? + + [[name, subselection.to_h]] + else + [[name, nil]] + end + end) + end + end +end |