graphql_includable 0.4.0.alpha.1 → 0.4.0
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 +0 -1
- data/lib/graphql_includable/edge.rb +5 -2
- data/lib/graphql_includable/relay/edge_with_node.rb +2 -2
- data/lib/graphql_includable/relay/edge_with_node_connection.rb +17 -12
- data/lib/graphql_includable/relay/edge_with_node_connection_type.rb +10 -5
- data/lib/graphql_includable/relay/instrumentation/connection.rb +35 -19
- data/lib/graphql_includable/resolver.rb +25 -19
- data/lib/graphql_includable.rb +2 -2
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c26fc967e743b93dc24703e364dc4500f17d94b9
|
4
|
+
data.tar.gz: 2c63040e1ed7695b36c9911fd44f6892d9c48c8f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7fda91af53b2e1057d0eb3acdaa251bda2b96b394f69445c309fe388a79ef6b0f4db76e694af58083b64676d5ced3a291fcbd82a3ad62064025637d08cd09e7d
|
7
|
+
data.tar.gz: 294fcbba508907345fc91a672e55a8305ff9702a89b0b34cbb0f397dbf64b15ef20fcb230c11ecf72281a6e12db4b7aafdcab0a5be554868e2410dee22844ba4
|
@@ -9,7 +9,6 @@ module GraphQLIncludable
|
|
9
9
|
node = Resolver.find_node_by_return_type(ctx.irep_node, name)
|
10
10
|
manager = IncludesManager.new(nil)
|
11
11
|
Resolver.includes_for_node(node, manager)
|
12
|
-
puts "INCLUDES!!! #{manager.includes}"
|
13
12
|
includes(manager.includes)
|
14
13
|
rescue => e
|
15
14
|
Rails.logger.error(e)
|
@@ -1,3 +1,6 @@
|
|
1
|
+
# rubocop:disable Style/ConditionalAssignment
|
2
|
+
# rubocop:disable Lint/HandleExceptions
|
3
|
+
# rubocop:disable Metrics/AbcSize
|
1
4
|
module GraphQLIncludable
|
2
5
|
class Edge < GraphQL::Relay::Edge
|
3
6
|
def edge
|
@@ -9,7 +12,7 @@ module GraphQLIncludable
|
|
9
12
|
root_association_key = class_to_str(parent.class)
|
10
13
|
unless edge_class.reflections.keys.include?(root_association_key)
|
11
14
|
is_polymorphic = true
|
12
|
-
root_association_key = edge_class.reflections.select { |
|
15
|
+
root_association_key = edge_class.reflections.select { |_k, r| r.polymorphic? }.keys.first
|
13
16
|
end
|
14
17
|
|
15
18
|
if parent.class.delegate_cache&.key?(edge_class_name)
|
@@ -39,7 +42,7 @@ module GraphQLIncludable
|
|
39
42
|
end
|
40
43
|
end
|
41
44
|
|
42
|
-
def respond_to_missing(method_name, include_private = false)
|
45
|
+
def respond_to_missing?(method_name, include_private = false)
|
43
46
|
edge.respond_to?(method_name) || super
|
44
47
|
end
|
45
48
|
|
@@ -3,7 +3,7 @@ module GraphQLIncludable
|
|
3
3
|
class EdgeWithNode < GraphQL::Relay::Edge
|
4
4
|
def initialize(node, connection)
|
5
5
|
@edge = node
|
6
|
-
node = connection.edge_to_node(@edge)
|
6
|
+
node = connection.edge_to_node(@edge) # TODO: Make lazy
|
7
7
|
super(node, connection)
|
8
8
|
end
|
9
9
|
|
@@ -15,7 +15,7 @@ module GraphQLIncludable
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
def respond_to_missing(method_name, include_private = false)
|
18
|
+
def respond_to_missing?(method_name, include_private = false)
|
19
19
|
@edge.respond_to?(method_name) || super
|
20
20
|
end
|
21
21
|
end
|
@@ -1,9 +1,13 @@
|
|
1
1
|
module GraphQLIncludable
|
2
2
|
module Relay
|
3
3
|
class ConnectionEdgesAndNodes
|
4
|
-
attr_reader :parent, :args, :ctx, :edges_property, :nodes_property, :edge_to_node_property
|
4
|
+
attr_reader :parent, :args, :ctx, :edges_property, :nodes_property, :edge_to_node_property
|
5
|
+
attr_reader :edges_resolver, :nodes_resolver
|
5
6
|
|
6
|
-
|
7
|
+
# rubocop:disable Metrics/ParameterLists
|
8
|
+
def initialize(parent, args, ctx,
|
9
|
+
edges_property, nodes_property, edge_to_node_property,
|
10
|
+
edges_resolver, nodes_resolver)
|
7
11
|
@parent = parent
|
8
12
|
@args = args
|
9
13
|
@ctx = ctx
|
@@ -13,11 +17,12 @@ module GraphQLIncludable
|
|
13
17
|
@edges_resolver = edges_resolver
|
14
18
|
@nodes_resolver = nodes_resolver
|
15
19
|
end
|
20
|
+
# rubocop:enable Metrics/ParameterLists
|
16
21
|
end
|
17
22
|
|
18
23
|
class EdgeWithNodeConnection < GraphQL::Relay::RelationConnection
|
19
24
|
def initialize(nodes, *args, &block)
|
20
|
-
@
|
25
|
+
@edges_and_nodes = nodes
|
21
26
|
@loaded_nodes = nil
|
22
27
|
@loaded_edges = nil
|
23
28
|
super(nil, *args, &block)
|
@@ -28,14 +33,14 @@ module GraphQLIncludable
|
|
28
33
|
end
|
29
34
|
|
30
35
|
def fetch_edges
|
31
|
-
@loaded_edges ||= @
|
36
|
+
@loaded_edges ||= @edges_and_nodes.edges_resolver.call(@edges_and_nodes.parent, args, ctx)
|
32
37
|
# Set nodes to make underlying BaseConnection work
|
33
38
|
@nodes = @loaded_edges
|
34
39
|
@loaded_edges
|
35
40
|
end
|
36
41
|
|
37
42
|
def fetch_nodes
|
38
|
-
@loaded_nodes ||= @
|
43
|
+
@loaded_nodes ||= @edges_and_nodes.nodes_resolver.call(@edges_and_nodes.parent, args, ctx)
|
39
44
|
# Set nodes to make underlying BaseConnection work
|
40
45
|
@nodes = @loaded_nodes
|
41
46
|
@loaded_nodes
|
@@ -47,7 +52,7 @@ module GraphQLIncludable
|
|
47
52
|
end
|
48
53
|
|
49
54
|
def edge_to_node(edge)
|
50
|
-
edge.public_send(@
|
55
|
+
edge.public_send(@edges_and_nodes.edge_to_node_property)
|
51
56
|
end
|
52
57
|
|
53
58
|
def total_count
|
@@ -58,23 +63,23 @@ module GraphQLIncludable
|
|
58
63
|
private
|
59
64
|
|
60
65
|
def args
|
61
|
-
@
|
66
|
+
@edges_and_nodes.args
|
62
67
|
end
|
63
68
|
|
64
69
|
def ctx
|
65
|
-
@
|
70
|
+
@edges_and_nodes.ctx
|
66
71
|
end
|
67
72
|
|
68
73
|
def determin_page_info_nodes
|
69
|
-
# If the query asks for `pageInfo` before `edges` or `nodes`, we dont directly know which to use most
|
70
|
-
# We can have a guess by checking if either of the associations are preloaded
|
74
|
+
# If the query asks for `pageInfo` before `edges` or `nodes`, we dont directly know which to use most
|
75
|
+
# efficently. We can have a guess by checking if either of the associations are preloaded
|
71
76
|
return @loaded_nodes if @loaded_nodes.present?
|
72
77
|
return @loaded_edges if @loaded_edges.present?
|
73
78
|
|
74
|
-
nodes_preloaded = @
|
79
|
+
nodes_preloaded = @edges_and_nodes.parent.association(@edges_and_nodes.nodes_property).loaded?
|
75
80
|
return fetch_nodes if nodes_preloaded
|
76
81
|
|
77
|
-
edges_preloaded = @
|
82
|
+
edges_preloaded = @edges_and_nodes.parent.association(@edges_and_nodes.edges_property).loaded?
|
78
83
|
return fetch_edges if edges_preloaded
|
79
84
|
|
80
85
|
fetch_nodes
|
@@ -3,7 +3,8 @@ module GraphQLIncludable
|
|
3
3
|
class EdgeWithNodeConnectionType
|
4
4
|
def self.create_type(
|
5
5
|
wrapped_type,
|
6
|
-
edge_type: wrapped_type.edge_type, edge_class: EdgeWithNode,
|
6
|
+
edge_type: wrapped_type.edge_type, edge_class: EdgeWithNode,
|
7
|
+
nodes_field: GraphQL::Relay::ConnectionType.default_nodes_field, &block
|
7
8
|
)
|
8
9
|
custom_edge_class = edge_class
|
9
10
|
|
@@ -11,15 +12,19 @@ module GraphQLIncludable
|
|
11
12
|
name("#{wrapped_type.name}Connection")
|
12
13
|
description("The connection type for #{wrapped_type.name}.")
|
13
14
|
|
14
|
-
field :totalCount, types.Int,
|
15
|
+
field :totalCount, types.Int, 'Total count.', property: :total_count
|
15
16
|
|
16
|
-
field :edges, types[edge_type],
|
17
|
+
field :edges, types[edge_type], 'A list of edges.' do
|
18
|
+
edge_class custom_edge_class
|
19
|
+
property :fetch_edges
|
20
|
+
_includable_connection_marker true
|
21
|
+
end
|
17
22
|
|
18
23
|
if nodes_field
|
19
|
-
field :nodes, types[wrapped_type],
|
24
|
+
field :nodes, types[wrapped_type], 'A list of nodes.', property: :fetch_nodes
|
20
25
|
end
|
21
26
|
|
22
|
-
field :pageInfo, !GraphQL::Relay::PageInfo,
|
27
|
+
field :pageInfo, !GraphQL::Relay::PageInfo, 'Information to aid in pagination.', property: :page_info
|
23
28
|
block && instance_eval(&block)
|
24
29
|
end
|
25
30
|
end
|
@@ -2,10 +2,11 @@ module GraphQLIncludable
|
|
2
2
|
module Relay
|
3
3
|
module Instrumentation
|
4
4
|
class Connection
|
5
|
+
# rubocop:disable Metrics/AbcSize
|
5
6
|
def instrument(_type, field)
|
6
|
-
return field unless
|
7
|
+
return field unless edge_with_node_connection?(field)
|
7
8
|
|
8
|
-
raise ArgumentError
|
9
|
+
raise ArgumentError, 'Connection does not support fetching using :property' if field.property.present?
|
9
10
|
|
10
11
|
validate!(field)
|
11
12
|
edge_to_node_property = field.metadata[:edge_to_node_property]
|
@@ -13,55 +14,70 @@ module GraphQLIncludable
|
|
13
14
|
edges_prop = explicit_includes[:edges]
|
14
15
|
nodes_prop = explicit_includes[:nodes]
|
15
16
|
|
16
|
-
if
|
17
|
+
if proc_based?(field)
|
17
18
|
edges_resolver = field.metadata[:resolve_edges]
|
18
19
|
nodes_resolver = field.metadata[:resolve_nodes]
|
19
20
|
else
|
20
21
|
# Use the edges and nodes symbols from the incldues pattern as the propeties to fetch
|
21
|
-
edges_resolver = ->(obj,
|
22
|
-
nodes_resolver = ->(obj,
|
22
|
+
edges_resolver = ->(obj, _args, _ctx) { obj.public_send(edges_prop) }
|
23
|
+
nodes_resolver = ->(obj, _args, _ctx) { obj.public_send(nodes_prop) }
|
23
24
|
end
|
24
25
|
|
25
26
|
_original_resolve = field.resolve_proc
|
26
27
|
new_resolve_proc = ->(obj, args, ctx) do
|
27
|
-
ConnectionEdgesAndNodes.new(obj, args, ctx,
|
28
|
+
ConnectionEdgesAndNodes.new(obj, args, ctx,
|
29
|
+
edges_prop, nodes_prop, edge_to_node_property,
|
30
|
+
edges_resolver, nodes_resolver)
|
28
31
|
end
|
29
32
|
|
30
33
|
field.redefine { resolve(new_resolve_proc) }
|
31
34
|
end
|
35
|
+
# rubocop:enable Metrics/AbcSize
|
32
36
|
|
33
37
|
private
|
34
38
|
|
35
|
-
def
|
39
|
+
def edge_with_node_connection?(field)
|
36
40
|
field.connection? && field.type.fields['edges'].metadata.key?(:_includable_connection_marker)
|
37
41
|
end
|
38
42
|
|
39
|
-
def
|
43
|
+
def proc_based?(field)
|
40
44
|
required_metadata = [:resolve_edges, :resolve_nodes]
|
41
45
|
has_a_resolver = required_metadata.any? { |key| field.metadata.key?(key) }
|
42
46
|
|
43
47
|
return false unless has_a_resolver
|
44
|
-
|
48
|
+
unless required_metadata.all? { |key| field.metadata.key?(key) }
|
49
|
+
raise ArgumentError, "Missing one of #{required_metadata}"
|
50
|
+
end
|
45
51
|
|
46
52
|
true
|
47
53
|
end
|
48
54
|
|
55
|
+
# rubocop:disable Metrics/AbcSize
|
49
56
|
def validate!(field)
|
50
|
-
|
51
|
-
|
57
|
+
unless field.metadata.key?(:edge_to_node_property)
|
58
|
+
raise ArgumentError, 'Missing edge_to_node_property definition for field'
|
59
|
+
end
|
60
|
+
unless field.metadata[:edge_to_node_property].is_a?(Symbol)
|
61
|
+
raise ArgumentError, ':edge_to_node_property must be a symbol'
|
62
|
+
end
|
52
63
|
|
53
|
-
raise ArgumentError
|
64
|
+
raise ArgumentError, 'Missing includes definition for field' unless field.metadata.key?(:includes)
|
54
65
|
includes = field.metadata[:includes]
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
raise ArgumentError
|
59
|
-
raise ArgumentError
|
66
|
+
unless includes.is_a?(Hash)
|
67
|
+
raise ArgumentError, 'Connection includes must be a hash containing :edges and :nodes keys'
|
68
|
+
end
|
69
|
+
raise ArgumentError, 'Missing :nodes includes' unless includes.key?(:nodes)
|
70
|
+
raise ArgumentError, 'Missing :edges includes' unless includes.key?(:edges)
|
71
|
+
raise ArgumentError, ':edges must be a symbol' unless includes[:edges].is_a?(Symbol)
|
72
|
+
raise ArgumentError, ':nodes must be a symbol' unless includes[:edges].is_a?(Symbol)
|
60
73
|
end
|
74
|
+
# rubocop:enable Metrics/AbcSize
|
61
75
|
end
|
62
76
|
|
63
|
-
GraphQL::Relay::BaseConnection.register_connection_implementation(
|
77
|
+
GraphQL::Relay::BaseConnection.register_connection_implementation(
|
78
|
+
GraphQLIncludable::Relay::ConnectionEdgesAndNodes,
|
79
|
+
GraphQLIncludable::Relay::EdgeWithNodeConnection
|
80
|
+
)
|
64
81
|
end
|
65
|
-
|
66
82
|
end
|
67
83
|
end
|
@@ -35,7 +35,7 @@ module GraphQLIncludable
|
|
35
35
|
|
36
36
|
if child_includes_arr.present?
|
37
37
|
child_includes_arr << child_includes if child_includes.present?
|
38
|
-
child_includes =
|
38
|
+
child_includes = child_includes_arr
|
39
39
|
end
|
40
40
|
|
41
41
|
return child_includes if @parent_attribute.nil?
|
@@ -48,16 +48,16 @@ module GraphQLIncludable
|
|
48
48
|
def self.find_node_by_return_type(node, desired_return_type)
|
49
49
|
return_type = node.return_type.unwrap.to_s
|
50
50
|
return node if return_type == desired_return_type
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
break if matching_node
|
51
|
+
return nil unless node.respond_to?(:scoped_children)
|
52
|
+
|
53
|
+
matching_node = nil
|
54
|
+
node.scoped_children.values.each do |selections|
|
55
|
+
matching_node = selections.values.find do |child_node|
|
56
|
+
find_node_by_return_type(child_node, desired_return_type)
|
58
57
|
end
|
59
|
-
matching_node
|
58
|
+
break if matching_node
|
60
59
|
end
|
60
|
+
matching_node
|
61
61
|
end
|
62
62
|
|
63
63
|
# Translate a node's selections into `includes` values
|
@@ -74,8 +74,11 @@ module GraphQLIncludable
|
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
|
-
|
78
|
-
|
77
|
+
# rubocop:disable Metrics/AbcSize
|
78
|
+
# rubocop:disable Metrics/MethodLength
|
79
|
+
def self.includes_from_connection(node, _parent_model, associations_from_parent_model, includes_manager)
|
80
|
+
# TODO: Possibly basic support for connections with only nodes
|
81
|
+
return unless node.return_type.fields['edges'].edge_class <= GraphQLIncludable::Relay::EdgeWithNode
|
79
82
|
|
80
83
|
edges_association = associations_from_parent_model[:edges]
|
81
84
|
nodes_association = associations_from_parent_model[:nodes]
|
@@ -128,21 +131,23 @@ module GraphQLIncludable
|
|
128
131
|
end
|
129
132
|
end
|
130
133
|
end
|
134
|
+
# rubocop:enable Metrics/MethodLength
|
135
|
+
# rubocop:enable Metrics/AbcSize
|
131
136
|
|
132
137
|
def self.includes_for_child(node, parent_model, includes_manager)
|
133
138
|
associations = possible_associations(node, parent_model)
|
139
|
+
return unless associations.present?
|
134
140
|
|
135
|
-
if
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
includes_for_node(node, child_includes_manager)
|
142
|
-
end
|
141
|
+
if node_is_relay_connection?(node)
|
142
|
+
includes_from_connection(node, parent_model, associations, includes_manager)
|
143
|
+
else
|
144
|
+
association = associations[:default] # should only be one
|
145
|
+
child_includes_manager = includes_manager.add_child_include(association)
|
146
|
+
includes_for_node(node, child_includes_manager)
|
143
147
|
end
|
144
148
|
end
|
145
149
|
|
150
|
+
# rubocop:disable Lint/HandleExceptions
|
146
151
|
def self.model_name_to_class(model_name)
|
147
152
|
begin
|
148
153
|
model_name.to_s.camelize.constantize
|
@@ -158,6 +163,7 @@ module GraphQLIncludable
|
|
158
163
|
model if model < ActiveRecord::Base
|
159
164
|
rescue NameError
|
160
165
|
end
|
166
|
+
# rubocop:enable Lint/HandleExceptions
|
161
167
|
|
162
168
|
def self.node_is_relay_connection?(node)
|
163
169
|
node.return_type.unwrap.name =~ /Connection$/
|
data/lib/graphql_includable.rb
CHANGED
@@ -13,13 +13,13 @@ GraphQL::Field.accepts_definitions(
|
|
13
13
|
resolve_edges: GraphQL::Define.assign_metadata_key(:resolve_edges),
|
14
14
|
resolve_nodes: GraphQL::Define.assign_metadata_key(:resolve_nodes),
|
15
15
|
# Internal use
|
16
|
-
_includable_connection_marker: GraphQL::Define.assign_metadata_key(:_includable_connection_marker)
|
16
|
+
_includable_connection_marker: GraphQL::Define.assign_metadata_key(:_includable_connection_marker)
|
17
17
|
)
|
18
18
|
|
19
19
|
module GraphQL
|
20
20
|
class BaseType
|
21
21
|
def define_includable_connection(**kwargs, &block)
|
22
|
-
warn '[DEPRECATION] `define_includable_connection` is deprecated.
|
22
|
+
warn '[DEPRECATION] `define_includable_connection` is deprecated. Use `define_connection_with_fetched_edge`.'
|
23
23
|
define_connection(
|
24
24
|
edge_class: GraphQLIncludable::Edge,
|
25
25
|
**kwargs,
|
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.4.0
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dan Rouse
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2019-08-
|
13
|
+
date: 2019-08-07 00:00:00.000000000 Z
|
14
14
|
dependencies: []
|
15
15
|
description:
|
16
16
|
email:
|
@@ -44,9 +44,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
44
44
|
version: '0'
|
45
45
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
46
46
|
requirements:
|
47
|
-
- - "
|
47
|
+
- - ">="
|
48
48
|
- !ruby/object:Gem::Version
|
49
|
-
version:
|
49
|
+
version: '0'
|
50
50
|
requirements: []
|
51
51
|
rubyforge_project:
|
52
52
|
rubygems_version: 2.6.14.1
|