graphiform 0.2.11 → 0.2.12

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