Class: Graphlyte::Editors::WithVariables

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

Overview

Use variable values to infer missing variables in the query signature

Direct Known Subclasses

InferSignature

Constant Summary collapse

CannotInfer =
Class.new(StandardError)
TypeMismatch =
Class.new(StandardError)

Instance Method Summary collapse

Constructor Details

#initialize(schema, operation, variables) ⇒ WithVariables

Returns a new instance of WithVariables.



15
16
17
18
19
# File 'lib/graphlyte/editors/with_variables.rb', line 15

def initialize(schema, operation, variables)
  @schema = schema
  @operation = operation
  @variables = variables
end

Instance Method Details

#annotate_types(doc) ⇒ Object



31
32
33
# File 'lib/graphlyte/editors/with_variables.rb', line 31

def annotate_types(doc)
  Editors::AnnotateTypes.new(@schema).edit(doc) if @schema
end

#cannot_infer!(ref) ⇒ Object

Raises:



82
83
84
# File 'lib/graphlyte/editors/with_variables.rb', line 82

def cannot_infer!(ref)
  raise CannotInfer, ref.variable
end

#current_operation_variables(operation) ⇒ Object



64
65
66
67
# File 'lib/graphlyte/editors/with_variables.rb', line 64

def current_operation_variables(operation)
  operation.variables ||= []
  operation.variables.to_h { [_1.variable, _1] }
end

#edit(doc) ⇒ Object



21
22
23
24
25
26
27
28
29
# File 'lib/graphlyte/editors/with_variables.rb', line 21

def edit(doc)
  select_operation(doc)
  annotate_types(doc)

  references = Editors::CollectVariableReferences.new.edit(doc)
  editor = infer_variable_type(references)

  editor.edit(doc)
end

#infer(variables, added, doc, ref) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/graphlyte/editors/with_variables.rb', line 69

def infer(variables, added, doc, ref)
  var = doc.variables.fetch(ref.variable, ref.to_definition)
  type = var.type || ref.inferred_type || runtime_type_of(ref)

  if type
    var.type ||= type
    variables << var
    added[ref.variable] = var
  else
    cannot_infer!(ref)
  end
end

#infer_operation(operation, refs, document) ⇒ Object



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/graphlyte/editors/with_variables.rb', line 48

def infer_operation(operation, refs, document)
  current_vars = current_operation_variables(operation)

  added = {}
  refs.to_a.reject { current_vars[_1.variable] }.each do |ref|
    # Only way this could happen is if `uniq` produces duplicate names
    # And that can only happen if there are two types inferred
    # for the same reference.
    if (prev = added[ref.variable])
      raise TypeMismatch, "#{ref.variable}: #{ref.inferred_type} != #{prev.type}"
    end

    infer(operation.variables, added, document, ref)
  end
end

#infer_variable_type(references) ⇒ Object



39
40
41
42
43
44
45
46
# File 'lib/graphlyte/editors/with_variables.rb', line 39

def infer_variable_type(references)
  Editor.new.on_operation do |operation, editor|
    refs = references[operation.class][operation.name]
    next unless refs

    infer_operation(operation, refs, editor.document)
  end
end

#runtime_type_of(ref) ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/graphlyte/editors/with_variables.rb', line 86

def runtime_type_of(ref)
  value = @variables[ref.variable]

  case value
  when Integer
    Syntax::Type.non_null('Int')
  when Float
    Syntax::Type.non_null('Float')
  when String
    Syntax::Type.non_null('String')
  when Date
    Syntax::Type.non_null('Date')
  when TrueClass, FalseClass
    Syntax::Type.non_null('Boolean')
  when Array
    Syntax::Type.list_of(runtime_type_of(value.first)) unless value.empty?
  end
end

#select_operation(doc) ⇒ Object



35
36
37
# File 'lib/graphlyte/editors/with_variables.rb', line 35

def select_operation(doc)
  Editors::SelectOperation.new(@operation).edit(doc) if @operation
end