graphiti_gql 0.2.3 → 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: 5d9dda0537212e47943587af28d28226e8ee6a4ad0d91b65f5074003ab370f17
4
- data.tar.gz: 222fb453e4f73c6e4d0de606bae88aea041b23c48ba28355f575025dff7e3c92
3
+ metadata.gz: a0558a0d0edaf2e03b09fe28ce603afb10eb0cbd02e8aa56be43cfd1044bebab
4
+ data.tar.gz: 69660d61a4191bd6428a2ad33d2f9e3e6a4227c31d4be636a6b886af543f35f3
5
5
  SHA512:
6
- metadata.gz: 8e5a6a8d98b058fb8237750190e6f051712d2f90f5bf49be615f68a594598589afb1811aec0f0fbe79bbcefd457d27a6cf78e84e8e90d539168da9ffd13b9a64
7
- data.tar.gz: 6515ba7accff3edb9490028bc3545f649d2a33877f5d6eb77a32a9183e365241be56b3ba6b99b1c27095390c110ee3c3f7d6743844049dab6576461b22a64c7c
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
@@ -2,6 +2,21 @@ module GraphitiGql
2
2
  module SpecHelper
3
3
  extend ActiveSupport::Concern
4
4
 
5
+ module ScopeTrackable
6
+ def self.prepended(klass)
7
+ klass.class_eval do
8
+ class << self
9
+ attr_accessor :resolved_scope
10
+ end
11
+ end
12
+ end
13
+
14
+ def resolve(scope)
15
+ self.class.resolved_scope = scope
16
+ super
17
+ end
18
+ end
19
+
5
20
  included do
6
21
  extend Forwardable
7
22
  def_delegators :result,
@@ -9,12 +24,38 @@ module GraphitiGql
9
24
  :errors,
10
25
  :error_messages,
11
26
  :nodes,
27
+ :node,
12
28
  :stats
13
29
 
30
+ Graphiti::Resource.send(:prepend, ScopeTrackable)
31
+
14
32
  if defined?(RSpec)
15
33
  let(:params) { {} }
16
34
  let(:resource) { described_class }
17
35
  let(:ctx) { {} }
36
+ let(:only_fields) { [] }
37
+ let(:except_fields) { [] }
38
+
39
+ def self.only_fields(*fields)
40
+ let(:only_fields) { fields }
41
+ end
42
+
43
+ def self.except_fields(*fields)
44
+ let(:except_fields) { fields }
45
+ end
46
+
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
18
59
  end
19
60
  end
20
61
 
@@ -26,9 +67,13 @@ module GraphitiGql
26
67
  end
27
68
  end
28
69
 
70
+ def proxy
71
+ q = defined?(query) ? query : nil
72
+ resource.gql(params.merge(fields: fields), ctx, q)
73
+ end
74
+
29
75
  def run
30
76
  lambda do
31
- proxy = resource.gql(params, ctx)
32
77
  proxy.to_h
33
78
  proxy
34
79
  end
@@ -1,3 +1,3 @@
1
1
  module GraphitiGql
2
- VERSION = "0.2.3"
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.3
4
+ version: 0.2.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lee Richmond
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-06-29 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
@@ -108,7 +108,7 @@ dependencies:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
110
  version: '7.0'
111
- description:
111
+ description:
112
112
  email:
113
113
  - richmolj@gmail.com
114
114
  executables: []
@@ -169,7 +169,7 @@ licenses:
169
169
  - MIT
170
170
  metadata:
171
171
  homepage_uri: https://www.graphiti.dev
172
- post_install_message:
172
+ post_install_message:
173
173
  rdoc_options: []
174
174
  require_paths:
175
175
  - lib
@@ -184,8 +184,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
184
184
  - !ruby/object:Gem::Version
185
185
  version: '0'
186
186
  requirements: []
187
- rubygems_version: 3.3.7
188
- signing_key:
187
+ rubygems_version: 3.0.3.1
188
+ signing_key:
189
189
  specification_version: 4
190
190
  summary: GraphQL support for Graphiti
191
191
  test_files: []