graphiti_gql 0.2.5 → 0.2.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b9a1b76315488d9389a214fc640f6029d9e1a05a08182ebbdb9ed7958565e4aa
4
- data.tar.gz: e4d6952a6929bf8310a99ba5b2d40e3821fe8bad51e89b3012c041fed9f1c47a
3
+ metadata.gz: a0558a0d0edaf2e03b09fe28ce603afb10eb0cbd02e8aa56be43cfd1044bebab
4
+ data.tar.gz: 69660d61a4191bd6428a2ad33d2f9e3e6a4227c31d4be636a6b886af543f35f3
5
5
  SHA512:
6
- metadata.gz: 30cb9c3f67aa059d0e68845fc64aee6313d9f0d14d36e19024357c619ca15e176d4178ae2836055c22b407a53187038b21b8447007e37fbed04ab70330c12ff4
7
- data.tar.gz: 6ece60976b6d36294e9ef01e8521efdf26d9637b28c6fcfec833e3f2a81d493eece073137071e3373f2ac948c786c18e79734904b62e369a1cc0c0353860d71d
6
+ metadata.gz: 892b44992e36645282bd7003218067d248e04ac6f440feaac137afa1449f9b01017d7bcb577bbaf3bd8dc7f1c808b7f9b6eaf6e0c4474b4f1d6910dabb49ad3e
7
+ data.tar.gz: 3d29b975b6748e292e4420707c2f8e4825a8e743c197f70126863c230a22ad75f0efece663a2400704716d2c7621d8cdd90732185ee7540c317c23708004a4d0
@@ -1,17 +1,24 @@
1
+ # TODO: Rushing here so tests are in app and code is gross
1
2
  module GraphitiGql
2
3
  module ActiveResource
3
4
  extend ActiveSupport::Concern
4
5
 
5
6
  class Node < OpenStruct
6
- def initialize(resource, hash)
7
+ def initialize(hash, resource = nil)
7
8
  @resource = resource
9
+ @edges = {}
10
+ @node_id = hash.delete(:node_id)
8
11
  hash.each_pair do |key, value|
9
12
  if value.is_a?(Hash)
10
13
  if (sideload = resource.sideload(key))
11
14
  if value.key?(:edges)
12
- hash[key] = value[:edges].map { |v| Node.new(sideload.resource.class, v[:node]) }
15
+ @edges[key] = value[:edges].map do |edge|
16
+ node_id = edge[:node][:id]
17
+ Node.new(edge.except(:node).merge(node_id: node_id))
18
+ end
19
+ hash[key] = value[:edges].map { |v| Node.new(v[:node], sideload.resource.class) }
13
20
  else
14
- hash[key] = Node.new(sideload.resource.class, value)
21
+ hash[key] = Node.new(value, sideload.resource.class)
15
22
  end
16
23
  end
17
24
  end
@@ -19,6 +26,15 @@ module GraphitiGql
19
26
  super(hash)
20
27
  end
21
28
 
29
+ def edge(name, node_id)
30
+ found = @edges[name].empty? ? nil : @edges[name]
31
+ if found && node_id
32
+ found.find { |f| f.instance_variable_get(:@node_id) == node_id.to_s }
33
+ else
34
+ found
35
+ end
36
+ end
37
+
22
38
  def decoded_id
23
39
  Base64.decode64(self.id)
24
40
  end
@@ -29,7 +45,8 @@ module GraphitiGql
29
45
  end
30
46
 
31
47
  class Proxy
32
- def initialize(resource, params, ctx)
48
+ def initialize(resource, params, ctx, query)
49
+ @query = query
33
50
  @resource = resource
34
51
  @ctx = ctx
35
52
  @params = params.deep_transform_keys { |key| key.to_s.camelize(:lower).to_sym }
@@ -46,10 +63,18 @@ module GraphitiGql
46
63
  result
47
64
  end
48
65
 
66
+ def node(id)
67
+ nodes.find { |n| n.id == id.to_s }
68
+ end
69
+
49
70
  def nodes
50
71
  return [] unless data
51
- nodes = edges.map { |e| underscore(e[:node]) }
52
- nodes.map { |n| Node.new(@resource, n) }
72
+ elements = if edges
73
+ edges.map { |e| e[:node] }
74
+ else
75
+ data[data.keys.first][:nodes] || []
76
+ end
77
+ elements.map { |n| Node.new(underscore(n), @resource) }
53
78
  end
54
79
  alias :to_a :nodes
55
80
 
@@ -85,7 +110,10 @@ module GraphitiGql
85
110
  underscore(data[data.keys.first][:pageInfo])
86
111
  end
87
112
 
113
+ # barf
88
114
  def query
115
+ return @query if @query
116
+
89
117
  name = Schema.registry.key_for(@resource)
90
118
  filter_bang = "!" if @resource.filters.values.any? { |f| f[:required] }
91
119
  sortvar = "$sort: [#{name}Sort!]," if @resource.sorts.any?
@@ -118,6 +146,7 @@ module GraphitiGql
118
146
  node {|
119
147
 
120
148
  fields.each do |name|
149
+ next if name.is_a?(Hash)
121
150
  q << %|
122
151
  #{name.to_s.camelize(:lower)}|
123
152
  end
@@ -129,17 +158,36 @@ module GraphitiGql
129
158
  sideload = @resource.sideload(inc.to_sym)
130
159
  to_one = [:belongs_to, :has_one, :polymorphic_belongs_to].include?(sideload.type)
131
160
  indent = " " if !to_one
161
+
162
+ edge_fields = []
163
+ runtime_sideload_fields = @params[:fields].find { |f| f.is_a?(Hash) && f.key?(inc.to_sym) }
164
+ if runtime_sideload_fields
165
+ runtime_sideload_fields = runtime_sideload_fields.values
166
+ edge_fields = runtime_sideload_fields.find { |f| f.is_a?(Hash) && f.key?(:edge) }
167
+ runtime_sideload_fields = runtime_sideload_fields.reject { |f| f.is_a?(Hash) }
168
+ edge_fields = edge_fields[:edge] if edge_fields
169
+ end
170
+
132
171
  q << %|
133
172
  #{inc.to_s.camelize(:lower)} {|
134
173
  if !to_one
135
174
  q << %|
136
- edges {
175
+ edges {|
176
+
177
+ edge_fields.each do |ef|
178
+ q << %|
179
+ #{ef.to_s.camelize(:lower)}|
180
+ end
181
+
182
+ q << %|
137
183
  node {|
138
184
  end
139
185
 
140
- r = @resource.sideload(inc.to_sym).resource
141
- r.attributes.each_pair do |name, config|
142
- next unless config[:readable]
186
+ sideload_fields = runtime_sideload_fields
187
+ if sideload_fields.blank?
188
+ sideload_fields = @resource.sideload(inc.to_sym).resource.attributes.select { |_, config| config[:readable] }.map(&:first)
189
+ end
190
+ sideload_fields.each do |name|
143
191
  q << %|
144
192
  #{indent}#{name.to_s.camelize(:lower)}|
145
193
  end
@@ -200,8 +248,8 @@ module GraphitiGql
200
248
  end
201
249
 
202
250
  class_methods do
203
- def gql(params = {}, ctx = {})
204
- Proxy.new(self, params, ctx)
251
+ def gql(params = {}, ctx = {}, query = nil)
252
+ Proxy.new(self, params, ctx, query)
205
253
  end
206
254
  end
207
255
  end
@@ -143,22 +143,41 @@ module GraphitiGql
143
143
  Graphiti::Scoping::Paginate.send(:prepend, PaginateExtras)
144
144
 
145
145
  module ManyToManyExtras
146
- extend ActiveSupport::Concern
146
+ def self.prepended(klass)
147
+ klass.class_eval do
148
+ class << self
149
+ attr_accessor :edge_resource
147
150
 
148
- class_methods do
149
- attr_accessor :edge_resource
151
+ def attribute(*args, &blk)
152
+ @edge_resource ||= Class.new(Graphiti::Resource) do
153
+ def self.abstract_class?
154
+ true
155
+ end
156
+ end
157
+ @edge_resource.attribute(*args, &blk)
158
+ end
159
+ end
160
+ end
161
+ end
162
+
163
+ def apply_belongs_to_many_filter
164
+ super
165
+ self_ref = self
166
+ fk_type = parent_resource_class.attributes[:id][:type]
167
+ fk_type = :hash if polymorphic?
168
+ filters = resource_class.config[:filters]
150
169
 
151
- def attribute(*args, &blk)
152
- @edge_resource = Class.new(Graphiti::Resource) do
153
- def self.abstract_class?
154
- true
170
+ # Keep the options, apply the eq proc
171
+ if (filter = filters[inverse_filter.to_sym])
172
+ if filter[:operators][:eq].nil?
173
+ filter[:operators][:eq] = proc do |scope, value|
174
+ self_ref.belongs_to_many_filter(scope, value)
155
175
  end
156
176
  end
157
- @edge_resource.attribute(*args, &blk)
158
177
  end
159
178
  end
160
179
  end
161
- Graphiti::Sideload::ManyToMany.send(:include, ManyToManyExtras)
180
+ Graphiti::Sideload::ManyToMany.send(:prepend, ManyToManyExtras)
162
181
 
163
182
  module StatsExtras
164
183
  def calculate_stat(name, function)
@@ -42,6 +42,7 @@ module GraphitiGql
42
42
  params = {
43
43
  filter: { id: { eq: value.join(",") } }
44
44
  }
45
+
45
46
  futures << Concurrent::Future.execute do
46
47
  { type: key, data: klass.resource.class.all(params).data }
47
48
  end
@@ -19,8 +19,11 @@ module GraphitiGql
19
19
  def add_join_table_magic(proxy)
20
20
  if defined?(ActiveRecord) && proxy.resource.model.ancestors.include?(ActiveRecord::Base)
21
21
  thru = @sideload.foreign_key.keys.first
22
- thru_model = proxy.resource.model.reflect_on_association(thru).klass
22
+ reflection = @sideload.parent_resource.model.reflect_on_association(thru)
23
+ thru_model = reflection.klass
24
+
23
25
  names = thru_model.column_names.map do |n|
26
+ next if n == :id
24
27
  "#{thru_model.table_name}.#{n} as _edge_#{n}"
25
28
  end
26
29
  scope = proxy.scope.object
@@ -38,7 +38,7 @@ module GraphitiGql
38
38
 
39
39
  value = if _config[:proc]
40
40
  if _sideload
41
- instance_exec(edge_attrs, &_config[:proc])
41
+ instance_exec(edge_attrs, object.node, &_config[:proc])
42
42
  else
43
43
  instance_eval(&_config[:proc])
44
44
  end
@@ -42,24 +42,41 @@ module GraphitiGql
42
42
  end
43
43
 
44
44
  def build_customized_edge_type(sideload_type)
45
- # build the edge class
46
- prior_edge_class = sideload_type.edge_type_class
47
- edge_class = Class.new(prior_edge_class)
45
+ edge_type_class = build_edge_type_class(sideload_type)
46
+
47
+ # Build the sideload type with new edge class applied
48
+ if sideload_type.is_a?(Module)
49
+ klass = sideload_type
50
+ # There's some magic that happens when subclassing, but modules
51
+ # don't subclass. This is the kind of resetting we need to happen.
52
+ # Might be a graphql-ruby issue.
53
+ klass.instance_variable_set(:@connection_type, nil)
54
+ klass.instance_variable_set(:@edge_type, nil)
55
+ klass.edge_type_class(edge_type_class)
56
+ klass
57
+ else
58
+ klass = Class.new(sideload_type)
59
+ klass.edge_type_class(edge_class)
60
+ klass
61
+ end
62
+ end
63
+
64
+ def build_edge_type_class(sideload_type)
65
+ prior_edge_type_class = sideload_type.edge_type_class
66
+ edge_type_class = Class.new(prior_edge_type_class)
48
67
  edge_resource = @sideload.class.edge_resource
49
68
  edge_resource.attributes.each_pair do |name, config|
50
69
  next if name == :id
51
- Schema::Fields::Attribute.new(name, config, @sideload).apply(edge_class)
70
+ Schema::Fields::Attribute.new(name, config, @sideload).apply(edge_type_class)
52
71
  end
53
72
  registered_parent = Schema.registry.get(@sideload.parent_resource.class)
54
73
  parent_name = registered_parent[:type].graphql_name
55
- edge_class.define_method :graphql_name do
56
- "#{parent_name}To#{sideload_type.graphql_name}Edge"
74
+ edge_type_class_name = "#{parent_name}To#{sideload_type.graphql_name}Edge"
75
+ edge_type_class.define_method :graphql_name do
76
+ edge_type_class_name
57
77
  end
58
-
59
- # build the sideload type with new edge class applied
60
- klass = Class.new(sideload_type)
61
- klass.edge_type_class(edge_class)
62
- klass
78
+ edge_type_class.graphql_name(edge_type_class_name)
79
+ edge_type_class
63
80
  end
64
81
  end
65
82
  end
@@ -34,14 +34,19 @@ module GraphitiGql
34
34
 
35
35
  private
36
36
 
37
- def process_polymorphic_parent(type)
37
+ def process_polymorphic_parent(interface_type)
38
+ registry_name = registry.key_for(@resource, interface: false)
39
+ type = Class.new(Schema.base_object)
40
+ type.graphql_name(registry_name)
41
+ type.implements(interface_type)
42
+
38
43
  # Define the actual class that implements the interface
39
44
  registry.set(@resource, type, interface: false)
40
45
  @resource.children.each do |child|
41
46
  if (registered = registry.get(child))
42
- registered[:type].implements(type)
47
+ registered[:type].implements(interface_type)
43
48
  else
44
- self.class.new(child, implements: type).build
49
+ self.class.new(child, implements: interface_type).build
45
50
  end
46
51
  end
47
52
  end
@@ -24,6 +24,7 @@ module GraphitiGql
24
24
  :errors,
25
25
  :error_messages,
26
26
  :nodes,
27
+ :node,
27
28
  :stats
28
29
 
29
30
  Graphiti::Resource.send(:prepend, ScopeTrackable)
@@ -42,20 +43,20 @@ module GraphitiGql
42
43
  def self.except_fields(*fields)
43
44
  let(:except_fields) { fields }
44
45
  end
45
- end
46
- end
47
46
 
48
- def fields
49
- fields = []
50
- resource.attributes.each_pair do |name, config|
51
- (fields << name) if config[:readable]
52
- end
53
- if respond_to?(:only_fields) && only_fields.present?
54
- fields.select! { |f| only_fields.include?(f) }
55
- elsif respond_to?(:except_fields) && except_fields.present?
56
- fields.reject! { |f| except_fields.include?(f) }
47
+ let(:fields) do
48
+ fields = []
49
+ resource.attributes.each_pair do |name, config|
50
+ (fields << name) if config[:readable]
51
+ end
52
+ if respond_to?(:only_fields) && only_fields.present?
53
+ fields.select! { |f| only_fields.include?(f) }
54
+ elsif respond_to?(:except_fields) && except_fields.present?
55
+ fields.reject! { |f| except_fields.include?(f) }
56
+ end
57
+ fields
58
+ end
57
59
  end
58
- fields
59
60
  end
60
61
 
61
62
  def gql_datetime(timestamp, precise = false)
@@ -67,11 +68,8 @@ module GraphitiGql
67
68
  end
68
69
 
69
70
  def proxy
70
- resource.gql(params.merge(fields: fields), ctx)
71
- end
72
-
73
- def query
74
- proxy.query
71
+ q = defined?(query) ? query : nil
72
+ resource.gql(params.merge(fields: fields), ctx, q)
75
73
  end
76
74
 
77
75
  def run
@@ -1,3 +1,3 @@
1
1
  module GraphitiGql
2
- VERSION = "0.2.5"
2
+ VERSION = "0.2.6"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphiti_gql
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.5
4
+ version: 0.2.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lee Richmond
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-06-30 00:00:00.000000000 Z
11
+ date: 2022-07-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: graphql