Module: GraphQLIncludable

Extended by:
ActiveSupport::Concern
Defined in:
lib/graphql_includable.rb

Defined Under Namespace

Modules: ClassMethods

Class Method Summary collapse

Class Method Details

.find_association(return_model, child_name) ⇒ Object

find a valid association on return_model, following method delegation



112
113
114
115
116
117
118
# File 'lib/graphql_includable.rb', line 112

def self.find_association(return_model, child_name)
  delegated_model = return_model.instance_variable_get('@delegate_cache').try(:[], child_name.to_sym)
  association_model = delegated_model ? return_model.reflect_on_association(delegated_model).klass : return_model
  association = association_model.reflect_on_association(child_name)

  [association, delegated_model]
end

.find_child_node_matching_model_name(node, model_name) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/graphql_includable.rb', line 35

def self.find_child_node_matching_model_name(node, model_name)
  matching_node = nil
  return_type = unwrapped_type(node)
  if return_type.to_s == model_name
    matching_node = node
  elsif node.respond_to? :scoped_children
    node.scoped_children[return_type].each do |child_name, child_node|
      matching_node = find_child_node_matching_model_name(child_node, model_name)
      break if matching_node
    end
  end
  matching_node
end

.generate_includes_from_graphql(query_context, model_name) ⇒ Object



30
31
32
33
# File 'lib/graphql_includable.rb', line 30

def self.generate_includes_from_graphql(query_context, model_name)
  matching_node = GraphQLIncludable.find_child_node_matching_model_name(query_context.irep_node, model_name)
  GraphQLIncludable.includes_from_irep_node(matching_node)
end

.includes_from_irep_node(node) ⇒ Object



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
# File 'lib/graphql_includable.rb', line 49

def self.includes_from_irep_node(node)
  includes = []
  nested_includes = {}

  return_type = unwrapped_type(node)
  return_model = node_return_class(node)
  return [] unless node && return_type && return_model

  node.scoped_children[return_type].each do |child_name, child_node|
    child_association_name, explicit_includes = suggested_association_name(child_name, child_node)
    association, delegated_model_name = find_association(return_model, child_association_name)
    if association
      child_includes = includes_from_irep_node(child_node)

      if node_has_active_record_children(child_node) && child_includes.size > 0
        nested_includes[delegated_model_name || child_association_name] = wrap_delegate(child_includes, delegated_model_name, child_association_name)
      else
        includes << wrap_delegate(child_association_name, delegated_model_name)
      end
    elsif explicit_includes
      includes << explicit_includes
    end
  end

  includes << nested_includes if nested_includes.size > 0
  includes
end

.node_has_active_record_children(node) ⇒ Object



77
78
79
80
81
# File 'lib/graphql_includable.rb', line 77

def self.node_has_active_record_children(node)
  node.scoped_children[unwrapped_type(node)].each do |child_return_name, child_node|
    node_returns_active_record?(child_node)
  end
end

.node_return_class(node) ⇒ Object



83
84
85
86
87
88
# File 'lib/graphql_includable.rb', line 83

def self.node_return_class(node)
  begin
    Object.const_get(unwrapped_type(node).name)
  rescue NameError
  end
end

.node_returns_active_record?(node) ⇒ Boolean

Returns:

  • (Boolean)


90
91
92
93
# File 'lib/graphql_includable.rb', line 90

def self.node_returns_active_record?(node)
  klass = node_return_class(node)
  klass && klass < ActiveRecord::Base
end

.suggested_association_name(name, node) ⇒ Object

find the association to look for based on a field definition precedence is includes key, then property key, then the field name



122
123
124
125
126
127
128
129
# File 'lib/graphql_includable.rb', line 122

def self.suggested_association_name(name, node)
   = node.definitions[0].[:includes]

  assoc_name = node.definitions[0].property || name
  assoc_name =  if  && .is_a?(Symbol)

  [assoc_name.to_sym, ]
end

.unwrapped_type(node) ⇒ Object

unwrap GraphQL ListType and NonNullType wrappers



105
106
107
108
109
# File 'lib/graphql_includable.rb', line 105

def self.unwrapped_type(node)
  type = node.return_type
  type = type.of_type while type.respond_to? :of_type
  type
end

.wrap_delegate(contents, delegate, delegate_key = delegate) ⇒ Object

return raw contents, or contents wrapped in a hash (for delegated associations)



96
97
98
99
100
101
102
# File 'lib/graphql_includable.rb', line 96

def self.wrap_delegate(contents, delegate, delegate_key = delegate)
  return contents unless delegate

  obj = {}
  obj[delegate_key] = contents
  obj
end