graphiti_gql 0.2.5 → 0.2.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b9a1b76315488d9389a214fc640f6029d9e1a05a08182ebbdb9ed7958565e4aa
4
- data.tar.gz: e4d6952a6929bf8310a99ba5b2d40e3821fe8bad51e89b3012c041fed9f1c47a
3
+ metadata.gz: c8711fac905c21ac485bec3ead197d2c5a8e2135eb5fcf1ff4156fec2a34d3ec
4
+ data.tar.gz: 82a643591b6f630d78d67e480cf915b8dbf1c0531fa0c817f204a9ae405d237c
5
5
  SHA512:
6
- metadata.gz: 30cb9c3f67aa059d0e68845fc64aee6313d9f0d14d36e19024357c619ca15e176d4178ae2836055c22b407a53187038b21b8447007e37fbed04ab70330c12ff4
7
- data.tar.gz: 6ece60976b6d36294e9ef01e8521efdf26d9637b28c6fcfec833e3f2a81d493eece073137071e3373f2ac948c786c18e79734904b62e369a1cc0c0353860d71d
6
+ metadata.gz: 6a6935dda01d0d68bacfc8c49252469322e93c96613a852f092dc76aa80cc44545b7e3c3d478fd5da28d6039c1a33940c9164f8bb1aad0b8018b1d2a5c92de72
7
+ data.tar.gz: fd9004e64db1c3dc39321e4eb2df56e5a7bf37a221c5323b062ddce182446ea1a4285649f61fdbb8508ac0b1a654c3311a7429bdc535f2589866b053c9d0617e
@@ -0,0 +1,2 @@
1
+ enabled:
2
+ - cla
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- graphiti_gql (0.2.2)
4
+ graphiti_gql (0.2.7)
5
5
  graphiti (~> 1.3.9)
6
6
  graphql (~> 2.0)
7
7
  graphql-batch (~> 0.5)
@@ -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,42 @@ 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
+ return unless respond_to?(:belongs_to_many_filter) # activerecord
166
+ self_ref = self
167
+ fk_type = parent_resource_class.attributes[:id][:type]
168
+ fk_type = :hash if polymorphic?
169
+ filters = resource_class.config[:filters]
150
170
 
151
- def attribute(*args, &blk)
152
- @edge_resource = Class.new(Graphiti::Resource) do
153
- def self.abstract_class?
154
- true
171
+ # Keep the options, apply the eq proc
172
+ if (filter = filters[inverse_filter.to_sym])
173
+ if filter[:operators][:eq].nil?
174
+ filter[:operators][:eq] = proc do |scope, value|
175
+ self_ref.belongs_to_many_filter(scope, value)
155
176
  end
156
177
  end
157
- @edge_resource.attribute(*args, &blk)
158
178
  end
159
179
  end
160
180
  end
161
- Graphiti::Sideload::ManyToMany.send(:include, ManyToManyExtras)
181
+ Graphiti::Sideload::ManyToMany.send(:prepend, ManyToManyExtras)
162
182
 
163
183
  module StatsExtras
164
184
  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
@@ -4,11 +4,8 @@ module GraphitiGql
4
4
  class ToMany
5
5
  def initialize(sideload, sideload_type)
6
6
  @sideload = sideload
7
- @sideload_type = if customized_edge?
8
- build_customized_edge_type(sideload_type)
9
- else
10
- sideload_type
11
- end
7
+ @sideload_type = sideload_type
8
+ @connection_type = find_or_build_connection
12
9
  end
13
10
 
14
11
  def apply(type)
@@ -18,7 +15,7 @@ module GraphitiGql
18
15
  extras: [:lookahead]
19
16
  }
20
17
  opts[:extensions] = [RelayConnectionExtension] unless has_one?
21
- field_type = has_one? ? @sideload_type : @sideload_type.connection_type
18
+ field_type = has_one? ? @sideload_type : @connection_type
22
19
  field = type.field @sideload.name,
23
20
  field_type,
24
21
  **opts
@@ -41,25 +38,39 @@ module GraphitiGql
41
38
  @sideload.type == :many_to_many && @sideload.class.edge_resource
42
39
  end
43
40
 
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)
41
+ def find_or_build_connection
42
+ if customized_edge?
43
+ prior = @sideload_type.connection_type
44
+ klass = Class.new(prior)
45
+ registered_parent = Schema.registry.get(@sideload.parent_resource.class)
46
+ parent_name = registered_parent[:type].graphql_name
47
+ name = "#{parent_name}To#{@sideload_type.graphql_name}Connection"
48
+ klass.graphql_name(name)
49
+ edge_type_class = build_edge_type_class(@sideload_type)
50
+ edge_type_class.node_type(prior.node_type)
51
+ klass.edge_type(edge_type_class)
52
+ klass
53
+ else
54
+ @sideload_type.connection_type
55
+ end
56
+ end
57
+
58
+ def build_edge_type_class(sideload_type)
59
+ prior_edge_type_class = sideload_type.edge_type_class
60
+ edge_type_class = Class.new(prior_edge_type_class)
48
61
  edge_resource = @sideload.class.edge_resource
49
62
  edge_resource.attributes.each_pair do |name, config|
50
63
  next if name == :id
51
- Schema::Fields::Attribute.new(name, config, @sideload).apply(edge_class)
64
+ Schema::Fields::Attribute.new(name, config, @sideload).apply(edge_type_class)
52
65
  end
53
66
  registered_parent = Schema.registry.get(@sideload.parent_resource.class)
54
67
  parent_name = registered_parent[:type].graphql_name
55
- edge_class.define_method :graphql_name do
56
- "#{parent_name}To#{sideload_type.graphql_name}Edge"
68
+ edge_type_class_name = "#{parent_name}To#{sideload_type.graphql_name}Edge"
69
+ edge_type_class.define_method :graphql_name do
70
+ edge_type_class_name
57
71
  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
72
+ edge_type_class.graphql_name(edge_type_class_name)
73
+ edge_type_class
63
74
  end
64
75
  end
65
76
  end
@@ -23,12 +23,15 @@ module GraphitiGql
23
23
  Registry.instance
24
24
  end
25
25
 
26
+ # TODO - when no sorts schema error, when no filters schema error
26
27
  def define_filters(field)
27
28
  filter_type = generate_filter_type(field)
28
29
  required = @resource.filters.any? { |name, config|
29
30
  value = !!config[:required]
30
31
  if @sideload
31
- value && @sideload.foreign_key != name
32
+ fk = @sideload.foreign_key
33
+ fk = fk.values.first if fk.is_a?(Hash)
34
+ value && fk != name
32
35
  else
33
36
  value
34
37
  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.8"
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.8
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-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
@@ -108,13 +108,14 @@ 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: []
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"
@@ -169,7 +170,7 @@ licenses:
169
170
  - MIT
170
171
  metadata:
171
172
  homepage_uri: https://www.graphiti.dev
172
- post_install_message:
173
+ post_install_message:
173
174
  rdoc_options: []
174
175
  require_paths:
175
176
  - lib
@@ -184,8 +185,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
184
185
  - !ruby/object:Gem::Version
185
186
  version: '0'
186
187
  requirements: []
187
- rubygems_version: 3.0.3.1
188
- signing_key:
188
+ rubygems_version: 3.3.7
189
+ signing_key:
189
190
  specification_version: 4
190
191
  summary: GraphQL support for Graphiti
191
192
  test_files: []