graphiti_gql 0.2.0 → 0.2.1

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: 2a19fd68dc698b8a7284fe80686da9f50ee137365508241cd374e32aa6c505aa
4
- data.tar.gz: d509f137452b90e94986c46267f8728160021de305e599ba47512af9366fe109
3
+ metadata.gz: ff76a3032a8378019cc0034c48cc1bd33302a8d662515fd722d970e642ee355e
4
+ data.tar.gz: 532980890cd827d260bceebd5f944eeb999a561cde6df3e14cff5ddbfaa5f146
5
5
  SHA512:
6
- metadata.gz: 22f8643e779d272d806d53179e5f83e6ca6157fc8c261e03ea3232fdf685faa35ad50c70bd3f5f0f445b8bd4578e616b9a538c9205e330a301a30f370b2c612a
7
- data.tar.gz: ec6e08b56162dc2bb077bfd3cfc5fb5dcf8edcdc3680d940347eb33949f8530967e6d828e0b914f0920a406bad4807d83c643981f9ab0136dd7a3e9e422e068a
6
+ metadata.gz: 8a67a1e359377aa6682b2f23fd0461b2547a05df41c14739d4abf691d879682dd8cd83a4e4deda386855ae6c7a587feb453b2aff5490d2e0d44998955ff6bba9
7
+ data.tar.gz: f5f83d5859fc24f3215723d3abd7d1105dcefc3f02002853f829a4d954923444df0d1a37c0cbbb736dbb79df9745dd1be1c197c6151b07febb117272eb12e8e7
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- graphiti_gql (0.1.0)
4
+ graphiti_gql (0.2.1)
5
5
  graphiti (~> 1.3.9)
6
6
  graphql (~> 2.0)
7
7
  graphql-batch (~> 0.5)
@@ -121,6 +121,24 @@ module GraphitiGql
121
121
  end
122
122
  Graphiti::Scoping::Paginate.send(:prepend, PaginateExtras)
123
123
 
124
+ module ManyToManyExtras
125
+ extend ActiveSupport::Concern
126
+
127
+ class_methods do
128
+ attr_accessor :edge_resource
129
+
130
+ def attribute(*args, &blk)
131
+ @edge_resource = Class.new(Graphiti::Resource) do
132
+ def self.abstract_class?
133
+ true
134
+ end
135
+ end
136
+ @edge_resource.attribute(*args, &blk)
137
+ end
138
+ end
139
+ end
140
+ Graphiti::Sideload::ManyToMany.send(:include, ManyToManyExtras)
141
+
124
142
  module StatsExtras
125
143
  def calculate_stat(name, function)
126
144
  config = @resource.all_attributes[name] || {}
@@ -166,7 +184,9 @@ module GraphitiGql
166
184
  alias_method :filter_precise_datetime_not_eq, :filter_not_eq
167
185
  end
168
186
  end
169
- Graphiti::Adapters::ActiveRecord.send(:include, ActiveRecordAdapterExtras)
187
+ if defined?(Graphiti::Adapters::ActiveRecord)
188
+ Graphiti::Adapters::ActiveRecord.send(:include, ActiveRecordAdapterExtras)
189
+ end
170
190
 
171
191
  Graphiti::Adapters::Abstract.class_eval do
172
192
  class << self
@@ -215,4 +235,17 @@ module GraphitiGql
215
235
  end
216
236
  end
217
237
  Graphiti::Scope.send(:prepend, ScopeExtras)
238
+
239
+ module ActiveRecordManyToManyExtras
240
+ # flipping .includes to .joins
241
+ def belongs_to_many_filter(scope, value)
242
+ scope
243
+ .joins(through_relationship_name)
244
+ .where(belongs_to_many_clause(value, type))
245
+ end
246
+ end
247
+ if defined?(ActiveRecord)
248
+ ::Graphiti::Adapters::ActiveRecord::ManyToManySideload
249
+ .send(:prepend, ActiveRecordManyToManyExtras)
250
+ end
218
251
  end
@@ -2,15 +2,32 @@ module GraphitiGql
2
2
  module Loaders
3
3
  class ManyToMany < Many
4
4
  def assign(ids, proxy)
5
- records = proxy.data
6
5
  thru = @sideload.foreign_key.keys.first
7
6
  fk = @sideload.foreign_key[thru]
7
+ add_join_table_magic(proxy)
8
+ records = proxy.data
8
9
  ids.each do |id|
9
- match = ->(thru) { thru.send(fk) == id }
10
- corresponding = records.select { |record| record.send(thru).any?(&match) }
10
+ corresponding = records.select do |record|
11
+ record.send(:"_edge_#{fk}") == id
12
+ end
11
13
  fulfill(id, [corresponding, proxy])
12
14
  end
13
15
  end
16
+
17
+ private
18
+
19
+ def add_join_table_magic(proxy)
20
+ if defined?(ActiveRecord) && proxy.resource.model.ancestors.include?(ActiveRecord::Base)
21
+ thru = @sideload.foreign_key.keys.first
22
+ thru_model = proxy.resource.model.reflect_on_association(thru).klass
23
+ names = thru_model.column_names.map do |n|
24
+ "#{thru_model.table_name}.#{n} as _edge_#{n}"
25
+ end
26
+ scope = proxy.scope.object
27
+ scope = scope.select(["#{proxy.resource.model.table_name}.*"] + names)
28
+ proxy.scope.object = scope
29
+ end
30
+ end
14
31
  end
15
32
  end
16
33
  end
@@ -2,10 +2,12 @@ module GraphitiGql
2
2
  class Schema
3
3
  module Fields
4
4
  class Attribute
5
- def initialize(name, config)
5
+ # If sideload is present, we're applying m2m metadata to an edge
6
+ def initialize(name, config, sideload = nil)
6
7
  @config = config
7
8
  @name = name
8
9
  @alias = config[:alias]
10
+ @sideload = sideload # is_edge: true
9
11
  end
10
12
 
11
13
  def apply(type)
@@ -13,20 +15,39 @@ module GraphitiGql
13
15
  _config = @config
14
16
  _name = @name
15
17
  _alias = @alias
18
+ _sideload = @sideload
16
19
  opts = @config.slice(:null, :deprecation_reason)
17
20
  type.field(_name, field_type, **opts)
18
21
  type.define_method _name do
19
22
  if (readable = _config[:readable]).is_a?(Symbol)
20
- resource = object.instance_variable_get(:@__graphiti_resource)
23
+ obj = object
24
+ obj = object.node if _sideload
25
+ resource = obj.instance_variable_get(:@__graphiti_resource)
21
26
  unless resource.send(readable)
22
27
  path = Graphiti.context[:object][:current_path].join(".")
23
28
  raise Errors::UnauthorizedField.new(path)
24
29
  end
25
30
  end
31
+
32
+ edge_attrs = nil
33
+ if _sideload
34
+ edge_attrs = object.node.attributes
35
+ .select { |k, v| k.to_s.starts_with?("_edge_") }
36
+ edge_attrs.transform_keys! { |k| k.to_s.gsub("_edge_", "").to_sym }
37
+ end
38
+
26
39
  value = if _config[:proc]
27
- instance_eval(&_config[:proc])
40
+ if _sideload
41
+ instance_exec(edge_attrs, &_config[:proc])
42
+ else
43
+ instance_eval(&_config[:proc])
44
+ end
28
45
  else
29
- object.send(_alias || _name)
46
+ if _sideload
47
+ edge_attrs[_alias || _name]
48
+ else
49
+ object.send(_alias || _name)
50
+ end
30
51
  end
31
52
  return if value.nil?
32
53
  Graphiti::Types[_config[:type]][:read].call(value)
@@ -36,9 +57,12 @@ module GraphitiGql
36
57
  private
37
58
 
38
59
  def field_type
39
- canonical_graphiti_type = Graphiti::Types.name_for(@config[:type])
40
- field_type = GQL_TYPE_MAP[canonical_graphiti_type.to_sym]
41
- field_type = String if @name == :id
60
+ field_type = Graphiti::Types[@config[:type]][:graphql_type]
61
+ if !field_type
62
+ canonical_graphiti_type = Graphiti::Types.name_for(@config[:type])
63
+ field_type = GQL_TYPE_MAP[canonical_graphiti_type.to_sym]
64
+ field_type = String if @name == :id
65
+ end
42
66
  field_type = [field_type] if @config[:type].to_s.starts_with?("array_of")
43
67
  field_type
44
68
  end
@@ -4,7 +4,11 @@ module GraphitiGql
4
4
  class ToMany
5
5
  def initialize(sideload, sideload_type)
6
6
  @sideload = sideload
7
- @sideload_type = sideload_type
7
+ @sideload_type = if customized_edge?
8
+ build_customized_edge_type(sideload_type)
9
+ else
10
+ sideload_type
11
+ end
8
12
  end
9
13
 
10
14
  def apply(type)
@@ -31,6 +35,33 @@ module GraphitiGql
31
35
  Loaders::Many.factory(_sideload, params).load(id)
32
36
  end
33
37
  end
38
+
39
+ private
40
+
41
+ def customized_edge?
42
+ @sideload.type == :many_to_many && @sideload.class.edge_resource
43
+ end
44
+
45
+ def build_customized_edge_type(sideload_type)
46
+ # build the edge class
47
+ prior_edge_class = sideload_type.edge_type_class
48
+ edge_class = Class.new(prior_edge_class)
49
+ edge_resource = @sideload.class.edge_resource
50
+ edge_resource.attributes.each_pair do |name, config|
51
+ next if name == :id
52
+ Schema::Fields::Attribute.new(name, config, @sideload).apply(edge_class)
53
+ end
54
+ registered_parent = Schema.registry.get(@sideload.parent_resource.class)
55
+ parent_name = registered_parent[:type].graphql_name
56
+ edge_class.define_method :graphql_name do
57
+ "#{parent_name}To#{sideload_type.graphql_name}Edge"
58
+ end
59
+
60
+ # build the sideload type with new edge class applied
61
+ klass = Class.new(sideload_type)
62
+ klass.edge_type_class(edge_class)
63
+ klass
64
+ end
34
65
  end
35
66
  end
36
67
  end
@@ -1,3 +1,3 @@
1
1
  module GraphitiGql
2
- VERSION = "0.2.0"
2
+ VERSION = "0.2.1"
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.0
4
+ version: 0.2.1
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-16 00:00:00.000000000 Z
11
+ date: 2022-06-23 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: []
@@ -167,7 +167,7 @@ licenses:
167
167
  - MIT
168
168
  metadata:
169
169
  homepage_uri: https://www.graphiti.dev
170
- post_install_message:
170
+ post_install_message:
171
171
  rdoc_options: []
172
172
  require_paths:
173
173
  - lib
@@ -182,8 +182,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
182
182
  - !ruby/object:Gem::Version
183
183
  version: '0'
184
184
  requirements: []
185
- rubygems_version: 3.0.3.1
186
- signing_key:
185
+ rubygems_version: 3.3.7
186
+ signing_key:
187
187
  specification_version: 4
188
188
  summary: GraphQL support for Graphiti
189
189
  test_files: []