graphql_includable 0.2.2 → 0.2.3
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/concern.rb +5 -152
- data/lib/graphql_includable/edge.rb +24 -14
- data/lib/graphql_includable.rb +1 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 67916fbd68ce3698cbecbc818655408ba89f8f1a
|
4
|
+
data.tar.gz: 930edfc340b740528fd689b2bfd196f2f81aeef8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 48fe0a1f6e0bb028e7f643df33ecfcecec7701cfc382f33cb0928305a00fa6b6007e3e71ed5890be67b25d50c41079dfbfdbaece299c18e1c47f85ed116ad8a0
|
7
|
+
data.tar.gz: cd524919a412f7e98dff775b2b676d16c6fd30868c8f63f982c44e6a10110cd3cbb7dc2ecf93d0d91034561f3282b47a804e67afd3845cbc538e3c66891839f9
|
@@ -6,16 +6,18 @@ module GraphQLIncludable
|
|
6
6
|
|
7
7
|
module ClassMethods
|
8
8
|
def includes_from_graphql(ctx)
|
9
|
-
node =
|
10
|
-
generated_includes =
|
9
|
+
node = Resolver.find_node_by_return_type(ctx.irep_node, model_name)
|
10
|
+
generated_includes = Resolver.includes_for_node(node)
|
11
|
+
byebug if generated_includes == {}
|
11
12
|
includes(generated_includes)
|
13
|
+
rescue => e
|
14
|
+
self
|
12
15
|
end
|
13
16
|
|
14
17
|
def delegate_cache
|
15
18
|
@delegate_cache ||= {}
|
16
19
|
end
|
17
20
|
|
18
|
-
# hook ActiveSupport's delegate method to track models and where their delegated methods go
|
19
21
|
def delegate(*methods, args)
|
20
22
|
methods.each do |method|
|
21
23
|
delegate_cache[method] = args[:to]
|
@@ -23,154 +25,5 @@ module GraphQLIncludable
|
|
23
25
|
super(*methods, args) if defined?(super)
|
24
26
|
end
|
25
27
|
end
|
26
|
-
|
27
|
-
def self.first_child_by_return_type(node, model_name)
|
28
|
-
matching_node = nil
|
29
|
-
return_type = node.return_type.unwrap
|
30
|
-
if return_type.to_s == model_name
|
31
|
-
matching_node = node
|
32
|
-
elsif node.respond_to?(:scoped_children)
|
33
|
-
node.scoped_children[return_type].each_value do |child_node|
|
34
|
-
matching_node = first_child_by_return_type(child_node, model_name)
|
35
|
-
break if matching_node
|
36
|
-
end
|
37
|
-
end
|
38
|
-
matching_node
|
39
|
-
end
|
40
|
-
|
41
|
-
def self.children_through_connection(node, return_model)
|
42
|
-
includes = {}
|
43
|
-
# if node_is_relay_connection?(node)
|
44
|
-
# all_connection_children = node.scoped_children[node.return_type.unwrap]
|
45
|
-
# connection_children = all_connection_children.except('edges')
|
46
|
-
# edge_node = all_connection_children['edges']
|
47
|
-
# all_edge_children = edge_node.scoped_children[edge_node.return_type.unwrap]
|
48
|
-
# edge_children = all_edge_children.except('node')
|
49
|
-
# target_node = all_edge_children['node']
|
50
|
-
# children = target_node.scoped_children[target_node.return_type.unwrap]
|
51
|
-
|
52
|
-
# target_association = return_model.reflect_on_association(node_return_class(target_node).name.underscore)
|
53
|
-
# includes[target_association.name] = includes_from_graphql_node(target_node) if target_association
|
54
|
-
# else
|
55
|
-
children = node.scoped_children[node.return_type.unwrap]
|
56
|
-
# end
|
57
|
-
|
58
|
-
[children, includes]
|
59
|
-
end
|
60
|
-
|
61
|
-
def self.includes_from_graphql_node(node)
|
62
|
-
return_model = node_return_class(node)
|
63
|
-
return [] unless return_model
|
64
|
-
|
65
|
-
includes = []
|
66
|
-
children, nested_includes = children_through_connection(node, return_model)
|
67
|
-
children.each_value do |child_node|
|
68
|
-
child_includes = includes_from_graphql_child(child_node, return_model)
|
69
|
-
|
70
|
-
if child_includes.is_a?(Hash)
|
71
|
-
nested_includes.merge!(child_includes)
|
72
|
-
else
|
73
|
-
includes += child_includes.is_a?(Array) ? child_includes : [child_includes]
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
includes << nested_includes unless nested_includes.blank?
|
78
|
-
includes.uniq
|
79
|
-
end
|
80
|
-
|
81
|
-
def self.includes_from_graphql_child(child_node, return_model)
|
82
|
-
specified_includes = child_node.definitions[0].metadata[:includes]
|
83
|
-
attribute_name = node_predicted_association_name(child_node)
|
84
|
-
includes_chain = delegated_includes_chain(return_model, attribute_name)
|
85
|
-
association = get_model_association(return_model, attribute_name, includes_chain)
|
86
|
-
|
87
|
-
if association
|
88
|
-
child_includes = includes_from_graphql_node(child_node)
|
89
|
-
join_name = (specified_includes || attribute_name)
|
90
|
-
|
91
|
-
# if node_is_relay_connection?(child_node)
|
92
|
-
# join_name = association.options[:through]
|
93
|
-
# edge_includes_chain = [association.name]
|
94
|
-
# edge_includes_chain << child_includes.pop[association.name.to_s.singularize.to_sym] if child_includes.last&.is_a?(Hash)
|
95
|
-
# edge_includes = array_to_nested_hash(edge_includes_chain)
|
96
|
-
# end
|
97
|
-
|
98
|
-
includes_chain << join_name
|
99
|
-
includes_chain << child_includes unless child_includes.blank?
|
100
|
-
# byebug if node_is_relay_connection?(child_node)
|
101
|
-
edge_includes=nil
|
102
|
-
[edge_includes, array_to_nested_hash(includes_chain)].reject(&:blank?)
|
103
|
-
else
|
104
|
-
includes = []
|
105
|
-
includes << array_to_nested_hash(includes_chain) unless includes_chain.blank?
|
106
|
-
includes << specified_includes if specified_includes
|
107
|
-
includes
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
def self.node_return_class(node)
|
112
|
-
# rubocop:disable Lint/HandleExceptions, Style/RedundantBegin
|
113
|
-
begin
|
114
|
-
Object.const_get(node.return_type.unwrap.name.gsub(/(^SquareFoot|Edge$|Connection$)/, ''))
|
115
|
-
rescue NameError
|
116
|
-
end
|
117
|
-
# rubocop:enable Lint/HandleExceptions, Style/RedundantBegin
|
118
|
-
end
|
119
|
-
|
120
|
-
def self.node_is_relay_connection?(node)
|
121
|
-
node.return_type.unwrap.name =~ /Connection$/
|
122
|
-
end
|
123
|
-
|
124
|
-
def self.node_returns_active_record?(node)
|
125
|
-
klass = node_return_class(node)
|
126
|
-
klass && klass < ActiveRecord::Base
|
127
|
-
end
|
128
|
-
|
129
|
-
def self.node_predicted_association_name(node)
|
130
|
-
definition = node.definitions[0]
|
131
|
-
specified_includes = definition.metadata[:includes]
|
132
|
-
if specified_includes.is_a?(Symbol)
|
133
|
-
specified_includes
|
134
|
-
else
|
135
|
-
(definition.property || definition.name).to_sym
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
def self.get_model_association(model, association_name, includes_chain = nil)
|
140
|
-
delegated_model = model_name_to_class(includes_chain.last) unless includes_chain.blank?
|
141
|
-
(delegated_model || model).reflect_on_association(association_name)
|
142
|
-
end
|
143
|
-
|
144
|
-
# get a 1d array of the chain of delegated model names,
|
145
|
-
# so if model A delegates method B to model C, which delegates method B to model D,
|
146
|
-
# delegated_includes_chain(A, :B) => [:C, :D]
|
147
|
-
def self.delegated_includes_chain(base_model, method_name)
|
148
|
-
chain = []
|
149
|
-
method = method_name.to_sym
|
150
|
-
model_name = base_model.instance_variable_get('@delegate_cache').try(:[], method)
|
151
|
-
while model_name
|
152
|
-
chain << model_name
|
153
|
-
model = model_name_to_class(model_name)
|
154
|
-
model_name = model.instance_variable_get('@delegate_cache').try(:[], method)
|
155
|
-
end
|
156
|
-
chain
|
157
|
-
end
|
158
|
-
|
159
|
-
# convert a 1d array into a nested hash
|
160
|
-
# e.g. [:foo, :bar, :baz] => { :foo => { :bar => :baz }}
|
161
|
-
def self.array_to_nested_hash(arr)
|
162
|
-
arr.reverse.inject { |acc, item| { item => acc } }
|
163
|
-
end
|
164
|
-
|
165
|
-
# convert a model name into a class variable,
|
166
|
-
# e.g. :search_parameters -> SearchParameters
|
167
|
-
def self.model_name_to_class(model_name)
|
168
|
-
begin
|
169
|
-
model = model_name.to_s.camelize.constantize
|
170
|
-
rescue NameError
|
171
|
-
model = model_name.to_s.singularize.camelize.constantize
|
172
|
-
end
|
173
|
-
model
|
174
|
-
end
|
175
28
|
end
|
176
29
|
end
|
@@ -5,15 +5,17 @@ module GraphQLIncludable
|
|
5
5
|
edge_class_name = join_chain.shift
|
6
6
|
edge_class = str_to_class(edge_class_name)
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
root_association_key = class_to_str(parent.class).to_sym
|
9
|
+
root_node = { root_association_key => [parent] }
|
10
|
+
terminal_node = { class_to_str(node.class) => node }
|
10
11
|
join_chain.reverse.each do |rel_name|
|
11
12
|
terminal_node = { rel_name.to_s.pluralize => terminal_node }
|
12
13
|
end
|
14
|
+
|
13
15
|
search_hash = root_node.merge(terminal_node)
|
14
16
|
edge_includes = join_chain.map { |s| s.to_s.singularize }
|
15
17
|
edge_class = edge_class.includes(*edge_includes) unless edge_includes.empty?
|
16
|
-
@edge ||= edge_class.find_by(search_hash)
|
18
|
+
@edge ||= edge_class.joins(root_association_key).find_by(search_hash)
|
17
19
|
end
|
18
20
|
|
19
21
|
def method_missing(method_name, *args, &block)
|
@@ -36,21 +38,29 @@ module GraphQLIncludable
|
|
36
38
|
end
|
37
39
|
|
38
40
|
def class_to_str(klass)
|
39
|
-
klass.name.
|
41
|
+
klass.name.downcase
|
40
42
|
end
|
41
43
|
|
42
44
|
def joins_along_edge
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
while
|
47
|
-
|
48
|
-
|
49
|
-
join_chain << association_name if association_name
|
50
|
-
starting_class = str_to_class(association_name)
|
51
|
-
node_relationship_name = node_relationship_name.singularize
|
45
|
+
edge_association_name = node.class.name.pluralize.downcase.to_sym
|
46
|
+
edge_association = parent.class.reflect_on_association(edge_association_name)
|
47
|
+
edge_joins = []
|
48
|
+
while edge_association.is_a? ActiveRecord::Reflection::ThroughReflection
|
49
|
+
edge_joins.unshift edge_association.options[:through]
|
50
|
+
edge_association = parent.class.reflect_on_association(edge_association.options[:through])
|
52
51
|
end
|
53
|
-
|
52
|
+
edge_joins
|
53
|
+
# join_chain = []
|
54
|
+
# starting_class = parent.class
|
55
|
+
# node_relationship_name = class_to_str(node.class)
|
56
|
+
# while starting_class
|
57
|
+
# reflection = starting_class.reflect_on_association(node_relationship_name)
|
58
|
+
# association_name = reflection&.options&.try(:[], :through)
|
59
|
+
# join_chain << association_name if association_name
|
60
|
+
# starting_class = str_to_class(association_name)
|
61
|
+
# node_relationship_name = node_relationship_name.singularize
|
62
|
+
# end
|
63
|
+
# join_chain
|
54
64
|
end
|
55
65
|
end
|
56
66
|
end
|
data/lib/graphql_includable.rb
CHANGED
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.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dan Rouse
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2018-
|
12
|
+
date: 2018-04-09 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description:
|
15
15
|
email:
|
@@ -42,7 +42,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
42
42
|
version: '0'
|
43
43
|
requirements: []
|
44
44
|
rubyforge_project:
|
45
|
-
rubygems_version: 2.
|
45
|
+
rubygems_version: 2.6.11
|
46
46
|
signing_key:
|
47
47
|
specification_version: 4
|
48
48
|
summary: An ActiveSupport::Concern for GraphQL Ruby to eager-load query data
|