graphql_includable 0.2.3 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/graphql_includable/resolver.rb +105 -0
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6545a0cd3202a2d518e38696954b7797fd185684
|
4
|
+
data.tar.gz: 484b44d89aacbc52585f73657646fd12cd770ef6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8c3562e409a36d572f2899d21317a382eacda8d0c8f5413f0faa37423a5161c83278b7182dd99146c1bc3be095bfddd5419fa3ae279056b50964f5a66407b900
|
7
|
+
data.tar.gz: afe70bfba8d8f6459ff67301e44de68a5bcb66309ef9c293e803b8e77a6a05f05c5a812a2f55d99a56d2968d538f50a3d727c2011f1b6a47ca3b8e0aeba76922
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module GraphQLIncludable
|
2
|
+
class Resolver
|
3
|
+
# Returns the first node in the tree which returns a specific type
|
4
|
+
def self.find_node_by_return_type(node, desired_return_type)
|
5
|
+
return_type = node.return_type.unwrap
|
6
|
+
return node if return_type == desired_return_type
|
7
|
+
if node.respond_to?(:scoped_children)
|
8
|
+
node.scoped_children[return_type].find do |_child_name, child_node|
|
9
|
+
find_node_by_return_type(child_node, desired_return_type)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Translate a node's selections into `includes` values
|
15
|
+
# Combine and format children values
|
16
|
+
# Noop on nodes that don't return AR (so no associations to include)
|
17
|
+
def self.includes_for_node(node)
|
18
|
+
return_model = node_return_model(node)
|
19
|
+
return [] if return_model.blank?
|
20
|
+
|
21
|
+
children = node.scoped_children[node.return_type.unwrap]
|
22
|
+
nested_includes = {}
|
23
|
+
|
24
|
+
children.each_value do |child_node|
|
25
|
+
child_includes = includes_for_child(child_node, return_model)
|
26
|
+
|
27
|
+
if child_includes.is_a?(Hash)
|
28
|
+
nested_includes.merge!(child_includes)
|
29
|
+
elsif child_includes.is_a?(Array)
|
30
|
+
includes += child_includes
|
31
|
+
else
|
32
|
+
includes << child_includes
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
includes << nested_includes if nested_includes.present?
|
37
|
+
includes.uniq
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.includes_for_child(node, parent_model)
|
41
|
+
attribute_name = node_predicted_association_name(node)
|
42
|
+
delegated_through = includes_delegated_through(parent_model, attribute_name)
|
43
|
+
delegated_model = model_name_to_class(delegated_through.last) if delegated_through.present?
|
44
|
+
(delegated_model || parent_model).reflect_on_association(association_name)
|
45
|
+
association = get_model_association(parent_model, attribute_name, interceding_includes)
|
46
|
+
|
47
|
+
if association
|
48
|
+
child_includes = includes_for_node(node)
|
49
|
+
array_to_nested_hash(interceding_includes + [attribute_name, child_includes].reject(&:blank?))
|
50
|
+
# if node_is_relay_connection?(node)
|
51
|
+
# join_name = association.options[:through]
|
52
|
+
# edge_includes_chain = [association.name]
|
53
|
+
# edge_includes_chain << child_includes.pop[association.name.to_s.singularize.to_sym] if child_includes.last&.is_a?(Hash)
|
54
|
+
# edge_includes = array_to_nested_hash(edge_includes_chain)
|
55
|
+
# end
|
56
|
+
else
|
57
|
+
[array_to_nested_hash(interceding_includes), specified_includes].reject(&:blank?)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.model_name_to_class(model_name)
|
62
|
+
begin
|
63
|
+
model_name.to_s.camelize.constantize
|
64
|
+
rescue NameError
|
65
|
+
model_name.to_s.singularize.camelize.constantize
|
66
|
+
end
|
67
|
+
rescue
|
68
|
+
end
|
69
|
+
|
70
|
+
# Translate a node's return type to an ActiveRecord model
|
71
|
+
def self.node_return_model(node)
|
72
|
+
model = Object.const_get(node.return_type.unwrap.name.gsub(/(^SquareFoot|Edge$|Connection$)/, ''))
|
73
|
+
model if model < ActiveRecord::Base
|
74
|
+
rescue NameError
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.node_predicted_association_name(node)
|
78
|
+
definition = node.definitions.first
|
79
|
+
definition.metadata[:includes] || (definition.property || definition.name).to_sym
|
80
|
+
end
|
81
|
+
|
82
|
+
# If method_name is delegated from base_model, return an array of
|
83
|
+
# associations through which those methods can be delegated
|
84
|
+
def self.includes_delegated_through(base_model, method_name)
|
85
|
+
chain = []
|
86
|
+
method = method_name.to_sym
|
87
|
+
model_name = base_model.instance_variable_get(:@delegate_cache).try(:[], method)
|
88
|
+
while model_name
|
89
|
+
chain << model_name
|
90
|
+
model = model_name_to_class(model_name)
|
91
|
+
model_name = model.instance_variable_get(:@delegate_cache).try(:[], method)
|
92
|
+
end
|
93
|
+
chain
|
94
|
+
end
|
95
|
+
|
96
|
+
# Right-reduce an array into a nested hash
|
97
|
+
def self.array_to_nested_hash(arr)
|
98
|
+
arr.reverse.inject { |acc, item| { item => acc } } || {}
|
99
|
+
end
|
100
|
+
|
101
|
+
# def self.node_is_relay_connection?(node)
|
102
|
+
# node.return_type.unwrap.name =~ /Connection$/
|
103
|
+
# end
|
104
|
+
end
|
105
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphql_includable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dan Rouse
|
@@ -22,6 +22,7 @@ files:
|
|
22
22
|
- lib/graphql_includable.rb
|
23
23
|
- lib/graphql_includable/concern.rb
|
24
24
|
- lib/graphql_includable/edge.rb
|
25
|
+
- lib/graphql_includable/resolver.rb
|
25
26
|
homepage: https://github.com/thesquarefoot/graphql_includable
|
26
27
|
licenses:
|
27
28
|
- MIT
|