graphql_includable 0.1.7 → 0.2.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.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql_includable.rb +10 -146
  3. metadata +3 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 78dc263783852ec3090c807ab090253f08608de1
4
- data.tar.gz: 46aec07790da54100a3787a6c45df8064c90beda
3
+ metadata.gz: d25c20a822decf0d9e5ee56419b85a5794c9ae5f
4
+ data.tar.gz: a0a6803c0cde3cb012b57b2b6bd51bdad46d9971
5
5
  SHA512:
6
- metadata.gz: c7ee1838d8167126aecad34b00eaf338ec7515812a2290d724a5f1f7e8eb65c5bcbef139eb0a09a59837938b9cc35030ef239258d584867f95a316d84c3e3255
7
- data.tar.gz: fb5d17e8a29ecc47d8f819098573e25dfdd82250906273d105f2ae984303941ead7b0f97cf18b99057a11faea779901659b733c567fa018e22a0f3926ca67168
6
+ metadata.gz: 3e70cf65b71d6299ed2b118b600fdffc7b330c43c3a357e378c72bcfdc88623b0eed2fb7651a1531c2f9ac2b256919652a98b75487a9d05261fb24b47152dca1
7
+ data.tar.gz: f87b181a30dbb8f806380bead5fdcb163ed51762ccaaef7a0d4cb6f36b2f5cf5a9f1376bc21661baa1ea4ef4e1d9a7ec5578aeb4321920961ba85f22ac50916a
@@ -1,155 +1,19 @@
1
1
  require 'graphql'
2
- require 'active_support/concern'
2
+ require 'graphql_includable/concern'
3
+ require 'graphql_includable/edge'
3
4
 
4
5
  GraphQL::Field.accepts_definitions(
5
6
  includes: GraphQL::Define.assign_metadata_key(:includes)
6
7
  )
7
8
 
8
- module GraphQLIncludable
9
- extend ActiveSupport::Concern
10
-
11
- module ClassMethods
12
- def includes_from_graphql(ctx)
13
- generated_includes = GraphQLIncludable.generate_includes_from_graphql(ctx, model_name.to_s)
14
- includes(generated_includes)
15
- end
16
-
17
- def delegate_cache
18
- @delegate_cache ||= {}
19
- end
20
-
21
- # hook ActiveSupport's delegate method to track models and where their delegated methods go
22
- def delegate(*methods, args)
23
- methods.each do |method|
24
- delegate_cache[method] = args[:to]
25
- end
26
- super(*methods, args) if defined?(super)
27
- end
28
- end
29
-
30
- def self.generate_includes_from_graphql(ctx, model_name)
31
- matching_node = find_child_returning_model_name(ctx.irep_node, model_name)
32
- includes_from_graphql_field(matching_node)
33
- end
34
-
35
- def self.find_child_returning_model_name(node, model_name)
36
- matching_node = nil
37
- return_type = node_return_type(node)
38
- if return_type.to_s == model_name
39
- matching_node = node
40
- elsif node.respond_to? :scoped_children
41
- node.scoped_children[return_type].each do |_child_name, child_node|
42
- matching_node = find_child_returning_model_name(child_node, model_name)
43
- break if matching_node
44
- end
45
- end
46
- matching_node
47
- end
48
-
49
- def self.includes_from_graphql_field(node)
50
- includes = []
51
- nested_includes = {}
52
-
53
- return_model = node_return_class(node)
54
- return [] unless node && return_model
55
-
56
- node.scoped_children[node_return_type(node)].each do |_child_name, child_node|
57
- child_includes = includes_from_graphql_child(child_node, return_model)
58
- if child_includes.is_a?(Hash)
59
- nested_includes.merge!(child_includes)
60
- else
61
- child_includes = [child_includes] unless child_includes.is_a?(Array)
62
- includes += child_includes
63
- end
64
- end
65
-
66
- includes << nested_includes unless nested_includes.empty?
67
- includes
68
- end
69
-
70
- def self.includes_from_graphql_child(child_node, return_model)
71
- specified_includes = child_node.definitions[0].metadata[:includes]
72
- attribute_name = node_predicted_association_name(child_node)
73
- includes_chain = delegated_includes_chain(return_model, attribute_name)
74
-
75
- if model_has_association?(return_model, attribute_name, includes_chain)
76
- child_includes = includes_from_graphql_field(child_node)
77
- includes_chain << (specified_includes || attribute_name)
78
- includes_chain << child_includes unless child_includes.empty?
79
- array_to_nested_hash(includes_chain)
80
- else
81
- includes = []
82
- includes << array_to_nested_hash(includes_chain) unless includes_chain.empty?
83
- includes << specified_includes if specified_includes
84
- includes
85
- end
86
- end
87
-
88
- def self.node_return_class(node)
89
- # rubocop:disable Lint/HandleExceptions, Style/RedundantBegin
90
- begin
91
- Object.const_get(node_return_type(node).name)
92
- rescue NameError
93
- end
94
- # rubocop:enable Lint/HandleExceptions, Style/RedundantBegin
95
- end
96
-
97
- def self.node_returns_active_record?(node)
98
- klass = node_return_class(node)
99
- klass && klass < ActiveRecord::Base
100
- end
101
-
102
- def self.node_predicted_association_name(node)
103
- definition = node.definitions[0]
104
- specified_includes = definition.metadata[:includes]
105
- if specified_includes.is_a?(Symbol)
106
- specified_includes
107
- else
108
- (definition.property || definition.name).to_sym
109
- end
110
- end
111
-
112
- # get unwrapped return type from a field, stripping ListType / NonNullType wrappers
113
- def self.node_return_type(node)
114
- type = node.return_type
115
- type = type.of_type while type.respond_to? :of_type
116
- type
117
- end
118
-
119
- def self.model_has_association?(model, association_name, includes_chain)
120
- delegated_model = model_name_to_class(includes_chain.last) unless includes_chain.empty?
121
- (delegated_model || model).reflect_on_association(association_name)
122
- end
123
-
124
- # get a 1d array of the chain of delegated model names,
125
- # so if model A delegates method B to model C, which delegates method B to model D,
126
- # delegated_includes_chain(A, :B) => [:C, :D]
127
- def self.delegated_includes_chain(base_model, method_name)
128
- chain = []
129
- method = method_name.to_sym
130
- model_name = base_model.instance_variable_get('@delegate_cache').try(:[], method)
131
- while model_name
132
- chain << model_name
133
- model = model_name_to_class(model_name)
134
- model_name = model.instance_variable_get('@delegate_cache').try(:[], method)
135
- end
136
- chain
137
- end
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
9
+ module GraphQL
10
+ class BaseType
11
+ def define_includable_connection(**kwargs, &block)
12
+ define_connection(
13
+ edge_class: GraphQLIncludable::Edge,
14
+ **kwargs,
15
+ &block
16
+ )
152
17
  end
153
- model
154
18
  end
155
19
  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.7
4
+ version: 0.2.0
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-10 00:00:00.000000000 Z
12
+ date: 2018-02-09 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description:
15
15
  email:
@@ -40,7 +40,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
40
40
  version: '0'
41
41
  requirements: []
42
42
  rubyforge_project:
43
- rubygems_version: 2.6.12
43
+ rubygems_version: 2.6.11
44
44
  signing_key:
45
45
  specification_version: 4
46
46
  summary: An ActiveSupport::Concern for GraphQL Ruby to eager-load query data