Class: Graphlyte::Editors::SelectOperation

Inherits:
Object
  • Object
show all
Defined in:
lib/graphlyte/editors/select_operation.rb

Overview

Reduce a document down to a single operation, removing unnecessary fragments

eg:

pry(main)> puts doc

query A {
  foo(bar: $baz) {
    ...foos
  }
}

fragment foos on Foo {
  a
  b
  ...bars
}

fragment bars on Foo { d e f }

query B {
  foo {
    ...bars
  }
}

pry(main)> puts Graphlyte::Editors::SelectOperation.new('A').edit(doc.dup)

query A {
  foo(bar: $baz) {
    ...foos
  }
}

fragment foos on Foo {
  a
  b
  ...bars
}

fragment bars on Foo { d e f }

pry(main)> puts Graphlyte::Editors::SelectOperation.new('B').edit(doc.dup)

fragment bars on Foo { d e f }

query B {
  foo {
    ...bars
  }
}

Instance Method Summary collapse

Constructor Details

#initialize(operation) ⇒ SelectOperation

Returns a new instance of SelectOperation.



61
62
63
# File 'lib/graphlyte/editors/select_operation.rb', line 61

def initialize(operation)
  @operation = operation
end

Instance Method Details

#build_fragment_tree(doc) ⇒ Object

Compute the transitive closure of fragments used in each operation.



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/graphlyte/editors/select_operation.rb', line 81

def build_fragment_tree(doc)
  names = collect_fragment_names(doc)

  # Promote fragments in fragments to the operation at the root
  names[Syntax::Operation].each do |_op_name, spreads|
    unvisited = spreads.to_a

    until unvisited.empty?
      names[Syntax::Fragment][unvisited.pop]&.each do |name|
        next if spreads.include?(name)

        spreads << name
        unvisited << name
      end
    end
  end

  names_per_op
end

#collect_fragment_names(doc) ⇒ Object



101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/graphlyte/editors/select_operation.rb', line 101

def collect_fragment_names(doc)
  names = { Syntax::Operation => {}, Syntax::Fragment => {} }

  collect = Editor.new.on_fragment_spread do |spread, action|
    set = (names[action.definition.class] ||= [].to_set)

    set << spread.name
  end

  collect.edit(doc)

  names
end

#edit(doc) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/graphlyte/editors/select_operation.rb', line 65

def edit(doc)
  to_keep = build_fragment_tree(doc)[@operation]

  doc.definitions.select! do |definition|
    case definition
    when Syntax::Operation
      definition.name == @operation
    else
      to_keep.include?(definition.name)
    end
  end

  doc
end