graphql_includable 0.1.4 → 0.1.5
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.rb +75 -40
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 803a100d8819528d092fd114ab447f1eabcb3872
|
4
|
+
data.tar.gz: 18b7e345903158ed2bcf003852061a34d6ccaf04
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dd8826b97ddcb70b6701a4da2136593f0b8743f284b8f0115ea547f1b3b8f4cbdc1e25291a5b6efc30bac98a44e8641e1a5a0d2e641144003594f2cb61257b21
|
7
|
+
data.tar.gz: d5a44484141daeae5667cdc06c550623dd636a3324b273672a0ef5918f0bd65c33561f68af35d386f68a5481a56339393278eec22cf8dd45aa9a05389f4f2195
|
data/lib/graphql_includable.rb
CHANGED
@@ -9,6 +9,7 @@ module GraphQLIncludable
|
|
9
9
|
module ClassMethods
|
10
10
|
def includes_from_graphql(query_context)
|
11
11
|
generated_includes = GraphQLIncludable.generate_includes_from_graphql(query_context, self.model_name.to_s)
|
12
|
+
puts "final gen: #{generated_includes}"
|
12
13
|
includes(generated_includes)
|
13
14
|
end
|
14
15
|
|
@@ -28,66 +29,68 @@ module GraphQLIncludable
|
|
28
29
|
private
|
29
30
|
|
30
31
|
def self.generate_includes_from_graphql(query_context, model_name)
|
31
|
-
matching_node = GraphQLIncludable.
|
32
|
-
GraphQLIncludable.
|
32
|
+
matching_node = GraphQLIncludable.find_child_returning_model_name(query_context.irep_node, model_name)
|
33
|
+
GraphQLIncludable.includes_from_graphql_field(matching_node)
|
33
34
|
end
|
34
35
|
|
35
|
-
def self.
|
36
|
+
def self.find_child_returning_model_name(node, model_name)
|
36
37
|
matching_node = nil
|
37
|
-
return_type =
|
38
|
+
return_type = node_return_type(node)
|
38
39
|
if return_type.to_s == model_name
|
39
40
|
matching_node = node
|
40
41
|
elsif node.respond_to? :scoped_children
|
41
42
|
node.scoped_children[return_type].each do |child_name, child_node|
|
42
|
-
matching_node =
|
43
|
+
matching_node = find_child_returning_model_name(child_node, model_name)
|
43
44
|
break if matching_node
|
44
45
|
end
|
45
46
|
end
|
46
47
|
matching_node
|
47
48
|
end
|
48
49
|
|
49
|
-
def self.
|
50
|
+
def self.includes_from_graphql_field(node)
|
50
51
|
includes = []
|
51
52
|
nested_includes = {}
|
52
53
|
|
53
|
-
return_type =
|
54
|
+
return_type = node_return_type(node)
|
54
55
|
return_model = node_return_class(node)
|
55
56
|
return [] unless node && return_type && return_model
|
56
57
|
|
57
|
-
node.scoped_children[return_type].each do |
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
if association
|
66
|
-
child_includes = includes_from_irep_node(child_node)
|
67
|
-
if node_has_active_record_children(child_node) && child_includes.size > 0
|
68
|
-
child_key = delegated_model_name || association_name
|
69
|
-
nested_includes[child_key] = wrap_delegate(child_includes, delegated_model_name, raw_association_name)
|
70
|
-
else
|
71
|
-
includes << wrap_delegate(specified_includes || association_name, delegated_model_name)
|
72
|
-
end
|
73
|
-
elsif specified_includes
|
74
|
-
includes << specified_includes
|
58
|
+
node.scoped_children[return_type].each do |_child_name, child_node|
|
59
|
+
child_includes = includes_from_graphql_child(child_node, return_model)
|
60
|
+
if child_includes.is_a?(Hash)
|
61
|
+
nested_includes.merge!(child_includes)
|
62
|
+
elsif child_includes.is_a?(Array)
|
63
|
+
includes += child_includes
|
64
|
+
elsif child_includes
|
65
|
+
includes << child_includes
|
75
66
|
end
|
76
67
|
end
|
77
68
|
|
78
|
-
includes << nested_includes
|
69
|
+
includes << nested_includes unless nested_includes.empty?
|
79
70
|
includes
|
80
71
|
end
|
81
72
|
|
82
|
-
def self.
|
83
|
-
|
84
|
-
|
73
|
+
def self.includes_from_graphql_child(child_node, return_model)
|
74
|
+
specified_includes = child_node.definitions[0].metadata[:includes]
|
75
|
+
attribute_name = node_predicted_association_name(child_node)
|
76
|
+
includes_chain = delegated_includes_chain(return_model, attribute_name)
|
77
|
+
|
78
|
+
if model_has_association?(return_model, attribute_name, includes_chain)
|
79
|
+
child_includes = includes_from_graphql_field(child_node)
|
80
|
+
includes_chain << (specified_includes || attribute_name)
|
81
|
+
includes_chain << child_includes unless child_includes.empty?
|
82
|
+
array_to_nested_hash(includes_chain)
|
83
|
+
else
|
84
|
+
includes = []
|
85
|
+
includes << array_to_nested_hash(includes_chain) unless includes_chain.empty?
|
86
|
+
includes << specified_includes if specified_includes
|
87
|
+
includes
|
85
88
|
end
|
86
89
|
end
|
87
90
|
|
88
91
|
def self.node_return_class(node)
|
89
92
|
begin
|
90
|
-
Object.const_get(
|
93
|
+
Object.const_get(node_return_type(node).name)
|
91
94
|
rescue NameError
|
92
95
|
end
|
93
96
|
end
|
@@ -97,24 +100,56 @@ module GraphQLIncludable
|
|
97
100
|
klass && klass < ActiveRecord::Base
|
98
101
|
end
|
99
102
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
103
|
+
def self.node_predicted_association_name(node)
|
104
|
+
definition = node.definitions[0]
|
105
|
+
specified_includes = definition.metadata[:includes]
|
106
|
+
if specified_includes.is_a?(Symbol)
|
107
|
+
specified_includes
|
108
|
+
else
|
109
|
+
(definition.property || definition.name).to_sym
|
110
|
+
end
|
107
111
|
end
|
108
112
|
|
109
113
|
# unwrap GraphQL ListType and NonNullType wrappers
|
110
|
-
def self.
|
114
|
+
def self.node_return_type(node)
|
111
115
|
type = node.return_type
|
112
116
|
type = type.of_type while type.respond_to? :of_type
|
113
117
|
type
|
114
118
|
end
|
115
119
|
|
116
|
-
def self.
|
117
|
-
|
120
|
+
def self.model_has_association?(model, association_name, includes_chain)
|
121
|
+
delegated_model = model_name_to_class(includes_chain.last) unless includes_chain.empty?
|
122
|
+
(delegated_model || model).reflect_on_association(association_name)
|
123
|
+
end
|
124
|
+
|
125
|
+
# get a 1d array of the chain of delegated model names,
|
126
|
+
# so if model A delegates method B to model C, which delegates method B to model D,
|
127
|
+
# delegated_includes_chain(A, :B) => [:C, :D]
|
128
|
+
def self.delegated_includes_chain(model, method_name)
|
129
|
+
chain = []
|
130
|
+
delegated_model_name = model.instance_variable_get('@delegate_cache').try(:[], method_name.to_sym)
|
131
|
+
while delegated_model_name
|
132
|
+
chain << delegated_model_name
|
133
|
+
delegated_model = model_name_to_class(delegated_model_name)
|
134
|
+
delegated_model_name = delegated_model.instance_variable_get('@delegate_cache').try(:[], method_name.to_sym)
|
135
|
+
end
|
136
|
+
chain
|
118
137
|
end
|
119
138
|
|
139
|
+
# convert a 1d array into a nested hash
|
140
|
+
# e.g. [:foo, :bar, :baz] => { :foo => { :bar => :baz }}
|
141
|
+
def self.array_to_nested_hash(arr)
|
142
|
+
arr.reverse.inject { |acc, item| { item => acc } }
|
143
|
+
end
|
144
|
+
|
145
|
+
# convert a model name into a class variable,
|
146
|
+
# e.g. :search_parameters -> SearchParameters
|
147
|
+
def self.model_name_to_class(model_name)
|
148
|
+
begin
|
149
|
+
model = model_name.to_s.camelize.constantize
|
150
|
+
rescue NameError
|
151
|
+
model = model_name.to_s.singularize.camelize.constantize
|
152
|
+
end
|
153
|
+
model
|
154
|
+
end
|
120
155
|
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.1.
|
4
|
+
version: 0.1.5
|
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: 2017-11-
|
12
|
+
date: 2017-11-10 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description:
|
15
15
|
email:
|