graphiti_gql 0.2.4 → 0.2.7

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: 84a7ebf615007ac087b7bab32e53b78fc1bbdb7abcd9d65e38beac1ec7e578fc
4
- data.tar.gz: d5c625d0e34f750d8fc3bc8c71f39ccabb70aa1c87340978620e965137e15feb
3
+ metadata.gz: d38c8d27dc214efd323ee98932bcb858bca8553e45c5e4428858b3b5503db44d
4
+ data.tar.gz: ae38e08ba55f6c38b464ed9a3cbd592394568c080aac2361d0549adea259b9fe
5
5
  SHA512:
6
- metadata.gz: e8ea8defdb4712239187bcbb14a0d5dbeee9e52bf11a7c32dd747da2eae62247ef66fda15dd63b57886920a895f8215fe7a33b8eb3dc156194b3b2e3fd2f75c6
7
- data.tar.gz: 42f885befb9c54a6b915642e40f2d2bb8704571c901c392f2a6fe11196d805113ca7af546ff15db7b336fdceff172ba2c27e9f443381462db26b4b44461eab6b
6
+ metadata.gz: d50257d774787869a18187e76e924503fb34dfad8c4d93fd73d99289fc203626d120585448bc646175cb9ff80e607df5c374a6207a95732aeccedb2d20ea9d39
7
+ data.tar.gz: e1f1ff11574682dd8946907f2e76e3b9279c08039e29e4bc1f53436f184c1e6bd0e04f2ef52f391526abd1d837ef6a9dbd3f1a8a617528ee90942857b66d9706
@@ -0,0 +1,2 @@
1
+ enabled:
2
+ - cla
@@ -1,17 +1,26 @@
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) }
20
+ elsif value.key?(:nodes)
21
+ hash[key] = value[:nodes].map { |n| Node.new(n, sideload.resource.class) }
13
22
  else
14
- hash[key] = Node.new(sideload.resource.class, value)
23
+ hash[key] = Node.new(value, sideload.resource.class)
15
24
  end
16
25
  end
17
26
  end
@@ -19,6 +28,15 @@ module GraphitiGql
19
28
  super(hash)
20
29
  end
21
30
 
31
+ def edge(name, node_id)
32
+ found = @edges[name].empty? ? nil : @edges[name]
33
+ if found && node_id
34
+ found.find { |f| f.instance_variable_get(:@node_id) == node_id.to_s }
35
+ else
36
+ found
37
+ end
38
+ end
39
+
22
40
  def decoded_id
23
41
  Base64.decode64(self.id)
24
42
  end
@@ -29,7 +47,8 @@ module GraphitiGql
29
47
  end
30
48
 
31
49
  class Proxy
32
- def initialize(resource, params, ctx)
50
+ def initialize(resource, params, ctx, query)
51
+ @query = query
33
52
  @resource = resource
34
53
  @ctx = ctx
35
54
  @params = params.deep_transform_keys { |key| key.to_s.camelize(:lower).to_sym }
@@ -46,10 +65,18 @@ module GraphitiGql
46
65
  result
47
66
  end
48
67
 
68
+ def node(id)
69
+ nodes.find { |n| n.id == id.to_s }
70
+ end
71
+
49
72
  def nodes
50
73
  return [] unless data
51
- nodes = edges.map { |e| underscore(e[:node]) }
52
- nodes.map { |n| Node.new(@resource, n) }
74
+ elements = if edges
75
+ edges.map { |e| e[:node] }
76
+ else
77
+ data[data.keys.first][:nodes] || []
78
+ end
79
+ elements.map { |n| Node.new(underscore(n), @resource) }
53
80
  end
54
81
  alias :to_a :nodes
55
82
 
@@ -85,10 +112,14 @@ module GraphitiGql
85
112
  underscore(data[data.keys.first][:pageInfo])
86
113
  end
87
114
 
115
+ # barf
88
116
  def query
117
+ return @query if @query
118
+
89
119
  name = Schema.registry.key_for(@resource)
90
- filter_bang = "!" if @resource.filters.values.any? { |f| f[:required] }
91
120
  sortvar = "$sort: [#{name}Sort!]," if @resource.sorts.any?
121
+ filter_bang = "!" if @resource.filters.values.any? { |f| f[:required] }
122
+ filtervar = "$filter: #{name}Filter#{filter_bang}," if @resource.filters.any?
92
123
 
93
124
  if !(fields = @params[:fields])
94
125
  fields = []
@@ -99,7 +130,7 @@ module GraphitiGql
99
130
 
100
131
  q = %|
101
132
  query #{name} (
102
- $filter: #{name}Filter#{filter_bang},
133
+ #{filtervar}
103
134
  #{sortvar}
104
135
  $first: Int,
105
136
  $last: Int,
@@ -107,7 +138,7 @@ module GraphitiGql
107
138
  $after: String,
108
139
  ) {
109
140
  #{@resource.graphql_entrypoint} (
110
- filter: $filter,
141
+ #{ 'filter: $filter,' if filtervar }
111
142
  #{ 'sort: $sort,' if sortvar }
112
143
  first: $first,
113
144
  last: $last,
@@ -118,6 +149,7 @@ module GraphitiGql
118
149
  node {|
119
150
 
120
151
  fields.each do |name|
152
+ next if name.is_a?(Hash)
121
153
  q << %|
122
154
  #{name.to_s.camelize(:lower)}|
123
155
  end
@@ -129,17 +161,36 @@ module GraphitiGql
129
161
  sideload = @resource.sideload(inc.to_sym)
130
162
  to_one = [:belongs_to, :has_one, :polymorphic_belongs_to].include?(sideload.type)
131
163
  indent = " " if !to_one
164
+
165
+ edge_fields = []
166
+ runtime_sideload_fields = @params[:fields].find { |f| f.is_a?(Hash) && f.key?(inc.to_sym) }
167
+ if runtime_sideload_fields
168
+ runtime_sideload_fields = runtime_sideload_fields.values
169
+ edge_fields = runtime_sideload_fields.find { |f| f.is_a?(Hash) && f.key?(:edge) }
170
+ runtime_sideload_fields = runtime_sideload_fields.reject { |f| f.is_a?(Hash) }
171
+ edge_fields = edge_fields[:edge] if edge_fields
172
+ end
173
+
132
174
  q << %|
133
175
  #{inc.to_s.camelize(:lower)} {|
134
176
  if !to_one
135
177
  q << %|
136
- edges {
178
+ edges {|
179
+
180
+ edge_fields.each do |ef|
181
+ q << %|
182
+ #{ef.to_s.camelize(:lower)}|
183
+ end
184
+
185
+ q << %|
137
186
  node {|
138
187
  end
139
188
 
140
- r = @resource.sideload(inc.to_sym).resource
141
- r.attributes.each_pair do |name, config|
142
- next unless config[:readable]
189
+ sideload_fields = runtime_sideload_fields
190
+ if sideload_fields.blank?
191
+ sideload_fields = @resource.sideload(inc.to_sym).resource.attributes.select { |_, config| config[:readable] }.map(&:first)
192
+ end
193
+ sideload_fields.each do |name|
143
194
  q << %|
144
195
  #{indent}#{name.to_s.camelize(:lower)}|
145
196
  end
@@ -200,8 +251,8 @@ module GraphitiGql
200
251
  end
201
252
 
202
253
  class_methods do
203
- def gql(params = {}, ctx = {})
204
- Proxy.new(self, params, ctx)
254
+ def gql(params = {}, ctx = {}, query = nil)
255
+ Proxy.new(self, params, ctx, query)
205
256
  end
206
257
  end
207
258
  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,29 +24,37 @@ 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
- let(:params) do
16
- fields = []
17
- resource.attributes.each_pair do |name, config|
18
- (fields << name) if config[:readable]
19
- end
20
- { fields: fields }
21
- end
33
+ let(:params) { {} }
22
34
  let(:resource) { described_class }
23
35
  let(:ctx) { {} }
36
+ let(:only_fields) { [] }
37
+ let(:except_fields) { [] }
24
38
 
25
39
  def self.only_fields(*fields)
26
- before do
27
- fields.each { |f| params[:fields].select! { |p| p == f } }
28
- end
40
+ let(:only_fields) { fields }
29
41
  end
30
42
 
31
43
  def self.except_fields(*fields)
32
- before do
33
- fields.each { |f| params[:fields].reject! { |p| p == f } }
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) }
34
56
  end
57
+ fields
35
58
  end
36
59
  end
37
60
  end
@@ -44,9 +67,13 @@ module GraphitiGql
44
67
  end
45
68
  end
46
69
 
70
+ def proxy
71
+ q = defined?(query) ? query : nil
72
+ resource.gql(params.merge(fields: fields), ctx, q)
73
+ end
74
+
47
75
  def run
48
76
  lambda do
49
- proxy = resource.gql(params, ctx)
50
77
  proxy.to_h
51
78
  proxy
52
79
  end
@@ -1,3 +1,3 @@
1
1
  module GraphitiGql
2
- VERSION = "0.2.4"
2
+ VERSION = "0.2.7"
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.4
4
+ version: 0.2.7
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-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: graphql
@@ -115,6 +115,7 @@ executables: []
115
115
  extensions: []
116
116
  extra_rdoc_files: []
117
117
  files:
118
+ - ".github/probots.yml"
118
119
  - ".gitignore"
119
120
  - ".rspec"
120
121
  - ".travis.yml"