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

[View source]

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

[View source]

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:

[View source]

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

[View source]

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