graphiform 0.2.11 → 0.2.12

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: 7ee58551bb7e16aeccf79e81c5665e74cfa9bd6750c517b02eaef9f28deefe24
4
- data.tar.gz: 1d37cf0e858774a84d88dd87e6bd67c00bfd5266c76ceb7aa656dc612019d275
3
+ metadata.gz: 68647a1e2a4781554b98f3e34e4b8d517bdee49c76459aa8445dffb13dd59f07
4
+ data.tar.gz: b66dcc28e233bf23a4468a1af531d1c650c50bf3d3054687e43831ee6fd3826f
5
5
  SHA512:
6
- metadata.gz: 056d9d69dfe38e12fd40dae4b62a758f86dea1daddb8c1f140910a5ea86beb51f1ecbd19a38b624bf51ee654058d4a63f7177781e6dde548c33bd2543d92eecd
7
- data.tar.gz: 84db19af1351992f07456ba23197661e8fc3a5843496ec2e2c53641f94786cbc7b8d675fd20566211e8ca419356f5b7d923de1b4da1f2a9a02b080095e80a3b8
6
+ metadata.gz: 9d87c2c3723f8e643a3370bce93a86231466aa6f8d90ef264b308942cc6b7d832e1c4db4e9ab3a503d6f13804f3beedaef70106fd253c7fb67f9ad4863af01b4
7
+ data.tar.gz: 6f4c3e3784b7c70aea0044fff3bda3dd9c79780e5835ee2ea2593025be264da83798a6379ea0f9acbbe807e08fb237946f7e04910c746f17a480ad083247bc2b
data/lib/graphiform.rb CHANGED
@@ -19,4 +19,12 @@ module Graphiform
19
19
  include Graphiform::Fields
20
20
  end
21
21
  end
22
+
23
+ def self.configuration
24
+ @configuration ||= {}
25
+ end
26
+
27
+ def self.configure
28
+ yield(configuration)
29
+ end
22
30
  end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Graphiform
4
+ class AssociationSource < GraphQL::Dataloader::Source
5
+ def initialize(model, attribute, **options)
6
+ super()
7
+
8
+ @model = model
9
+ @attribute = attribute
10
+ @options = options
11
+ end
12
+
13
+ def fetch(values)
14
+ normalized_values = normalize_values(values)
15
+ records = query(normalized_values.uniq).to_a
16
+ results(normalized_values, records)
17
+ end
18
+
19
+ def query(values)
20
+ query = @model.where(@attribute => values)
21
+
22
+ query = query.includes(@options[:includes]) if @options[:includes].present? && query.respond_to?(:includes)
23
+ query = query.apply_filters(@options[:where].to_h) if @options[:where].present? && query.respond_to?(:apply_filters)
24
+ query = query.apply_sorts(@options[:sort].to_h) if @options[:sort].present? && query.respond_to?(:apply_sorts)
25
+
26
+ query
27
+ end
28
+
29
+ def normalize_value(value)
30
+ value = value.downcase if !@options[:case_sensitive] && value.is_a?(String)
31
+
32
+ value
33
+ end
34
+
35
+ def normalize_values(values)
36
+ type_for_attribute = @model.type_for_attribute(@attribute) if @model.respond_to?(:type_for_attribute)
37
+ values.map do |value|
38
+ value = type_for_attribute.cast(value) if type_for_attribute.present?
39
+ normalize_value(value)
40
+ end
41
+ end
42
+
43
+ def results(values, records)
44
+ record_attributes = records.map { |record| normalize_value(record[@attribute]) }
45
+ values.map do |value|
46
+ if @options[:multi]
47
+ indexes = record_attributes.each_index.select { |index| record_attributes[index] == value }
48
+ indexes.map { |index| index && records[index] }
49
+ else
50
+ index = record_attributes.index(value)
51
+ index && records[index]
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -3,6 +3,7 @@
3
3
  require 'active_support/concern'
4
4
 
5
5
  require 'graphiform/helpers'
6
+ require 'graphiform/association_source'
6
7
 
7
8
  module Graphiform
8
9
  module Core
@@ -174,18 +175,61 @@ module Graphiform
174
175
  end
175
176
  end
176
177
 
177
- def graphql_create_resolver(method_name, resolver_type = graphql_type, read_prepare: nil, read_resolve: nil, null: true, **)
178
+ def graphql_create_resolver(method_name, resolver_type = graphql_type, read_prepare: nil, read_resolve: nil, null: true, skip_dataloader: false, case_sensitive: Graphiform.configuration[:case_sensitive], **)
178
179
  Class.new(graphql_base_resolver) do
179
180
  type resolver_type, null: null
180
181
 
181
182
  define_method :base_resolve do |**args|
182
183
  @value = object
183
184
 
184
- @value = instance_exec(@value, context, &read_resolve) if read_resolve
185
- @value = @value.public_send(method_name) if !read_resolve && @value.respond_to?(method_name)
186
- @value = instance_exec(@value, context, &read_prepare) if read_prepare
185
+ association_def = @value.association(method_name)&.reflection
186
+ join_keys = association_def&.join_keys
187
187
 
188
- apply_built_ins(**args)
188
+ skip_dataloader ||=
189
+ !association_def ||
190
+ !Helpers.dataloader_support?(dataloader, association_def, join_keys.foreign_key) ||
191
+ read_resolve ||
192
+ read_prepare ||
193
+ args[:group]
194
+
195
+ if skip_dataloader
196
+ @value = instance_exec(@value, context, &read_resolve) if read_resolve
197
+ @value = @value.public_send(method_name) if !read_resolve && @value.respond_to?(method_name)
198
+ @value = instance_exec(@value, context, &read_prepare) if read_prepare
199
+
200
+ apply_built_ins(**args)
201
+ else
202
+ dataloader
203
+ .with(
204
+ AssociationSource,
205
+ association_def.klass,
206
+ join_keys.key,
207
+ where: args[:where],
208
+ sort: args[:sort],
209
+ multi: true,
210
+ case_sensitive: case_sensitive,
211
+ )
212
+ .load(
213
+ @value.public_send(join_keys.foreign_key)
214
+ )
215
+ end
216
+ end
217
+ end
218
+ end
219
+
220
+ def graphql_create_association_resolver(association_def, resolver_type, null: true, skip_dataloader: false, case_sensitive: nil, **)
221
+ Class.new(::Resolvers::BaseResolver) do
222
+ type resolver_type, null: null
223
+
224
+ define_method :resolve do |*|
225
+ join_keys = association_def.join_keys
226
+
227
+ skip_dataloader ||= !Helpers.dataloader_support?(dataloader, association_def, join_keys.foreign_key)
228
+
229
+ return object.public_send(association_def.name) if skip_dataloader
230
+
231
+ value = object.public_send(join_keys.foreign_key)
232
+ dataloader.with(AssociationSource, association_def.klass, join_keys.key, case_sensitive: case_sensitive).load(value)
189
233
  end
190
234
  end
191
235
  end
@@ -12,16 +12,17 @@ module Graphiform
12
12
  as: nil,
13
13
  **options
14
14
  )
15
- column_def = column(as || name)
16
- association_def = association(as || name)
15
+ identifier = as || name
16
+ column_def = column(identifier)
17
+ association_def = association(identifier)
17
18
 
18
19
  graphql_add_column_field(name, column_def, as: as, **options) if column_def.present?
19
20
  graphql_add_association_field(name, association_def, as: as, **options) if association_def.present?
20
21
  graphql_add_method_field(name, as: as, **options) unless column_def.present? || association_def.present?
21
22
 
22
- graphql_add_scopes_to_filter(name, as || name)
23
- graphql_field_to_sort(name, as || name)
24
- graphql_field_to_grouping(name, as || name)
23
+ graphql_add_scopes_to_filter(name, identifier)
24
+ graphql_field_to_sort(name, identifier)
25
+ graphql_field_to_grouping(name, identifier)
25
26
  end
26
27
 
27
28
  def graphql_writable_field(
@@ -266,6 +267,8 @@ module Graphiform
266
267
  include_connection: true,
267
268
  read_prepare: nil,
268
269
  read_resolve: nil,
270
+ skip_dataloader: false,
271
+ case_sensitive: Graphiform.configuration[:case_sensitive],
269
272
  **options
270
273
  )
271
274
  unless association_def.klass.respond_to?(:graphql_type)
@@ -291,7 +294,9 @@ module Graphiform
291
294
  klass.graphql_connection,
292
295
  read_prepare: read_prepare,
293
296
  read_resolve: read_resolve,
294
- null: false
297
+ null: false,
298
+ skip_dataloader: true,
299
+ case_sensitive: case_sensitive
295
300
  ),
296
301
  false,
297
302
  **options
@@ -306,10 +311,17 @@ module Graphiform
306
311
  [klass.graphql_type],
307
312
  read_prepare: read_prepare,
308
313
  read_resolve: read_resolve,
309
- null: false
314
+ null: false,
315
+ skip_dataloader: skip_dataloader,
316
+ case_sensitive: case_sensitive
310
317
  )
311
318
  else
312
- klass.graphql_type
319
+ klass.graphql_create_association_resolver(
320
+ association_def,
321
+ klass.graphql_type,
322
+ skip_dataloader: skip_dataloader,
323
+ case_sensitive: case_sensitive
324
+ )
313
325
  end
314
326
  )
315
327
 
@@ -72,5 +72,15 @@ module Graphiform
72
72
  association_def.klass.send(method).respond_to?(:arguments) &&
73
73
  !association_def.klass.send(method).arguments.empty?
74
74
  end
75
+
76
+ def self.dataloader_support?(dataloader, association_def, keys)
77
+ (
78
+ association_def.present? &&
79
+ !association_def.polymorphic? &&
80
+ !association_def.through_reflection? &&
81
+ !keys.is_a?(Array) &&
82
+ !dataloader.is_a?(GraphQL::Dataloader::NullDataloader)
83
+ )
84
+ end
75
85
  end
76
86
  end
@@ -1,3 +1,3 @@
1
1
  module Graphiform
2
- VERSION = '0.2.11'.freeze
2
+ VERSION = '0.2.12'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphiform
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.11
4
+ version: 0.2.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - jayce.pulsipher
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-07-12 00:00:00.000000000 Z
11
+ date: 2021-07-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 0.2.7
47
+ version: 0.2.9
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 0.2.7
54
+ version: 0.2.9
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: appraisal
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -120,6 +120,7 @@ files:
120
120
  - Rakefile
121
121
  - lib/graphiform.rb
122
122
  - lib/graphiform/active_record_helpers.rb
123
+ - lib/graphiform/association_source.rb
123
124
  - lib/graphiform/core.rb
124
125
  - lib/graphiform/fields.rb
125
126
  - lib/graphiform/helpers.rb