graphiti_gql 0.2.5 → 0.2.8

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: 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: []