Class: GraphQL::StaticValidation::DefinitionDependencies

Inherits:
Object
  • Object
show all
Defined in:
lib/graphql/static_validation/definition_dependencies.rb

Overview

Track fragment dependencies for operations and expose the fragment definitions which are used by a given operation

Defined Under Namespace

Classes: DependencyMap, NodeWithPath

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeDefinitionDependencies

Returns a new instance of DefinitionDependencies.



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/graphql/static_validation/definition_dependencies.rb', line 14

def initialize
  @node_paths = {}

  # { name => node } pairs for fragments
  @fragment_definitions = {}

  # This tracks dependencies from fragment to Node where it was used
  # { fragment_definition_node => [dependent_node, dependent_node]}
  @dependent_definitions = Hash.new { |h, k| h[k] = Set.new }

  # First-level usages of spreads within definitions
  # (When a key has an empty list as its value,
  #  we can resolve that key's depenedents)
  # { definition_node => [node, node ...] }
  @immediate_dependencies = Hash.new { |h, k| h[k] = Set.new }
end

Class Method Details

.mount(visitor) ⇒ Object



8
9
10
11
12
# File 'lib/graphql/static_validation/definition_dependencies.rb', line 8

def self.mount(visitor)
  deps = self.new
  deps.mount(visitor)
  deps
end

Instance Method Details

#dependency_map(&block) ⇒ DependencyMap

A map of operation definitions to an array of that operation's dependencies

Returns:



33
34
35
# File 'lib/graphql/static_validation/definition_dependencies.rb', line 33

def dependency_map(&block)
  @dependency_map ||= resolve_dependencies(&block)
end

#mount(context) ⇒ Object



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/graphql/static_validation/definition_dependencies.rb', line 37

def mount(context)
  visitor = context.visitor
  # When we encounter a spread,
  # this node is the one who depends on it
  current_parent = nil

  visitor[GraphQL::Language::Nodes::Document] << ->(node, prev_node) {
    node.definitions.each do |definition|
      case definition
      when GraphQL::Language::Nodes::OperationDefinition
      when GraphQL::Language::Nodes::FragmentDefinition
        @fragment_definitions[definition.name] = definition
      end
    end
  }

  visitor[GraphQL::Language::Nodes::OperationDefinition] << ->(node, prev_node) {
    @node_paths[node] = NodeWithPath.new(node, context.path)
    current_parent = node
  }

  visitor[GraphQL::Language::Nodes::OperationDefinition].leave << ->(node, prev_node) {
    current_parent = nil
  }

  visitor[GraphQL::Language::Nodes::FragmentDefinition] << ->(node, prev_node) {
    @node_paths[node] = NodeWithPath.new(node, context.path)
    current_parent = node
  }

  visitor[GraphQL::Language::Nodes::FragmentDefinition].leave << ->(node, prev_node) {
    current_parent = nil
  }

  visitor[GraphQL::Language::Nodes::FragmentSpread] << ->(node, prev_node) {
    @node_paths[node] = NodeWithPath.new(node, context.path)

    # Track both sides of the dependency
    @dependent_definitions[@fragment_definitions[node.name]] << current_parent
    @immediate_dependencies[current_parent] << node
  }
end